gcc编译参数

1.gcc -static main.cpp -o staticBuild
-static就是静态链接,好处是可移植性好,不依赖其他库就可以运行,坏处是binary比较大。
2. gcc -shared -fPIC main.cpp -o sharedBuild.
链接选项和路径

现代连接器在处理动态库时将链接时路径(Link-time path)和运行时路径(Run-time path)分开,用户可以通过-L指定链接时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大提高了库应用的灵活性。比如我们做嵌入式移植时#arm-linux-gcc $(CFLAGS) –o target –L/work/lib/zlib/ -llibz-1.2.3 (work/lib/zlib下是交叉编译好的zlib库),将target编译好后我们只要把zlib库拷贝到开发板的系统默认路径下即可。或者通过-rpath(或-R )(链接参数)、LD_LIBRARY_PATH(运行目标板上环境变量)指定查找路径。

链接器ld的选项有 -L,-rpath 和 -rpath-link,看了下 man ld,大致是这个意思:

-L: “链接”的时候,去找的目录,也就是所有的 -lFOO 选项里的库,都会先从 -L 指定的目录去找,然后是默认的地方。编译时的-L选项并不影响环境变量LD_LIBRARY_PATH,-L只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径,系统还是会到默认路径下查找该程序所需要的库,如果找不到,还是会报错,类似cannot open shared object file。

-rpath-link:这个也是用于“链接”的时候的,例如你显示指定的需要 FOO.so,但是 FOO.so 本身是需要 BAR.so 的,后者你并没有指定,而是 FOO.so 引用到它,这个时候,会先从 -rpath-link 给的路径里找。

-rpath: “运行”的时候,去找的目录。运行的时候,要找 .so 文件,会从这个选项里指定的地方去找。对于交叉编译,交叉编译链接器需已经配置 --with-sysroot 选项才能起作用。也就是说,-rpath指定的路径会被记录在生成的可执行程序中,用于运行时查找需要加载的动态库。-rpath-link 则只用于链接时查找

链接选项:
用gcc命令编译目标,要指定链接选项时,需要使用“-Wl,” (大W小l逗号)来表明后面跟着是链接选项。注意有逗号。
1。-Wl,-as-needed 这个选项时表明编译某个库或者可执行文件时所有用到的库都需要 “-l” 来指定,否则会报错。比如liba.so用到了libm.so, 可执行文件B用到了liba.so. 如果不加该选项,我们编译liba.so的时候,可以不指定 -lm, 而编译B的时候,同时指定-lm -la,但其实这种方式不是很合理,所以最好是谁用到的库,谁指定。编译B的时候我只知道用到了liba.so, 而可能我不知道liba.so用到了哪些库。所以,我们编译的时候最好都加上这个选项,谁用到的库谁指定。

Address Sanitizer 用法 这个也是gcc的flag,打开之后会加入debug信息和check mem错误的工具,当遇到内存越界等错误时,会终止程序运行,并打印出错误backtrace,方便调试,比valgrind工具快很多。要enable这个参数时,编译参数和链接参数都需要加上,内容如下:

  1. enable address sanitizer
    CFLAGS += -fsanitize=address,
    LDFLAGS += -fsanitize=address,
    2.enable memory leak sanitizer
    CFLAGS += -fsanitize=leak,
    LDFLAGS += -fsanitize=leak,
    3.enable thread sanitizer
    CFLAGS += -fsanitize=thread,
    LDFLAGS += -fsanitize=thread,
    具体参考
    https://www.jianshu.com/p/3a2df9b7c353

还有两个flag是增强编译检查的选项,
CFLAGS += -D_FORTIFY_SOURCE=2  
https://access.redhat.com/blogs/766093/posts/1976213
加上后预编译对返回值会检查的更严格,有返回值必须check。
Relro flag:
LDFLAGS += -Wl,-z,relro,-z,now 这个是为了防止内存越界,一旦越界,就会segmentation fault

3.关于soname这里说一点,编译某个so库的时候需要指定soname, 这个soname会被写到该库文件的header里面,比如我们编译lib11.so.1.0.0, 指定soname为lib11.so.1.
然后我们编译一个可执行文件binary_test,需要用到lib11.so.1.0.0, 则我们编译binary_test的时候只需要指定lib11.so.1就可以了,如果只有一个版本的lib11.so, 则指定lib11.so就可以,都不用带版本号,如果有多个版本的库共存,则需要创建软链接lib11.so.1来指向lib11.so.1.0.0。但是我们用readelf -d binary_test来看needed字段时,里面写入的是lib11.so.1这个库的soname,这里要注意。

