자료구조인 스택, C언어의 함수에 대응되는 프로시저, 시스템콜에 관한 어셈블리 내용이다.
스택
push val : val을 스택 최상단에 쌓음
pop reg : 스택 최상단의 값을 꺼내서 reg에 대입
프로시저
Procedure는 특정 기능을 수행하는 코드 조각을 말한다. 프로시저를 사용하면 반복되는 연산을 프로시저 호출로 대체할 수 있는 장점이 있다. 그리고 기능별로 코드 조각에 이름을 붙여 가독성을 높일 수 있다.
프로시저를 부르는 행위를 호출(Call)이라고 하고, 돌아오는 것을 반환(Return)이라 한다. 프로시저를 실행 하고 나서 원래 실행 흐름으로 돌아와야 하므로 call 다음의 명령어 주소 즉, 반환 주소(return address)를 스택에 저장하고 프로시저로 rip를 이동시킨다.
call addr : addr에 위치한 프로시져 호출
leave : 스택 프레임 정리
함수별로 서로가 사용하는 스택의 영역을 명확히 구분하기 위해 스택프레임이 사용된다.
ret : return address 반환
시스템콜
운영체제는 연결된 모든 하드웨어 및 소프트웨어에 접근할 수 있으며, 이들을 제어할 수도 있다. 그리고 해킹으로부터 이 막강한 권한을 보호하기 위해 커널 모드와 유저 모드로 권한을 나눈다.
커널 모드는 운영체제가 전체 시스템을 제어하기 위해 시스템 소프트웨어에 부여하는 권한이다. 파일 시스템, 입력/출력, 네트워크 통신, 메모리 관리 등 모든 저수준의 작업은 사용자 모르게 커널 모드에서 진행된다.
유저 모드는 사용자에게 부여하는 권한이다. 브라우저를 이용하거나 게임을 하고 프로그래밍을 하는 등은 모두 유저 모드에서 이루어진다. 유저 모드에서 해킹이 발생해도 커널의 권한은 보호 된다.
시스템 콜(system call, syscall)은 유저 모드에서 커널 모드의 시스템 소프트웨어에게 동작을 요청하기 위해 사용된다.
x64아키텍처에서 시스템 콜을 위해 syscall 명령어가 있다.
시스템 콜은 함수이기 때문에, 필요한 기능과 인자에 대한 정보를 레지스터로 전달하면, 커널이 이를 읽어서 요청을 처리한다.
x64아키텍처에서는 rax로 무슨 요청인지 나타내고, 인자 순서대로 인자를 전달한다.
인자 순서: rdi -> rsi -> rdx -> rcx -> r8 -> r9 -> stack
x64 syscall 테이블
syscall | rax | arg0(rdi) | arg1(rsi) | arg2(rdx) |
read | 0x00 | unsigned int fd | char *buf | size_t count |
write | 0x01 | unsigned int fd | const char *buf | size_t count |
open | 0x02 | const char *filename | int flags | umode_t mode |
close | 0x03 | unsigned int fd | ||
mprotect | 0x0a | unsigned long start | size_t len | unsigned long prot |
connect | 0x2a | int sockfd | struct sockaddr * addr | int addrlen |
execve | 0x3b | const char *filename | const char *const *argv | const char *const *envp |