把一个源文件,编译成可执行文件,经过了预处理、汇编、编译与链接。
例如:g++ -E test.cpp -o test.i
例如:g++ -S test.cpp -o test.s
例如:g++ -c test.cpp -o test.o
系统级的配置,不属于gcc编译器的范畴。
栈保护在编译阶段进行,所以下面的参数是传给编译器的。
直接上英文, 更容易明白。
-fstack-protector
:
Emit extra code to check for buffer overflows, such as stack smashing attacks.
This is done by adding a guard variable to functions with vulnerable objects.
This includes functions that call alloca, and functions with buffers larger than
or equal to 8 bytes. The guards are initialized when a function is entered and
then checked when the function exits. If a guard check fails, an error message
is printed and the program exits. Only variables that are actually allocated
on the stack are considered, optimized away variables or variables allocated in
registers don’t count.
-fstack-protector-all
:
Like ‘-fstack-protector’ except that all functions are protected.
-fstack-protector-strong
:
Like ‘-fstack-protector’ but includes additional functions to be protected —
those that have local array definitions, or have references to local frame addresses. Only variables that are actually allocated on the stack are considered,
optimized away variables or variables allocated in registers don’t count.
-fstack-protector-explicit
:
Like ‘-fstack-protector’ but only protects those functions which have the
stack_protect attribute.
说明:
该保护作用于链接阶段,所以需要把参数传递给链接器。 使用-Wl,<optional>
的格式传递给链接器。
使用格式为:-Wl, -z noexecstack
选项。可用于动态库、ELF格式的可执行文件。
作用原理:首先,缓冲区溢出成功后都是通过执行shellcode来达到攻击目的的, 而shellcode基本都是放到缓冲区中,只要操作系统限制了堆栈内存区域不可执行状态就可以,一旦被攻击就报错并返回。
该保护作用于链接阶段, 同样把参数传递给链接器。
使用格式:
-Wl, -z relro
: Create RELRO program header, RELRO表示 relocation read only, 重定位段为只读。 GOT表就是用于重定位的。-Wl, -z now
: Mark object non-lazy runtime binding作用原理:动态链的ELF二进制程序使用称为全局偏移表(GOT)的的查找表去动态解析位于共享库的函数。攻击者通过缓冲区溢出修改GOT表项的函数地址来达到攻击目的。通过增加RELRO选项可以防止GOT表被恶意重写。 另外,GOT表的保护会影响到程序的加载速度。
作用阶段为编译器,参数格式为:-fPIC
或者 -fpic
.
-fpic
: Generate position-independent code (PIC) suitable for use in a shared library,
if supported for the target machine. Such code accesses all constant addresses
through a global offset table (GOT). The dynamic loader resolves the GOT
entries when the program starts (the dynamic loader is not part of GCC; it
is part of the operating system). If the GOT size for the linked executable
exceeds a machine-specific maximum size, you get an error message from the
linker indicating that ‘-fpic’ does not work; in that case, recompile with ‘-fPIC’
instead. (These maximums are 8k on the SPARC, 28k on AArch64 and 32k on
the m68k and RS/6000. The x86 has no such limit.)
Position-independent code requires special support, and therefore works only on
certain machines. For the x86, GCC supports PIC for System V but not for the
Sun 386i. Code generated for the IBM RS/6000 is always position-independent.
When this flag is set, the macros pic and PIC are defined to 1.
-fPIC
: If supported for the target machine, emit position-independent code, suitable
for dynamic linking and avoiding any limit on the size of the global offset table.
This option makes a difference on AArch64, m68k, PowerPC and SPARC.
Position-independent code requires special support, and therefore works only
on certain machines
作用于编译器, 参数格式为:-fPIE
或者 -fPIC
, 与fPIC
非常类似。
These options are similar to ‘-fpic’ and ‘-fPIC’, but the generated positionindependent code can be
only linked into executables. Usually these options are used to compile code that will be linked using
the ‘-pie’ GCC option.
说明: PIE是GCC与操作系统的产物,提供了地址无关的功能。 ASLR是基础,只有操作系统开启了ASLR功能时,-fpie选项添加的随机化特征才会在程序加载和运行时展现。
stack-check选项作用于编译器。它会在每个栈空间最低层部分设置一个安全缓冲区,如果函数中申请的栈空间进入了该区域,就会触发异常。对应的英文资料如下:
Generate code to verify that you do not go beyond the boundary of the stack. You should specify this flag if you are running in an environment with multiple threads, but you only rarely need to specify it in a single-threaded environment since stack overflow is automatically detected on nearly all systems if there is only one stack.
Note that this switch does not actually cause checking to be done; the operating system or the language runtime must do that. The switch causes generation of code to ensure that they see the stack being extended.
编译选项,使用了它之后,在执行有符号整数间的加减乘运算时,不是通过CPU的指令,而是用包含了GCC附属库的libgcc.c里面的函数来实现。对性能影响比较大。
忽略栈指针-fomit-frame-pointer和-fno-omit-frame-pointer
如果在编译时指定了-fno-omit-frame-pointer,那么就没有帧指针了,所以也就无法进行栈回溯了,默认有帧指针。backtrace
禁止了所有的告警(完全不推荐使用)
把所有的警告标识为错误。
把指定的警告标识为错误。
取消指定的警告为错误。
对数组下标为char类型给出警告。这是一个常见的错误。因为大多数char类型为有符号数。
编译器遇到第一个错误时,就停止下来,不继续检查更多错误。
我不建议使用, 每次编译就出一个错误,多浪费时间。
Warn whenever a function is defined with a return type that defaults to int.
当函数定义了非void
类型的返回值类型但是没有return时,给出警告。
当函数定义中,没有控制所有的返回值路径时,也会给出警告。
定义了变量不使用,一个函数声明为静态但不定义,函数有返回值,调用了函数不使用(想要避免,加void强转一下), 等等等等, 都会给警告。具体包含了以下这些:
-Wunused-but-set-parameter
-Wunused-but-set-variable
-Wunused-const-variable
-Wunused-const-variable=
-Wunused-dummy-argument
-Wunused-function
-Wunused-label
-Wunused-local-typedefs
-Wunused-macros
-Wunused-parameter
-Wunused-result
-Wunused-value
-Wunused-variable
变量不初始化就使用, 给警告。
c++类的能成员变量为非静态的引用或者const变量, 如果不使用构造函数进行初始化, 给警告。
Warn if an automatic variable is used without first being initialized. In C++,
warn if a non-static reference or non-static const member appears in a class
without constructors.
对有符号数与无符号数的比较,给出警告。
它打开了一大堆常用的编译告警选项,能覆盖大部分的需求了。
-Waddress
-Warray-bounds=1 (only with ‘-O2’)
-Wbool-compare
-Wbool-operation
-Wc++11-compat -Wc++14-compat
-Wcatch-value (C++ and Objective-C++ only)
-Wchar-subscripts
-Wcomment
-Wduplicate-decl-specifier (C and Objective-C only)
-Wenum-compare (in C/ObjC; this is on by default in C++)
-Wenum-conversion in C/ObjC;
-Wformat
-Wformat-overflow
-Wformat-truncation
-Wint-in-bool-context
-Wimplicit (C and Objective-C only)
-Wimplicit-int (C and Objective-C only)
-Wimplicit-function-declaration (C and Objective-C only)
-Winit-self (only for C++)
-Wlogical-not-parentheses
-Wmain (only for C/ObjC and unless ‘-ffreestanding’)
-Wmaybe-uninitialized
-Wmemset-elt-size
-Wmemset-transposed-args
-Wmisleading-indentation (only for C/C++)
-Wmissing-attributes
-Wmissing-braces (only for C/ObjC)
-Wmultistatement-macros
-Wnarrowing (only for C++)
-Wnonnull
-Wnonnull-compare
-Wopenmp-simd
-Wparentheses
-Wpessimizing-move (only for C++)
-Wpointer-sign
-Wreorder
-Wrestrict
-Wreturn-type
-Wsequence-point
-Wsign-compare (only in C++)
-Wsizeof-pointer-div
-Wsizeof-pointer-memaccess
-Wstrict-aliasing
-Wstrict-overflow=1
-Wswitch
-Wtautological-compare
-Wtrigraphs
-Wuninitialized
-Wunknown-pragmas
-Wunused-function
-Wunused-label
-Wunused-value
-Wunused-variable
-Wvolatile-register-var
-Wzero-length-bounds
它会打开-Wall
选项没有打开的一些编译警告,包括:
-Wclobbered
-Wcast-function-type
-Wdeprecated-copy (C++ only)
-Wempty-body
-Wignored-qualifiers
-Wimplicit-fallthrough=3
-Wmissing-field-initializers
-Wmissing-parameter-type (C only)
-Wold-style-declaration (C only)
-Woverride-init
-Wsign-compare (C only)
-Wstring-compare
-Wredundant-move (only for C++)
-Wtype-limits
-Wuninitialized
-Wshift-negative-value (in C++03 and in C99 and newer)
-Wunused-parameter (only with ‘-Wunused’ or ‘-Wall’)
-Wunused-but-set-parameter (only with ‘-Wunused’ or ‘-Wall’)
-Wl
表示编译器将后面的参数传递给链接器ld。
-Wl,-rpath-link=./lib
-Wl,-rapth='${ORIGIN}'/lib//ORIGIN elf文件位置,so就是so的位置所在目录
--enable-new-dtags //-rpath 产生DL_RUNPATH 建议用这个,可以被LD_LIBRARY_PATH覆盖
--disable-new-dtags //-rpath 产生DL_RPATH
编译时链接库需要分为两类: 直接引用 间接引用
指定搜索路径的其他方法:
1 export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:my_lib_dir
/etc下三个ld.so的条目
$ls /etc/ | grep ld.so
ld.so.cache
ld.so.conf
ld.so.conf.d
ld.so.conf.d是在ld.so.conf中include的
$cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
/usr/local/lib
2 /etc/ld.so.cache中缓存了动态库路径,可以通过修改配置文件/etc/ld.so.conf中指定的动态库搜索路径,然后执行ldconfig命令来改变。
3 放到系统默认搜索路径下,找到缺少的动态库,将其加到/lib,/usr/lib中的一个文件夹下, 系统默认的搜索路径。将库文件放置在其中,运行时就可以搜索到了。
顺序 Unless loading object has RUNPATH: RPATH of the loading object, then the RPATH of its loader (unless it has a RUNPATH), ..., until the end of the chain, which is either the executable or an object loaded by dlopen Unless executable has RUNPATH: RPATH of the executable LD_LIBRARY_PATH RUNPATH of the loading object ld.so.cache default dirs