X86 64位汇编Linux“Hello World”链接问题

6

我正在尝试跟进这个线程,但不幸的是它并没有完全解决我的问题。我要运行的代码如下:

; File hello.asm

        section .data
msg:    db      "Hello World!",0x0a,0

        section .text
        global main
        extern printf

main:
        push  rbp
        mov   rbp, rsp
        lea   rdi, [msg]  ; parameter 1 for printf
        xor   eax, eax    ; 0 floating point parameter
        call  printf
        xor   eax, eax    ; returns 0
        pop   rbp
        ret

我的系统是Debian Stretch:

$ uname -a
Linux <host> 4.8.0-1-amd64 #1 SMP Debian 4.8.7-1 (2016-11-13) x86_64 GNU/Linux

我正在使用 yasm 汇编器,如下所示:

$ yasm -f elf64 -g dwarf2 hello.asm

由于我在上文中的入口点是带有最终指令 retmain,我猜想我需要与gcc链接而不是ld -e main

$ gcc -lc hello.o

然而,我收到了以下错误信息:
/usr/bin/ld: hello.o: relocation R_X86_64_32 against `.data' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status

这个错误提到需要使用-fPIC重新编译,但这是gcc编译器选项,不是汇编器yasm的有效选项。所以我不知道该怎么办。
为了测试,我试图链接ld
$ ld -e main -lc hello.o

这个操作是成功的,但是当我运行以下命令时,我遇到了与上面提到的线程中相同的错误:

$ ./a.out
bash: ./a.out: No such file or directory       # The file *is* there ...

(根据帖子的答案,我已经尝试比较ld二进制文件中提到的.so库与我的系统库,它们都是/lib64/ld-linux-x86-64.so.2。)我也尝试将main入口点替换为_start(暂时忘记程序正确退出的问题),并链接ld -lc hello.o,但我得到了与之前相同的“没有这样的文件或目录”的错误消息。虽然我会继续尝试,但我还是想问一下有没有有效建议(包括使用main_start,以及gccld)。如果您有任何有效建议,请告诉我。 编辑:如Jim所建议的,我在hello.asm顶部添加了default rel,并在使用gcc链接时获得不同的错误消息(使用ld -e main -lc没有变化)。
$ gcc -lc hello.o

/usr/bin/ld: hello.o: relocation R_X86_64_PC32 against symbol `printf@@GLIBC_2.2.5' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status

编辑2:本文与Debian Stretch上的失败有关:

Linux: 4.8.0-1-amd64 #1 SMP Debian 4.8.7-1 (2016-11-13) x86_64 GNU/Linux
yasm: 1.3.0
gcc: (Debian 6.2.1-5) 6.2.1 20161124
ld: GNU ld (GNU Binutils for Debian) 2.27.51.20161220

在Jim的评论后,我刚刚在debian jessie上测试了相同的代码,使用gcc -lc hello.o和以下版本,一切正常:

Linux: 3.16.0-4-amd64 #1 SMP Debian 3.16.36-1+deb8u2 (2016-10-19) x86_64 GNU/Linux
yasm: 1.2.0
gcc: (Debian 4.9.2-10) 4.9.2
ld: GNU ld (GNU Binutils for Debian) 2.25

编辑3: 在等待迈克尔·佩奇的正式回答时:问题已解决方法是 gcc -static hello.o


1
你的代码在我这里实际上是可以工作的(在不同的发行版上)。你的问题似乎与hello.o的重定位类型有关。我建议在hello.asm的顶部添加指令default rel,看看是否可以解决问题或提供不同的错误信息。你是故意尝试使用R_X86_64_32重定位吗? - JimD.
@JimD。非常感谢您的帮助。我已经编辑了我的帖子以指示新的错误消息。 - Sven Williamson
2
如果使用 gcc -static hello.o 静态构建,会发生什么? - Michael Petch
@MichaelPetch 你说对了!!! gcc -lc -static hello.odebian stretch 机器上完美运行。顺便提一下,在 debian jessie 上也可以运行。如果你想写一个答案,我很乐意验证它。如果你有任何关于可能发生的事情的见解,也非常欢迎(但我不想占用你太多时间)。非常感谢!!! - Sven Williamson
好的,现在我们已经通过了数据部分,但是遇到了文本重定位问题。我喜欢@MichaelPetch的建议尝试显式静态构建。但是为什么链接时要显式添加"-lc"呢?也许尝试只使用"gcc hello.o"看看是否获得不同的结果? - JimD.
@JimD. 确实,使用 gcc 时,-lc 选项是不必要的(我也是从 ld 养成这个习惯)。然而,无论是否在 hello.asm 的顶部加上 default relgcc hello.o 都会导致相同的错误,而 gcc -static hello.o 则成功。 - Sven Williamson
1个回答

8
在Debian Stretch中,GCC 默认构建位置无关可执行文件,如果要构建链接到特定地址的可执行文件,可以向GCC传递-no-pie。或者指定正确的重定位类型,在yasm中我不知道如何做到这一点。

嗨,Timothy,尽管 gcc -static hello.o 成功了,但链接命令 gcc -fno-pie hello.o 在我的 debian stretch 机器上失败了。我错过了什么? - Sven Williamson
抱歉,链接时应该使用“-no-pie”,而“-fno-pie”用于控制编译。 - Timothy Baldwin
谢谢Timothy,gcc -static hello.ogcc -no-pie hello.o 都非常完美! - Sven Williamson
相关链接:https://dev59.com/F1cQ5IYBdhLWcg3wFPya - Ciro Santilli OurBigBook.com

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接