main.cpp
#include <stdio.h>
#include <inttypes.h>
#include "../../commonfiles/miscdefs.h"
extern "C" Int64 Cc1(Int8 a, Int16 b, Int32 c, Int64 d, Int8 e, Int16 f, Int32 g, Int64 h);
int main(int argc, char* argv[])
{
Int8 a = 10, e = -20;
Int16 b = -200, f = 400;
Int32 c = 300, g = -600;
Int64 d = 4000, h = -8000;
Int64 x = Cc1(a, b, c, d, e, f, g, h);
printf("\nResults for CallingConvention1\n");
printf("a, b, c, d: %8" PRId8 " %8" PRId16 " %8" PRId32 " %8" PRId64 "\n", a, b, c, d);
printf("e, f, g, h: %8" PRId8 " %8" PRId16 " %8" PRId32 " %8" PRId64 "\n", e, f, g, h);
printf(" x: %" PRId64 "\n", x);
return 0;
}
callingconvention1.asm
; Name: callingconvention1.asm
;
; Build: g++ -m32 -c main.cpp -o main.o
; nasm -f elf32 -o callingconvention1.o callingconvention1.asm
; g++ -m32 -o callingconvention1 callingconvention1.o main.o
;
; Remark: Allthough this example was for VC++ and GCC uses a different ABI
; I converted this example to GCC to demonstrate the use of a
; stackframe to store the intermediate sum of a, b, c, d and
; e, f, g and h. At the end the program reads both intermediate sums,
; add them together and returns it to the calling routine.
; Another thought is that since this function is a leaf function,
; we don't need to push rbp onto the stack and save rsp. We can use
; rsp to write directly into the memory below rsp to store the intermediate
; results as long as they don't exceed the 128 bytes of red zone.
; More on that in another example.
;
; Source: Modern x86 Assembly Language Programming p.524
global Cc1
bits 64
section .text
; extern "C" Int64 Cc1_(Int8 a, Int16 b, Int32 c, Int64 d, Int8 e, Int16 f, Int32 g, Int64 h);
;
; Description: The following function illustrates how to create and
; use a basic x86-64 stack frame pointer.
%define FRAMESIZE 16 ; number of bytes to preserve (2 variables x 8 bytes)
%define RETURNADDR 16 ; size of rbp and returnaddress on the stack
Cc1:
; Registers: rdi = a
; rsi = b
; rdx = c
; rcx = d
; r8 = e
; r9 = f
; stack g
; stack h
; Function prolog
push rbp ;save caller's rbp register
sub rsp,FRAMESIZE ;create space on stack for our arguments
mov rbp,rsp ;set frame pointer
;Calculate a + b + c + d
movsx rdi,dil ;sign_extend(a)
movsx rsi,si ;sign_extend(b)
movsx rdx,edx ;sign_extend(c)
mov rax,rdi ;rax = a
add rax,rsi ;rax = a + b
add rax,rcx ;rax = a + b + c
add rax,rdx ;rax = a + b + c + d
mov [rbp+FRAMESIZE-8],rax ;Save temporarly sum
;Calculate e + f + g + h
movsx r8,r8b ;sign_extend(e)
movsx r9,r9w ;sign_extend(f)
mov eax,dword[rbp+FRAMESIZE+RETURNADDR] ;get g
movsx r11,eax ;sign_extend(g)
mov rax,r8 ;rax = e
add rax,r9 ;rax = e + f
add rax,r11 ;rax = e + f + g
add rax,qword[rbp+FRAMESIZE+RETURNADDR+8] ;rax = e + f + g + h
mov [rbp+FRAMESIZE-16],rax ;Save temporarly sum
;Get the intermediate sum to calculate the final sum
mov rax,[rbp+FRAMESIZE-8] ;get a + b + c + d
add rax,[rbp+FRAMESIZE-16] ;add e + f + g + h
; Function epilog
add rsp,FRAMESIZE ;release local stack space
pop rbp ;restore caller's rbp register
ret
build
g++ -m32 -c main.cpp -o main.o
nasm -f elf32 -o callingconvention1.o callingconvention1.asm
g++ -m32 -o callingconvention1 callingconvention1.o main.o