기계어를 읽기 편한 형태로 번역한 언어
니모닉 기호를 사용하여 연산 과정을 단어화
class Program { static void Main() { int a = 10; int b = 20; Console.WriteLine(a + b); }
어셈블리어 역시 고급 언어로 작성된 것보다는 한눈에 파악하기 어렵다는 것을 알 수 있다.
컴파일 (Compile)
: 컴파일 언어로 작성된 소스 코드 전체가 저급 언어로 변환되는 과정목적 코드 (Object Code)
: 컴파일러를 통해 저급 언어로 변환된 코드인터프리터 (Interpreter)
: 소스 코드를 한 줄씩 변환하는 도구 목적 파일
: 목적 코드로 이루어진 파일 링킹 (Linking)
: 목적 코드 -> 실행 파일 연산 코드(opreration code = 연산자)
: 명령어가 수행할 연산 오퍼랜드(operand = 피연산자)
: 연산에 사용할 데이터
- ALU 명령 코드 예
연산코드 니모닉(mnemonic) 설명 0000 clr 결과의 모든 비트를 0으로 만든다. 0001 set 결과의 모든 비트를 1으로 만든다. 0010 not A의 비트 중 0은 1로, 1은 0으로 만든다. 0011 neg A에 2의 보수를 취한 -A를 결과값으로 반환한다. 1001 and A and B 1010 or A or B 1011 xor A xor B 1100 add A + B 1101 sub A - B
![]()
위에서 본 캡쳐에서
int = a = 10;
이라는 코드가 실행 될 때의 메모리를 확인할 수 있다.
초록색으로 표시한 주소의 명령어가 dword ptr 와 [rbh+2ch], 0Ah 로 구성되어 있음을 확인할 수 있다.
연산 코드 dword의 경우 앞서 Chapter 2. 에서 봤던 double word 를 의미하며 ptr은 포인터.
현재 코드에서 오퍼랜드가 [rbp+2Ch], 0Ah 두 개로 구성되어 있음을 알 수 있다.
rbp는 포인터를 저장하는 레지스터(스택 프레임에서 복귀 주소를 저장한다)
0A는 a 변수에 저장한 값 10과 일치한다.
이와 같은 명령어를 2-주소 명령어라고 한다.
- Intel 64 명령어 구조
이미지 출처
(Prefixes) [Opcode] (Mod R/M) (SIB) (Displacement) (Immediate)
(Prefixes): 4가지 그룹으로 구분되며 각 그룹에 속하는 접두사(각 1 바이트)가 선택적으로 붙을 수 있다.
[Opcode]: 1-3 바이트 길이로 수행하고자 하는 명령어의 종류를 지정한다. 이때 일부 SSE 명령어의 경우 prefix를 사용하는 것과 동일하게 인코딩되어 있으나(예: CVTDQ2PD: F3 0F E6h) 이는 opcode의 일부로, prefix로 취급되지 않는다.
(Mod R/M): 피연산자의 형태(레지스터/메모리) 및 메모리 주소 형식을 지정한다. 명령어에 따라 선택적으로 요구한다.
(SIB): [base + index * scale (+ disp.)] 형식으로 계산되는 메모리의 base 레지스터, index 레지스터 및 scale을 지정한다. 명령어에 따라 선택적으로 요구한다.
(Displacement): 1/2/4 바이트 크기의 displacement로 명령어에 따라 선택적으로 요구한다.
(Immediate): 1/2/4 바이트 크기의 immediate(명령어에 인코딩되는 숫자) 값으로 명령어에 따라 선택적으로 요구한다.
참고자료
📚강민철, 『혼자 공부하는 컴퓨터 구조 + 운영체제』, 한빛미디어, 2022.
📹유튜브 공식 강의 6강, 7강
🐈⬛책 부록 GitHub
📚 조너선 스타인하트, 『한 권으로 읽는 컴퓨터 구조와 프로그래밍』, 오현석 옮김, 책만, 2021.
🖥️Intel® 64 and IA-32 Architectures Developer's Manual: Vol. 2A
많은 것을 배웠습니다, 감사합니다.