INTERLUDE ✦/2022 SYSTEM STUDY

[ DreamHack ] x86 Assembly

L_Chae 2022. 9. 25. 14:53

 

어셈블러 - 개발자들이 어셈블리어로 코드를 작성하면 컴퓨터가 이해할 수 있는 기계어로 코드를 치환해줌

어셈블리어 - 컴퓨터의 기계어로 치환되는 언어, low-level programming language에 속함

x86-64 어셈블리 언어

피연산자

총 3가지 종류가 올 수 있다 -> 상수 / 레지스터 / 메모리

메모리 : [대괄호]로 둘러싸인 것으로 표현됨. 앞에 크기 지정자 TYPE PTR(BYTE, WORD, DWORD, QWORD)이 추가될 수 있다.

ex) QWORD PTR [0x8048000] = 0x8048000의 데이터를 8바이트만큼 참조함

 

데이터 이동 - 어떤 값을 레지스터나 메모리에 옮기도록 지시함

연산자 사용 예시 해석
mov mov des, src src에 들어있는 값을 dst에 대입
lea lea dst, src src의 유효 주소(EA : Effective Address)를 dst에 저장

 

산술 연산 - 사칙연산을 지시함

연산자 사용 예시 해석
add add dst, src dst에 src의 값을 더함
sub sub dst, src dst에서 src의 값을 뺌
inc  inc op op의 값을 1 증가시킴
dec  dec op op의 값을 1 감소시킴

 

논리 연산 - 비트 연산을 지시함

연산자 사용 예시 해석
and and dst, src dst와 src의 비트가 모두 1이면 1, 아니면 0을 반환
or or dst, src dst와 src의 비트 중 하나라도 1이면 1, 아니면 0
xor xor dst, src dst와 src의 비트가 서로 다르면 1, 같으면 0
not not op op의 비트를 전부 반전

 

 

비교 - 두 피연산자의 값을 비교하고, 플래그를 반환

연산자 사용 예시 해석
cmp cmp op1, op2 op1과 op2를 비교 (두 피연산자를 빼서 대소를 비교)
test  test op1, op2 op1과 op2를 비교 (두 피연산자에 AND 비트 연산을 취함)

 

 

분기 - rip를 이동시켜 프로그램 실행의 흐름을 바꿈

연산자 사용 예시 해석
jmp jmp addr addr로 rip를 이동
je je addr 직전에 비교한 두 피연산자가 같으면 점프 (jump if equal)
jg jg addr 직전에 비교한 두 연산자 중 전자가 더 크면 점프 (jump if greater)

 

스택

연산자 사용 예시 해석
push push val rsp를 8만큼 빼고, val을 스택의 최상단에 쌓음
pop pop reg 스택 최상단의 값을 reg에 대입, rsp를 8만큼 더함

- 스택 : 함수별로 자신의 지역변수 or 연산과정에서 부차적으로 생겨나는 임시 값들을 저장하는 영역

 

프로시저(Procedure)

: 특정 기능을 수행하는 코드 조각을 말함, 반복되는 연산을 프로시저 호출로 대체하여 전체 코드의 크기를 줄일 수 있음

연산자 사용 예시 해석
call call addr addr에 위치한 프로시저 호출
leave leave 스택프레임 정리
ret ret return address로 반환

- 스택프레임 : 함수별로 서로가 사용하는 스택의 영역을 명확히 구분하기 위해 사용

 

스택 프레임의 할당과 해제 과정

 

시스템 콜(system call, syscall) - 유저 모드에서 커널 모드의 시스템 소프트웨게 어떠한 동작을 요청하기 위해 사용

- 필요한 기능과 인자에 대한 정보를 레지스터로 전달하면 커널이 이를 읽어 요청을 처리함

- in Linux : x64아키텍처에서 rax로 무슨 요청인지 나타내고, 순서대로 필요한 인자를 전달함

 

syscall 예시

더보기

 

syscall table을 보면, rax가 0x1일 때, 커널에 write 시스템콜을 요청함

 

rdi, rsi, rdx가 0x1, 0x401000, 0xb 이므로 커널은 write(0x1, 0x401000, 0xb)를 수행하게 됨

 

write함수의 각 인자는 출력 스트림, 출력 버퍼, 출력 길이를 나타내는데

여기서 0x1은 stdout이며, 이는 일반적으로 화면을 의미함

 

0x401000에는 Hello World가 저장되어 있고,

길이는 0xb로 지정되어 있으므로 화면에 Hello World가 출력