x86_64汇编实现read函数时无-no-pie编译失败求助
x86_64汇编实现read系统调用编译PIE时重定位错误解决方法
问题情况
我是汇编新手,用x86_64汇编实现read系统调用函数,使用命令nasm -f elf64 ft_read.s && gcc -no-pie main.c ft_read.o编译可正常运行,但去掉-no-pie参数后出现重定位错误。尝试多种编译命令及修改extern __errno_location的声明位置均无效,机器环境为Ubuntu 23.10、Linux 6.5.0-25-generic、gcc 13.2.0、NASM 2.16.01。
原代码:
extern __errno_location section .note.GNU-stack section .text global ft_read ft_read: mov rax, 0 ; rdi already set ; rsi already set ; rdx already set syscall cmp rax, 0 jl _syscallFail ret _syscallFail: neg rax push rax call __errno_location pop qword [rax] mov rax, -1 ret
错误信息:
/usr/bin/ld: ft_read.o: warning: relocation against `__errno_location@@GLIBC_2.2.5' in read-only section `.text' /usr/bin/ld: ft_read.o: relocation R_X86_64_PC32 against symbol `__errno_location@@GLIBC_2.2.5' can not be used when making a PIE object; recompile with -fPIE /usr/bin/ld: final link failed: bad value collect2: error: ld returned 1 exit status
错误原因
PIE(位置无关可执行文件)是当前Linux系统的默认编译模式,它要求代码使用位置无关的寻址方式。原代码中直接用call __errno_location会生成R_X86_64_PC32类型的重定位,这种重定位依赖固定内存地址,不符合PIE动态加载的要求,因此链接器报错。
解决方案
1. 编译汇编文件时添加位置无关参数
NASM需要加上-fPIC参数生成位置无关的目标文件,这是兼容PIE的基础。
2. 修改外部函数调用方式
在PIC/PIE模式下,调用外部函数需要通过PLT(过程链接表)或GOT(全局偏移表)进行,确保寻址是位置无关的。以下两种写法均可:
写法一:通过PLT调用
修改call __errno_location为call __errno_location wrt ..plt,让NASM生成兼容PIE的调用代码:
extern __errno_location section .note.GNU-stack section .text global ft_read ft_read: mov rax, 0 ; read系统调用号 syscall cmp rax, 0 jl _syscallFail ret _syscallFail: neg rax ; 将负错误码转为正数 push rax call __errno_location wrt ..plt ; 通过PLT调用,兼容PIE pop qword [rax] mov rax, -1 ret
写法二:RIP相对寻址访问GOT
通过lea指令以RIP相对方式获取函数地址,再间接调用:
extern __errno_location section .note.GNU-stack section .text global ft_read ft_read: mov rax, 0 ; read系统调用号 syscall cmp rax, 0 jl _syscallFail ret _syscallFail: neg rax ; 将负错误码转为正数 push rax lea rdi, [rel __errno_location] ; RIP相对寻址获取函数地址 call [rdi] pop qword [rax] mov rax, -1 ret
3. 正确编译命令
使用以下命令编译,无需添加-no-pie:
nasm -f elf64 -fPIC ft_read.s && gcc main.c ft_read.o
内容的提问来源于stack exchange,提问作者aldisti
相关产品推荐
相关产品推荐

