이번에는 if문과 switch문을 어셈블리로 분석해 보도록 하겠습니다.

사실 요새 개강도 있고 학원일도 있고 해서 기존에 올리려던 글들을 못올리고 있네요. 으앙 암튼


1. if 문 분석해 보기

 if 문은 조건부 분기의 일종입니다. 아주 많이 쓰이는 구문이라고 할 수 있지요.

if문 분석에 쓰일 소스는 아래와 같습니다.


#include <stdio.h>


int main()

{

int a = 100;


++a;


if( a < 0 )

{

--a;

}

else if( a == 0 )

{


}

else

{

++a;

}


a = a + 100;


return 0;

}


아주 심플한 소스이지만 어셈블리로는 어떻게 이루어져 있을까요?

소스에 Breakpoint를 걸어놓고 Debug를 클릭하여 디버깅 모드로 들어간 후 Alt+8 혹은 Debug -> Window -> Disassembly 메뉴로 들어가 어셈블리 코드를 보도록 하겠습니다. 디스어셈블리를 하면 아래와 같은 코드를 볼 수 있습니다.

(잡스러운 코드가 길어 if 문만 빼내도록 합니다.)


if( a < 0 )

0041137E  jns         main+3Bh (41138Bh)  

{

--a;

00411380  mov         eax,dword ptr [a]  

00411383  sub         eax,1  

00411386  mov         dword ptr [a],eax  

00411389  jmp         main+4Ch (41139Ch)  

}

else if( a == 0 )

0041138B  cmp         dword ptr [a],0  

0041138F  jne         main+43h (411393h)  

{


}

00411391  jmp         main+4Ch (41139Ch)  

else

{

++a;

00411393  mov         eax,dword ptr [a]  

00411396  add         eax,1  

00411399  mov         dword ptr [a],eax  

}


하나하나 뜯어서 살펴보도록 하겠습니다.


if( a < 0 )

0041137E  jns         main+3Bh (41138Bh)  


if( a < 0 )는 jns main+3Bh와 동일한 문장이라는 의미입니다.

 jns는 무슨 의미일까요? 바로 Jump if the Sign flag is Not set의 줄임말입니다. 플래그 레지스터의 SF가 1로 세팅되어 있지 않다면 뒤에 나오는 라벨 혹은 주소로 분기하라는 의미이죠. SF는 부호 비트 플래그, 음수가 발생하면 일어나는 플래그입니다. 즉 해당 값의 부호비트가 1이 아닐 때(양수일 때) 뒤의 주소로 이동하게 되겠죠. 이를 만족하지 않으면 이 명령어는 없던 일로 취급되어 바로 아래로 내려갑니다.

 jns의 뒤에 있는 main+3Bh (41138Bh)은, jns명령어를 만족할 때 이동하게 되는 주소로, main의 주소(411350h)에서 3Bh만큼 더한 위치(41138Bh)로 이동하겠다는 의미입니다. 이곳은 어디일까요? 바로 두번째 비교(else if( a == 0 ))가 일어나는 곳의 위치로 점프합니다. 처음 if문은 만족하지 못하였으니 else if로 이동하여 두번째 비교를 하라는 의미이죠...


00411389  jmp         main+4Ch (41139Ch)


if문을 수행했다면 더 이상 진행할 필요가 없습니다. 중괄호 밖으로 나오기 위해 jmp합니다..


else if( a == 0 )

0041138B  cmp         dword ptr [a],0  

0041138F  jne         main+43h (411393h)  


이 부분은 원래 의도한 바와는 조금 다르게 되었습니다. ^^;; jnz대신 cmp와 jne가 나왔네요... cmp는 두 값을 비교하는 명령어입니다. 사실 두 값의 차이를 계산하는 명령어라고 할 수 있습니다. 둘 다 같은 값이라면 둘의 차이가 0이 되어 버리므로 ZF가 1로 세팅됩니다. 그리고 상태 플래그를 체크하여 점프하는 jne, je 등의 명령어를 이용해 함께 사용합니다. 이 경우 cmp한 결과가 jne, 즉 not equal시 점프하라는 의미입니다. 즉 if문의 조건에 부합되지 않으면 else문으로 점프시킵니다.


00411391  jmp         main+4Ch (41139Ch)  


역시 이 부분도 else if문을 수행했다면 더 이상 진행할 필요가 없습니다. 중괄호 밖으로 나오기 위해 jmp합니다..

이후 else문은 제일 마지막 부분이므로 점프할 필요도 없고 밖으로 분기할 필요도 없습니다.


이렇게 if문이 이루어 집니다. 어셈블리로 보니 되게 직관적이네요.



2. switch 문 분석해 보기

 이번에는 switch 문을 분석하여 보겠습니다. 우선 분석하기 위한 기본 소스는 아래와 같습니다.


#include <stdio.h>


int main()

{

int a = 1;


switch( a )

{

case 0:

a++;

break;

case 1:

a--;

break;

case 3:

a = 0;

default:

a = 100;

break;

}


return 0;

}


보시는 바와 같이, int형 변수 a에 초기값을 1로 지정하였고, switch문으로 a의 값에 따라 case문에 들어가도록 되어 있습니다.

그리고 case 3을 제외한 모든 경우에 break;를 끝에 넣어주었습니다.


switch( a )

004117C5  mov         eax,dword ptr [a]  

004117C8  mov         dword ptr [ebp-0D0h],eax  

004117CE  cmp         dword ptr [ebp-0D0h],0  

004117D5  je          main+4Bh (4117EBh)  

004117D7  cmp         dword ptr [ebp-0D0h],1  

004117DE  je          main+56h (4117F6h)  

004117E0  cmp         dword ptr [ebp-0D0h],3  

004117E7  je          main+61h (411801h)  

004117E9  jmp         main+68h (411808h)  

{

case 0:

a++;

004117EB  mov         eax,dword ptr [a]  

004117EE  add         eax,1  

004117F1  mov         dword ptr [a],eax  

break;

004117F4  jmp         main+6Fh (41180Fh)  

case 1:

a--;

004117F6  mov         eax,dword ptr [a]  

004117F9  sub         eax,1  

004117FC  mov         dword ptr [a],eax  

break;

004117FF  jmp         main+6Fh (41180Fh)  

case 3:

a = 0;

00411801  mov         dword ptr [a],0  

default:

a = 100;

00411808  mov         dword ptr [a],64h  

break;

}


!?!?!?!?!?!?


다소 복잡한 구조를 띄고 있습니다.

우선 switch문에서는 if문과 같이 값을 비교하여 해당 위치에 맞게 점프해주는 역할을 하는 걸로 보입니다.

케이스 문이 아래에 있을 수록 비교하는 데에 오래걸리겠군요. if 문도 순서에 신경을 써야 하는데 switch문도 순서에 다소 신경을 써야할 것 같아요.


break문은 if문 분석에서 예상했던 바와 같이 switch문을 아예 벗어나는 역할을 담당하고 있습니다.

break문이 없는 case 3:의 경우 해당 점프 문이 아예 없는 것을 볼 수 있습니다.


if문과의 차이점은 if문은 명령어가 시작되는 곳 전으로 점프하여 그곳에서 비교하고 틀리면 점프를 반복하는 반면에,

switch문은 처음부터 모든 경우를 비교하여 점프하는 방식이라는 점과

if문이 해당 조건을 완수하면 다른 조건이 실행되기 전에 밖으로 자동으로 점프하게 해주지만 switch문은 수동으로 점프(break)명령을 넣어주어야 한다는 점인 것 같습니다.

+ Recent posts