汇编编写共享对象跨文件调用符号时ld报R_X86_64_PC32错误,如何解决?
解决x86_64汇编共享对象的R_X86_64_PC32重定位错误
这个错误的核心原因很明确:x86_64架构下的共享对象(.so文件)必须是位置无关代码(PIC),而你当前的编译/链接流程没有生成符合要求的代码。R_X86_64_PC32是一种针对固定地址的重定位类型,无法用于加载地址不固定的共享对象,所以我们需要调整汇编代码和编译链接选项来解决。
第一步:调整汇编代码的调用方式
当你在第二个文件中调用第一个文件的符号(比如strchr)时,不能直接用普通的call strchr,而要通过**过程链接表(PLT)**来调用,这是PIC代码的要求。修改调用语句为:
call strchr wrt ..plt
同时,确保在定义strchr的第一个ASM文件中,用global声明该符号为全局可导出:
global strchr
在调用它的第二个文件中,用extern声明该符号:
extern strchr
第二步:编译生成PIC兼容的目标文件
使用NASM编译每个ASM文件时,必须加上-PIC选项来生成位置无关代码,同时指定64位ELF格式:
nasm -f elf64 -PIC file1.asm -o file1.o nasm -f elf64 -PIC file2.asm -o file2.o
-f elf64确保生成x86_64架构的目标文件,-PIC让NASM生成不依赖固定加载地址的代码,所有内存访问和函数调用都会采用相对寻址或通过GOT/PLT表实现。
第三步:链接生成共享对象
用ld链接时,加上-shared选项明确告诉链接器要生成共享对象,而不是可执行文件:
ld -shared -o libyourlib.so file1.o file2.o
如果需要指定共享对象的soname(可选,但推荐),可以加上-soname libyourlib.so.1这样的选项,方便后续版本管理。
示例完整流程
假设我们有两个文件:
file1.asm(定义strchr)
global strchr section .text strchr: mov rax, rdi ; 把字符串起始地址存入rax .loop: cmp byte [rax], sil ; 比较当前字符和目标字符 je .found ; 找到就返回当前地址 cmp byte [rax], 0 ; 遇到字符串结尾就返回空 je .not_found inc rax ; 否则移动到下一个字符 jmp .loop .found: ret .not_found: mov rax, 0 ret
file2.asm(调用strchr)
extern strchr global find_a_char section .text find_a_char: ; 示例:调用strchr查找字符串中的'a' mov rdi, rsi ; 第一个参数:传入的字符串 mov sil, 'a' ; 第二个参数:要查找的字符 call strchr wrt ..plt ; 通过PLT调用strchr ret
编译链接命令:
nasm -f elf64 -PIC file1.asm -o file1.o nasm -f elf64 -PIC file2.asm -o file2.o ld -shared -o libmystr.so file1.o file2.o
这样生成的libmystr.so就是符合要求的共享对象,不会再出现R_X86_64_PC32的重定位错误。
内容的提问来源于stack exchange,提问作者Nathan Schwarz
相关产品推荐
相关产品推荐

