Tech & IT/프로그래밍

Calling Convention정확히 알아야 함(어셈으로 살펴보는 함수 call의 원리)

해피콧 2012. 3. 22. 10:48
'); }
'); }
어셈으로 살펴보는 함수 call의 원리
     java는 __stdcall이라는 방식을 사용합니다.
     java와 C가 통신하려면 __stdcall방식을 아셔야 합니다.

www.nasm.us 에서 download에서 win최신 버전을 설치한다
nasm -f win32 -o 1.obj 1.asm 

////////////////////////////////////////
// main.c

#include <stdio.h>

int asm_main();

int main()
{
int n = asm_main();
printf("result = %d\n", n);
return 0;
}
 
; 3. asm - 함수의 인자 전달 방식
; 1. 레지스터를 사용한 인자 전달 - 빠르다!! 하지만 갯수의 제약이 있다.
; 2. 스택을 사용한 인자 전달 - 인자 전달에 사용한 스택을 파괴해야 한다.
; (1) 호출자 파괴
; (2) 호출당한자 파괴 - 시스템에 안정적이고 메모리 사용량이 약간 줄어 든다

segment .text

global _asm_main
_asm_main:
; 레지스터를 사용한 인자의 전달.
mov edx, 2
mov ecx, 1
call foo
; 스택을 사용한 인자 전달
push 5
push 8
call goo ; 돌아올 주소를 스택에 넣는다( push 돌아올 주소 \ jmp goo)
add esp, 8 ; 인자 전달에 사용한 스택을 파괴해야 한다
ret
goo: ; 인자를 꺼내야 한다. 어떻게?? 잘 생각해보자
mov eax, dword[esp+4]
add eax, dword[esp+8]
ret
foo:
mov eax, ecx ;eax = ecx
add eax, edx ;eax += edx
ret
 








#include <stdio.h>

void __stdcall foo(int a, int b)
{
printf("foo\n");
}

//함수 포인터와 Calling Convention문제
//typedef void(*F)(int, int);   // 이렇게 하면 _cdecl로 함수포인터가 동작한다. 여기에 __stdcall함수를 넣으면 stack이 2번 파괴됨
typedef void(__stdcall *F)(int, int) ; //이렇게 해야 맞다

int main()
{
F f = (F)&foo;
f(1,2); //어떻게 될까요? 정확하게 어떤 현상이 나올 지 정확히 예측가능해야 함
// push 2
// push 1
// call foo
// add esp, 8
// 결국은 stack이 2번 파괴됨