본문 바로가기

dis & asm

main 분석 (2)

어제 알바뛰고 낮에 자서 새벽까지 눈이 탱글탱글하다..ㅋㅋ


어셈 코드만 보고 해석하기 힘들다
gdb로 브레이크 걸면서 레지 변화를 주목하면서 따라가면
그나마 이해하기 쉽다



main에서 변수하나를 선언했다.



08048344 <main>:
int main()
{
 8048344:   8d 4c 24 04             lea    0x4(%esp),%ecx
 8048348:   83 e4 f0                and    $0xfffffff0,%esp
 804834b:   ff 71 fc                pushl  -0x4(%ecx)
 804834e:   55                      push   %ebp
 804834f:   89 e5                   mov    %esp,%ebp
 8048351:   51                      push   %ecx
 8048352:   83 ec 10                sub    $0x10,%esp
    int i;

    i=10;
 8048355:   c7 45 f8 0a 00 00 00    movl   $0xa,-0x8(%ebp)

    return 0;
 804835c:   b8 00 00 00 00          mov    $0x0,%eax
}
 8048361:   83 c4 10                add    $0x10,%esp
 8048364:   59                      pop    %ecx
 8048365:   5d                      pop    %ebp
 8048366:   8d 61 fc                lea    -0x4(%ecx),%esp
 8048369:   c3                      ret


음 어디서 부터 시작해야 할지 모르겟네

 8048344:   8d 4c 24 04             lea    0x4(%esp),%ecx
 8048348:   83 e4 f0                and    $0xfffffff0,%esp
 804834b:   ff 71 fc                pushl  -0x4(%ecx)

요부분은 gcc 최근버전에 추가된 거다

lea    0x4(%esp),%ecx    
esp+0x4 번지 주소에 있는 값을 ecx에 넣는다.


gdb 로 디스어셈 한거다

(gdb) disassemble main
Dump of assembler code for function main:
0x08048344 <main+0>:    lea    0x4(%esp),%ecx
0x08048348 <main+4>:    and    $0xfffffff0,%esp
0x0804834b <main+7>:    pushl  -0x4(%ecx)
0x0804834e <main+10>:    push   %ebp
0x0804834f <main+11>:    mov    %esp,%ebp
0x08048351 <main+13>:    push   %ecx
0x08048352 <main+14>:    sub    $0x10,%esp
0x08048355 <main+17>:    movl   $0xa,-0x8(%ebp)
0x0804835c <main+24>:    mov    $0x0,%eax
0x08048361 <main+29>:    add    $0x10,%esp
0x08048364 <main+32>:    pop    %ecx
0x08048365 <main+33>:    pop    %ebp
0x08048366 <main+34>:    lea    -0x4(%ecx),%esp
0x08048369 <main+37>:    ret   


b *0x08048348   <--- 브레이크
레지값 확인해 볼까

(gdb) x $esp+4
0xbff4cc30:    0x00000001
(gdb) x $ecx
0xbff4cc30:    0x00000001

값은 잘 들어갔다

0xbff4cc30:    0x00000001  
이거 해석방법은  왼쪽은 주소값    :  오른쪽은 왼쪽주소에 들어있는 값
말 해놓고 이상한데 쉽게 말해 c언어의 포인터를 생각하면 쉽다

1이 뭘까   다들 프로그램에 인자값을 넣어 봤을꺼다
그 인자의 count  -> argc 다

여기서 영어공부하나   argc  : argument count     argv : argument vector    ㅡㅡ

인자값을 않넣었으니 1이 됀거다
if (argc값이 왜 1인지 모르겠다)
{
     puts("c언어 책 다시보삼");
}

다시 돌아가 어셈코드를 보면
 804834e:   55                      push   %ebp
 804834f:   89 e5                   mov    %esp,%ebp
 8048351:   51                      push   %ecx
 8048352:   83 ec 10              sub    $0x10,%esp

