-
[libasm] 01. 기초지식 - 리눅스의 호출 규약과 어셈블리코드 정리과제/libasm 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
long32-bit
int16-bit
short8-bit
charrax 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 하는 것이 안전하다 (라고 나는 생각했다)