【问题标题】:Troubles with the compilation of the assembler汇编器编译的问题
【发布时间】:2023-03-08 09:43:01
【问题描述】:

我在汇编器上复制了示例程序并使用 gcc 编译它,但得到以下输出:

gcc hello.s -o hello1

/usr/bin/ld: /tmp/ccPs5dcq.o: 重定位 R_X86_64_32 对 `.data' 在制作 PIE 对象时不能使用;使用 -fPIE 重新编译

/usr/bin/ld:最终链接失败:输出部分无法表示

collect2:错误:ld 返回 1 个退出状态

代码:

.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    

我做错了什么?

附:我绝对是汇编程序的初学者,只是试图解析示例

【问题讨论】:

  • 尝试用-fno-pie编译。让我看看我能不能找到一个好的副本。
  • @fuz 谢谢,它有效,这是什么意思?
  • 指令movl $hello_str, %ecx在链接时需要知道hello_str的地址。在创建 PIE(位置无关)可执行文件时情况并非如此,因此链接器会对您大喊大叫。可以以与位置无关的方式编写相同的代码,但是在 32 位代码中,这要困难得多,因此最好暂时忽略这一点。另外,鉴于您编写的是 32 位代码,您需要与 -m32 进行汇编和链接,否则会出现奇怪的问题。
  • @fuz:注意R_X86_64_32 重定位:问题是不支持 64 位模式下的 32 位 绝对修正。使用-m32,动态链接器可以修复一个 32 位绝对值以保存整个地址空间中的任何指针,因此它是受支持的。错误消息与32-bit absolute addresses no longer allowed in x86-64 Linux? 重复,但真正的修复是-m32(即使不需要,-no-pie 也可能是个好主意)。
  • 如果您编译为 64 位代码,What happens if you use the 32-bit int 0x80 Linux ABI in 64-bit code? 也适用。

标签: linux assembly x86


【解决方案1】:

我在使用gcc 和他的代码时遇到了与 OP 相同的问题,但我可以使用默认的 GNU as 来组装它:

as hello.s -o hello.out && ld hello.out -e main -o hello && ./hello

来源:https://askubuntu.com/questions/1064619/how-can-i-compile-run-assembly-in-ubuntu-18-04

另一个有效的 hello world 是来自 here 的第一个示例。


通过使用lea (still magic to me) 来避免所有这些可能是一个更好的 hello world(感谢 Peter Cordes):

.text

.global main

main:
        # write(1, message, 13)
        mov     $1, %rax                # system call 1 is write
        mov     $1, %rdi                # file handle 1 is stdout
        lea     message(%rip),%rsi      # address of string to output
        mov     $13, %rdx               # number of bytes
        syscall                         # invoke operating system to do the write

        # exit(0)
        mov     $60, %rax               # system call 60 is exit
        xor     %rdi, %rdi              # we want return code 0
        syscall                         # invoke operating system to exit

.section .rodata
message:
        .ascii  "Hello, world\n"

然后你可以无错误地组装:

gcc hello.s -o hello

然后使用./hello 运行

也许值得一读的是list of linux syscalls,看看为什么以及你需要写什么才能让终端上显示的东西。

【讨论】:

  • 您仍在使用 32 位绝对地址,因此 only 适用于非 PIE 可执行文件。因此,与 cmets 不同的是,它只能使用 gcc -nostdlib -static foo.s(或 -no-pie)构建。使用lea message(%rip), %rsi 与符号扩展mov $imm32, %reg64 的大小相同,并且适用于任何地方。 How to load address of function or label into register。此外,通常您希望将您的消息放在.section .rodata
  • 我按照您的建议进行了更改,效果很好,谢谢!
  • 回复:这个答案的第一部分:一般建议使用_start作为ELF入口点的名称,而不是main。也就是说,不要使用让每个人都感到困惑的-e main,而是将源更改为_start。在这种情况下这是安全的,因为它使用退出系统调用,而不是尝试返回。 (而且它也不需要任何 libc 函数,因此您可以使用 ld 将其链接到一个静态可执行文件,根本不需要其他代码。)
猜你喜欢
  • 2012-10-26
  • 2013-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-04
  • 1970-01-01
相关资源
最近更新 更多