이번엔 함수에 인자값을 넘겨주는 프로그램이다
08048344 <func>:
void func(int a, int b)
{
8048344: 55 push %ebp
8048345: 89 e5 mov %esp,%ebp
8048347: 83 ec 10 sub $0x10,%esp
int c;
c=a;
804834a: 8b 45 08 mov 0x8(%ebp),%eax
804834d: 89 45 fc mov %eax,-0x4(%ebp)
}
8048350: c9 leave
8048351: c3 ret
08048352 <main>:
int main()
{
8048352: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048356: 83 e4 f0 and $0xfffffff0,%esp
8048359: ff 71 fc pushl -0x4(%ecx)
804835c: 55 push %ebp
804835d: 89 e5 mov %esp,%ebp
804835f: 51 push %ecx
8048360: 83 ec 18 sub $0x18,%esp
int a=10, b=15;
8048363: c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%ebp)
804836a: c7 45 f4 0f 00 00 00 movl $0xf,-0xc(%ebp)
func(a, b);
8048371: 8b 45 f4 mov -0xc(%ebp),%eax
8048374: 89 44 24 04 mov %eax,0x4(%esp)
8048378: 8b 45 f8 mov -0x8(%ebp),%eax
804837b: 89 04 24 mov %eax,(%esp)
804837e: e8 c1 ff ff ff call 8048344 <func>
return 0;
8048383: b8 00 00 00 00 mov $0x0,%eax
}
func(a, b);
8048371: 8b 45 f4 mov -0xc(%ebp),%eax
8048374: 89 44 24 04 mov %eax,0x4(%esp)
8048378: 8b 45 f8 mov -0x8(%ebp),%eax
804837b: 89 04 24 mov %eax,(%esp)
804837e: e8 c1 ff ff ff call 8048344 <func>
-0xc(%ebp) <-- b값이 있는 스택
b값을 0x4(%esp) 여기로 넣는다 즉 esp의 바로 위값이다
() 괄호를 쓰면 간접참조한다 %esp번지에서 4를 더한 번지에 값을 넣는다는 것이다
-0x8(%ebp) <-- a값이 있는 스택
mov %eax,(%esp) 현재 스택에(%esp) a값을 저장한다
그다음 call 호출 그럼 스택은 간단하게 이런 모양일것이다
|----------
| 변수 b값 | 스택이 증가하는 방향
08048344 <func>:
void func(int a, int b)
{
8048344: 55 push %ebp
8048345: 89 e5 mov %esp,%ebp
8048347: 83 ec 10 sub $0x10,%esp
int c;
c=a;
804834a: 8b 45 08 mov 0x8(%ebp),%eax
804834d: 89 45 fc mov %eax,-0x4(%ebp)
}
8048350: c9 leave
8048351: c3 ret
08048352 <main>:
int main()
{
8048352: 8d 4c 24 04 lea 0x4(%esp),%ecx
8048356: 83 e4 f0 and $0xfffffff0,%esp
8048359: ff 71 fc pushl -0x4(%ecx)
804835c: 55 push %ebp
804835d: 89 e5 mov %esp,%ebp
804835f: 51 push %ecx
8048360: 83 ec 18 sub $0x18,%esp
int a=10, b=15;
8048363: c7 45 f8 0a 00 00 00 movl $0xa,-0x8(%ebp)
804836a: c7 45 f4 0f 00 00 00 movl $0xf,-0xc(%ebp)
func(a, b);
8048371: 8b 45 f4 mov -0xc(%ebp),%eax
8048374: 89 44 24 04 mov %eax,0x4(%esp)
8048378: 8b 45 f8 mov -0x8(%ebp),%eax
804837b: 89 04 24 mov %eax,(%esp)
804837e: e8 c1 ff ff ff call 8048344 <func>
return 0;
8048383: b8 00 00 00 00 mov $0x0,%eax
}
func(a, b);
8048371: 8b 45 f4 mov -0xc(%ebp),%eax
8048374: 89 44 24 04 mov %eax,0x4(%esp)
8048378: 8b 45 f8 mov -0x8(%ebp),%eax
804837b: 89 04 24 mov %eax,(%esp)
804837e: e8 c1 ff ff ff call 8048344 <func>
-0xc(%ebp) <-- b값이 있는 스택
b값을 0x4(%esp) 여기로 넣는다 즉 esp의 바로 위값이다
() 괄호를 쓰면 간접참조한다 %esp번지에서 4를 더한 번지에 값을 넣는다는 것이다
-0x8(%ebp) <-- a값이 있는 스택
mov %eax,(%esp) 현재 스택에(%esp) a값을 저장한다
그다음 call 호출 그럼 스택은 간단하게 이런 모양일것이다
|----------
| 변수 b값 | 스택이 증가하는 방향
|---------- |
| 변수 a값 V
|----------
| 8048383 <--- call 호출시 다음 주소를 스택에 저장됨 <--- 현재 esp
|----------
|
func 함수
8048344: 55 push %ebp
8048345: 89 e5 mov %esp,%ebp
8048347: 83 ec 10 sub $0x10,%esp
int c;
c=a;
804834a: 8b 45 08 mov 0x8(%ebp),%eax
804834d: 89 45 fc mov %eax,-0x4(%ebp)
}
8048350: c9 leave
8048351: c3 ret
push %ebp <-- 기존에 ebp주소를 스택에 저장한다
8048345: 89 e5 mov %esp,%ebp <--- esp 주소를 ebp에 덮어쓰운다
그러면 ebp주소는 스택끝에 있을것이다
sub $0x10,%esp <--- 스택을 감소시킨다 (스택은 밑으로 증가)
함수에서 int c 변수 하나만 선언하므로 4바이트만 감소시켜도 되는데
굳이 0x10바이트 만큼 감소시킨 이유는 나도 잘모르것다.ㅡㅡ
c=a;
804834a: 8b 45 08 mov 0x8(%ebp),%eax <--- ebp+0x8번지 a값이 저장되있는 곳이다
804834d: 89 45 fc mov %eax,-0x4(%ebp) <--- ebp-0x4에 저장한다
즉 ebp를 기준으로 + 된곳은 main에서 저장된 스택이고 - 된곳은 func함수에서 저장한것이다
push %esp %ebp 이걸 왜 해야 하는지 이해되시죠
ebp포인터를 기준으로 스택공간을 잡는것이다
그럴려면 esp포인터 스택끝을 기준으로 잡아야 할것이다
8048350: c9 leave <-- 함수가 끝나면 이제 스택을 다시 제자리로 돌려야 한다
esp스택은 원래 있던 esp즉 call함수에서 저장한 스택으로 다시 돌아가야 한다
그러면 현재 func함수에서 총 0x14 바이트 증가 하였으니 다시 감소시켜야 한다
0x14는 push %ebp (4바이트) + sub $0x10,%esp (16바이트)
ebp스택도 다시 초기화 되어야 한다 main시점으로 func함수 시작시 push ebp를 한 이유이다
leave를 풀어쓰면
add $0x10, %esp <--- esp 0x10증가
pop %ebp <-- 현재 스택을 증가시켜서 값을 ebp에 저장
그럼 원래되로 스택은 돌아왔다
마지막으로 main코드로 점프를 해야한다
점프 위치는 call 호출시 스택에 저장되었다
바로 현재 esp 스택에 저장되있다
그걸 꺼내서 main으로 점프를 한다
8048351: c3 ret
(gdb) x $esp
0xbfd7ea28: 0x08048383 <-- main 코드이다 ret 가 실행되면 pop 되고 main코드로 이동한다
집에서 다들 실험해 보길 바란다
직접 해보는게 머리에서도 이해가 빠르니...
| 변수 a값 V
|----------
| 8048383 <--- call 호출시 다음 주소를 스택에 저장됨 <--- 현재 esp
|----------
|
func 함수
8048344: 55 push %ebp
8048345: 89 e5 mov %esp,%ebp
8048347: 83 ec 10 sub $0x10,%esp
int c;
c=a;
804834a: 8b 45 08 mov 0x8(%ebp),%eax
804834d: 89 45 fc mov %eax,-0x4(%ebp)
}
8048350: c9 leave
8048351: c3 ret
push %ebp <-- 기존에 ebp주소를 스택에 저장한다
8048345: 89 e5 mov %esp,%ebp <--- esp 주소를 ebp에 덮어쓰운다
그러면 ebp주소는 스택끝에 있을것이다
sub $0x10,%esp <--- 스택을 감소시킨다 (스택은 밑으로 증가)
함수에서 int c 변수 하나만 선언하므로 4바이트만 감소시켜도 되는데
굳이 0x10바이트 만큼 감소시킨 이유는 나도 잘모르것다.ㅡㅡ
c=a;
804834a: 8b 45 08 mov 0x8(%ebp),%eax <--- ebp+0x8번지 a값이 저장되있는 곳이다
804834d: 89 45 fc mov %eax,-0x4(%ebp) <--- ebp-0x4에 저장한다
즉 ebp를 기준으로 + 된곳은 main에서 저장된 스택이고 - 된곳은 func함수에서 저장한것이다
push %esp %ebp 이걸 왜 해야 하는지 이해되시죠
ebp포인터를 기준으로 스택공간을 잡는것이다
그럴려면 esp포인터 스택끝을 기준으로 잡아야 할것이다
8048350: c9 leave <-- 함수가 끝나면 이제 스택을 다시 제자리로 돌려야 한다
esp스택은 원래 있던 esp즉 call함수에서 저장한 스택으로 다시 돌아가야 한다
그러면 현재 func함수에서 총 0x14 바이트 증가 하였으니 다시 감소시켜야 한다
0x14는 push %ebp (4바이트) + sub $0x10,%esp (16바이트)
ebp스택도 다시 초기화 되어야 한다 main시점으로 func함수 시작시 push ebp를 한 이유이다
leave를 풀어쓰면
add $0x10, %esp <--- esp 0x10증가
pop %ebp <-- 현재 스택을 증가시켜서 값을 ebp에 저장
그럼 원래되로 스택은 돌아왔다
마지막으로 main코드로 점프를 해야한다
점프 위치는 call 호출시 스택에 저장되었다
바로 현재 esp 스택에 저장되있다
그걸 꺼내서 main으로 점프를 한다
8048351: c3 ret
(gdb) x $esp
0xbfd7ea28: 0x08048383 <-- main 코드이다 ret 가 실행되면 pop 되고 main코드로 이동한다
집에서 다들 실험해 보길 바란다
직접 해보는게 머리에서도 이해가 빠르니...