参考 https://www.cnblogs.com/fengbeihong/p/3641384.html

gcc提供了大量的警告选项,对代码中可能存在的问题提出警告,通常可以使用-Wall来开启以下警告:
-Waddress -Warray-bounds (only with -O2) -Wc++0x-compat
-Wchar-subscripts -Wimplicit-int -Wimplicit-function-declaration
-Wcomment -Wformat -Wmain (only for C/ObjC and unless
-ffreestanding) -Wmissing-braces -Wnonnull -Wparentheses
-Wpointer-sign -Wreorder -Wreturn-type -Wsequence-point
-Wsign-compare (only in C++) -Wstrict-aliasing -Wstrict-overflow=1
-Wswitch -Wtrigraphs -Wuninitialized (only with -O1 and above)
-Wunknown-pragmas -Wunused-function -Wunused-label -Wunused-value
-Wunused-variable
unused-function:警告声明但是没有定义的static函数;
unused- label:声明但是未使用的标签;
unused-parameter:警告未使用的函数参数;
unused-variable:声明但是未使用的本地变量;
unused-value:计算了但是未使用的值;
format:printf和scanf这样的函数中的格式字符串的使用不当;
implicit-int:未指定类型;
implicit-function:函数在声明前使用;
char- subscripts:使用char类作为数组下标(因为char可能是有符号数);
missingbraces:大括号不匹配;
parentheses: 圆括号不匹配;
return-type:函数有无返回值以及返回值类型不匹配;
sequence-point:违反顺序点的代码,比如 a[i] = c[i++];
switch:switch语句缺少default或者switch使用枚举变量为索引时缺少某个变量的case;
strict- aliasing=n:使用n设置对指针变量指向的对象类型产生警告的限制程度,默认n=3;只有在-fstrict-aliasing设置的情况下有效;
unknow-pragmas:使用未知的#pragma指令;
uninitialized:使用的变量为初始化,只在-O2时有效;

以下是在-Wall中不会激活的警告选项:
cast-align:当指针进行类型转换后有内存对齐要求更严格时发出警告;
sign- compare:当使用signed和unsigned类型比较时;
missing-prototypes:当函数在使用前没有函数原型时;
packed:packed 是gcc的一个扩展,是使结构体各成员之间不留内存对齐所需的空间,有时候会造成内存对齐的问题;
padded:也是gcc的扩展,使结构体成员之间进行内存对齐的填充,会造成结构体体积增大.
unreachable-code:有不会执行的代码时.
inline:当inline函数不再保持inline时 (比如对inline函数取地址);
disable-optimization:当不能执行指定的优化时.(需要太多时间或系统资源).
可以使用 -Werror时所有的警告都变成错误,使出现警告时也停止编译.需要和指定警告的参数一起使用.

优化:
gcc默认提供了5级优化选项的集合:
-O0:无优化(默认)
-O和-O1:使用能减少目标文件大小以及执行时间并且不会使编译时间明显增加的优化.在编译大型程序的时候会显著增加编译时内存的使用.
-O2: 包含-O1的优化并增加了不需要在目标文件大小和执行速度上进行折衷的优化.编译器不执行循环展开以及函数内联.此选项将增加编译时间和目标文件的执行性能.
-Os:专门优化目标文件大小,执行所有的不增加目标文件大小的-O2优化选项.并且执行专门减小目标文件大小的优化选项.
-O3: 打开所有-O2的优化选项并且增加 -finline-functions, -funswitch-loops,-fpredictive-commoning, -fgcse-after-reload and -ftree-vectorize优化选项.

-O1包含的选项-O1通常可以安全的和调试的选项一起使用:
-fauto-inc-dec -fcprop-registers -fdce -fdefer-pop -fdelayed-branch
-fdse -fguess-branch-probability -fif-conversion2 -fif-conversion
-finline-small-functions -fipa-pure-const -fipa-reference
-fmerge-constants -fsplit-wide-types -ftree-ccp -ftree-ch
-ftree-copyrename -ftree-dce -ftree-dominator-opts -ftree-dse
-ftree-fre -ftree-sra -ftree-ter -funit-at-a-time

