본문 바로가기

dis & asm

함수 분석 (2)

이번엔 함수에 인자값을 넘겨주는 프로그램이다


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코드로 이동한다


집에서 다들 실험해 보길 바란다
직접 해보는게 머리에서도 이해가 빠르니...