어제 알바뛰고 낮에 자서 새벽까지 눈이 탱글탱글하다..ㅋㅋ
어셈 코드만 보고 해석하기 힘들다
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로 디버깅 해보면서 차근차근 따라가 보면 이해가 될거다
코드는 외우는게 아니다 이해하는 거다
틀린점 있으면 지적좀 해주세요~
어셈 코드만 보고 해석하기 힘들다
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로 디버깅 해보면서 차근차근 따라가 보면 이해가 될거다
코드는 외우는게 아니다 이해하는 거다
틀린점 있으면 지적좀 해주세요~