GCC、G++
mian.c
int main() { return 0; }
编译:gcc main.c && ./a.out,给 gcc 加上 -verbose 可以看到更多信息
GCC 编译过程:https://www3.ntu.edu.sg/home/ehchua/programming/cpp/gcc_make.html
# 预处理(Preprocessing) gcc -E main.c -o main.i # 编译(Compilation) gcc -S main.i -o main.s # 汇编(Assemble)。.s 只能包含纯粹的汇编代码,.S 可以使用预处理命令(#开头) gcc -c main.s -o main.o # 链接(Linking) # ld main.o -o main gcc main.o -o main
查看 gcc 编译调用了那些命令:https://man7.org/linux/man-pages/man1/strace.1.html
sudo apt install -y strace # strace -f gcc main.c &| vim - # 用 strace 跟踪 gcc,并将信息输出到 vim vim -c ':r! strace -f gcc main.c' # 留下包含 execve 的行 :%! grep execve # 一行显示,不换行 :set nowrap # 去除包含 ENOENT 的行 :%! grep -v ENOENT # 去除包含 resumed 的行 :%! grep -v resumed # 把 , 换成 \r(换行) :%s /, /\r /g # 去掉所有行尾空格和 tab :%s /\s\+$/ /g
过滤后的结果中可看到 gcc(源码 .c 到预处理 .i) 还调用了其它程序:cc1(预处理 .i 到汇编 .s)、as(汇编 .s 到机器码 .o)、collect2(多个机器码 .o 到可执行 .out)、ld(可执行 .out 与 libc 等库链接)
execve("/usr/bin/gcc" ["gcc" "main.c"] 0x7ffe4b6efd70 /* 28 vars */) = 0 execve("/usr/lib/gcc/x86_64-linux-gnu/12/cc1" ["/usr/lib/gcc/x86_64-linux-gnu/12"... "-quiet" "-imultiarch" "x86_64-linux-gnu" "main.c" "-quiet" "-dumpdir" "a-" "-dumpbase" "main.c" "-dumpbase-ext" ".c" "-mtune=generic" "-march=x86-64" "-fasynchronous-unwind-tables" "-o" "/tmp/ccxzcfJ7.s"] 0x18704a0 /* 33 vars */ <unfinished ...> execve("/usr/bin/as" ["as" "--64" "-o" "/tmp/ccPVAv5P.o" "/tmp/ccxzcfJ7.s"] 0x18704a0 /* 33 vars */ <unfinished ...> execve("/usr/lib/gcc/x86_64-linux-gnu/12/collect2" ["/usr/lib/gcc/x86_64-linux-gnu/12"... "-plugin" "/usr/lib/gcc/x86_64-linux-gnu/12"... "-plugin-opt=/usr/lib/gcc/x86_64-"... "-plugin-opt=-fresolution=/tmp/cc"... "-plugin-opt=-pass-through=-lgcc" "-plugin-opt=-pass-through=-lgcc_"... "-plugin-opt=-pass-through=-lc" "-plugin-opt=-pass-through=-lgcc" "-plugin-opt=-pass-through=-lgcc_"... "--build-id" "--eh-frame-hdr" "-m" "elf_x86_64" "--hash-style=gnu" "--as-needed" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-pie" "/usr/lib/gcc/x86_64-linux-gnu/12"... "/usr/lib/gcc/x86_64-linux-gnu/12"... "/usr/lib/gcc/x86_64-linux-gnu/12"... "-L/usr/lib/gcc/x86_64-linux-gnu/"... "-L/usr/lib/gcc/x86_64-linux-gnu/"... "-L/usr/lib/gcc/x86_64-linux-gnu/"... "-L/lib/x86_64-linux-gnu" "-L/lib/../lib" "-L/usr/lib/x86_64-linux-gnu" "-L/usr/lib/../lib" "-L/usr/lib/gcc/x86_64-linux-gnu/"... "/tmp/ccPVAv5P.o" "-lgcc" ...] 0x1870900 /* 35 vars */ <unfinished ...> execve("/usr/bin/ld" ["/usr/bin/ld" "-plugin" "/usr/lib/gcc/x86_64-linux-gnu/12"... "-plugin-opt=/usr/lib/gcc/x86_64-"... "-plugin-opt=-fresolution=/tmp/cc"... "-plugin-opt=-pass-through=-lgcc" "-plugin-opt=-pass-through=-lgcc_"... "-plugin-opt=-pass-through=-lc" "-plugin-opt=-pass-through=-lgcc" "-plugin-opt=-pass-through=-lgcc_"... "--build-id" "--eh-frame-hdr" "-m" "elf_x86_64" "--hash-style=gnu" "--as-needed" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-pie" "/usr/lib/gcc/x86_64-linux-gnu/12"... "/usr/lib/gcc/x86_64-linux-gnu/12"... "/usr/lib/gcc/x86_64-linux-gnu/12"... "-L/usr/lib/gcc/x86_64-linux-gnu/"... "-L/usr/lib/gcc/x86_64-linux-gnu/"... "-L/usr/lib/gcc/x86_64-linux-gnu/"... "-L/lib/x86_64-linux-gnu" "-L/lib/../lib" "-L/usr/lib/x86_64-linux-gnu" "-L/usr/lib/../lib" "-L/usr/lib/gcc/x86_64-linux-gnu/"... "/tmp/ccPVAv5P.o" "-lgcc" ...] 0x7ffe8c224bd0 /* 35 vars */ <unfinished ...>
可执行文件格式:ABI、PE/COFF(Windows)、ELF(Linux)、MACH-O(Mac)
binutils:https://www.gnu.org/software/binutils
sudo apt -y install binutils # 查看文件信息 readelf -a a.out sudo apt -y install file && file a.out # 查看数据段大小 size a.out # 查看字符串 strings a.out # 反编译 objdump -d a.out # 删除调式符号 strip a.out # 列出目标文件中的符号和地址 nm a.out # 将地址转换为文件名和行号 addr2line -e a.out 0000000000001129 # 复制 objcopy -S --set-section-flags .bss=alloc,contents -O binary a.elf a.bin
参数
# 保存中间文件 -save-temps=obj # 生成调试符号 -ggdb