EvilZone

Programming and Scripting => Assembly - Embedded => : Deque November 06, 2012, 05:15:46 PM

: [ASM] Calling C functions on 64bit architecture
: Deque November 06, 2012, 05:15:46 PM
Hello EZ.

Here is something I only found out after a few hours of research. Calling C functions on 32 bit systems is pretty easy. You just push your parameters on the stack. Here is a simple hello world example that uses the printf function of C. It is NASM code for Linux. The keyword extern tells the compiler that printf is defined somewhere else. Using gcc will provide the C libraries.

: (ASM)
;type this to create an executable file:
;
;nasm -f elf hello.asm
;gcc -o hello hello.o
;
;this code only works on 32 bit Linux
;

extern printf

section .data

message: db "Hello World", 10, 0

section .text

global main

main:
push message
call printf
mov eax, 1 ;exit syscall
mov ebx, 0
int 80h

Since I use a book that only covers 32 bit assembly, I got into trouble trying it on my 64 bit system. The code above threw a segmentation fault. I found the answer in this document: www.x86-64.org/documentation/abi.pdf

Obviously calling C functions became more complicated. First you need to know the classification of your parameter (MEMORY, INTEGER, SSE, ...). For INTEGER arguments general purpose registers are used to pass the parameters. The order is the following:

%rdi, %rsi, %rdx, %rcx, %r8 and %r9

That means %rdi is used for the first parameter, %rsi for the second and so on. The printf parameters in our example are INTEGER, because you pass memory addresses instead of the string itself.  The printf function however has another speciality. The number of arguments is arbitrary. The ellipsis in the declaration shows this:

:
int printf ( const char * format, ... );
Because of that you also have to put the number of arguments you passed in vector registers into %al. Vector registers are %xmm0 - %xmm15 and %ymm0-%ymm15  The following example shows the implementation of a hello world using printf with two parameters. Since no vector registers are used, 0 is put into %al.

: (ASM)
;type this to create an executable file:
;
;nasm -f elf64 -g -F stabs hello.asm
;gcc -o hello hello.o
;
;this code only works on 64 bit Linux
;

extern printf

section .data

message: db "Hello World", 0
type: db "%s",10,0

section .text

global main

main:
mov rdi, type ;first parameter
mov rsi, message ;second parameter
mov rax, 0 ;no floating point register used
call printf
mov rax, 1 ;exit syscall
mov rbx, 0
int 80h

This code works well. The call to the printf function is equal to this (yes, I could have done this with one argument, but I want to show how to use several of them):
:
printf("%s\n", "Hello World");
This example should be enough for a quick start into using C functions in 64 bit assembly. Have a look at the documentation I linked above to get all the information you need.

Deque
: Re: [ASM] Calling C functions on 64bit architecture
: Daemon November 06, 2012, 06:37:06 PM
Very nice share. I can't think of any uses for it atm but I'm new to ASM and so I'm sure ill think.of something in the future. Very readable post too, thanks deque :)
: Re: [ASM] Calling C functions on 64bit architecture
: ca0s November 07, 2012, 12:48:12 PM
Nice intro Deque.
For more info:
:
http://www.x86-64.org/documentation/abi.pdf3.2 - Function calling sequence
: Re: [ASM] Calling C functions on 64bit architecture
: Deque November 07, 2012, 01:00:54 PM
Nice intro Deque.
For more info:
:
http://www.x86-64.org/documentation/abi.pdf3.2 - Function calling sequence

Thank you. I already gave that link in my first post. ;)
: Re: [ASM] Calling C functions on 64bit architecture
: ca0s November 07, 2012, 01:02:25 PM
Thank you. I already gave that link in my first post. ;)
Derp for me. Didn't read carefully. Sorry 'bout that.