[ 공 부 ]/[ C ]

[ C ] 어 셈 블 리

HiStar__ 2020. 9. 26. 11:28

어 셈 블 리

 

  • 어셈블리어 : 기계어에서 한 단계 위의 언어이며 기계어와 함께 단 둘뿐인 저급언어.

  • 인라인 어셈블리를 통하여 직접적으로 어셈블리 언어를 입력하여, 원하는 어셈블리 코드를 짤 수 있지만,
    32bit만 가능하다. 그렇기 때문에, 코드를 개발하는 단계에서 어셈블리 명령어가 깔끔하게 나오도록 코드를 
    짜려고 노력하는 습관을 들어야 한다.

 

CPU 레지스터

 

  • 레지스터 : CPU 내부에서 처리할 명령어나 연산의 중간 값 등을 일시적으로 기억하는 임시 기억장소.

  • Visual Studio 레지스터

 

EAX = 00ECC003

eax ( Extended Accumulator Register ) : 산술, 논리 연산에 사용하는 레지스터.

EBX = 010B3000

ebx ( Extended Base Register ) : ESI, EDI와 결합하여 인덱스에 사용된다.
메모리 주소 지정을 확장하기 위해 인덱스로 사용될 수 있는 유일한 범용 레지스터.

ECX = 00ECC003

ecx ( Extended Counter Register ) : 반복문 등의 카운팅을 위한 레지스터.

EDX = 00000001

edx ( Extended Data Register ) : , 출력 포인터 값을 저장.

ESI = 00EC1325

esi ( Extended Source Index ) : 데이터 복사시 원본 주소

EDI = 012FF7AC

edi ( Extended Destination Index ) : 데이터 복사시 목적지 주소

EIP = 00EC1788

eip ( Extended Instruction Pointer ) : 확장된 명령 지시자

ESP = 012FF6C8

esp ( Extended Stack Pointer ) : 현 스택의 포인터.

EBP = 012FF7AC

ebp ( Extended Base Pointer ) : 현 스택 프레임의 시작 주소.

 - 32bit 컴파일러의 경우에는 E ( Extended ) 가 앞에 붙지만, 64bit 컴파일러의 경우에는 R 이 붙는다.

 

지 역  변 수

 

  • 지역변수는 STACK 메모리를 사용한다. ( 기본적으로 1MB로 설정 된다. )

  • 이 때, 다음과 같은 코드를 Debug, Release 모드로 확인 후 비교 해 보겠다.
#include <stdio.h>

void Test() {
	int x, y;
	x = 0;
}

int main() {

	int x = 0;
	int y = -1;

	Test();

	y = x;

	return 0;
}

 

  • Debug 

더보기

int main() {
00541760  push        ebp  
00541761  mov         ebp,esp  
00541763  sub         esp,0D8h  
00541769  push        ebx  
0054176A  push        esi  
0054176B  push        edi  
0054176C  lea         edi,[ebp-0D8h]  
00541772  mov         ecx,36h  
00541777  mov         eax,0CCCCCCCCh  
0054177C  rep stos    dword ptr es:[edi]  
0054177E  mov         ecx,offset _DF75C5A9_어셈블리02@cpp (054C003h)  
00541783  call        @__CheckForDebuggerJustMyCode@4 (0541208h)  

int x = 0;
00541788  mov         dword ptr [x],0  
int y = -1;
0054178F  mov         dword ptr [y],0FFFFFFFFh  

Test();
00541796  call        Test (0541014h)  

y = x;
0054179B  mov         eax,dword ptr [x]  
0054179E  mov         dword ptr [y],eax  

return 0;
005417A1  xor         eax,eax  
}
005417A3  pop         edi  
005417A4  pop         esi  
005417A5  pop         ebx  
005417A6  add         esp,0D8h  
005417AC  cmp         ebp,esp  
005417AE  call        __RTC_CheckEsp (0541212h)  
005417B3  mov         esp,ebp  
005417B5  pop         ebp  
005417B6  ret  

 

  • Release
더보기

int x = 0;
int y = -1;

Test();

y = x;

return 0;
007F1000  xor         eax,eax  
}
007F1002  ret  

 

Debug와 Release 두 동작의 차이가 확연히 나오는 것을 볼 수 있다.
Debug의 경우에는 안전 장치가 적용되어, 

#include <stdio.h>

int main() {

	int x = 0;
	int y = -1;

	printf(" &x - &y : %d \n", (int)&x - (int)&y);

	return 0;
}

위의 코드를 돌려봤을 경우, 
Debug : 12, Release : 4 가 나온다.
int가 4byte일 때, 보통은 4가 나오는 결과를 생각한다.

하지만, Debug모드에서는 변수의 앞과 뒤에 4byte의 정보를 추가하기 때문에 이러한 결과가 나온다.

 

x

 

 

y

 

이런 결과가 나올 것이다. 이것을 확인 해보자.

 

32bit에서 스택의 경우에는 아래에서 위로 올라가는 형식으로 데이터를 관리한다.

x의 경우에는 0x0133F998  ebp - 0Ch  // 12

y의 경우에는 0x0133F98C  ebp - 18h  // 24

* h의 경우에는 16진수 라는 걸 표현

위의 방식으로 저장된다.
이것을 제외하고도 Debug에서 사용하는 안전장치 때문에 성능이 느릴 수 있다.

'[ 공 부 ] > [ C ]' 카테고리의 다른 글

[ C ] 메모리의 종류 ( 물리적 관점 )  (0) 2020.09.22
[C] 스코프 ( Scope )  (0) 2020.08.24
[ C ] SCE ( Short - Circuit Evaluation )  (0) 2020.08.20
[ C ] 실수의 표현방식  (0) 2020.08.12
[ C ] 데이터 표현의 단위  (0) 2020.08.11