如何彻底移除静态链接二进制中的.dynsym、.dynstr和.dynamic节?
解决静态二进制文件残留动态节的问题
问题根源
你看到的.dynsym、.dynstr、.dynamic等动态节,是因为编译时使用了-fpic/-fPIC参数——这两个参数会强制编译器生成位置无关代码(PIC),而PIC模式下链接器默认会保留动态链接相关的节,哪怕你指定了--no-dynamic-linker也无法完全消除。另外,-fpic/-fPIC并不是用来消除重定位的,它的作用是让代码能在任意地址加载,反而会引入PLT/GOT这类动态重定位机制,这也是你看到残留重定位的原因。
对于同一代码段内的call main,如果用了PIC编译,编译器会把它转换成通过PLT的间接调用,从而产生不必要的重定位;去掉PIC参数后,会生成直接的相对地址调用,不会有重定位问题。
解决方案:调整编译链接参数
修改你的Makefile,移除-fpic/-fPIC,添加-static链接器参数,明确生成完全静态的二进制:
hello: start.s hello.c Makefile gcc -o hello -nostartfiles -nostdlib -static -Wl,--no-dynamic-linker -fno-asynchronous-unwind-tables -s start.s hello.c strip -R .comment hello
参数说明
-static:告诉链接器生成完全静态链接的二进制,不依赖任何动态库,同时会自动抑制动态节的生成。- 移除
-fpic/-fPIC:既然目标是静态二进制,不需要位置无关代码,这两个参数只会增加冗余。 - 保留
-nostartfiles -nostdlib:继续使用自定义的启动代码,不依赖标准库和启动文件。
验证结果
修改后重新编译,再用objdump -x hello检查,会发现.dynsym、.dynstr、.dynamic这些动态节已经消失,二进制体积也会进一步缩小,同一代码段内的call main也不会有多余的重定位。
内容的提问来源于stack exchange,提问作者Joshua
相关产品推荐
相关产品推荐

