all. I was trying to get into programming with NASM, and I also wanted to learn how to make those functions callable in C. I am fairly certain the code that I have so far is correct, in that I need to set up a stack frame, and then undo that stack frame before I return from the routine. I also know I need to return a zero to ensure that there were no errors. I am using debian linux as well, in case I need to adjust for my OS.
The code:
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
I feel as if I should point out that I ask this because all of the programs I found made external calls to printf. I do not wish to do this, I would really like to learn how to print things in assembly. So I suppose my questions are: What are the calling conventions for C functions in NASM? How do I print a string in NASM 64bit assembly?
Also, to make sure I have this part right, is this the proper way to call the assembly function in C?
#include <stdio.h>
int main() {
hello();
return 0;
}
EDIT: Okay, I was able to work this out. Here's the assembly code. I assembled the .asm
file along with the .c
file using 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
The relevant C code (hello.c
) looked like this:
int main(int argc, char **argv) {
hello();
return 0;
}
Some explanations include the lack of an #include
, due to the I/O being done in the assembly file. Another thing that I needed to see to believe was that all the work was not done in assembly, as I did not have a _start
identifier, or whatever that's called. Definitely need to learn more about system calls. Thank you so much to everyone who pointed me in the right direction.