본문 바로가기
운영체제/[ecourse] Windows Programming

1-4. Stack Frame

by 헛둘이 2022. 9. 4.
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

댓글