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

汇编程序编译报错求助:PIE对象R_X86_64_32重定位失败问题

GCC编译x86汇编程序时遇到R_X86_64_32重定位错误的解决方案

问题描述

我刚接触汇编,复制了一个示例程序用GCC编译时遇到了报错:

gcc hello.s -o hello1
/usr/bin/ld: /tmp/ccPs5dcq.o: relocation R_X86_64_32 against `.data' can not be used when making a PIE object; recompile with -fPIE
/usr/bin/ld: final link failed: nonrepresentable section on output
collect2: error: ld returned 1 exit status

我的汇编代码如下:

.data
hello_str: .string "Hello, world!\n"
.set hello_str_length, . - hello_str - 1
.text
.globl main
.type main, @function
main:
movl $4, %eax
movl $1, %ebx
movl $hello_str, %ecx
movl $hello_str_length, %edx
int $0x80
movl $1, %eax
movl $0, %ebx
int $0x80
.size main, . - main

请问我哪里操作错了?

问题原因

咱们先拆解下报错的核心原因:

  1. 默认PIE编译限制:现在绝大多数Linux发行版的GCC默认会生成PIE(位置无关可执行文件),这种程序要求代码能在任意内存地址运行,不能直接使用像movl $hello_str, %ecx这样的32位绝对地址引用——而你的代码正好用了这种方式,所以链接器报错说R_X86_64_32重定位不允许在PIE中使用。
  2. 过时的32位系统调用:你代码里的int $0x80是x86 32位系统的调用方式,虽然x86_64系统能兼容,但这不是64位环境下的最优选择,寄存器使用和系统调用号都和原生64位规范不一样。

解决方案

这里给你两种可行的方案,按需选择:

方案1:快速绕过PIE限制(适合保留现有代码)

如果你不想修改代码,只需要在编译时加上-no-pie参数,告诉链接器不要生成PIE文件:

gcc hello.s -o hello1 -no-pie

执行这个命令后,链接器就会允许32位绝对重定位,你的程序就能正常编译运行了。

方案2:修改代码适配现代x86_64规范(更推荐)

如果想写出符合64位系统标准的汇编代码,建议改成以下版本:

.data
hello_str: .string "Hello, world!\n"
hello_str_length = . - hello_str - 1  # 用=替代.set,语法更直观,效果一致

.text
.globl main
.type main, @function
main:
    # 64位系统调用:write(1, hello_str, hello_str_length)
    mov $1, %rax               # 64位系统调用号,write对应的是1
    mov $1, %rdi               # 文件描述符,stdout是1
    lea hello_str(%rip), %rsi  # 通过RIP相对寻址获取字符串地址(位置无关,兼容PIE)
    mov $hello_str_length, %rdx# 字符串长度
    syscall                    # 触发64位系统调用

    # 64位系统调用:exit(0)
    mov $60, %rax              # exit对应的系统调用号是60
    mov $0, %rdi               # 退出码设为0(正常退出)
    syscall
.size main, . - main

然后直接用原来的命令编译即可:

gcc hello.s -o hello1

这个版本的优势:

  • 使用lea hello_str(%rip), %rsi实现位置无关的地址引用,完美适配PIE编译要求
  • 采用x86_64原生的syscall指令和64位系统调用号,比int $0x80更高效,也更符合现代系统的规范

额外小贴士

作为汇编初学者,建议优先明确自己学习的是32位还是64位汇编——现在主流Linux都是x86_64架构,学64位规范会更实用。另外,系统调用号可以通过man syscalls命令查看,不同架构的系统调用号是有区别的哦。

内容的提问来源于stack exchange,提问作者Galina_1960

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 08:52:36