1) Introduction of common compilation parameters
GCC can be said to be a great collection of compilers. Supports a large stack of languages such as C, C + +, OBJECT-C, Java, Fortran, Pascal, Ada, and supports almost all 32-bit CPUs and some 16-bit, 8-bit CPUs. As a result, almost all open source operating systems, commercial UNIX operating systems, and embedded development use GCC as compilers. The Wind River also uses GCC to compile VxWorks code. The following are some of the most common compilation parameters (described only when GCC is used as the C compiler). For more parameters, refer to the GCC documentation. Or tornado Online Manual in the Start menu.
-O optimization parameters. The following can be represented by the number of optimization level-o0 represents not optimized,-O1,-O2,-O3 optimization degree in turn. Most platforms have the highest level of-O3, which means that numbers after 3 are basically useless. In addition, we recommend that you use only the highest-o2. Most open-source operating systems are compiled using the-o2 parameter thoroughly tempered. The optimization level is too high for debugging. In order to optimize, the compiler may disrupt the order of some of the code, causing us to step into the trace in the C source code to jump.
There is also a-os that is optimized for code size, which can be used to generate as short a machine code as possible.
-e means that only the code is preprocessed and not compiled. That is, only the header file inclusions and macro definitions are expanded. If the output file is not specified with-O, the result of the processing is output to the console.
-C means to assemble and compile the code only, not to link. That is, the source code is compiled into an. o file.
-S means that only the assembly is compiled without compiling and linking. That is, the source code is translated into assembly instructions. Gcc-s generated files are less readable than objdump. o file generated results are comfortable. It is recommended to analyze assembly instructions using the Objdump command to decompile.
-o filename indicates the output file name. Generally with-e-c-s three commands to use. Like what:
Gcc-c A.c-o A.O
GCC-E A.c-o A.E
-ansi indicates that other features other than the ANSI C standard are considered syntactically wrong. such as//single-line comments. It is important to note that this option is only strictly enforced for most ANSI standards.
-std= can be followed with c89 C99 gnu89 and other standards. Indicates which standard the compiler uses to compile. For example, the use of the C89 standard-std=c89, if you want some of the GCC extension features to use-std=gnu89. This gnu89 is the default value, which is the extension with C89 standard +GCC when nothing is specified. -ansi is the equivalent of-std=c89.
-pedantic strictly enforces the ANSI C standard. Typically used in conjunction with-ansi, the source code is subject to the ANSI C standard Strictly. You can print out more alarm information than-wall.
-W Turn off all alarm prompts
Although the-wall is-wall but is not open to all alarm prompts but most, but the following the-W start alarm needs to be opened separately.
-W Display more detailed information on some alarms
-wfloat-equal floating-point number directly using = = To determine whether the alarm is equal
-wtraditional If you use the original C language has and C standardized after the abandoned features on the alarm
-wshadow Alarms the shadow variable. Like what:
There is a global variable ncount, when you write the function has a parameter also called Ncount. The compiler will alert you that the local parameter ncount function and the global ncount does not work. If that's not the case, you need to change the code.
-werror turns all alarms into compile errors. Stop compiling as soon as you have an alarm.
-G generates debug information. The back is like-O, with numbers indicating richness of information. It is essential that you do not follow the numbers by default to-G2,-G1. -G3 even the macro information is appended. Some debuggers can use this information to expand macros while debugging. Generally just use-G. Note Additional debugging information will significantly increase the elf file size, but will not affect the size of the generated code.
-fstrict-aliasing The following is a separate introduction
-mlong-calls for ARM platforms, this parameter is required if the. o file that you want to compile is dynamically loaded by the shell under the LD command. Otherwise you'll be prompted
Relocation value does not fit in.
BTW: This is Wang Luxian to try out. I learned it from stealing.
-d defines the macro. Like what
Gcc-d_debug=1-dver= "1.0"-C a.c-o A.O
-fvolatile forces all pointer accesses to be of volatile type, that is, forcing the data to be accessed inside. If you are unsure whether all pointers pointing to the device address space are recommended for the volatile type declaration, add this parameter. will lose the optimization effect.
-I dirname instructs the preprocessor to add dirname to the Include file search path. Like what
Gcc-c a.c-i. /include-i./include-o A.O
-include filename contains the filename as the header file in front of the source file. Like what
Gcc-include. /common.h-c A.c-o A.O
Effects and A.C # include ". /common.h "is the same. Note that-include contains header files that will be equivalent to inserting # include in the first line of code
Recommended compilation Parameters-o2-g-fno-strict-aliasing-wall-fvolatile-i./
2) How to generate dependencies
When writing makefile manually, you need to determine which header files a source file depends on. It is troublesome to have each file open to look at the header file of include, and some of the absolute paths of header files with relative path include are not OK. So we can use compilers to generate dependencies for us.
C:\>CCARM-MM stone.c
Stone.o:stone.c e://tornado2.2/target/h/types/vxarch.h \
e://tornado2.2/target/h/arch/arm/archarm.h \
e://tornado2.2/target/h/arch/arm/arm.h \
E://TORNADO2.2/TARGET/H/TYPES/VXPARAMS.H \
E://tornado2.2/target/h/types/vxtypesbase.h \
E://tornado2.2/target/h/types/vxtypesold.h \
E://TORNADO2.2/TARGET/H/SYS/TYPES.H \
E://TORNADO2.2/TARGET/H/TYPES/VXTYPES.H \
E://TORNADO2.2/TARGET/H/TOOL/GNU/TOOLMACROS.H \
e://tornado2.2/target/h/vwmodnum.h \
E://tornado2.2/target/h/objlib.h \
E://tornado2.2/target/h/errno.h \
E://tornado2.2/target/h/memlib.h \
E://tornado2.2/target/h/private/objlibp.h \
E://TORNADO2.2/TARGET/H/VXWORKS.H \
E://tornado2.2/target/h/objlib.h \
E://tornado2.2/target/h/classlib.h \
E://tornado2.2/target/h/private/classlibp.h \
e://tornado2.2/target/h/vwmodnum.h \
E://tornado2.2/target/h/memlib.h \
E://tornado2.2/target/h/private/objlibp.h \
E://tornado2.2/host/x86-win32/lib/gcc-lib/arm-wrs-vxworks/2.9-010413/include/stdarg.h
Take the absolute path and use the variable instead of the tornado path to put it in the makefile. Note that it is best to keep the full compilation command-line option when generating dependencies, just replace-C with-mm, such as ccarm-mm-dxxx-dyyy-fno-strict-aliasing-dzzz=123 STONE.C, so that if some macro definitions affect the include, we can still generate the correct dependencies.
3) Very important strict aliasing rules
Suppose someone asks you (i++) + (++i) + (++i++) What the result is, and you may be directly answering this with the compiler implementation. But if someone asks you,
INT ABC ()
{
Short a[2];
int *b = (int *) A;
a[0]=0x1111;
a[1]=0x1111;
*b = 0x22222222;
printf ("%x%x\n", a[0], a[1]);
return 0;
}
How much of this function is running on a single board. You may not hesitate to say 2222 2222.
In fact, this procedure is not necessarily the same as before (i++) + (++i) + (++i++), and its results are related to compiler implementation and compilation parameters. If you do not believe, you find an arm of the single Board (other platform I have not tried), with the ccarm-c-O2 parameter compiled results are 1111 1111. If you compile with parameter ccarm-c-o1 The result is 2222 2222. The parameters that result in two results are not-o2 and-o1 but a compilation parameter called Strict-aliasing. This parameter is open by default when-o2 is optimized. Just two different results were caused by-fstrict-aliasing and-fno-strict-aliasing. That is to say-o2 result is 1111 1111,-o2-fno-strict-aliasing result is programmer expected 2222 2222.
The reason for this is that the compiler assumes that the memory that the different types of pointers point to does not overlap to optimize-fstrict-aliasing.
As an example of the above example, because the type A and B are different, when the-fstrict-aliasing is opened, the compiler assigns values to the *b without affecting the values inside the A array. The compiler analyzes when optimizing: since the value of a array is not modified after assignment, the next time you read the value of a array, there is no need to read it from memory. So the printf line is optimized to take the value from the register when it takes a[0],a[1]. The result is 1111 1111 printed.
If-fno-strict-aliasing is used, however, the compiler thinks any pointer may point to the same memory area. So the compiler thinks it might affect the value of a in the *b assignment. So the compiler to the printf line to pass the parameters of the time that the register a[0],a[1] value is not necessarily correct, only the memory is reliable, so can only be honest from the stack to take the value.
The above analysis is done on the arm platform. I also made comparisons under x86, but both parameters were compiled with a result of 2222 2222. The main reason is that the number of universal registers under the x86 is very small, and it is not always possible to put variables in the register when optimization, so this example doesn't affect x86. But in the research and development support system, someone has suggested that-o2 generated code is problematic, because strict aliasing influence.
2007-10-08 gcc compiler optimization problem Consult, please enter the cattle!
The code for the problem appears as follows:
Xxxx_uint32 Xxxx_map_get_free
(
Xxxx_map_ptr io_map_p
)
{
Xxxx_void_ptr cur_data_p;
Xxxx_buff_ptr buff_p;
buff_p = io_map_p->buff_p;
Cur_data_p = buff_p->free_data_p;
buff_p->free_data_p = * (xxxx_void_ptr*) cur_data_p;
* (xxxx_uint32*) cur_data_p = 0;
buff_p->used + +;
return xxxx_success;
}
Once we know this feature, we need to pay special attention to the code when we write it. Do not lazy to use the force pointer conversion to assign value to BUF. The security version of the above program is:
INT ABC ()
{
Union
{
Short a[2];
int b;
}u;
u.a[0]=0x1111;
u.a[1]=0x1111;
u.b = 0x22222222;
printf ("%x%x\n", u.a[0], u.a[1]);
return 0;
}
This way, no matter how it goes wrong.
Here you may ask, why should have this characteristic, since the-fno-strict-aliasing is more safe, that is all the place to use it anyway. In fact,-fstrict-aliasing appears to provide better optimization results. For example, the following program:
void sum (int *array, short * num, int n)
{
int i = 0;
for (i = 0;i < n;i++)
{
Array[i] + = (int) num[0];
}
}
If compiled with the-fno-strict-aliasing parameter, the compiler thinks that num and array may point to the same area. The value of the loop internal num[0] is taken from memory every time because the compiler thinks that assigning a value to Array[i] can change num[0].
And if you compile with the-fstrict-aliasing parameter. The compiler thinks num and array do not affect each other. This reads the value of num[0] outside the loop to the register. Each time inside the loop is the value of the register to accumulate. Reduces the number of read memory, thus optimizing the speed.
If there is a large number of pointers and arrays in a function, the compiler's optimizations will likely be expected by the programmer. At the same time, the compilation parameters work for the entire file and cannot be directed against a single pointer variable and a single function. In order to tell the compiler exactly what pointers refer to if the memory will overwrite each other, a new keyword restrict is introduced into the C99 standard. Restrict is used in the same place as the Const. It indicates that the memory pointed to by this pointer is only modified by this pointer, and the other pointers do not modify this part of memory. In this way, the compiler can generate code that is consistent with the programmer's expectations and efficiency by explicitly telling the compiler. But Tornado2.2 in the GCC version is quite old, the C99 standard support is very poor, do not support the Restrict keyword, here is not much to say. The C99 standard can be consulted in more detail. It is recommended that you add-fno-strict-aliasing to the compile command line, although the optimization effect is compromised but secure.
4) How to view the default macros defined by the preprocessor
Different versions of GCC are defined differently by default macros. Sometimes GCC, which is compatible with different platforms, may want to be separated from the compilation macros in the code. This makes you wonder what macros the compiler and processor have defined by default to provide for us to use. You can create an empty file and then use the following command
Ccsimpc-dm-e Emptyfilename
Or
CCSIMPC-DM-E-< NUL
can get output
#define _stdcall __attribute__ ((__stdcall__))
#define CPU Simnt
#define __I386__ 1
#define _X86_ 1
#define __I386 1
#define ___STDCALL__ __attribute__ ((__stdcall__))
#define __GNUC_MINOR__ 96
#define __declspec (x) __attribute__ ((x))
#define __vxworks 1
#define I386 1
#define __stdcall __attribute__ ((__stdcall__))
#define __GNUC__ 2
#define __CDECL __attribute__ ((__cdecl__))
#define __STDC__ 1
#define ___stdcall __attribute__ ((__stdcall__))
CCARM-DM-E filename
Or
CCARM-DM-E-< NUL
can get output
#define __ARM__ 1
#define __ARM_ARCH_4__ 1
#define ARM 1
#define __GNUC__ 2
#define __APCS_32__ 1
#define __ARM_ELF__ 1
#define __ARM_ELF 1
#define __vxworks 1
#define __CHAR_UNSIGNED__ 1
#define __ARMEL__ 1
#define __ELF__ 1
#define ARM_ELF 1
#define __GNUC_MINOR__ 9
#define CPU ARMSA110
Introduction to GCC common compilation parameters