본문 바로가기
기타 언어/Assembly

mov와 lea 명령어 / call by value, call by reference, call by address 쉽게 이해하기

by woohyeon 2019. 12. 5.
반응형

MOV EAX, EBP
LEA  EDX, EBP

mov (move) 명령어는 좌변에 우변(상수 가능)의 값을 복사합니다.
lea (load effective address) 명령어는 좌변(레지스터)에 우변의 주소값을 저장합니다.


사용 예시)

mov eax, ecx 라는 명령은
 ecx 레지스터에 저장된 값을 eax 레지스터에 복사한다는 의미입니다.

mov eax, [adr] 라는 명령은
 adr 주소가 가리키는 값을 eax 레지스터에 저장한다는 의미입니다.

mov eax, dword ptr [num] 라는 명령은
 num의 주소가 가리키는 4바이트(dword) 값이 eax에 저장된다는 의미입니다.

mov dword ptr [num], 12345
  지역변수 num에 12345라는 상수 값을 복사(저장)합니다.

mov는 우변에 다음과 같이 연산자가 올 수 없습니다.
 mov eax, ecx+10
즉 ecx 레지스터에 저장된 값에 10을 더해서 eax에 저장할 수 없습니다.
위와 같은 연산을 하기위해선 다음과 같이 두 번의 명령을 내려야 합니다.
add ecx, 10
mov eax, ecx

하지만 다음과 같은 연산은 가능합니다.
mov eax, [ebp+4]
주소를 나타내는 [] 표시 내에선 연산이 가능하며 위 명령은 ebp 레지스터가 저장한 주소에 4를 더한 주소의 메모리 위치에 저장된 값을 eax 레지스터에 저장합니다.

예를 들어 ebp 레지스터가 100번지 주소를 저장하고 있고 104번지에 20이라는 값이 있다면 eax엔 20이라는 값이 저장됩니다.

이와 같이 mov 명령어는 데이터 값을 옮기는 명령이기 때문에 좌변에 레지스터 또는 지역 변수 전역 변수가 올 수 있습니다.

좀 더 이해하기 쉽도록 C++ 에서 함수 호출을 통해 위 명령어가 어떻게 사용되는지 보겠습니다. 

Call by value
void func(int num) 이라는 함수가 있다고 가정해보겠습니다.
이 함수는 인자를 func의 스택 프레임 영역 내에 복사하여, 함수 내에서 복사된 값을 사용하는 함수입니다.

메인 함수에서 func(3) 또는 func(num)와 같이 호출을 하게 되면 3이라는 상수 리터럴이나 int형 변수 num에 저장된 value가 복사가 되어 스택에 저장되고 함수는 그 복사된 값을 사용하게 됩니다.  이를 call by value라고도 하죠. 즉 원본이 아닌 복사된 값을 func 함수 내에서 사용하기 때문에 이 값을 수정한다 해도 인자로 전달한 main 함수의 지역 변수에는 변함이 없습니다.  

func(num)으로 함수를 호출하면 내부적으로 다음과 같은 준비 단계를 가지게 됩니다.

변수 num의 메모리에 저장된 값을 어떤 공간에 복사합니다. 복사된 값을 스택에 push하면 함수를 호출할 준비가 끝나고 함수는 스택에 올라온 값을 매개변수에 저장해서 사용합니다.

이 어떤 공간에 값을 복사하는 과정을 어셈블리어로 나타내면 mov eax, dword ptr [num] 이 됩니다. 
변수 num에 저장된 '값'을 eax 레지스터라는 공간에 복사하는 것입니다.

실제로 visual studio 에서 디스어셈블 기능을 통해 보면 다음과 같은 명령을 확인할 수 있습니다.
역순으로 전달되기 때문에 아래 코드는 4번째 인자에 대한 명령입니다.

 



다음으로 lea 명령어입니다.

lea는 포인터처럼 좌변에 우변의 주소값을 저장한다고 생각하면 이해하기 쉽습니다. (사실 포인터의 원리가 이것인거죠.)
int* ptr; 
위 포인터 변수 ptr이 주소값만 저장할 수 있듯이 lea도 좌변에 주소값만 저장할 수 있습니다.

따라서 lea명령어의 좌변은 레지스터만 올 수 있습니다.
또한 상수는 주소값이 존재하지 않기때문에 mov와 달리 우변에 상수가 올 수 없습니다.
 

lea REG MEM 
 위 명령어는 MEM의 주소값을 REG에 저장합니다.

lea edx, [ebp+4] 
 위 명령어는 ebp 레지스터가 저장한 주소값에 4만큼 더한 주소 값을 edx 레지스터에 저장합니다.

lea edx, 3
 상수엔 주소값이 존재하지 않기 때문에 위와 같은 연산은 불가능합니다.

lea명령어의 사용을 함수의 호출로 이해해보면
void func(int* num) 이라는 함수가 선언되어 있을 때, func(&num)으로 호출한다면 다음과 같이 표현됩니다.

num의 주소를 edx 레지스터에 저장



결론)
ebp 레지스터 값이 0x0010이고 0x0014 위치에 값 30이 저장되어 있다면

mov eax, [ebp+4] 명령을 통해 eax 레지스터엔 값 30이 저장되고
lea eax, [ebp+4] 명령을 통해 eax 레지스터엔 0x0014가 저장됩니다.

(참고: 16진수를 나타낼 때 0x로 시작하는 포맷도 있고 뒤에 'h'가 붙는 포맷도 있습니다.
0x0a가 10을 나타내듯이 '0Ah' 또한 10을 나타냅니다.)


아래 코드를 보며 이해한 것이 맞는지 확인해보세요.




틀린 부분이 있다면 댓글 남겨주세요 :)

'기타 언어 > Assembly' 카테고리의 다른 글

rep stos 명령어  (2) 2020.04.05



댓글