[ASM] Intel 어셈블리 명령어 정리 + hello world 분석
42Seoul/그 외

[ASM] Intel 어셈블리 명령어 정리 + hello world 분석

이전 글에서 어셈블리어로 "hello world"를 출력하는 예제를 작성하였습니다. 이번에는 기초적인 명령어들을 학습하고, 코드를 분석해보겠습니다.

 

어셈블리어의 명령어 구조

Intel문법에서의 어셈블리 명령어는 다음과 같은 구조를 하고 있습니다.

라벨 : <명령어> <피연산자1> <피연산자2> ;주석

 

여기서 라벨(label)은 기계어로 직접 번역되지는 않으며, 점프(jmp) 명령어를 사용하는 등, 메모리 주소의 참조가 필요할 때 사용됩니다.

라벨 명령어의 집합. 명령어 또는 데이터의 주소를 나타냄.
명령어 mov, jmp 등의 동작을 지시.
피연산자 명령어의 피연산자(operand). 레지스터, 숫자, 문자, 메모리 주소 등.
주석 앞에 ;문자를 붙여 주석처리

 

 

어셈블리 명령어

libasm을 구현하며 학습한 명령어들을 위주로 추가 중입니다.

 

 조작 명령어

ret return. 함수의 동작을 마치고 (함수의)호출 지점으로 복귀.
(정확하게는 함수 호출지점의 다음 위치로 이동하여, 그 다음 명령을 수행할 수 있게 한다)
ret
jmp jump. 분기(라벨) 실행 jmp <피연산자(라벨=분기)>

 

 데이터 전송  명령어

mov 피연산자1로 피연산자2을 이동. 전송 mov <피연산자1> <피연산자2>
push 레지스터의 값을 스택에 저장 push <피연산자(레지스터)>
pop 스택의 값을 레지스터로 가져옴 pop <피연산자(레지스터)>

 

 산술 명령어

inc 피연산자의 값을 1 증가 inc <피연산자>
dec 피연산자의 값을 1 감소 dec <피연산자>
add 피연산자1에 피연산자 2의 값을 더함(캐리 포함x) add <피연산자1> <피연산자2>
sub 피연산자1에 피연산자 2의 값을 뺌(캐리 포함x) sub <피연산자1> <피연산자2>
cmp compare. 피연산자1,2의 값을 비교 cmp <피연산자1> <피연산자2>

cmp결과에 따라, 아래 명령어로 분기를 실행할 수 있음
a==b : je <분기>
a!=b  : jne <분기>
a>b   : ja <분기>
a<b   : jb <분기>

 

 문자열 조작 명령어

rep repeat. 문자열 조작 명령어를 CX(rcx/ecx/cx)가 0이 될 때까지 반복 rep <명령어>

movs

SI(rsi/esi/si)의 메모리 데이터를 DI(rdi/edi/di)의 메모리로 전송

movsb: byte (1byte) 단위
movsw: word (4byte) 단위
movsd: double (8byte) 단위
주로 rep와 함께 사용
rep movsb

 

 


 

hello.s 코드 분석하기

section .data;data섹션
	msg db "hello world",0x0A;개행문자

먼저, 데이터 섹션을 선언했습니다. msg는 변수명이고, db는 데이터 타입입니다. db 외에도 다음과 같은 데이터 타입이 있습니다.

db byte (1byte)
dw word (4byte)
dd double (8byte)

 

 

다음은 _main함수를 global로 설정하여, 전역에서 접근 가능하도록 했습니다.

함수 라벨 앞에 _(언더바)를 사용하는 이유는, 대부분의 c언어 컴파일러들이 함수 앞에 _문자를 붙이기 때문이라고 합니다.

section .text;text섹션
	global _main;전역에서 접근가능
_main :;메인함수
	mov rax, 0x2000004;맥OS의 syscall write()함수 번호. 아래는 매개변수
	mov rdi, 1
	mov rsi, msg
	mov rdx, 12
	syscall;호출

syscall을 위해서는 rax레지스터에 함수의 호출 번호를 할당해야 합니다. 0x2000004는 mac에서 write()함수의 syscall번호입니다. 그리고 rdi, rsi, rdx 레지스터는, 순서대로 함수 호출 규약에 따라 매개변수를 받아오는 역할을 합니다.

이후 syscall호출로 wirte(1, msg, 12)을 실행합니다.

 

	mov rax, 0x2000001;맥OS의 syscall exit()함수. 아래는 매개변수
	mov rdi, 0
	syscall;호출

마찬가지로 rax레지스터에 0x2000001에 해당하는 exit()함수를 불러옵니다. rdi레지스터에 매개변수 값 0을 넘겨주고, syscall호출로 exit(0)를 실행합니다.

 

 

 

다음에는 레지스터와 함수 호출 규약에 대해 더 자세하게 알아보겠습니다.