NASM编写x64共享库遇R_X86_64_PC32重定位错误求助
解决NASM x64编译共享库的R_X86_64_PC32重定位错误
问题本质:NASM的PIC写法和GCC不兼容
你提到已经启用了PIC选项,但NASM生成位置无关代码的逻辑和GCC的-fPIC完全不同。x64共享库要求所有符号引用必须使用位置无关寻址方式,R_X86_64_PC32错误就是因为你的代码里用了绝对地址引用,不符合PIC规范——当前这个错误和GLIBC函数名冲突无关,但重名确实可能埋下后续隐患,可以后续排查。
修正PIC兼容的函数调用方式
如果你的putstr里调用strlen是直接写call strlen,必须改成PIC兼容的PLT调用格式:
call strlen wrt ..plt
要是代码里有引用全局数据,也得换成rip-relative寻址,比如[rip+my_data],不能直接使用绝对地址。
符号冲突的排查方法
虽然当前错误不是冲突导致,但重名可能引发隐式依赖:
- 编译完目标文件后用
nm strlen.o查看符号表,确认strlen是T(文本段,已定义)而非U(未定义),确保你的实现被正确导出。 - 链接时添加
-z defs参数,强制链接器检查未定义符号,这样如果不小心引用了GLIBC的同名函数,会直接报错,方便定位问题。
正确的Makefile配置示例
确保NASM编译用-f elf64,链接用ld -shared,并加上必要的参数:
NASM_FLAGS := -f elf64 LDFLAGS := -shared -z noexecstack -z defs minilibc.so: strlen.o putstr.o ld $(LDFLAGS) -o $@ $^ strlen.o: strlen.asm nasm $(NASM_FLAGS) -o $@ $< putstr.o: putstr.asm nasm $(NASM_FLAGS) -o $@ $<
注意:NASM的-DPIC只是定义一个宏,真正的PIC逻辑需要在汇编代码里手动实现(比如用wrt ..plt调用函数)。
额外注意事项
- 如果
putstr需要输出内容,别依赖GLIBC的write函数,直接写x64系统调用汇编,彻底避免和GLIBC的依赖:; x64 Linux下的write系统调用示例 mov rax, 1 ; syscall编号:write mov rdi, 1 ; 文件描述符:stdout mov rsi, buffer ; 要输出的缓冲区地址 mov rdx, len ; 输出长度 syscall - 用
readelf -r minilibc.so查看重定位表,正常情况下应该只有R_X86_64_PLT32或R_X86_64_GOTPCREL类型的重定位项,没有R_X86_64_PC32。
内容的提问来源于stack exchange,提问作者Nayrosk
相关产品推荐
相关产品推荐