以下所有的优化选项需要在名字前加上-f,如果不需要此选项可以使用-fno-前缀
defer-pop:延迟到只在必要时从函数参数栈中pop参数;
thread- jumps:使用跳转线程优化,避免跳转到另一个跳转;
branch-probabilities:分支优化;
cprop- registers:使用寄存器之间copy-propagation传值;
guess-branch-probability:分支预测;
omit- frame-pointer:可能的情况下不产生栈帧;

-O2:以下是-O2在-O1基础上增加的优化选项:
-falign-functions -falign-jumps -falign-loops -falign-labels
-fcaller-saves -fcrossjumping -fcse-follow-jumps -fcse-skip-blocks
-fdelete-null-pointer-checks -fexpensive-optimizations -fgcse
-fgcse-lm -foptimize-sibling-calls -fpeephole2 -fregmove
-freorder-blocks -freorder-functions -frerun-cse-after-loop
-fsched-interblock -fsched-spec -fschedule-insns
-fschedule-insns2 -fstrict-aliasing -fstrict-overflow -ftree-pre
-ftree-vrp
cpu架构的优化选项,通常是-mcpu(将被取消);-march,-mtune

Debug选项:
在 gcc编译源代码时指定-g选项可以产生带有调试信息的目标代码,gcc可以为多个不同平台上帝不同调试器提供调试信息,默认gcc产生的调试信息是为 gdb使用的,可以使用-gformat 指定要生成的调试信息的格式以提供给其他平台的其他调试器使用.常用的格式有
-ggdb:生成gdb专用的调试信息,使用最适合的格式(DWARF 2,stabs等)会有一些gdb专用的扩展,可能造成其他调试器无法运行.
-gstabs:使用 stabs格式,不包含gdb扩展,stabs常用于BSD系统的DBX调试器.
-gcoff:产生COFF格式的调试信息,常用于System V下的SDB调试器;
-gxcoff:产生XCOFF格式的调试信息,用于IBM的RS/6000下的DBX调试器;
-gdwarf- 2:产生DWARF version2 的格式的调试信息,常用于IRIXX6上的DBX调试器.GCC会使用DWARF version3的一些特性.
可以指定调试信息的等级:在指定的调试格式后面加上等级:
如: -ggdb2 等,0代表不产生调试信息.在使用-gdwarf-2时因为最早的格式为-gdwarf2会造成混乱,所以要额外使用一个-glevel来指定调试信息的等级,其他格式选项也可以另外指定等级.

gcc可以使用-p选项指定生成信息以供porf使用.

GCC常用选项

选项 含义
–help
–target-help 显示 gcc 帮助说明。‘target-help’是显示目标机器特定的命令行选项。
–version 显示 gcc 版本号和版权信息 。
-o outfile 输出到指定的文件。
-xlanguage 指明使用的编程语言。允许的语言包括:c c++ assembler none 。 ‘none’意味着恢复默认行为,即根据文件的扩展名猜测源文件的语言。
-v 打印较多信息,显示编译器调用的程序。
-### 与 -v 类似,但选项被引号括住,并且不执行命令。
-E 仅作预处理,不进行编译、汇编和链接。如上图所示。
-S 仅编译到汇编语言,不进行汇编和链接。如上图所示。
-c 编译、汇编到目标代码,不进行链接。如上图所示。
-pipe 使用管道代替临时文件。
-combine 将多个源文件一次性传递给汇编器。

3 其他GCC选项

更多有用的GCC选项:

