【问题标题】:relocation R_X86_64_8 against undefined symbol `ELF' can not be used when making a PIE object在制作 PIE 对象时,不能使用针对未定义符号“ELF”的重定位 R_X86_64_8
【发布时间】:2020-06-08 08:56:11
【问题描述】:

在气体里有这个:

    .text
    .globl main
main:
    xor %eax, %eax
    lea str(%rip), %rdi
    call printf
    call exit

str: .byte 0x7F, "ELF", 1,1,1,0

我认为.byte 指令可以像在 nasm 中那样连接

db      0x7F, "ELF", 1, 1, 1, 0         ;   e_ident

来源:http://www.muppetlabs.com/~breadbox/software/tiny/teensy.html

【问题讨论】:

  • 请注意,如果您希望它实际运行,您必须在调用printf 之前对齐堆栈。在调用之前添加任何push 指令。
  • @NateEldredge 对齐只是惯例。如果程序很复杂,这将是一个问题,但是由于调用一个函数,然后调用另一个函数,因此对齐不是生活必需的,它仍然可以正常工作
  • 当前 glibc printf 在违反 ABI 时不会崩溃,但有趣的事实是:scanf 确实出错,即使没有 FP 参数。 glibc scanf Segmentation faults when called from a function that doesn't align RSP。允许函数依赖 ABI 保证的正确性,因此违反它们是个坏主意。当它碰巧起作用时,您可以提供玩具示例,但请注意您在做什么。
  • 这不仅仅是惯例。 printf 和其他库函数可以并且有时会执行仅在堆栈对齐时才有效的指令。幸运的是,它现在可能恰好可以使用printf 的特定参数集以及使用特定编译器构建的特定libc,但它可能随时中断。调用 C 函数时,堆栈对齐不是可选的。

标签: assembly x86-64 string-literals gnu-assembler


【解决方案1】:

在 GAS 语法中,"ELF" 是对符号名称 ELF 的符号引用,而不是多字符字符串。在.byte 指令的上下文中,它只是在寻找一个数字,而不是一个可能的字符串。

并且由于您将它用作.byte 值列表的一个元素,它要求绝对地址的低字节,因此.._8 重定位。含义与NASM的db完全不同。

在 GAS 中,当它需要一个数字时,'E' 被允许作为 ASCII 常量,但 "E" 不是。例如mov $"E", %eax 会给你一个R_X86_64_32 E 重定位。

单引号也不起作用。单字符文字确实可以用作数字,例如就像mov $'a', %eax 一样直接。但与 NASM 不同,GAS 不支持多字符字符文字。所以mov eax, 'Hey!' 在 NASM 中有效,但 mov $'Hey!', %eax 在 GAS 中无效。

AFAIK,GAS 仅允许您将多个 ASCII 字符序列用作 .ascii / .asciz 指令或相关 .string / .string16 / .string32 窄或宽字符指令的文字数据。 (GAS manual)


你有几个选择:

str: .byte 0x7F
     .ascii "ELF"         # separate directives
     .byte 1,1,1,0
str: .byte 0x7F, 'E', 'L', 'F', 1,1,1,0   # separate character literals
str: .asciz "\x7F\ELF\x1\x1\x1"         # hex escapes in a string

\E 阻止整个 7FE 被视为一个十六进制数字。如果没有额外的反斜杠,它会组装成fe 4c 46 01...(坏)而不是所需的7f 45 4c 46 01...(好)。

IDK,如果有更好/更清洁的方法来做到这一点;可能是 3 位八进制转义序列?


该教程使用 NASM 的平面二进制输出模式手动创建 ELF 程序头(对于 32 位可执行文件)。我猜您出于某种原因正在尝试创建一个打印该输出的 64 位程序?它恰好不包含任何0% 字节,所以是的,您可以使用printf 输出它。

将教程移植到 GAS 语法的更直接的方法是使用 ld 链接到 as 输出到平面二进制文件中。 How to generate plain binaries like nasm -f bin with the GNU GAS assembler?

或者使用objcopy.o 或可执行文件的.text 部分复制到平面二进制文件中。如果您使用objcopy,请确保所有内容都在.text 部分中。

【讨论】:

  • Peter Corders,实际上唯一的意图是以气体语法移植它,但在 x64 上没有(我将保持默认教程目标 x32)。但是无论如何,从上面,为什么"x7F\ELF",翻译成fe 4c 46,我理解了十六进制46(F) 和4c(L),但是为什么是fe7 在哪里?我不明白转义十六进制如何改变最终输出。从您写的内容看来, \xn 将保持其价值并且不会翻译。但它必须翻译,因为它是 ascii 字符串,所以当这不是 ascii 中的条目时,fe 字节将翻译成什么字符? (ascii 中的最大值为0x7F -> DEL
  • @autistic456:我认为\x7FE 被解析为一个十六进制数字 0x7FE,然后被截断为 0xFE 以适应一个字节。这与观察到的行为一致。字母L 不是十六进制数字,因此解析停止在那里。就像反斜杠停止数字解析一样,即使 \E 在病房之后仍然只是文字 E。 (顺便说一句,在我的回答中更新了该段落;我在第一次尝试时就说明了它。) GAS 不像 NASM 那样用户友好。它主要设计用于汇编编译器输出。
  • 另一个问题是这部分mov $'a', %eax。我试图实现它:.text .globl main main: xor %eax, %eax mov $'a', %rdi call printf call exit,但command terminated
  • @autistic456:IDK 为什么你认为这会起作用。在 C 中,printf('a') 也不起作用,这就是您要实现的。您需要将指针传递给字符串,而不是整数字符值。或者call putchar
  • 好的,但如果我尝试了lea $'a', %rdi,那么lea 不匹配
猜你喜欢
  • 2020-01-17
  • 1970-01-01
  • 2018-08-12
  • 2021-01-17
  • 2017-04-10
  • 2018-06-19
  • 2022-12-10
  • 1970-01-01
  • 2019-02-03
相关资源
最近更新 更多