[42Seoul] libasm : 켠김에 왕까지

    자료 조사

    추천 사이트1: yeosong님의 42wiki

    libasm

    🖥 42 학습 노트 by yeosong

    yeosong1.github.io

    추천 사이트2: libasm notion

    libasm

    Introduction

    www.notion.so

    작업환경 구축

    더보기

    MacBook Pro (16-inch, 2019)

    macOS Big Sur 11.2.1

    Homebrew 설치하기

    Homebrew는 Mac OS에서 기본적으로 제공되지 않는 라이브러리를 설치하는 도구입니다. Docker를 사용할 때 등 여러모로 유용하니 설치하도록 합시다.

    Homebrew

    The Missing Package Manager for macOS (or Linux).

    brew.sh

    공식 사이트에서 지시하는 대로 설치해 봅시다. 터미널에서 다음 명령어를 실행해 보세요!

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

    성공하셨다면 아마 이렇게 나오셨을 것 같습니다. 정확히는 다를 수도 있지만요!

    더보기
    ==> Checking for `sudo` access (which may request your password).
    Password:
    ==> This script will install:
    /usr/local/bin/brew
    /usr/local/share/doc/homebrew
    /usr/local/share/man/man1/brew.1
    /usr/local/share/zsh/site-functions/_brew
    /usr/local/etc/bash_completion.d/brew
    /usr/local/Homebrew
    
    Press RETURN to continue or any other key to abort
    ==> /usr/bin/sudo /usr/sbin/chown -R kimkwanho:admin /usr/local/Homebrew
    ==> Downloading and installing Homebrew...
    remote: Enumerating objects: 250, done.
    remote: Counting objects: 100% (250/250), done.
    remote: Compressing objects: 100% (70/70), done.
    remote: Total 323 (delta 195), reused 209 (delta 175), pack-reused 73
    Receiving objects: 100% (323/323), 139.51 KiB | 358.00 KiB/s, done.
    Resolving deltas: 100% (213/213), completed with 97 local objects.
    From https://github.com/Homebrew/brew
     * [new branch]		  dependabot/bundler/Library/Homebrew/sorbet-0.5.6287 -> origin/dependabot/bundler/Library/Homebrew/sorbet-0.5.6287
    	 485f73a32..25d098764  master	 -> origin/master
    HEAD is now at 25d098764 Merge pull request #10723 from Homebrew/assert_not_match
    Ignoring json-2.3.1 because its extensions are not built. Try: gem pristine json --version 2.3.1
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:4: warning: already initialized constant JSON::VERSION
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:4: warning: previous definition of VERSION was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:5: warning: already initialized constant JSON::VERSION_ARRAY
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:5: warning: previous definition of VERSION_ARRAY was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:6: warning: already initialized constant JSON::VERSION_MAJOR
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:6: warning: previous definition of VERSION_MAJOR was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:7: warning: already initialized constant JSON::VERSION_MINOR
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:7: warning: previous definition of VERSION_MINOR was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/version.rb:8: warning: already initialized constant JSON::VERSION_BUILD
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/version.rb:8: warning: previous definition of VERSION_BUILD was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:107: warning: already initialized constant JSON::NaN
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:100: warning: previous definition of NaN was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:109: warning: already initialized constant JSON::Infinity
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:102: warning: previous definition of Infinity was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:111: warning: already initialized constant JSON::MinusInfinity
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:104: warning: previous definition of MinusInfinity was here
    /Library/Ruby/Gems/2.6.0/gems/json-2.3.1/lib/json/common.rb:136: warning: already initialized constant JSON::UnparserError
    /System/Library/Frameworks/Ruby.framework/Versions/2.6/usr/lib/ruby/2.6.0/json/common.rb:129: warning: previous definition of UnparserError was here
    Updated 2 taps (homebrew/core and homebrew/cask).
    ==> New Formulae
    crispy-doom							  projectm
    ==> Updated Formulae
    cairo ✔					haxe					   perl
    arduino-cli				highlight				  phpstan
    argocd					 ipython					pipx
    armadillo				  jetty					  pspg
    aws-sdk-cpp				jetty-runner			   python-markdown
    azcopy					 jruby					  python@3.7
    babel					  kotlin					 python@3.8
    berkeley-db				kubeaudit				  richmd
    cabal-install			  kubectx					s-nail
    circleci				   kustomize				  snakemake
    commitizen				 libgr					  sofia-sip
    conan					  libgxps					stella
    csvprintf				  liblinear				  stress-ng
    cubejs-cli				 libomp					 supervisor
    dasel					  lmod					   tendermint
    docker					 mermaid-cli				tfsec
    docker-compose			 microplane				 tree-sitter
    docker-compose-completion  minetest				   ugrep
    dolt					   mosquitto				  vault
    earthly					mozjpeg					vercel-cli
    eccodes					name-that-hash			 verilator
    eksctl					 nano					   vim
    envoy					  nativefier				 vultr
    erlang					 newrelic-cli			   waffle
    etcd					   nfpm					   webpack
    exploitdb				  ocaml-findlib			  xorgproto
    fonttools				  ocrmypdf				   yq
    freerdp					pdm
    ==> Deleted Formulae
    geant4
    ==> Updated Casks
    ableton-live			   dash					   opencore-configurator
    ableton-live-intro		 deskreen				   pgadmin4
    ableton-live-lite		  digital					qgis
    ableton-live-standard	  drawio					 qownnotes
    ableton-live-suite		 exodus					 raven-reader
    apache-directory-studio	figma					  subethaedit
    autopkgr				   figmadaemon				teamviewer
    biscuit					imazing					telegram
    calibre					little-snitch			  tunnelbear
    cleanmymac				 macupdater				 tutanota
    clover-configurator		mmhmm					  visual-studio
    cocktail				   nova					   webstorm
    daedalus-mainnet		   objectivesharpie
    ==> Deleted Casks
    protonmail-unofficial
    
    You have 15 outdated formulae and 1 outdated cask installed.
    You can update them with brew upgrade.
    ==> Installation successful!
    
    ==> Homebrew has enabled anonymous aggregate formulae and cask analytics.
    Read the analytics documentation (and how to opt-out) here:
    	https://docs.brew.sh/Analytics
    No analytics data has been sent yet (or will be during this `install` run).
    
    ==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
    	https://github.com/Homebrew/brew#donations
    
    ==> Next steps:
    - Run `brew help` to get started
    - Further documentation:
    	https://docs.brew.sh
    					

    NASM 설치하기

    TIP

    NASM의 개념에 대한 정보는 여기를 확인하세요!

    brew를 설치하셨으니 터미널에서 윗 줄의 명령어를 실행해 주세요!

    설치가 완료되었다면 밑의 줄의 명령어를 실행해서 버전을 확인해 봅시다.

    brew install nasm
    nasm -ver

    제 버전은 다음과 같습니다.

    더보기
    NASM version 2.15.05 compiled on Nov 14 2020

    NASM에서 "Hello, world!" 출력하기

    NASM 설치가 완료되었으니 어셈블리어 파일 hello.s 파일을 만들어 봅시다.

    global _main
    	section		.text
    
    _main:
    	mov			rax, 0x02000004	
    	mov			rdi, 1
    	mov			rsi, message
    	mov			rdx, 13
    	syscall
    	mov			rax, 0x02000001
    	xor			rdi, rdi
    	syscall
    	section		.data
    
    message:
    	db			"Hello, World!", 10

    hello.s 파일에 대한 해석은 다음과 같습니다.

    번외: hello.s 파일 해석해보기

    TIP

    어셈블리어에 관한 자세한 내용은 여기를 참고하세요!

    ☎️ System Call이란?

    더보기

    먼저 _main에서 syscall을 기점으로 둘로 나뉘는 듯이 생겼으니 syscall의 의미에 대해 알아봅시다.

    위키백과에서 이 개념을 확인해 봅시다!

    시스템 호출은 운영 체제의 커널이 제공하는 서비스에 대해, 응용 프로그램의 요청에 따라 커널에 접근하기 위한 인터페이스이다.
    보통 C나 C++과 같은 고급 언어로 작성된 프로그램들은 직접 시스템 호출을 사용할 수 없기 때문에 고급 API를 통해 시스템 호출에 접근하게 하는 방법이다.

    이 블로그에서도 정리를 잘 해주신 거 같네요. 읽어보면 좋을 거 같습니다!

    다들 아시겠지만, 운영체제에는 Kernel Mode와 User Mode가 있습니다.

    TIP

    잠깐! 커널의 개념이 헷갈리신다면? 커널의 정의를 찾아보면 되죠!

    커널(kernel)은 컴퓨터의 운영 체제의 핵심이 되는 컴퓨터 프로그램의 하나로, 시스템의 모든 것을 완전히 통제한다.
    운영 체제의 다른 부분 및 응용 프로그램 수행에 필요한 여러 가지 서비스를 제공한다.

    이처럼 커널은 사용자 명령 해석 - 파일 입출력 등 많은 역할을 담당하며,

    시스템 콜은 커널 영역의 기능을 사용자 모드가 사용 가능하게 -
    다시 말해서 프로세스가 자원에 직접 접근해서 필요한 기능을 사용할 수 있게 해준다고 보시면 될 것 같습니다!

    mov 명령어가 뭐지..?

    더보기

    여기서 정리를 잘 해 놓으셨으니까 참조해 보세요! (옛날 자료지만 ㄱㅊ)

    mov 명령어는 mov [destination] [source]의 형식으로 사용합니다.

    [source]의 값을 [destination]으로 복사한다고 생각하시면 됩니다.

    move라고 생각해서 복사가 아니라 이동이라고 생각하실 수도 있는데, 복사의 개념이 맞습니다.

    xor 명령어

    더보기

    여기서 정리를 잘 해 놓으셨으니까 참조해 보세요! (옛날 자료지만 ㄱㅊ)

    xor 명령어는 말 그대로 실제로 xor 연산을 수행하는 것입니다.

    mov 명령어와 비슷하게 xor [param1] [param2].

    아시겠지만, xor 연산은 두 값이 같을 때 0을 반환합니다.

    param1과 param2을 xor 연산하여 연산 결과를 param1에 넣습니다.

    저희 코드에서는 xor rdi, rdi로 사용하였는데,

    같은 값을 xor하면 0이 되는 원리를 이용하여 rdi를 0으로 초기화한다고 생각할 수 있습니다.

    파일을 만드셨다면 다음 명령어를 입력해서 실행시켜 봅시다.

    두 명령어를 모두 실행하셨다면 아래와 같이 디렉토리가 구성될 겁니다.

    언제나 그래왔듯이 ./hello 명령어로 출력해 봅시다.

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

    본격적으로 시작해보기

    공부

    시작하기 전에 간단히 공부를 해봅시다.

    먼저 명령어입니다. 더보기란을 참고하여 대충 공부하세요!

    필요할 때마다 명령어는 찾아보면서 해도 될 거 같네요.

    더보기

    - 조작 명령어 -

    call : 함수 호출

    ret : call로 호출한 함수를 종료하고 다음 명령줄로 이동

    nop : 아무것도 하지 않음

    jmp : 분기(라벨) 실행

    조건 점프 명령어 : cmp 연산 결과에 따라 jmp

      1) je : cmp A B 에서 A == B 일때 jmp

      2) jne : cmp A B 에서 A != B 일때 jmp

      3) ja : cmp A B 에서 A > B일 때 jmp

      4) jb : cmp A B 에서 A < B일 때 jmp

      5) jae : cmp A B 에서 A >= B일 때 jmp

      6) jae : cmp A B 에서 A <= B일 때 jmp

    - 데이터 전송 명령어 -

    push : 스택에 값 넣기

    pop : 스택에서 값 가져오기

    mov : mov param1 param2에서 param2의 값을 param1에 대입

    lea : lea param1 param2에서 param2의 주소를 param1에 대입

    조건 점프 명령어 : cmp 연산 결과에 따라 jmp

    - 산술 명령어 -

    inc : 인자의 값 1 증가

    dec : 인자의 값 1 감소

    add : add param1 param2에서 param2의 값을 param1에 더함

    sub : sub param1 param2에서 param2의 값을 param1에 뺌

    cmp : cmp param1 param2에서 값을 비교할 때 사용; 위의 조건 점프 명령어와 같이 사용

    test : test param1 param2에서 두 인자의 값을 AND 연산함.

    그 다음은 레지스터들입니다.

    레지스터는 프로세서에 있는 고속 메모리입니다.

    작은 데이터와 중간 결과 같은 값을 저장할 수 있기에,

    어셈블리어에서는 변수 대용으로 레지스터를 사용합니다.

    저희는 반환값을 rax에 저장하고, 매개변수를 rdi rsi rdx rcx r8 r9를 차례대로 사용해야 합니다.

     1. 산술-논리 연산을 맡는 레지스터

     EAX

    Accumulator Register

     가장 자주 사용하는 변수로, 사칙연산과 논리연산에서 주로 사용한다.
     함수의 리턴 값도 저장한다.

     EBX

    Base Register

     특별한 목적으로 만들어진 레지스터가 아니다.
     공간이 필요할 때 적당히 사용하기도 하고,
     범용 레지스터가 부족할 때 서포팅 용도로도 사용한다.
     메모리 주소를 저장한다고도 한다.

     ECX

    Count Register

     C는 Count의 의미로써 사용되었다. 반복문에서의 idx 역할을 맡는다.
     다만 실행방식이 조금 다른데, 초기화 값에 n을 넣고 idx--을 한다고 생각하자.
     반복문이 없을 때는 변수로 사용할 수 있다.

     EDX

    Data Register

     일반적으로 EAX와 함께 연동하여 사용한다.
     큰 수의 계산이나 부호 확장 명령 등에 사용한다.

     2. 메모리 주소를 저장하는 레지스터

     EBP

    Base Point Register

     Stack의 첫 시작 주소를 저장한다.
     Stack이 소멸하지 않는 한 값이 변하지 않는다.

     ESP

    Stack Pointer Register

     Stack의 끝 주소를 저장한다.
     Push Pop 명령어를 사용할 때 (Stack의 값을 변경시킬 때) 값이 4씩 변한다.

     ESI

    Source Index Register

     데이터 조작/복사 시 소스 데이터의 주소를 저장한다.

     EDI

    Destination Index Register

     데이터 복사 시 목적지의 주소를 저장한다.

    등등 다양한 레지스터들이 있네요.. 넘 많으니 여러 블로그에서 대략적으로만 보시고 일단 사용해 봅시다.

    Code with goooooood comments

    프로그래머 원툴, 깃허브에서 보실 수 있어요. 아마도?