여기서부터 main의 시작이라고 생각해도 좋다
esp 는 스택에서 top을 가리킨다 즉 마지막을 뜻하는거다
다들 스택 알지?
ebp는 base포인터인데 나도 설명을 잘못하것다  
이것도 스택에 저장된다 이건 쉽게 말해 백업용도로 보면 될려나

push %ebp  <-- ebp레지를 스택에 저장하였다
왜 저장했을까
센스있는 분들은 대충 감이 올거다
스택에 들어간 이유는 당연히 저장할려구 하는거구
ebp 가 스택에 들어갔단 말은 현재 ebp 값을 저장한 다음 ebp를 수정하겠다는 것이다
그럼 esp값이 감소한다 4바이트

push는 스택에 값을 넣는건데 esp값은 감소한다
이건 인텔에서 이렇게 만들었다 ㅡㅡ
즉 스택이 거꾸로 달려있다 생각하면 된다
밑으로 스택은 자란다. 
push 면 esp값이 감소
pop이면 esp값이 증가

추가적으로 pop이 되면 값이 사라지는게 아니다
pop이되면 단순히 esp값이 증가된거다
나중에 push되면 기존값은 새로 들어온 값에 의해 덮어씌워진다
ok?

mov %esp , %ebp  <--- esp값을 ebp에 넣었다
그럼 %esp값과 %ebp값이 똑같아졌다

<증거자료> ㅡㅡ
(gdb) x $esp
0xbfe032d8:    0xbfe03348
(gdb) x $ebp
0xbfe032d8:    0xbfe03348

그다음 push %ecx  <--- ecx값 즉 argc값이다   (사실 이것도 정확한 말이 아니다) 이건 직접해보시길... 손아퍼서
그럼 esp값이 또 감소한다
머릿속에 대충 그림이 그려지길 바란다


그다음
sub $0x10 , %esp <--- c언어로 바꾸면 esp=esp-10;    쉽죠? ㅋㅋ
자 여기서 esp값을 감소 시켰다 그말은 스택에 넣을 공간이 생겼다는 거다

다음 코드에서
movl $0xa, -0x8(%ebp)  <-- c언어로 바꾸면 *(ebp-0x8) = 0xa;  
이상한점 처음 esp, ebp주소값을 같게하고 esp에서 0x10만큼 여유를 줬다
근데 ebp-0x4 부터 시작을 한게 아니라 0x8부터 시작했다
왜 그럴까

push %ecx  <-- 요게 ebp-0x4 번지에 있다..ㅡㅡ
그러니 그 다음 주소값은 ebp-0x8 번지에 저장해야 한다  (왜 4바이트인지는  숙제)


mov 0x0, %eax <- 이건 너무 쉽죠 eax=0;
즉 return 0; 을 어셈코드로 나타낸거임


main 코드는 끝났다
하지만 어셈에서는 아직 할일이 남아있나 보다
뭔지를 보면
0x08048361 <main+29>:    add    $0x10,%esp

esp값을 증가한다 0x10 만큼
이건 처음에 sub $0x10 , $esp 이거와 반대다
그 말은 이제 다시 esp값을 원상복귀 한거다

0x08048364 <main+32>:    pop    %ecx   <--- push 한 ecx값을 다시 ecx에 넣은거다  즉 다시 뒤로 되돌아가 값을 준거다  
0x08048365 <main+33>:    pop    %ebp   <--- 이것도 마찬가지로 ebp에 값을 다시 준다
이것도 똑같다  그 말은 위에서 push 한걸 다시 뺀거다
(ex) 방에 물건 넣었고 프로그램이 종료됐으니 방에 있는 물건 빼  순서는 Fist in Last out 순서로...

 8048366:   8d 61 fc                lea    -0x4(%ecx),%esp <-- 이건 모르것다
 8048369:   c3                      ret  <-- 종료..


단순한 main코드인데도 이렇게 복잡하다
다들 집에서 gdb로 디버깅 해보면서 차근차근 따라가 보면 이해가 될거다
코드는 외우는게 아니다 이해하는 거다

틀린점 있으면 지적좀 해주세요~