esp를 이용한 함수인자 접근 방식의 문제점
- 함수 내에서 스택을 사용할 수 없다.
- 함수에서 push로 인자를 넣을 경우 esp의 offset이 변경되기 때문
.model flat
public _asm_main
.code
_asm_main:
push 2
push 1
call _func
add esp, 8
ret
_func:
mov eax, dword ptr [esp + 4] // _func에서 push를 할 경우, esp가 변경되므로 [esp + 8]이 된다
add eax, dword ptr [esp + 8] // _func에서 push를 할 경우, esp가 변경되므로 [esp + 12]이 된다
ret
end
스택 프레임
- 그래서 레지스터 하나를 사용해 돌아갈 주소를 가리키도록 해놓음 (EBP 레지스터)
- EBP를 사용해서 인자에 접근하면 스택에 아무리 push 해도 offset이 변하지 않는다.
- 대신 ebp 레지스터를 그 전에 사용하고 있었다면, (함수에서 다른 함수를 호출한 경우라면)
- 그 값이 날아가므로 ebp 레지스터가 가진 값을 먼저 스택에 push 해준다.
- 그리고 함수 호출이 끝날 때 ebp가 갖고 있던 값을 복구한다.
.model flat
public _asm_main
.code
_asm_main:
push ebp
mov ebp, esp
push 5
push 5
call _asm_func
mov esp, ebp
pop ebp
ret
_asm_func:
push ebp
mov ebp, esp
mov eax, dword ptr[ebp+8]
add eax, dword ptr[ebp+12]
mov esp, ebp
pop ebp
ret 8
- 이 구조를 스택 프레임이라고 부른다.
- ebp가 원래 가지고 있던 값을 push함으로 인해 매개변수와의 거리가 32비트만큼 멀어지게 되었다.
함수 내에서 지역변수를 사용하는 경우
- 지역 변수는 스택에 만들어진다.
- int x, y 변수를 함수 내에서 선언해보자.
.model flat
public _asm_main
.code
_asm_main:
push ebp
mov ebp, esp
push 5
push 5
call _asm_func
mov esp, ebp
pop ebp
ret
_asm_func:
push ebp
mov ebp, esp
sub esp, 8 // 스택을 아래로 내려서 공간 확보
mov dword ptr[ebp-4], 3
mov dword ptr[ebp-8], 4
mov eax, dword ptr[ebp+8]
add eax, dword ptr[ebp-4] // 함수 내의 지역변수에 접근
add eax, dword ptr[ebp-8] // 함수 내의 지역변수에 접근
add eax, dword ptr[ebp+12]
mov esp, ebp // 원래 변경 전 ebp가 저장된 스택 위치로 이동
pop ebp // ebp 레지스터 원복
ret 8
- sub esp, 8로 지역변수가 들어갈 크기 확보
- 함수 내 지역변수에 접근할 때에는 [ebp-4]. [ebp-8].... 이런 식으로 접근
- 함수가 파괴되기 전 esp 주소를 ebp 주소로 덮어써서 esp가 기존 ebp가 가지고 있던 값을 넣어둔 스택 위치를 가리키게 함
- pop ebp로 ebp가 원래 가지고 있던 값으로 다시 원복
- 함수 종료
C언어 코드를 어셈블리 코드로 작성하기 실습
int add(int a, int b)
{
int c = 0;
int d = 0;
c = a + b;
return c;
}
int main()
{
int n = add(1, 2);
}
.model flat
public _main
public _add
.code
_main:
push ebp
mov ebp, esp
push ecx
push 3
push 2
call _add
add esp, 8
mov dword ptr[ebp-4], eax
mov esp, ebp
pop ebp
ret
_add:
push ebp
mov ebp, esp
sub esp, 8
mov dword ptr[ebp-4], 0
mov dword ptr[ebp-8], 0
mov eax, dword ptr[ebp+8]
add eax, dword ptr[ebp+12]
mov dword ptr[ebp-4], eax
mov eax, dword ptr[ebp-4]
mov esp, ebp
pop ebp
ret
end
- _mainCRTStartup 함수가 없으므로 asm 파일 단독으로 컴파일 되지 않는다.
- ml 파일명.asm /link /entry:main(메인함수명) 개발자 프롬프트에서 이렇게 작성하여 컴파일
- 컴파일 완료
'운영체제 > [ecourse] Windows Programming' 카테고리의 다른 글
2-1. 윈도우 핸들과 API (0) | 2022.09.06 |
---|---|
1-5. C++과 MASM (0) | 2022.09.05 |
1-3. Calling Convention (0) | 2022.09.03 |
1-2. MASM 기본 문법 (0) | 2022.09.01 |
1-1-2. 어셈블리 빌드 방법 (0) | 2022.09.01 |
댓글