어셈블리어 코드 분석 - int sum(int a, int b)
int sum(int a, int b){
return a + b;
}
이 함수를 어셈단으로 보니깐..
아래와 같이 요로 코롬 나온다.
각 옆에 주석을 달아서 해석을 해보자.
int sum(int a, int b){
00A71430 55 push ebp //ebp에 있는 레지스터 값을 스택에 저장 한다!
00A71431 8B EC mov ebp,esp //esp에 있는 값을 ebp로 이동시킨다. esp에는 스택 주소 값이 저장되어 있는데.. 이 스택 주소값을 따라가면, 함수로 넘어온 인자 2개의 값, 그리고 이 sum 함수가 끝나면 돌아갈 곳의 주소값이 저장되어 있다.
00A71433 81 EC C0 00 00 00 sub esp,0C0h // esp의 레지스터의 0C0h 즉 192의 숫자 만큼 뺀다.
00A71439 53 push ebx // ebx의 값을 스택에 저장
00A7143A 56 push esi //esi의 값을 스택에 저장
00A7143B 57 push edi //edi의 값을 스택에 저장
00A7143C 8D BD 40 FF FF FF lea edi,[ebp-0C0h] //mov랑 비슷한 명령어임, 주소값을 옮길때 사용, edi에 ebp-0C0h값을 대입.
ebp는 현재 esp의 값을 가지고 있는데, 거기에서 192만큼 뺀 주소값임
00A71442 B9 30 00 00 00 mov ecx,30h
ecx에 30h값을 넣느다. 48임.
00A71447 B8 CC CC CC CC mov eax,0CCCCCCCCh
eax에 0CCCCCCCCh 값을 넣는다.
00A7144C F3 AB rep stos dword ptr es:[edi] //이놈 해석 하느라 애먹었다. 우선 rep 자체는 반복문이라고 보면 된다. 조건은 ecx가 0이 될때까지 도는 거고, 한번 돌때마다 -1씩 된다. 그다음 stos는 eax의 값을 edi에 저장된 주소의 값에 저장하는 것이다.
단 만약에 앞에 단위가 DWORD면 EAX, WORD면 AX, BYTE면 AL 의 값으로 대체하는 것이다.
결론은 스택 일정 영역을 전부 ccccccccc 값으로 대입하는 작업이다.
8:
9: return a + b;
00A7144E 8B 45 08 mov eax,dword ptr [a] //eax는 리턴값을 담는곳, 우선 변수 a가 가르키는 값을 대입
00A71451 03 45 0C add eax,dword ptr [b]
//변수 b가 가르키는 값을 더한다.
10:
11:
12: }
00A71454 5F pop edi //스택에서 값을 꺼내서 edi에 저장한다. 아까 맨마지막에 스택에 저장한것이 edi니깐 edi값이 그대로 들어온다.
00A71455 5E pop esi //그다음 스택에서 값을 꺼내서 esj에 저장한다.
00A71456 5B pop ebx //위와 같다.
00A71457 8B E5 mov esp,ebp //ebp의 값을 esp에 넣는다. 즉 호출 전에 esp 값을 그대로 가져옴. 즉 스택 포인터가 그냥 복구됨
00A71459 5D pop ebp //스택에서 기존의 ebp값을 꺼낸다. 그리고 ebp레지스터의 값에 대입 .. 이러면서 원래 esp의 값에 +4되것네..
00A7145A C3 ret 리턴 하자
이 함수는 기본이 __cdecl 형태 이기 때문에..
리턴 주소를 저장하고 있는 스택 포인터의 값은 호출된 함수쪽에서 복구를 시켜줘야하는데.. 그부분이 pop ebp 마지막 부분이네..
나는 왜 +4가 없는지 한참 찾았는데... 이제 알았다.
근데 왜 전부 cccccc로 30h만큼 초기화를 시켜주는 지는 모르겠다.
궂이 없어도 되는 작업 같다.
이것 분석이 끝나고.. 보니.. 위에 문장은 모든 함수 콜할때 반복되는 문장들이다.. main함수도 위와 같은 어셈 문장이 반드시 들어간다. 근데 cpu종류.. 32bit인가 64bit인가 등등에 다라서 코드가 조금씩 바뀌는 것 같다. 아무튼 위에 코드는 최적화를 통해 필요 없으면 사라지기도 한다.
특히 ebp에 esp(스택포인터)의 값을 저장 하는 이유는 함수 중간에 push나 pop같은 스택포인터 값을 건드리는 명령어가 수행되면, "esp-8" 같이 넘어온 인자값에 접근하기위한 연산들이 꼬이게 된다. 그래서 esp 값을 ebp에 저장하는 행위를 반드시 하게 된다고 함.