You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 02:25:59