검색결과 리스트
글
함수가 호출되는 과정
1. 인자를 스택에 집어넣는다
호출된 함수가 인자를 받을 수 있도록 스택에 집어넣습니다.
2. 함수를 호출합니다
Call 명령이 실행되면 CPU는 EIP 레지스터, 즉 함수 호출이 종료된 뒤 돌아와야 할 코드의 주소를 스택에 집어 넣은 뒤,
Call 명령 뒤에 이어지는 인자를 EIP 레지스터에 로드한다.
스택에 집어넣은 EIP 레지스터 값은 이후 함수가 종료된 뒤에 돌아올 코드 위치가 된다.
3. 프레임 포인터를 설정한다
호출된 함수는 호출한 함수의 프레임 포인터를 스택에 보관하고, 그 시점의 스택 포인터 ESP를 프레임 포인터로 설정한다.
설정된 프레임 포인터는 스택 프레임 정보를 참조하는 기준 값으로 사용하게 된다.
4. 로컬 변수를 위한 공간을 할당한다
호출된 함수에서 사용할 로컬 변수를 저장할 공간을 준비한다.
이 작업은 스택 포인터를 이동시키는 것으로 완료된다.
즉 이 함수에서 로컬 변수는 EBP와 ESP 사이의 공간을 사용하게 되는 것으로,
프레임 포인터를 기준으로 첫 번째 로컬 변수는 [ebp-4], 두 번째 로컬 변수는 [ebp-8]과 같은 식으로 참조하게 된다.
5. 호출한 함수의 실행 상태를 보존한다
호출된 함수에서 범용 레지스터를 사용하는 경우, 이전 함수에서 범용 레지스터를 저장해 둔 값이 지워져서
원래 함수로 돌아간 뒤 정상적으로 실행을 재개할 수 없게 되니, 안전하게 이전 함수의 실행 내역을 보존하기 위해서
범용 레지스터의 내용을 스택에 보존한다.
6. 함수를 실행한다
함수의 실행에 필요한 준비과 되었으므로 실제 함수의 연산을 수행한다.
7. 호출한 함수의 실행 상태를 복구한다
5번 과정에서 저장한 레지스터를 복구한다.
⚠︎ 스택을 사용하고 있기 때문에 넣은 순서와 반대의 순서로 꺼내고 있다는 점에 주의해야 한다.
8. 스택을 정리하고, 프레임 포인터를 복구한다
로컬 변수 할당 등으로 사용한 원래대로 복구 한다.
이 과정은 함수에 진입할 시점의 스택 포인터를 복구하는 것으로 완료된다.
그 후 현재 프레임 포인터 위치에 있는 이전 함수의 프레임 포인터를 복구한다.
9. 함수로부터 돌아간다
ret 명령을 수행하면 스택에 저장해 둔 리턴 주소를 꺼내서 EIP에 로드 한다.
이로써 호출된 함수에서 완전히 빠져나와 원래 함수로 돌아온 상태가 된다.
10. 스택에 집어넣은 인자를 정리한다
cdecl 호출 규약에서는 호출자가 인자를 정리해야 하므로,
스택 포인터에 (인자당 바이트 수) * ( 인자의 개수) 만큼 이동시켜서 인자를 꺼내는 처리를 수행한다.
이것으로 함수 호출 과정이 끝나며 리턴값을 갖는다면 eax 레지스터에 함수 호출의 결과값이 들어있게 된다.
함수 호출 규약이나 예외 처리를 사용했는가의 여부에 따라서 스택 프레임의 구조는 약간씩 달라질 수 있다.
위의 과정에서 3 ~ 5 번에 해당하는 함수 실행 준비 과정을 프롤로그 (Prolog) 라고 부르며,
7 ~ 9번의 함수 실행을 마무리 하는 프롤로그의 반대 과정을 에필로그 (Epilog) 라고 부른다.
'Programming > Assembly' 카테고리의 다른 글
64bit 체제에서는 어떻게 인자전달을 할까? (0) | 2015.08.27 |
---|---|
메모리 구조 (0) | 2015.08.27 |
함수 호출 규약 (Calling Convention)과 스택 프레임 (Stack Frame) (0) | 2015.08.27 |
어셈블리 명령어 이해하기 - 하 (0) | 2015.08.27 |
어셈블리 명령어 이해하기 - 중 (0) | 2015.08.27 |
설정
트랙백
댓글
글
메모리 구조는 메모리를 필요에 따라 여러가지 종류로 나누어 둠을 의미한다.
나누는 이유는 유사한 성향의 데이터를 묶어서 저장하면 관리가 용이해지고 접근속도가 향상되기 때문이다.
일반적으로 4가지, 좀 더 세분화 하면 5가지 정도로 구분된다.
⚀ Code 영역
코드 자체를 구성하는 메모리 영역으로 Hex파일이나 BIN 파일 메모리가 있다.
프로그램 명령이 위치하는 곳으로 기계어로 제어되는 메모리 영역이다.
⚁ Data 영역
전역변수(global), 정적변수(static), 배열(array), 구조체(structure) 등이 저장된다.
🁀 초기화 된 데이터는 data 영역에 저장되고,
🁁 초기화 되지 않은 데이터는 BSS (Block Stated Symbol) 영역에 저장된다.
프로그램이 실행 될 때 생성되고 프로그램이 종료 되면 시스템에 반환 된다.
함수 내부에 선언된 Static 변수는 프로그램이 실행 될 때 공간만 할당되고, 그 함수가 실행 될 때 초기화 된다.
⚂ Heap 영역
필요에 의해 동적으로 메모리를 할당 하고자 할 때 위치하는 메모리 영역으로 동적 데이터 영역이라고 부르며,
메모리 주소 값에 의해서만 참조되고 사용되는 영역이다.
이 영역에 데이터를 저장 하기 위해서 C는 malloc(), C++은 new() 함수를 사용한다.
⚃ Stack 영역
프로그램이 자동으로 사용하는 임시 메모리 영역이다.
지역(local) 변수, 매개변수(parameter), 리턴 값 등 잠시 사용되었다가 사라지는 데이터를 저장하는 영역이다.
함수 호출 시 생성되고, 함수가 끝나면 시스템에 반환 된다.
스택 사이즈는 각 프로세스마다 할당 되지만 프로세스가 메모리에 로드 될 때
스택 사이즈가 고정되어 있어, 런타임 시에 스택 사이즈를 바꿀 수는 없다.
명령 실행시 자동 증가/감소 하기 때문에 보통 메모리의 마지막 번지를 지정 한다.
< 구체적인 메모리 영역 >
자료 출처 : http://sfixer.tistory.com/30
'Programming > Assembly' 카테고리의 다른 글
64bit 체제에서는 어떻게 인자전달을 할까? (0) | 2015.08.27 |
---|---|
함수 프롤로그(Prolog), 에필로그(Epilog) (0) | 2015.08.27 |
함수 호출 규약 (Calling Convention)과 스택 프레임 (Stack Frame) (0) | 2015.08.27 |
어셈블리 명령어 이해하기 - 하 (0) | 2015.08.27 |
어셈블리 명령어 이해하기 - 중 (0) | 2015.08.27 |
설정
트랙백
댓글
글
함수 호출 규약이란 함수를 호출 할 때 *파라미터를 어떤식으로 저장하는가에 대한 일종의 약속입니다.
함수를 호출하는 방식에 대해 인수는 어떻게 전달하며 리턴값은 어떻게 반환할 것이고 인수 전달을 위해 메모리는 누가 정리할 것인지를 규정한다.
*파라미터(Parameter) : 매개변수라는 뜻으로 함수를 정의 할 때 외부로 받아들이는 임의의 값을 의미한다.
Ⅰ. 스택 (Stack)
호출 규약에 대해 알기 위해서는 스택에 대해 알아야 한다.
스택은 시스템이 사용하는 메모리 공간이며 CPU가 임시적인 정보를 저장할 필요가 있을 때 이 영역을 사용한다.
일반적인 운영체제의 메모리 구조는 위의 그림과 같다.
앞부분에는 프로그램의 코드, 이어서 데이터 영역, 자유영역인 힙이 있다.
스택은 메모리의 가장 뒷부분에 있는데 힙과 스택이 만나게 되면 메모리가 부족한 상태가 된다.
Ⅱ. 스택 프레임 (Stack Frame)
함수가 호출될 때 스택에는 함수로 전달되는 인자, 실행을 마치고 돌아올 복귀 번지,
지역 변수등의 정보들이 저장된다. 이때 스택에 저장되는 함수의 호출 정보를 스택 프레임이라고 한다.
또한 함수 실행중에도 필요할 경우 임시적인 정보 저장을 위래 스택을 사용하되 이때 PUSH 함수와 POP 함수는
일치하므로 함수가 리턴하면 정확하게 호출 전의 상태로 돌아가 항상성을 유지한다.
즉, 함수가 호출될 때 인수와 복귀 번지, 지역변수 영역등을 가진
스택 프레임이 생성되고 리턴된 후 정확하게 복구하도록 되어있다.
⚀ 함수 호출에 대한 주요 내용
1. 인수도 함수 호출 중에만 유지되는 일종의 지역변수이다. 인수의 초기화 시점은 함수가 호출될 때이다.
2. 지역변수를 많이 선언하는 것과 함수의 실행속도와는 직접적인 상관이 없다.
3. 지역변수를 많이 쓴다고 해서 프로그램이 커지는 것도 아니다.
4. 지역변수를 위해 ESP를 위로 올려 공간만 만들 뿐이므로 별도의 초기식이 없으면
지역변수는 초기화 되지 않는다. 이때 원래 공간에 들어있던 값이 바로 쓰레기 값이다.
지역변수를 초기화화면 이때는 초기화하는 시간만큼 느려지고 필요한 코드만큼 프로그램의 크기도 늘어난다.
5. 함수를 호출할 때마다 스택프레임이 생성되었다가 사라지는 복잡한 과정을 거치므로
함수 호출에는 오버헤더가 있다.
(?) 오버헤드는 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 ,
메모리등을 말한다. 여기서 오버헤더는 오버헤드 인가?
Ⅲ. 호출 규약
기본적인 C/C++ 언어의 호출 규약인 _cdecl은 인수를 뒤쪽부터
순서대로 전달하며 인수 전달에 사용한 스택 영역은 *호출원이 정리한다.
이런 호출 규약이 변경되면 스택 프레임의 모양과 관리 방법도 달라진다.
아래는 각 호출 규약들에 대해 정리한 것이다.
* 호출원 : 함수를 호출한 곳
'Programming > Assembly' 카테고리의 다른 글
함수 프롤로그(Prolog), 에필로그(Epilog) (0) | 2015.08.27 |
---|---|
메모리 구조 (0) | 2015.08.27 |
어셈블리 명령어 이해하기 - 하 (0) | 2015.08.27 |
어셈블리 명령어 이해하기 - 중 (0) | 2015.08.27 |
어셈블리 명령어 이해하기 - 상 (0) | 2015.08.27 |
RECENT COMMENT