3

我最近一直在 linux 上玩 x86 64 位汇编,在编译了一个看似简单的程序后,我只能摸不着头脑:P

虽然我编译和链接它不会抛出任何错误并产生一个 linux ELF 当我尝试运行它时,我得到:

.:[ h4unt3r@sp3ctr4l-h0st asm ]:.
#(0)> ./hello 
bash: ./hello: No such file or directory

我假设它产生了一个无效的 ELF 文件,这就是为什么它报告 hello 不存在,即使它是。不知道为什么-我可能会继续玩它,只是好奇这是否可以用简单的方法解决^_^

这是我的编译/链接命令行:

nasm -f elf64 hello.s -g
ld -o hello hello.o -lc

这是代码:

section .data
    msg: db "Hello, world!",0xa,0

section .text
    extern printf
    global main

main:
    push rbp
    mov rbp, rsp

    mov rdi, msg
    xor rax, rax
    call printf
    xor rax, rax

    pop rbp
    ret

编辑——我不想使用 gcc :)

4

3 回答 3

4

我正在运行 32 位硬件,无法测试 64 位的东西。我在 32 位代码中看到了这个“没有这样的文件”错误。ld 默认使用“/lib/ld-linux.so.1” - 您可以在可执行文件中以纯文本形式看到此字符串。这是不存在的文件(显然“hello”就在那里!)。解决方案是告诉 ld -I/lib/ld-linux.so.2。我怀疑类似的解决方案适用于 64 位,但我不知道您需要什么“解释器”或“动态链接器”。尝试在可执行文件中查找类似的字符串,并在您的库中查找类似的 .so。你不应该“需要”使用 gcc ......但是 gcc 知道在哪里可以找到这些东西!可能更容易使用它。真是个令人困惑的错误,不是吗?

(我希望你的入口点是_start,而不是main如果你打算这样做的话。你将无法ret从这个 - 使用 sys_exit 或 exit()。)

我不熟悉 nrz 提到的关于“符号表 0”的错误。当然不是故意改变 Nasm!Nasm 开发人员在http://www.nasm.us上或周围闲逛,很高兴在那里听到反馈和错误报告。(好吧,也许不是对错误报告感到“高兴”。)我会看看我是否能找到任何东西......

FWIW,Nasm 默认只使用-g开关“刺伤”调试信息。要启用“矮人”调试信息,-F dwarf...应该工作得更好...

于 2013-03-17T23:12:07.843 回答
3

首先,要使用printf,您需要使用gcc而不是链接ld

gcc -o hello hello.o

那么,另一个问题可能和我自己遇到的一样。我不确定这是 NASM 中的错误还是预期的更改:

user@computer:~/code/asm$ nasm -f elf64 hello.asm -g; gcc -o 你好你好.o
/usr/bin/ld: 错误: 重定位节 9 使用了意外的符号表 0
collect2:错误:ld 返回 1 个退出状态

我已经通过转移到YASM解决了这个问题,并以这种方式进行组装和链接:

yasm -f elf64 hello.s -g dwarf2
gcc -o hello hello.o

这会产生一个具有预期输出的可执行文件:

./hello
Hello, world!
于 2013-03-17T21:19:08.070 回答
2

稍微修改一下代码。

section .data
        msg:    db "Hello, world!",0xa,0
section .text
        extern  printf
 global _start
_start:
        ; RSP already 16-byte aligned, ready for a function call.
        mov     rdi,msg           ; or better, lea rdi, [rel msg]
        xor     eax, eax          ; AL=0  - no XMM args
        call    printf

        mov     rax,60  ; use _exit syscall
        mov     rdi,0   ; exit code 0
        syscall         ; call kernel

并链接使用它来设置正确的现代 ld.so 路径,而ld不是现代 GNU/Linux 系统上不存在的默认路径。

ld hello.o -o hello -lc --dynamic-linker /lib64/ld-linux-x86-64.so.2

请注意,这只适用于动态链接的可执行文件。如果静态链接,则需要手动调用 glibc 的 init 函数来初始化其数据结构(如 stdio 缓冲区),然后类似的函数printf才能工作。

于 2017-04-04T15:03:28.063 回答