개인 스터디/어셈블리어

어셈블리어 코드 분석 - int sum(int a, int b)

오제이튜브[OJ Tube] 2020. 2. 7. 02:06

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에 저장하는 행위를 반드시 하게 된다고 함.