Skip to content

GCC

Bash
1
2
3
4
# 编译32位的参数(同架构)
-m32 # 将int、long和指针设为32位,适用于i386
-m64 # 将int设为32位、long和指针设为64位,适用于x86-64
-mx32 # 将int、long和指针设为32位,适用于x86-64

查看g++默认编译标准

使用info g++-std=中又default字眼,g++ 11.4中默认是c++17

编译汇编代码

Bash
1
2
3
4
# 该命令会在当前目录下生成 test.s 文件,且没有对初学者不友好的什么繁琐信息(栈保护相关信息bala什么的)
g++ -S -fverbose-asm -fno-stack-protector -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm [test.cpp]
# 生成与上面相对应的可供gdb调试的程序
g++ test.cpp -g -fverbose-asm -fno-stack-protector -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm -o test

调试汇编代码

Bash
1
2
3
4
5
6
7
8
# 可在gdb页面显示汇编代码
layout asm
# 以16进制输出 从$rsp地址开始的32各byte
x/32xb $rsp
# 打印rsp的地址信息
p $rsp
# 打印当前栈帧
info frames

调试小记: 移位操作,在32位系统和64位系统里面,被移位的数据默认传入$eax寄存器中,所以如果对(int16_t/int8_t)进行移位操作,即便移的位数超过了数据的位宽也不会变成0

objdump

显示二进制文件信息,查看反汇编代码

Bash
# -S 可以反汇编同时显示源代码
objdump -S -d main

nm

用于显示文件的符号信息

Bash
# 显示所有符号
nm -a

strip符号信息与调试信息

用于对可执行二进制文件和对象文件删除不必要的信息(符号),带来更好的性能和减少磁盘空间的使用

默认gcc/g++编译出来的程序是带有符号信息的,而加上-g是在此基础上再加上供调试的符号信息(.debug)(即创建符号表),并且关闭所有的优化机制。严格 按照程序执行,-Og优化成都介于-O0和-O1之间。

编译优化

  1. O0 不进行任何优化,默认设置
  2. O1 主要对代码分支、常量以及表达式进行优化(去除无用的inline和无用的static、死代码消除
  3. O2 尝试更多的寄存器级的优化和指令集级别的优化,自动对函数进行内联,可能修改代码和函数执行流程
  4. O3 在O2基础上,使用伪寄存器网络,普通函数的内联,比O2更激进,对循环、内联的优化,提高并行执行速度
  5. Os 相当于O2.5使用O2但不缩减代码尺寸
  6. Og 优化调试体验,在保持快速编译和良好调试体验的同时,提供合理的优化级别。

gdb

源代码编译过程:

.c =预处理=> .i =编译=>.s =汇编=> *.o =链接(ld)=> .out

其中:

  1. 预处理:文本替换、宏展开、删除注释,后生成*.i文件
  2. 编译:处理内联函数,生成汇编代码*.s
  3. 汇编:翻译成*.o机械语言
  4. 链接:链接静态库*.a和动态库*.so
参数 说明
-E 预编译生成*.i文件
-S 生成汇编代码*.s文件
-c 只编译不链接,生成*.o文件
-o 把输出文件输出到指定文件内
-g 在可执行程序中添加调试信息
-static 链接静态链接库
  • gdb调试fork多进程:set follow_fork_mode [mode],其中mode可选parentchild,分别表示fork之后调试父进程还是子进程。
  • info threads:显示当前可调试的线程;thread [ID]切换要调试的线程
  • set scheduler-blocking [off|on|step]off,默认值,不锁定线程即所有线程都可运行;on表示只有当前被调试的线程才会执行;step表示在单步运行时,只有当前线程会执行。
  • set disassemble-next-line on #打开汇编指令开关,这样gdb每执行一步,都会打印出来对应执行的汇编指令