Assembly 无法理解nasm错误。如何修复代码。

Assembly 无法理解nasm错误。如何修复代码。,assembly,x86,nasm,x86-64,Assembly,X86,Nasm,X86 64,我尝试从asm代码调用printf函数 hello.asm: %macro exit 0 mov eax, 1 mov ebx, 0 int 80h %endmacro extern printf ; the C function, to be called SECTION .data hello: db 'Hello world!', 0 SECTION .text GLOBAL main main: sub 8

我尝试从asm代码调用printf函数

hello.asm:

%macro exit 0
    mov eax, 1
    mov ebx, 0
    int 80h
%endmacro

extern   printf      ; the C function, to be called

SECTION .data
    hello:     db   'Hello world!', 0

SECTION .text
    GLOBAL main

main:
    sub 8, rsp
    push dword hello
    call printf      ; Call C function
    add 8, rsp
    exit
生成文件:

all:
    nasm -f elf64 hello.asm -o hello.o
    ld hello.o -e main -o hello -lc -I/lib/ld-linux.so.2

clean:
    rm -f hello.o hello
all:
    nasm -f elf64 hello.asm -o hello.o
    gcc -nostartfiles -no-pie hello.o -o hello

clean:
    rm -f hello.o hello
打电话:

nasm -f elf64 hello.asm -o hello.o
hello.asm:16: error: invalid combination of opcode and operands
hello.asm:19: error: invalid combination of opcode and operands
make: *** [all] Error 1
请解释错误以及如何修复代码


谢谢。

两条错误消息都提供了很好的线索。它们发生在第16行和第19行

在第16行中,您有:

sub 8, rsp
这里的问题是你不能从一个文字常量中减去任何东西。我认为实际意图是

sub rsp, 8
第19行也是如此。而不是

add 8, rsp
你想要的是

add rsp, 8
考虑到对于sub和add等指令,第一个操作数获取运算结果。而文字常量不能做到这一点

工作解决方案:

你好,c:

extern exit      ; the C function, to be called
extern puts      ; the C function, to be called

SECTION .data
    hello:     db   'Hello world!', 0

SECTION .text
    GLOBAL _start

_start:
    mov edi, hello
    call puts      ; Call C function
    mov edi, 0
    call exit      ; Call C function
生成文件:

all:
    nasm -f elf64 hello.asm -o hello.o
    ld hello.o -e main -o hello -lc -I/lib/ld-linux.so.2

clean:
    rm -f hello.o hello
all:
    nasm -f elf64 hello.asm -o hello.o
    gcc -nostartfiles -no-pie hello.o -o hello

clean:
    rm -f hello.o hello

sub和add的操作数向后。英特尔的语法是add dst,src,所以使用sub rsp,8。您是从AT&T语法翻译过来的吗?而且,如果您使用的是RSP指示的64位代码,那么您不应该使用int 80,而应该使用syscall,它也使用不同的寄存器。@PeterCordes是的。我修复了它,现在我收到错误bash:./hello:访问损坏的共享library@DavidWohlferd:是的,但是对于不需要64位输入(如指针)的系统调用,它仍然可以在大多数系统上工作。更重要的是,对于这种情况,x86-64 System V调用约定不会在堆栈上传递参数。它应该是mov edi,hello或leardi,[rel hello]@e42d3:与gcc链接,它知道如何传递正确的参数。gcc-v-nostartfiles-no-pie-hello.o-v打印它使用的实际链接器命令,以防您好奇。不要使用-e main,调用您的入口点\u start。不要弄乱RSP,它已经在ELF入口点对齐了16字节,不像在main。或者更好的办法是,省去-nostartfiles,这样正常的启动程序在main之前运行,而不是在调用stdio函数之前依赖动态链接器来初始化libc。推/弹出操作会使堆栈错位。与函数的输入不同,它在输入到_start时已经对齐了16字节_开始不是一个函数,这就是为什么你不能从中重新开始。此外,您仍在使用32位ABI作为sys_exit@谢谢。你仍然没有修复对齐错误。如果你这样叫它,它就可以崩溃。您正在使用的版本恰好没有使用任何movaps指令将内容复制到堆栈或从堆栈复制内容。如果你能解决这个问题,我会投赞成票。不过,使用libc exit3代替系统调用是一件好事。它使您的程序在退出之前刷新stdio缓冲区,所以如果您将输出重定向到文件,它仍然有效。因此,这比切换到mov eax、231/syscall要好。为了更好地理解,我认为最好在这里添加NASM通常以op dest、src的方式接受指令,而op是操作,dest是目标,src是源。因此,在C语法中,添加esp,8等于esp+=8。