Showing

[TIL] 어셈블리어 레지스터 기초 실습, 프로그래머용 계산기 다뤄보기 본문

Today I Learned (TIL)

[TIL] 어셈블리어 레지스터 기초 실습, 프로그래머용 계산기 다뤄보기

RabbitCode 2023. 3. 29. 02:06

 

0.  Today I Learned

 안녕하세요! FlyDuck Dev🦢입니다.

오늘은 전산학의 기본이 되는 레지스터 공부를 하기 위해서, SASM을 통해서 기초 어셈블리 언어를 작성해았습니다. 또한, 윈도우 프로그래머용 계산기를 가지고 놀면서 컴퓨터에서 자주 쓰이는 데이터를 이해해보는 시간을 가졌습니다.

TIL 목적상, 문어체로 작성하게 됨을 미리 밝힙니다!

 

🔭오늘의 공부 자료

(1) Rookiss님의 c++ 프로그래밍 입문 강좌

(2) [CS:APP] 컴퓨터 시스템 1장, 3장

 

 

1.  컴퓨터 상식 (레지스터)

 

https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=kjyong86&logNo=140161466414

컴퓨터가 꺼지면 하드디스크에 있는 내용은 비교적 영구적으로 보존이 되지만, 메인 메모리의 내용은 보존이 되지 않고 데이터가 휘발성이다. cpu에 가까우면 가까울수록 접근 속도도 월등하게 빨라진다.(레지스트 > 메인메모리 > 하드디스크) 다만 가까울수록 저장 용량을 크게 확보하기 어렵다.

 

레지스터를 사용하는 이유는, cpu가 연산을 할 때, 중간중간에 자기가 연산한 결과물들을 계속 임시적으로 어딘가에 저장을 해야 할 것이다. 특히 잠시 저장했다가 금방 쓰고 싶은 데이터를 굳이 멀리 있는 하드 디스크까지 보내서 저장할 필요없이 가깝고 데이터가 휘발되는 레지스터에 저장해놓게 된다.

 

실질적으로 cpu 명령어들을 보면, 레지스터에 있는 값을 ALU가 가지고 와라, 레지스터에 있는 값을 메모리로 보내라 등의 레지스터 기반 명령어들이 많다. 레지스터는 set로, 아주 다양한 레지스터들이 함께 있다. 

 

https://digiconfactory.tistory.com/entry/x86%EB%A0%88%EC%A7%80%EC%8A%A4%ED%84%B0%EB%AA%A8%EB%8D%B8

일반적으로 프로그래밍 시에는, a-b-c-d 라인이다.

https://velog.io/@kitkat-42/libasm, https://whitel0tus.tistory.com/24

rax는 64비트를 전면 다 사용한다는 뜻이다.(통상, 64비트 환경  컴퓨터라면 레지스터 가능한 가장 큰 크기가 64비트이다.)

부분적으로 사용할 수도 있다.

절반만 쪼개면 32bit인 eax, 16bit는 ax, 8bit(최하단 1바이트)만 사용할 것이라면 ah, al 등으로 다른 예약어를 씀으로 쪼개서 사용할 수 있다.

AL, AH, AX, EAX, RAX가 모두 다른 레지스터라고 이해하는 경우가 있는데, RAX가 EAX를 포함하고, EAX가 AX를 포함하는 형태이다. AX의 상위 8 bit를 al이 사용하고, 하위 8 bit를 ah가 사용하는 식.
이는 하위 비트 시스템(32비트, 16비트 시스템) 호환을 위한 설계이기도 하고, 레지스터 공간의 낭비를 없애기 위함이기도 하며, 효율적인 알고리즘을 위한 설계이기도 하다.

 

https://furysecurity.tistory.com/28, https://wikidocs.net/165974

실행파일은 다양한 섹션들의 종합이다. 이러한 파일이 메모리에 올라가게 된다.

 

 

 

2.  프로그래머용 계산기

(1) 보수 만들기

 2의 보수는 대부분의 산술연산에서 원래 숫자의 음수처럼 취급된다. (https://ko.wikipedia.org/wiki/2%EC%9D%98_%EB%B3%B4%EC%88%98)

주어진 이진수의 모든 자리의 숫자를 반전(0을 1로, 1을 0으로)시킨 뒤 여기에 1을 더하면 2의 보수를 얻을 수 있다.

(2) 2진법과 16진법의 호환성

2진법 00110011은 51인데, 16진법으로는 33이다. 복잡하게 계산하지 않고도 바로 알 수 있는 이유는,

 

2진법을 네글자씩 쪼개서 보면 16진법상 수를 알 수 있다.

 

0011 0011

= (2^0*1) + (2^1*1) = 3

33

 

(3) bit, byte, word

8bit = 1byte

16 bit = 2 byte = 1 word

32 bit = 4 byte = 2 word = 1 dword (double -word)

64 bit = 8 byte = 4 word = 1 qword (quad -word)

 

byte word
dword qword 

3.  어셈블리어 실습 (레지스터의 이해)

 

어셈블리 언어는 프로그래밍 언어 중에서 가장 컴퓨터에 가까운 방식으로 작업 가능하기 때문에 레지스터도 실시간으로 작업하면서 코딩을 할 수 있다.

(1) mov

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    mov rbp, rsp; for correct debugging
    mov eax, 0x1234
    mov rbx, 0x12345678
    mov cl, 0xff
    xor rax, rax
    ret

각 레지스터에 원하는 값(eax에 16진수인 0x1234, rbx에 0x12345678을, cl에 0xff을)을 실제로 넣어주었다.

(2) 범위 지정 후 특정 부분만 데이터 복사

%include "io64.inc"

section .text
global CMAIN
CMAIN:
    mov rbp, rsp; for correct debugging
    mov eax, 0x1234
    mov rbx, 0x12345678
    mov cl, 0xff
   ; 브레이크 포인트 1
    mov al, 0x00 
   ; 브레이크 포인트 2
    mov rax, rdx
   ; 브레이크 포인트 3
    
    xor rax, rax
    ret

-1- 브레이크 포인트 1

rax는 eax에 이미 0x1234를 넣어주었으므로 0x1234

 

-2- 브레이크 포인트 2

al 에다가 0을 넣어주고 실행하면

rax는 0이 아니라 0x1200이 된다.

 

-3- 브레이크 포인트 3

기존 rdx에 있던 값이 그대로 rax에 들어간다.

 

-2- 브레이크 포인트 이유

16진수 1234는 위와 같은 상태이고 mov al, 0x00 는 1바이트(8비트) 크기인 al를 전부 0으로 복사해주어라는 명령어 이므로, 8비트 까지를 전부 0으로 쭉 바꾸면 0x1200이 되는 것을 확인할 수 있다. 즉 al 을 0으로 밀어도 나머지 상위 비트에는 아무런 영향도 끼치지 않는다는 것이 핵심이다.

 

4.  다음 공부는📓

 

어셈블리 언어 상의 레지스터, 메모리, 변수에 대해서 오늘보다 더 밀도를 높여서 공부할 예정입니다!