2009년 10월 30일 금요일

나만의 노트

Scatter-Gatter I/O

: 우리말로 풀어 보자면 분배-집합 입출력이다. WSASend()함수를 이용하여 여러 개의 버퍼를 하나의 패킷으로 묶어 보내고 받는 쪽에서는 WSARecv()함수를 이용하여 하나의 패킷으로 받아서 다시 여러 개의 버퍼로 나눌 수 있다. 그러나 이것은 일반적으로 고정되고 형식화된 데이터를 송수신 하는 프로그램에서는 유용하나 게임 서버에서는 이 방식이 거의 쓰이지 않는다.

 

[함수 호출 규약(Function Calling Convention)]

: CALLBACK이란 것은 사용자가 호출하는 것이 아니고 윈도우에서 호출해주는 함수를 의미하는 것으로 선언 해놓은 것을 보면 #define CALLBACK _stdcall 라고 되어 있다. 이렇게 #define한 이유는 코드의 가독성을 위해서 그렇다. CALLBACK이란 키워드를 보면 "아 이것은 윈도우가 호출하는 함수구나"라는 것을 코드만 보아도 알 수 있도록 한 것이다. 이 외에도 우리에게 익숙한 WINAPI, APIENTRY도 이와 동일하게 선언 되어있다.

그러면 _stdcall은 무었일까? 함수를 호풀 하는 방식은 함수를 호출할 때 인자를 넘겨주는 방식과 함수를 다 사용한 후에 스탯에 담겨 있던 인자를 제거하는 방식에 따라서 크게 4가지로 나눌수 있다.

그 4가지는 _stdcall, _cdecl, _fastcall, _thiscall이 있다. 자 그럼 한가지씩 파해쳐 보자~

_stdcall

: _stdcall 윈도우상에서 기본적으로 사용되는 방식이다. _stdcall의 특징은 함수가 호출되어 인자를 전달할 때 스택을 이용해서 전달하는데 스택에 인자의 오른쪽을 시작으로 해서 왼쪽까지 스택에 순서대로 넣고 함수 처리가 모두 끝난 후에 스택에 있던 인자들을 호출 당한 함수에서 모두 해제를 하고 반환한다.

<_stdcall의 처리 순서>

오른쪽부터 스택에 인자를 넣는다 -> 함수 호출 -> 함수 처리가 끝난 후 스택의 인자를 해제 한다(스택 복원) -> 함수 반환

_cdecl

: 이것은 C와 C++에서 기본적으로 사용되는 방식으로써 _stdcall과 마찬가지로 호출할 때 스택에 인자를 오른쪽부터 순서대로 넣는다. 하지만 이 방식은 스택의 인자를 호출된 함수에서 처리하지 않고 호출된 함수가 반환된 후에 호출을 한 함수에서 그 스택에 있던 인자를 해제한다.

<_cdecl의 처리 순서>

오른쪽부터 스택에 인자를 넣는다 -> 함수 호출 -> 함수 반환 -> 호출한 함수로 돌아온 후 스택의 인자를 해제 한다(스택 복원)

_fastcall

: 이것은 볼랜드 델파이나 C 빌더에서 기본적으로 사용되는 방식으로써 두개의 인자를 레지스터 ecx와 edx를 이용해 전달하는 방식이다. 인자가 두개를 넘을 경우에는 두개만 레지스터에 넣어 전달하고 나머지는 다른 호출과 마찬가지로 스택에 넣어 전달하고 레지스터가 이미 사용 중이라면 모두 스택에 넣어 전달된다. 인자를 넣는 순서는 오른쪽부터 왼쪽이며 슽택 해제 방식은 _stdcall과 마찬가지로 반환되기 전 호출된 함수 내에서 해제를 한다.

<_fastcall의 처리 순서>

오른쪽부터 스택에 인자를 넣는데 2개의 인자에 대해서는 레지스터가 비어있다면 레지스터로 넣는다. -> 함수 호출 -> 함수 처리가 끝난 후 스택의 인자를 해제한다(스택 복원) -> 함수 반환

 

_thiscall

: 이것은 C++의 클래스에서 함수를 호출할 때 기본적으로 사용되는 방법이다. 이 방식은 인자 전달 방식이나 해제 방식은 _stdcall과 같다. 하지만 this라는 인자를 ecx 레지스터에 전달하는데 이유는 클래스라는 개념 때문에 그렇다. 클래스는 같은 형태로 여러 개의 객체를 만들수 있는데 이 각각의 객체들은 멤버 변수와 멤버 함수를 가지며 이 객체들의 멤버 변수는 메모리 상에서도 서로 다른 위치에서 독립적으로 있다. 하지만 멤버 함수는 메모리상에 같은 위치에 있어서 모든 객체들은 같은 멤버 함수를 사용한다. 그렇지만 멤버 함수에서는 각각의 객체에 해당하는 멤버 변수를 특별한 선언 없이도 접근이 가능 해야 하는데 그것을 하기 위해 this라는 객체의 포인터가 필요한 것이다.

<_thiscall의 처리 순서>

오른쪽부터 스택에 인자를 넣고this포인터를 ecx레지스터에 넣는다. -> 함수 호출 -> 함수 처리가 끝난 후 스택의 인자를 해제한다(스택 복원) -> 함수 반환

댓글 없음:

댓글 쓰기