使用 GCC 组装会导致 .data 出现奇怪的重定位错误

Posted

技术标签:

【中文标题】使用 GCC 组装会导致 .data 出现奇怪的重定位错误【英文标题】:Assembling with GCC causes weird relocation error with regards to .data 【发布时间】:2018-02-17 19:04:43 【问题描述】:

这是一个从未发生过的问题。我非常确信这可能是我的软件包存储库的问题(我最近重新安装了我的 Arch 系统,而这才刚刚开始发生)。

我在x86_64中写了一个小小的hello world:

.data
str:    .asciz  "Test"

.text
.globl main
main:
    sub $8, %rsp
    mov $str, %rdi
    call puts
    add $8, %rsp
    ret

然后我尝试使用 GCC 进行组装和链接 - 就像我过去做过很多次一样 - 简单地说:

gcc test.s -o 测试

然后输出这个错误:

/usr/bin/ld: /tmp/ccAKVV4D.o: 重定位 R_X86_64_32S 对 `.data' 在制作共享对象时不能使用;使用 -fPIC 重新编译 /usr/bin/ld:最终链接失败:输出中不可表示的部分 collect2:错误:ld 返回 1 个退出状态

我从来没有发生过这个错误。我试图通过谷歌搜索相同的错误消息来解决这个问题,但它提出了一些非常具体的问题,而我认为这是一个普遍的问题。我尝试重新安装 base-devel 和整个 GCC 工具链。我不知道我还能做什么(请不要建议使用 nasm,那是异端)。

我想我遗漏了一些明显的东西,但我长期以来一直使用 GCC 来满足我的装配需求。

【问题讨论】:

我有点确定这是重复的,但我稍后会搜索它,所以简单总结一下发生了什么。 Debian 前段时间确实在 64b 模式下切换到 PIC/PIE 二进制文件(就像 OS X 已经有一段时间了,现在其他发行版也随之而来),因此修改了工具链的默认值,在你的情况下 gcc 是试图将您的对象链接为 PIC,但它会在mov $str, %rdi 中遇到绝对地址。因此,您要么应该将代码重写为 rip 在任何地方都是相对的,要么可能有一些方法可以设置 gcc 链接以强制执行旧的非 PIC 链接。 感谢@Ped7g 的洞察力,我会调查一下 您可能正在使用更新/不同版本的 Arch Linux,它默认将 GCC 构建为可重定位的 64 位代码。处理此问题的最佳方法是修改您的代码以使用 RIP(相对指令指针)寻址。将您的 mov 更改为 lea str(%rip), %rdi 并在调用 C 库时使用 call puts@plt 而不是 call puts 使用no-pie 标志编译。那是gcc -no-pie test.s -o test。这必须有效,因为它不会生成共享对象,而是生成可执行文件。我在我的本地机器上尝试过它并且它工作但仍然不知道为什么。 @oldjohn1994 @MichaelPetch 谢谢,我只是想问一下如何在相关代码中使用 libc 函数。为此干杯。 【参考方案1】:

解决这个错误的方法是生成一个no-pie(非位置无关的可执行文件)可执行文件:

gcc -no-pie test.s -o test

@Ped7g 解释了这种行为的原因: Debian 切换到 64 位模式下的 PIC/PIE 二进制文件,在您的情况下,GCC 正在尝试将您的对象链接为 PIC,但它会在mov $str, %rdi 中遇到绝对地址。

【讨论】:

他在这种情况下使用 Arch,但同样适用于 Debian。字符串的地址不是唯一的问题。 C 库的调用也必须修改。 @MichaelPetch: -no-pie 修复一切,并将call puts 转换为call puts@plt 为您服务。如果您希望它在 PIE 中工作,您只需要修改 call 指令。具体来说,call *puts@GOTPCREL(%rip) 如果使用gcc -fno-plt 构建(非延迟动态链接以避免可写+可执行PLT,并避免额外间接),或者call puts@PLT 用于默认方式。 (或者 call puts@plt 也可以。编译器在编译 C 时会发出大写的 PLT。) 相关:32-bit absolute addresses no longer allowed in x86-64 Linux? 有同样的答案。顺便说一句,movabs $str, %rdi 在 PIE 可执行文件中工作;允许文本重定位,但不允许 32 位 符号或零扩展重定位。但不要那样做,对 PIC 使用相对于 RIP 的 LEA,或者对位置相关使用 mov $str, %edi

以上是关于使用 GCC 组装会导致 .data 出现奇怪的重定位错误的主要内容,如果未能解决你的问题,请参考以下文章

混合 Spring MVC + Spring Data Rest 会导致奇怪的 MVC 响应

Spring 4 Security + CORS + AngularJS - 奇怪的重定向

无法使用 gcc 在 Linux 中编译任何 c++ 程序,出现一些奇怪的错误 [重复]

创建结构会导致 remix ide 出现奇怪的行为

使用 extern 时 gcc 的重定位错误

制表符分隔文本的复制粘贴会导致 Excel 中出现奇怪的格式?