命令 描述
-l library
-llibrary 进行链接时搜索名为library的库。
例子: $ gcc test.c -lm -o test
-Idir 把dir加入到搜索头文件的路径列表中。
例子:$ gcc test.c -I../inc -o test
-Ldir 把dir加入到搜索库文件的路径列表中。
例子:$ gcc -I/home/foo -L/home/foo -ltest test.c -o test
-Dname 预定义一个名为name的宏,值为1。
例子:$ gcc -DTEST_CONFIG test.c -o test
-Dname=definition 预定义名为name,值为definition的宏。
-ggdb
-ggdblevel 为调试器 gdb 生成调试信息。level可以为1,2,3,默认值为2。
-g
-glevel 生成操作系统本地格式的调试信息。-g 和 -ggdb 并不太相同, -g 会生成 gdb 之外的信息。level取值同上。
-s 去除可执行文件中的符号表和重定位信息。用于减小可执行文件的大小。
-M 告诉预处理器输出一个适合make的规则,用于描述各目标文件的依赖关系。对于每个源文件,预处理器输出 一个make规则,该规则的目标项(target)是源文件对应的目标文件名,依赖项(dependency)是源文件中 #include引用的所有文件。生成的规则可以是单行,但如果太长,就用/换行符续成多行。规则 显示在标准输出,不产生预处理过的C程序。
-C 告诉预处理器不要丢弃注释。配合-E选项使用。
-P 告诉预处理器不要产生#line命令。配合-E选项使用。
-static 在支持动态链接的系统上,阻止连接共享库。该选项在其它系统上无效。
-nostdlib 不连接系统标准启动文件和标准库文件,只把指定的文件传递给连接器。
Warnings
-Wall 会打开一些很有用的警告选项,建议编译时加此选项。
-W
-Wextra 打印一些额外的警告信息。
-w 禁止显示所有警告信息。
-Wshadow 当一个局部变量遮盖住了另一个局部变量,或者全局变量时,给出警告。很有用的选项,建议打开。 -Wall 并不会打开此项。
-Wpointer-arith 对函数指针或者void *类型的指针进行算术操作时给出警告。也很有用。 -Wall 并不会打开此项。
-Wcast-qual 当强制转化丢掉了类型修饰符时给出警告。 -Wall 并不会打开此项。
-Waggregate-return 如果定义或调用了返回结构体或联合体的函数,编译器就发出警告。
-Winline 无论是声明为 inline 或者是指定了-finline-functions 选项,如果某函数不能内联,编译器都将发出警告。如果你的代码含有很多 inline 函数的话,这是很有用的选项。
-Werror 把警告当作错误。出现任何警告就放弃编译。
-Wunreachable-code 如果编译器探测到永远不会执行到的代码,就给出警告。也是比较有用的选项。
-Wcast-align 一旦某个指针类型强制转换导致目标所需的地址对齐增加时,编译器就发出警告。
-Wundef 当一个没有定义的符号出现在 #if 中时,给出警告。
-Wredundant-decls 如果在同一个可见域内某定义多次声明,编译器就发出警告,即使这些重复声明有效并且毫无差别。
Optimization
-O0 禁止编译器进行优化。默认为此项。
-O
-O1 尝试优化编译时间和可执行文件大小。
-O2 更多的优化,会尝试几乎全部的优化功能,但不会进行“空间换时间”的优化方法。
-O3 在 -O2 的基础上再打开一些优化选项:-finline-functions, -funswitch-loops 和 -fgcse-after-reload 。
-Os 对生成文件大小进行优化。它会打开 -O2 开的全部选项,除了会那些增加文件大小的。
-finline-functions 把所有简单的函数内联进调用者。编译器会探索式地决定哪些函数足够简单,值得做这种内联。
-fstrict-aliasing 施加最强的别名规则(aliasing rules)。
Standard
-ansi 支持符合ANSI标准的C程序。这样就会关闭GNU C中某些不兼容ANSI C的特性。
-std=c89
-iso9899:1990 指明使用标准 ISO C90 作为标准来编译程序。
-std=c99
-std=iso9899:1999 指明使用标准 ISO C99 作为标准来编译程序。
-std=c++98 指明使用标准 C++98 作为标准来编译程序。
-std=gnu9x
-std=gnu99 使用 ISO C99 再加上 GNU 的一些扩展。
-fno-asm 不把asm, inline或typeof当作关键字,因此这些词可以用做标识符。用__asm____inline____typeof__能够替代它们。 -ansi隐含声明了-fno-asm
-fgnu89-inline 告诉编译器在 C99 模式下看到 inline 函数时使用传统的 GNU 句法。
C options
-fsigned-char
-funsigned-char 把char定义为有/无符号类型,如同signed char/unsigned char。
-traditional 尝试支持传统C编译器的某些方面。详见GNU C手册。
-fno-builtin
-fno-builtin-function 不接受没有 __builtin_ 前缀的函数作为内建函数。
-trigraphs 支持ANSI C的三联符( trigraphs)。-ansi选项隐含声明了此选项。
-fsigned-bitfields
-funsigned-bitfields 如果没有明确声明signed或unsigned修饰符,这些选项用来定义有符号位域或无符号位域。缺省情况下,位域是有符号的,因为它们继承的基本整数类型,如int,是有符号数。
-Wstrict-prototypes 如果函数的声明或定义没有指出参数类型,编译器就发出警告。很有用的警告。
-Wmissing-prototypes 如果没有预先声明就定义了全局函数,编译器就发出警告。即使函数定义自身提供了函数原形也会产生这个警告。这个选项 的目的是检查没有在头文件中声明的全局函数。
-Wnested-externs 如果某extern声明出现在函数内部,编译器就发出警告。
C++ options
-ffor-scope 从头开始执行程序,也允许进行重定向。
-fno-rtti 关闭对 dynamic_cast 和 typeid 的支持。如果你不需要这些功能,关闭它会节省一些空间。
-Wctor-dtor-privacy 当一个类没有用时给出警告。因为构造函数和析构函数会被当作私有的。
-Wnon-virtual-dtor 当一个类有多态性,而又没有虚析构函数时,发出警告。-Wall会开启这个选项。
-Wreorder 如果代码中的成员变量的初始化顺序和它们实际执行时初始化顺序不一致,给出警告。
-Wno-deprecated 使用过时的特性时不要给出警告。
-Woverloaded-virtual 如果函数的声明隐藏住了基类的虚函数,就给出警告。
Machine Dependent Options (Intel)
-mtune=cpu-type 为指定类型的 CPU 生成代码。cpu-type可以是:i386,i486,i586,pentium,i686,pentium4 等等。
-msse
-msse2
-mmmx
-mno-sse
-mno-sse2
-mno-mmx 使用或者不使用MMX,SSE,SSE2指令。
-m32
-m64 生成32位/64位机器上的代码。
-mpush-args
-mno-push-args (不)使用 push 指令来进行存储参数。默认是使用。
-mregparm=num 当传递整数参数时,控制所使用寄存器的个数。
另外:

