Assembly 无法理解nasm错误。如何修复代码。
我尝试从asm代码调用printf函数 hello.asm: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
%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。