[libasm] 어셈블리 - 42

구름코딩·2021년 2월 9일

mac os에서 진행하기 위한 설정

아래 블로그를 참고해서 intel환경의 homebrew를 설치
참고

  1. apple silicon에서 인텔 빌드 앱을 실행하기 위해 로제타 설치
    /usr/sbin/softwareupdate --install-rosetta --agree-to-license

  2. 쉘에서 프로그램을 설치할 때 로제타를 이용해서 설치하게 함
    arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

  3. brew로 새로운 툴을 설치할 때마다 로제타를 이용하게 하기위해 alias 설정
    echo "alias brew='arch -x86_64 /usr/local/bin/brew'" >> .zshrc

테스트

정상적으로 homebrew가 설치되었는지 확인하기 위해 asm파일 작성후 컴파일

hello word를 출력하기 위한 asm파일

  • nasm으로 컴파일
section .data;data섹션
	msg db "hello world",0x0A;개행문자

section .text;text섹션
	global _main;전역에서 접근가능

_main :;메인함수
	mov rax, 0x2000004;맥OS의 syscall write()함수 번호. 아래는 매개변수
	mov rdi, 1
	mov rsi, msg
	mov rdx, 12
	syscall;호출
	mov rax, 0x2000001;맥OS의 syscall exit()함수. 아래는 매개변수
	mov rdi, 0
	syscall;호출

컴파일

nasm -f macho64 hello.s
gcc -o hello hello.o
./hello

출력
hello world

정상적으로 어셈블리어 코드로 작성한 파일이 컴파일 되고 실행되는 것을 확인하였으니 본격적으로 어셈블리 명령어를 익히고 과제를 수행해보자


어셈블리 명령어

어셈블리 명령어 구조

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

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

label : 명령어의 집합, 명령어 또는 데이터의 주소를 나타냄
명령어 : mov, jmp등의 동작을 지시
피연산자 : 명령어의 피연산자로 레지스터, 숫자, 문자, 메모리 주소 등이 올수있다

조작 명령어

  • ret, ret

return, 함수의 동작을 마치고 (함수의) 호출 지점으로 복귀한다
함수 호출 지점의 바로 다음 위치로 이동하므로 그 다음 명령을 수행할 수 있게된다

  • jmp, jmp<피연산자(label)>

jump, 분기(label) 실행

데이터 전송 명령어

  • mov, `mov <피연산자1> <피연산자2>

피연산자1을 피연산자 2로 이동

  • push, push <피연산자(레지스터)>

레지스터의 값을 스택에 저장

  • pop, pop <피연산자(레지스터)>

스택의 값을 레지스터로 가져온다

산술 명령어

  • inc, inc <피연산자>

피연산자의 값을 1 증가

  • dec, dec <피연산자>

피연산자의 값을 1 감소

  • add, add <피연산자1> <피연산자2>

피연산자1에 피연산자2의 값을 더한다

  • sub, sub <피연산자1> <피연산자2>

피연산자1에 피연산자2의 값을 뺀다

  • cmp, cmp <피연산자1> <피연산자2>

compare, 피연산자1, 2의 값을 비교한다. cmp의 결과에 따라, 아래 분기를 실행할 수 있다
a==b : JE <분기>
a!=b : JNE <분기>
a>b : JG <분기> // jump above (>=, greater)
a<b : jB <분기> // jump bellow (<=, less)

문자열 조작 명령어

  • rep, rep <명령어>

repeat, 문자열 조작 명령어를 CX(rcx, ecx, cx)가 0이 될때까지 반복한다

  • movs, rep mobsb

SI(rsi, esi, si)의 메모리 데이터를 DI(rdi, edi, di)의 메모리로 전송한다
movsb: byte단위 (1byte)
movsw: word단위 (4byte)
movsd: double단위 (8byte)

레지스터

31 ~~ 16 | 15 ~ 8 | 7 ~ 0 | 16bit | 32bit |

범용 레지스터

일반 레지스터 4개

  • rax, eax, ax, ah, al
    • Acuumulator(누산기)로 대부분의 연산(중간 산술 논리 장치)결과가 저장된다. 오프셋을 저장하기 위해 사용되며, 일반적으로 프로시저의 return값을 저장한다
  • rbx, ebx, bx, bh, bl
    • Base Index, 일반적인 데이터 레지스터이다. 데이터 포인터의 오프셋을 저장하기 위해 사용한다
  • rcx, ecx, cx, ch, cl
    • Count, 반복문, 루프 카운트를 저장한다, 데이터 포인터의 오프셋을 저장하기 위해 사용한다
  • rdx, edx, dx, dh, dl
    • Data, 곱의 결과, 나눗셈의 피연산자를 위한 부분을 가진다. RDX, RAX를 합쳐 128bit 연산을 하는 경우가 대표적이다

일반 주소 레지스터 4개

  • RSI (source index)
    • 문자열 연산에서 사용되는 원본 주소를 담는다
  • RDI (destination index)
    • 문자열 연산에서 사용되는 목적 주소를 담는다
  • RBP (base pointer)
    • 메모리 전소를 위한 현재 스택 프레임의 주소를 담으며, 일반적인 목적으로 쓰기도 한다
  • RSP (stack pointer)
    • 스택의 꼭대기 주소를 담는다

RIP, 비 일반 주소 레지스터 1개

  • RIP, (instruction pointer register)
    • 다음에 실행될 명령의 주소를 담는다 (PC+4)
    • 프로그램 카운터와 같은 역활이다, 프로그램이 실행되면 자동으로 RIP에 메모리가 지정되고 지속적으로 1씩 증가한다
    • JMP, Jcc, CALL, RET, IRET 명령어가 실행되었을 때 명령어의 수만큼 앞이나 뒤로 이동, offset의 값만큼 기준으로부터 이동한다. 이동된곳에서 다시 1씩 증가 반복 시행

시스템 호출(syscall)시 범용 레지스터

시스템 호출 번호 : rax

  • 함수의 syscall 번호를 가진다
  • ex. exit() = 0x2000001

반환 주소 : rcs

  • syscall을 호출했던 응용프로그램의 return 주소값을 가진다. syscall이 끝난 후 return 주소를 rcx의 값으로 채운다

레지스터 플래그 : r11

  • 이전 플래그 레지스터, syscall이 끝난 후 플래그를 r11의 값으로 채운다

매개변수 : (순서대로) rdi, rsi, rdx, r10, r8, r9

  • 6개 이상의 매개변수가 필요하면 스택을 이용한다

반환값은 일반적으로 rax레지스터로 넘겨진다
정수 : rax(하위 64bit), rdx(상위 64bit)
실수 : xmm0 (하위 128bit), xmm1 (상위 128bit)

profile
내꿈은 숲속의잠자는공주

0개의 댓글