当静态库和动态库同名时, gcc命令将优先使用动态库。

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
-L.:表示要连接的库在当前目录中
-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。
当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。调用动态库的时候有几个问题会经常碰到,有时,明明已经将库的头文件所在目录 通过 “-I” include进来了,库所在文件通过 “-L”参数引导,并指定了“-l”的库名,但通过ldd命令察看时,就是死活找不到你指定链接的so文件,这时你要作的就是通过修改 LD_LIBRARY_PATH或者/etc/ld.so.conf文件来指定动态库的目录。通常这样做就可以解决库无法链接的问题了。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: stack-protector 是 GCC 编译器中的一个参数,它可以在程序中增加栈溢出保护机制。该参数会在编译时在程序的栈帧中增加一个额外的保护字段,以便在运行时检测栈溢出。使用该参数可以有效防止栈溢出漏洞的产生。 ### 回答2: GCC编译参数 stack-protector 是用于在编译时启用堆栈保护机制的选项。堆栈保护是一种防御措施,旨在检测和防止栈溢出攻击。 栈溢出是一种常见的安全漏洞,它发生在栈内存被超出其分配大小的数据覆盖时。攻击者可以通过向缓冲区写入超过其容量的数据来修改目标程序的正常执行流程,并可能导致非法访问、代码执行等安全问题。 启用 stack-protector 参数后,GCC编译时会将堆栈保护代码插入到目标程序中。这些代码会通过检测栈是否被破坏来警告并阻止栈溢出攻击的发生。当检测到栈被破坏时,程序会终止并显示相关错误信息,从而防止攻击者利用栈溢出漏洞执行恶意代码。 具体来说,stack-protector 参数会在栈上分配一个随机的不可覆盖的值,称为"栈冲突保护 canary"。检测发生在函数返回之前或在修改栈上任何变量之前,通过比较 canary 的值是否仍然完好来检测栈是否发生溢出。 使用 stack-protector 参数可以增强目标程序的安全性,防止栈溢出攻击的发生。然而,应该注意,该参数并不能完全解决所有的安全问题,其他安全防御措施如输入验证、内存分配检查等仍然是必要的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值