所有。我试图用NASM编程,我也想学习如何在C中调用这些函数。我相当肯定我到目前为止的代码是正确的,因为我需要设置一个堆栈框架,然后在从例程返回之前撤消该堆栈帧。我也知道我需要返回零以确保没有错误。我也在使用debian linux,以防我需要调整我的操作系统。
代码:
global hello
section .data
message: db "Hello, world!",0 ; A C string needs the null terminator.
section .text
hello:
push rbp ; C calling convention demands that a
mov rbp,rsp ; stack frame be set up like so.
;THIS IS WHERE THE MAGIC (DOESN'T) HAPPEN
pop rbp ; Restore the stack
mov rax,0 ; normal, no error, return value
ret ; return
我觉得好像我应该指出我问这个因为我找到的所有程序都对printf进行了外部调用。我不想这样做,我真的想学习如何在装配中打印东西。所以我想我的问题是:NASM中C函数的调用约定是什么?如何在NASM 64位组件中打印字符串?
另外,为了确保我有这个部分,这是在C中调用汇编函数的正确方法吗?
#include <stdio.h>
int main() {
hello();
return 0;
}
编辑:好的,我能够解决这个问题。这是汇编代码。我使用.asm
汇总了.c
文件和nasm -f elf64 -l hello.lst hello.asm && gcc -o hello hello.c hello.o
文件
section .text
global hello
hello:
push rbp ; C calling convention demands that a
mov rbp,rsp ; stack frame be set up like so.
mov rdx,len ; Message length
mov rcx,message ; Message to be written
mov rax,4 ; System call number (sys_write)
int 0x80 ; Call kernel
pop rbp ; Restore the stack
mov rax,0 ; normal, no error, return value
ret
section .data
message: db "Hello, world!",0xa ; 0xa represents the newline char.
len: equ $ - message
相关的C代码(hello.c
)看起来像这样:
int main(int argc, char **argv) {
hello();
return 0;
}
由于在汇编文件中完成了I / O,因此一些解释包括缺少#include
。我需要看到的另一件事是,所有的工作都没有在汇编中完成,因为我没有_start
标识符,或者其他所谓的标识符。绝对需要了解有关系统调用的更多信息。非常感谢所有指出我正确方向的人。
答案 0 :(得分:1)
正如评论中所述,外部世界和代码之间的任何互动都是通过系统调用完成的。 C stdio函数将文本格式化为输出缓冲区,然后使用write(2)
编写它。或read(2)
进入输入缓冲区,并扫描或读取该行。
在asm中写作并不代表你应该避免使用libc
函数,例如:的printf / scanf函数。通常只有在asm中编写程序的一小部分才能获得速度。例如在asm中编写一个具有热循环的函数,并从C或其他任何语言调用它。使用系统调用返回值进行所有必要的错误检查来执行I / O在asm中不会很有趣。如果您对引擎盖下发生的事情感到好奇,请阅读编译器输出和/或单步执行asm。你有时会从编译器中学到很好的技巧,有时你会发现它生成的代码效率低于手工编写的代码。
这是一个问题:
mov rax,4 ; System call number (sys_write)
int 0x80 ; Call kernel
尽管64位进程可以使用i386 int 0x80
系统调用ABI,但它是 32位ABI,只有32位指针,依此类推。一旦你转到write(2)
堆栈上的一个char数组就会出现问题(因为amd64 Linux进程以一个设置了高位的堆栈指针开始。堆内存和{{从可执行文件映射的1}}和.data
内存映射到地址空间的低32b。)
本机amd64 ABI使用.rodata
,系统呼叫号码与i386 ABI不同。我发现this table of syscalls列出了数字和哪个参数在哪个寄存器中。 syscall
最终包含sys/syscall.h
以获取实际的/usr/include/x86_64-linux-gnu/asm/unistd_64.h
宏,依此类推。有一些标准规则可以映射参数以便注册。 (Given in the ABI doc, IIRC)。