编译时使用.rodata与-fPIE选项出现重定位错误的问题求助
解决汇编与C混合编译中.rodata段的R_X86_64_32S重定位错误
问题根源
你的个人机器GCC默认启用PIE(位置无关可执行文件)编译模式,而学校服务器可能默认关闭该模式。汇编文件func_select.s中对.rodata段的引用使用了32位绝对地址重定位(R_X86_64_32S),这种方式与PIE模式不兼容,导致链接报错。
错误分析
- 你之前把
-fPIE/-no-pie放在-o和a.out之间,属于参数顺序错误:-o选项必须紧跟输出文件名,GCC会误将-fPIE当成输出文件,因此报错找不到a.out。 - 仅在链接阶段加
-fPIE无效,因为旧的func_select.o是用非PIE模式编译的,必须重新编译所有目标文件才能适配PIE规则。
解决方案
方案1:禁用PIE模式(最适配学校作业代码)
修改Makefile,给编译、链接全阶段添加-no-pie选项,确保所有目标文件都以非PIE模式生成:
# 编译选项:-g用于调试,-no-pie禁用PIE CFLAGS = -g -no-pie ASFLAGS = -g -no-pie # 链接选项 LDFLAGS = -no-pie # 最终可执行文件规则 a.out: main.o run_main.o func_select.o pstring.o gcc $(CFLAGS) $(LDFLAGS) -o $@ $^ # C文件编译规则 %.o: %.c gcc $(CFLAGS) -c $< -o $@ # 汇编文件编译规则(原Makefile未定义时需添加) %.o: %.s gcc $(ASFLAGS) -c $< -o $@
执行以下命令重新编译:
make clean # 清除旧目标文件和可执行文件 make
方案2:修改汇编代码适配PIE模式(适合理解PIE原理)
如果想保留PIE模式,需修改汇编文件中对.rodata的引用方式,改用RIP相对寻址。例如:
原绝对地址引用:
movl $.rodata_str, %eax
改为RIP相对寻址:
leaq .rodata_str(%rip), %rax
这种方式使用R_X86_64_PC32重定位,兼容PIE模式。修改后用-fPIE重新编译:
CFLAGS = -g -fPIE ASFLAGS = -g -fPIE LDFLAGS = -fPIE a.out: main.o run_main.o func_select.o pstring.o gcc $(CFLAGS) $(LDFLAGS) -o $@ $^ %.o: %.c gcc $(CFLAGS) -c $< -o $@ %.o: %.s gcc $(ASFLAGS) -c $< -o $@
关键注意点
- 编译选项顺序不可乱:
-o后面必须直接跟输出文件名,不能插入其他选项。 - 修改Makefile后务必先清除旧目标文件,否则旧
.o文件会继续引发冲突。
内容的提问来源于stack exchange,提问作者someone
相关产品推荐
相关产品推荐

