3.4 정보 접근하기
- x86-64 주처리장치(CPU)는 64비트 값을 저장할 수 있는 16개의 범용 레지스터를 보유하고 있다.
- 위 그림에서 볼 수 있듯이 instruction들은 16개의 레지스터의 하위 바이트들에 저장된 다양한 크기에 대해 작동할 수 있다.
3.4.1 Operand Specifiers(오퍼랜드 식별자)
- 대부분의 instruction들은 하나 이상의 오퍼랜드를 갖는다.
오퍼랜드는 연산을 수행할 source값과 그 결과를 저장할 destination의 위치를 명시한다.
- x86-64는 위와 같이 다양한 오퍼랜드 형태들을 지원한다.
오퍼랜드는 세 가지 타입으로 구분할 수 있다.
1) immediate(상수 값을 말한다.)
ATT 형식의 어셈블리 코드에서 상수는 $ 기호 다음에 C 표준 서식을 사용하는 정수로, $-577, $0x1F와 같이 나타낸다.
2) register
· 레지스터의 내용을 나타내며, 각각 16개의 64bit, 32bit, 16bit, 8bit의 레지스터들이 하위 부분인 8, 4, 2, 1byte 중 하나의 레지스터를 가리킨다.
· 위 그림에서 r_a 는 레지스터 a를 나타내며, 해당 값은 R[r_a]를 참조하여 나타내며, 레지스터 집합을 r_a와 같은 레지스터 식별자를 index로 사용하는 array R로 본다.
3) 메모리 참조(memory reference)
· effective address라 불리는 계산된 주소에 의해 메모리 위치에 접근한다.
· 메모리를 거대한 바이트의 배열로 생각할 수 있으므로 M_b[Addr] 과 같이 표시한다.
(M_b[Addr] : 메모리 주소 Addr부터 저장된 b 바이트를 참조한다는 의미)
- 메모리 참조를 가능하게 하는 많은 주소 지정 방식 중 가장 일반적으로 Imm(r_b, r_i, s)와 같은 형태를 사용한다.
Imm : 상수 오프셋, r_b : 베이스 레지스터, r_s : 인덱스 레지스터, s : 배율(1, 2, 4, 8의 값을 가짐)
(레지스터는 64bit register이다.)
여기서 effective address는 Imm + R[r_b] + R[r_i] * s로 계산된다.
3.4.2 데이터 이동 instruction
- 가장 많이 사용되는 instruction은 데이터를 다른 위치로 복사시키는 것이다.
- 위 그림은 MOV class라 부르는 데이터 이동 instruction들을 나타낸 것이다.
- 이 클래스는 4개의 instruction들로 구성된다.(movb, movw, movl, movq)
4개의 instruction들은 서로 다른 크기의 데이터(왼쪽부터 1, 2, 4, 8byte)에 대해 작동한다는 것을 제외하면 유사한 효과를 갖는다.
- source 오퍼랜드는 immediate(상수), 레지스터, 메모리에 저장된 값을 나타내고,
destination 오퍼랜드는 레지스터 또는 메모리 주소의 위치를 나타낸다.
x86-64에서는 데이터 이동 instruction에서 두 개의 오퍼랜드 모두가 메모리 위치에 올 수 없게 한다.
- 따라서 어떤 값을 메모리로부터 다른 메모리 위치로 복사하기 위해서는 2개의 instruction이 필요하다.
1) source 값을 레지스터에 적재하는 instruction
2) 레지스터의 값을 destination에 쓰기 위한 instruction
- 그림 3.2를 보면 이 instruction들을 위한 레지스터 오퍼랜드들은 16개의 레지스터 중 이름이 붙은 부분이 될 수 있다.
(레지스터의 크기는 instruction의 마지막 문자 b, w, l, q와 같아야한다.)
- 대부분의 경우 MOV instruction들은 특정 레지스터 바이트들이나 destination 오퍼랜드로 지정된 메모리 위치만을 업데이트하지만, movl의 경우 레지스터를 목적지로 갖는 경우, 레지스터의 상위 4byte도 0으로 설정한다.
- 그림 3.4의 마지막 instruction movabsq는 64bit 상수를 다루기 위한 것으로, 오직 32bit 2의 보수로 나타낼 수 있는 immediate source 오퍼랜드들만을 갖는다.
이 값은 그 후 부호 확장되어서 destination을 위해 64bit 값으로 만들어진다.
movabsq instruction은 임의의 64bit 상수 값을 source 오퍼랜드로 가질 수 있고, destination으로는 레지스터 만을 가질 수 있다.
2의 보수 : 컴퓨터가 음수를 저장하기 위한 방법 중 하나(맨 앞 비트가 0이면 양수, 1이면 음수)
└> 원래 수를 2진수로 바꾼 후, 1 -> 0, 0 -> 1로 바꾸는 NOT 연산을 한 뒤, 1을 더하면 2의 보수가 완성됨
위의 두 그림은 작은 source 값을 더 큰 destination으로 복사하는 class 2개를 나타낸 것이다.
- MOVZ 클래스의 instruction들은 destination의 남는 byte들을 모두 0으로 채워주며,
MOVS 클래스는 가장 중요한 비트를 반복해서 복사하는 부호 확장으로 채운다.
- 이 instruction들은 마지막 2개 문자로 사이즈를 나타내는 것을 갖는다.
첫 번째 : source의 크기, 두 번째 : destination의 크기
각 class에 1, 2 byte의 source 크기, 2, 4 byte의 destination 크기를 모두 다루는 3개의 instruction들이 포함되어 있다.(destination이 source보다 더 긴 경우만 다룸)
- 그림 3.5에 4 byte source를 8 byte destination으로 zero-extend instruction이 없다.
논리상으로는 해당 instruction은 movzlq여야 하지만, 존재하지 않는다.
따라서 레지스터를 destination으로 하는 movl을 이용해서 구현할 수 있다.(4byte를 생성하는 instruction이 상위 4byte를 0으로 채울 수 있다는 성질을 활용)
64bit destination의 경우, 부호 확장은 세 종류 source 모두 지원하고, 0으로 확장하는 이동은 2개의 더 작은 source 타입에 대해 지원한다.
- 그림 3.6은 cltq instruction에 대해서도 소개한다.
이 instruction은 오퍼랜드가 없이, 항상 레지스터 %eax를 source로, %rax를 destination으로 사용해서 부호 확장 결과를 만든다.
movslq %eax, %rax와 같은 효과를 내지만 더 압축적인 인코딩을 가짐
3.4.3 데이터 이동 예제
- (b)에서 리턴 값을 레지스터 %rax에 저장해서 함수가 값을 리턴하거나, 이 레지스터의 하위 부분 중의 하나로 리턴한다.
- (b)에서 주목해야 할 특징 2가지
1) C언어에서 포인터라 부르는 것이 어셈블리어에서는 단순히 주소임
2) x 같은 지역 변수들은 메모리에 저장되기 보다 종종 레지스터에 저장된다.(레지스터 접근 속도 >>> 메모리 접근 속도)
3.4.4 스택 데이터의 저장과 추출(push, pop)
- 마지막 2개의 데이터 이동 연산은 프로그램 스택에 데이터를 push하거나 pop하기 위해 사용된다.
- x86-64에서 프로그램 스택은 메모리 특정 영역에 위치한다.
- 위 그림처럼 stack의 top에는 stack 원소 중 가장 낮은 주소를 갖는다.
- 스택 포인터 %rsp는 스택의 맨 위(top) 원소의 주소를 저장한다.
- pushq와 popq는 1개의 오퍼랜드를 사용한다.
(pushq : 추가할 source 데이터, popq : 추출을 위한 데이터 destination)
- 쿼드워드 값을 스택에 추가하려면, 스택 포인터를 8 감소시키고, 추가할 값을 스택 주소의 새로운 top에 기록하는 것으로 구현된다.
- 위의 2개의 instruction은 총 8byte가 필요하지만, pushq는 1byte 기계어 코드로 인코딩된다.
- 그림 3.9에서 왼쪽 2개의 그림은 pushq %rax를 실행한 결과를 보여준다.
- 쿼드워를 pop하는 것은 스택 top 위치에서의 읽기 작업 후에 스택 포인터를 8 증가시키는 것으로 구현된다.
- 그림 3.9의 세 번째 그림은 popq %rdx 를 실행한 결과를 보여준다.
보이는 것처럼 %rsp가 0x108로 복구되기만 할 뿐, 0x123 값은 다른 값으로 덮어써질 때까지 메모리 주소 0x100에 남아있다.
Stack top : %rsp 가 가리키는 곳(이 위의 주소 값들은 stack에 포함되지 않은 무효인 값들)
- stack이 프로그램 코드와 다른 형태의 프로그램 데이터와 같은 메모리에 저장되기 때문에 프로그램들은 표준 메모리 주소 지정 방법을 통해 스택 내 임의의 위치에 접근이 가능하다.
ex) stack top이 쿼드워드라 할 때, movq 8(%rsp), %rdx instruction은 스택의 두 번째 쿼드워드를 레지스터 %rdx에 복사해준다.
'TIL & WIL' 카테고리의 다른 글
[TIL] 크래프톤 정글 3주차 CS:app 6(배열의 할당과 접근) (0) | 2024.04.14 |
---|---|
[TIL] 크래프톤 정글 3주차 CS:app 5(Procedure) (0) | 2024.04.14 |
[TIL] 크래프톤 정글 2주차 - 자료구조(B-Tree) (0) | 2024.04.01 |
[TIL] 크래프톤 정글 2주차 CS:app 3(메모리 계층 구조, 운영체제) (1) | 2024.03.29 |
[TIL] 크래프톤 정글 1주차 CS:app 2(C 프로그램 컴파일 이후 실행 과정) (0) | 2024.03.27 |