과제/libasm

[libasm] 01. 기초지식 - 리눅스의 호출 규약과 어셈블리코드 정리

Pearan 2021. 2. 24. 22:28

1. 호출규약

윈도우와 리눅스의 호출규약은 서로 다르다.

출저 : https://kkamagui.tistory.com/811

 

 

 

출처: Paul A. Carter의 [PC 어셈블리어]에서 1.3.4 

출처: nasm 어셈블리 산술 연산 

출처: movsx, movzx

MOV MOV dest, src -> src에 있는 데이터를 dest에 복사  
ADD 정수 a, b 일때 a + b  
SUB 정수 a, b 일때 a - b  
INC INC dest -> dest를 1 증가 시킨다. dest++ 기계코드 크기가 ADD, SUB보다 더 작다.
DEC DEC dest -> dest를 1 감소 시킨다. dest– 기계코드 크기가 ADD, SUB보다 더 작다.
MUL MUL multiplier 부호 없는 데이터를 곱합니다.  
IMUL IMUL multiplier Integer mul. 부호 있는 데이터를 곱합니다.  
DIV    
IDIV    
movzx dst가 src보다 큰 공간이어도 복사가 되고, 남는 공간은 0으로 채워진다. 부호가 없는 정수에만 사용
movsx 남는 공간이 1로 채워진다. 부호가 있는 정수에만 사용한다
  *참고: 부호비트 자리가 1이라는 것은 컴퓨터에게 ‘음수거나 부호가 있는 정수’라는 뜻이다.  
  그니까 왜냐면.. 음수(부호가 있는 수)계산은 사실은 항상 보수처리해서 더하기로 진행하니까..?  

출처:  댕이댕이의 Network 블로그! - 리버싱 기초

 

 

64bit NASM Assembly Register

Name Notes Type 64-bit
long
32-bit
int
16-bit
short
8-bit
char
rax Values are returned from functions in this register.   scratch rax eax ax ah and al
rcx Typical scratch register.  Some instructions also use it as a counter. scratch rcx ecx cx ch and cl
rdx Scratch register. scratch rdx edx dx dh and dl
rbx
Preserved register: don't use it without saving it! preserved rbx ebx bx bh and bl
rsp
The stack pointer.  Points to the top of the stack (details coming soon!) preserved rsp esp sp spl
rbp
Preserved register.  Sometimes used to store the old value of the stack pointer, or the "base". preserved rbp ebp bp bpl
rsi Scratch register used to pass function argument #2 in 64-bit Linux.  In 64-bit Windows, a preserved register. scratch rsi esi si sil
rdi Scratch register and function argument #1 in 64-bit Linux.  In 64-bit Windows, a preserved register. scratch rdi edi di dil
r8 Scratch register.  These were added in 64-bit mode, so they have numbers, not names. scratch r8 r8d r8w r8b
r9 Scratch register. scratch r9 r9d r9w r9b
r10 Scratch register. scratch r10 r10d r10w r10b
r11 Scratch register. scratch r11 r11d r11w r11b
r12
Preserved register.  You can use it, but you need to save and restore it. preserved r12 r12d r12w r12b
r13
Preserved register. preserved r13 r13d r13w r13b
r14
Preserved register. preserved r14 r14d r14w r14b
r15
Preserved register. preserved r15 r15d r15w r15b

위 표는 어떨때 쓰냐면, 여기 과제에서는 대부분 char 형(8-bit) 를쓰기 때문에, 내가 만약에 rax가 가르키는 주소에서 char를 읽어서 다른 레지스터에 넣는다 하면

mov rcx, BYTE [rax]  이런식으로 쓰면 rcx 는 64bit 기 때문에 에러가 난다. 따라서 rcx 에 넣고 싶으면 저 위 표를 보고

mov cl, BYTE [rax] 이런식으로 넣어야 한다.

 

 

syscall 와 ___error 를 통한 에러처리 (write 를 예로)

section .text
    global _ft_write
    extern ___error

_ft_write:
    mov rax, 0x2000004		syscall을 사용하기 위해 rax 에 syscall 번호를 넣어줌
    syscall					rax에 write 의 리턴값을 저장
    jc err					만약 에러가 났다면 carry flag = 1 로 바뀌므로 jc 로 체크해서 점프
    ret						아니라면 그대로 리턴

err:
    push rax				write 는 에러가 났을경우 에러번호를 rax에 그대로 담아두기에 일단 푸쉬함
    call ___error			errno 을 담을 주소값을 rax에 리턴해줌
    pop rcx					write 가 push 해둔 rax의 값을 rcx 로 pop함
    mov [rax], rcx			rax 가 가르키는 주소의 값에 rcx값을 넣어줌
    mov rax, -1				rax (리턴값) 에는 -1 을 넣어줌
    ret

처음에

err:

함수 부분에서 

push rax

call ___error

pop rcx

 

하지말고 

mov rcx, rax

call ___error 

하면 되는것 아닌가? 했는데 ___error 에서 rcx 값에다가 무슨짓을 할지 모른다. 따라서 push 한 후 함수호출이 끝나면

pop 하는 것이 안전하다 (라고 나는 생각했다)