【发布时间】:2015-09-29 00:07:18
【问题描述】:
全部。我正在尝试使用 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;
}
编辑:好的,我能够解决这个问题。这是汇编代码。我使用nasm -f elf64 -l hello.lst hello.asm && gcc -o hello hello.c hello.o 组装了.asm 文件和.c 文件
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;
}
一些解释包括缺少 #include,因为 I/O 是在程序集文件中完成的。我需要相信的另一件事是,所有工作都没有在汇编中完成,因为我没有_start 标识符,或者任何所谓的标识符。肯定需要更多地了解系统调用。非常感谢所有为我指明正确方向的人。
【问题讨论】:
-
网上有很多讨论x86-64 calling conventions 的信息,尤其是来自 C 的。您的示例代码不是 64 位的,尽管您表示您希望使用 64 位。如何在汇编程序中打印字符串是通过对您正在使用的操作系统进行系统调用来完成的。所以这取决于操作系统。
-
64位寄存器以r开头,对吧?比如
rax、rdi等?我会编辑帖子来解决这个问题。 -
是的,他们有。但是,当您进入 64 位汇编程序时,除了在寄存器名称前面放置一个
r之外,还有更多的事情要做。调用约定不同于 x86。 -
更好的方法可能是先用 C 编写你的东西,然后让编译器输出汇编程序(例如
gcc -Wall -fverbose-asm -S -O code.c,然后查看code.s),以获得一些初步灵感跨度> -
@lurker,你是对的,我可能应该认为这不会那么容易。我正在使用 debian linux,如果这可以澄清任何事情。