본문으로 바로가기

2편에서는 어셈블리어를 해석? 하는 걸 중점으로 포스팅 하려고 합니다. 



- mov 명령어 예제




코드를 짤 때 흔히 사용하는 swap함수를 예로 들어 보겠습니다. 


함수에서 받아오는 인자 *x, *y같은 경우는 보통 레지스터 rdi나 rsi에 있습니다. 


long t0 = *x는 어셈블리어로 mov ($rdi), $rax로 표현되어 있습니다. 즉 $rdi(x가 저장된 레지스터)를 $rax에 복사하는 것인데 괄호가 있는 이유는 포인터로 메모리를 참조하기 때문에 ($rdi)로 표현합니다. 


마찬가지로 long t0 = *y도 move ($rsi), $rdx로 표현 됩니다. 


그다음 swap부분인 *x = t1은 $rdx레지스터에 저장되어 있는 값 (value = *y)를 x의 주소인 ($rdi)에 mov합니다. 

마찬가지로 *y = t0도 $rax레지스터에 저장되어 있는 값 (value = *x)를 y에 mov합니다. 





- 산술 연산 예제




연산 예제입니다. 

lea 명령어는 주소 연산을 할 때 사용되는 명령어입니다. 


각각 x, y, z인자들은 레지스터 rdi, rsi, rdx에 저장됩니다. 


long t1 = x + y 는 lea(%rdi, %rsi), %rax로 (%rdi, %rsi)는 %rdi + %rsi를 의미합니다. 인자 x, y를 더해서 %rax에 mov합니다. 


long t2 = z + t1는 add %rdx, %rax로 %rdx(value = z)를 이전에 연산한 %rax (t1)을 더해서 %rax에 저장합니다. 


long t3 = y * 48는 shift연산과 lea연산을 결합해서 합니다. lea(%rsi, %rsi, 2) 는 %rsi + 2*%rsi 즉 3%rsi입니다. 

이후에 shift left연산으로 3*%rsi*16으로 48*%rsi가 됩니다. 




- if / else 문 예제





조건문 코드의 어셈블리어 변환 예제입니다. 먼저 C코드를 보면 x > y이면 x-y를, 그 외에는 y-x 연산 이후에 result를 리턴하도록 되어있습니다. 이번에도 마찬가지로 인자 x y는 각각 %rdi, %rsi레지스터에 저장되어 있습니다. 


첫 번째 줄의 어셈블리어 부터 살펴보면 mov %rdi, %rax로 %rdi (value = x)를 %rax레지스터에 복사합니다. 

두 번째 줄의 sub 명령어로 %rax = %rax - %rsi를 수행합니다. 여기서 %rax는 이전의 복사되었던 x의 값으로 x-y연산을 하는 것을 알 수 있습니다. 


세 번째 줄의 어셈블리어 mov %rsi, %rdx는 y 값을 %rdx에 복사합니다. 그리고 윗 줄과 마찬가지로 %rdx = %rdx - %rdi로 y-x연산을 수행합니다. 


이제 %rax, %rdx 에 각각 x-y와 y-x의 값들이 저장되어 있는 것을 알 수 있습니다. 


그리고 cmp명령어로 %rsi와 %rdi를 비교합니다. 여기서 수행되는 연산은 %rdi - %rsi를 수행하고 flag가 일어나는지 일어나지 않는지를 통해 비교하는 것 입니다. 


cmovle 로 less or equal 이면 result = %rdx, 그렇지 않으면 result = %rax가 됩니다. 





- 반복문 예제 (goto Loop)



반복문 중 하나인 goto문으로 예시를 들었습니다. 사실 반복문은 쓰는 형식만 다를 뿐 기능은 비슷하기 때문에 하나만 알아도 다 적용시킬 수 있을 것 같습니다. 


c코드는 입력받은 숫자 x에 대하여 1의 개수를 카운트 하는 코드입니다. 

어셈블리어를 보면 처음에 result = 0을 mov $0, %eax로 합니다. 어셈블리어에서 숫자는 '$'표시를 붙입니다.

그다음에 인자값 %rdi( value = x)를 %rdx에 복사합니다. 복사한 값을 1과 and연산 시킨 후에 %rax ( value = result)와 add 합니다. 


그리고 %rdi (value = x)를 shift right 로 한칸 움직인 다음에 jump not equal ( = not Zero)일 시에 L2로 점프 합니다.