g++/gcc编译器——常用知识(一)

基本的命令

把一个源文件,编译成可执行文件,经过了预处理、汇编、编译与链接。

-E: 对目标文件只进行预处理,生成的还是源码。

例如:g++ -E 1.cpp -o 1.i

-S: 对目标文件进行预处理、编译操作,生成汇编代码。

例如:g++ -S 1.cpp -o 1.s

-o: 对目标文件进行预处理、编译和汇编操作,生效obj文件。

例如:g++ -c 1.cpp -o 1.o

-fsyntax-only : 对代码只进行语法检查,不做其它任何动作。

常用安全编译选项

ALSR 地址随机化处理

系统级的配置,不属于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.

说明:

  1. 原理就是在缓冲区与函数返回控制信息之间插入一个哨兵变量, 当缓冲区溢出时, 哨兵变量的值会首先被覆盖掉, 这样就能判断发生了溢出攻击。
  2. 使用堆栈保护选项在对字符数组进行溢出防护的同时,还有意将局部变量中的数组放到函数栈的高地址,而将其它变量放在低地址。
  3. 性能损失度:fstack-protector-all > fstack-protector-strong > fstack-protector.

堆栈不可执行保护

该保护作用于链接阶段,所以需要把参数传递给链接器。 使用-Wl,<optional>的格式传递给链接器。

使用格式为:-Wl, -z noexecstack 选项。可用于动态库、ELF格式的可执行文件。

作用原理:首先,缓冲区溢出成功后都是通过执行shellcode来达到攻击目的的, 而shellcode基本都是放到缓冲区中,只要操作系统限制了堆栈内存区域不可执行状态就可以,一旦被攻击就报错并返回。

GOT表的保护

该保护作用于链接阶段, 同样把参数传递给链接器。

使用格式:

  • -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.

  • -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

作用于编译器, 参数格式为:-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选项添加的随机化特征才会在程序加载和运行时展现。

栈检查 -fstack-check

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.

整数溢出检查 -ftrapv

编译选项,使用了它之后,在执行有符号整数间的加减乘运算时,不是通过CPU的指令,而是用包含了GCC附属库的libgcc.c里面的函数来实现。对性能影响比较大。

常用告警选项

-w 选项:

禁止了所有的告警(完全不推荐使用)

-Werror选项:

把所有的警告标识为错误。

-Werror= ** 选项:

把指定的警告标识为错误。

- Wno-error= **选项:

取消指定的警告为错误。

- Wchar-subscripts 选项:

对数组下标为char类型给出警告。这是一个常见的错误。因为大多数char类型为有符号数。

- Wfatal-errors 选项:

编译器遇到第一个错误时,就停止下来,不继续检查更多错误。
我不建议使用, 每次编译就出一个错误,多浪费时间。

-Wreturn-type 选项:

Warn whenever a function is defined with a return type that defaults to int.
当函数定义了非void类型的返回值类型但是没有return时,给出警告。
当函数定义中,没有控制所有的返回值路径时,也会给出警告。

-Wunused选项:

定义了变量不使用,一个函数声明为静态但不定义,函数有返回值,调用了函数不使用(想要避免,加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

-Wuninitialized 选项:

变量不初始化就使用, 给警告。
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.

Wsign-compare 选项:

对有符号数与无符号数的比较,给出警告。

-Wall 选项:

它打开了一大堆常用的编译告警选项,能覆盖大部分的需求了。

-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

-Wextra选项(原为-W, 已经弃用了):

它会打开-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’)
posted @ 2021-05-04 16:49  殷大侠  阅读(3126)  评论(0编辑  收藏  举报