연습문제 3.1
다음과 같은 값들이 표시된 메모리 주소와 레지스터에 저장되어 있다.
Address | Value | Register | Value |
0x100 | 0xFF | %rax | 0x100 |
0x104 | 0xAB | %rcx | 0x1 |
0x108 | 0x13 | %rdx | 0x3 |
0x10C | 0x11 |
다음에 나오는 표에 지시된 오퍼랜드의 값을 채우시오.
1. 그냥 레지스터의 값 자체 : 0x100
2. 메모리의 절대 주소 0x104에 저장된 값 : 0xAB
3. Immediate : 값 자체가 의미 있음 : 0x108
4. M[%rax] = M[0x100], 메모리 0x100에 있는 값 : 0xFF
5. 0x100 + 4 = 0x104, M[0x104] = 0xAB
6. 9 + 0x100 + 0x3 = 0x112 0x10C
7. 260 + 0x1 + 0x3 = 264(10진수) → 0x108(16진수)에 있는 값 : 0x13
8. 0xFC + 0x1 * 4 = 0xFC + 0x04 = 0x100에 있는 값 : 0xFF
9. 0x100 + 0x3 * 4 = 0x100 + 0x0C = 0x10C에 있는 값 : 0x11
연습문제 3.2
다음 어셈블리 언어의 각 줄에 대해 오퍼랜드를 고려하여 적절한 인스트럭션 접미어를 결정하시오.
(예를 들어, mov는 movb, movl, movq로 쓰일 수 있다.)
1. mov__ %eax, (%rsp)
|
2. mov__ (%rax), %dx
|
3. mov__ $0xFF, %bl
|
4. mov__ (%rsp, %rdx, 4), %dl
|
5. mov__ (%rdx), %rax
|
6. mov__ %dx, (%rax)
|
연습문제 3.3
다음 프로그램의 각 라인은 어셈블러를 호출하게 되면 에러 메시지를 생성한다. 각 줄마다 무엇이 잘못인지 설명하시오.
1. movb $0xF, (%ebx)
🛑 오류 : Cannot use %ebx as address register
- x86-64에서는 메모리 주소를 지정할 때 32비트 주소 레지스터(%ebx)를 사용할 수 없음
- 반드시 64비트 주소 레지스터(%rbx)를 써야 함
✅ movb $0xF, (%rbx)
2. movl %rax, (%rsp)
🛑 오류 : Mismatch between instruction suffix and register ID
- %rax는 64비트 레지스터, 그런데 movl은 32비트 명령어
- → 레지스터 크기와 접미사가 안 맞음
- 64비트 레지스터 → 64비트 명령어
✅ movq %rax, (%rsp)
3. movw (%rax), 4(%rsp)
🛑 오류 : Cannot have both source and destination be memory references
- x86 어셈블리에서는 메모리 ↔ 메모리 직접 이동 불가
- 하나는 반드시 레지스터여야 함
✅ movw (%rax), %ax
✅ movw %as, 4(%rsp)
4. movb %al, %sl
🛑 오류 : No register named %sl
- %sl이라는 존재하지 않는 잘못된 레지스터 이름
5. movq %rax, $0x123
🛑 오류 : Cannot have immediate as destination
- Immediate($0x123)은 읽기만 가능한 값
- Immediate는 소스(왼쪽)에만 와야 하고, 목적지(오른쪽)에 올 수 없음
✅ movq $0x123, %rax
6. movl %eax, %rdx
🛑 오류 : Destination operand incorrect size
- %eax : 32비트 레지스터
- %dx : 16비트 레지스터
- 두 오퍼랜드의 크기가 일치하지 않음 → 명령 실행 불가능
✅ movw %ax, %dx → 둘 다 16비트
✅ movi %eax, %edx → 둘 다 32비트
7. movb %si, 8(%rbp)
🛑 오류 : Mismatch between instruction suffix and register ID
- $si는 16비트 레지스터
- movb는 8비트 명령어 → 접미사와 레지스터 크기 불일치
✅ movw %si, 8(%rbp)
연습문제 3.4
변수 sp와 dp는 다음과 같은 자료형으로 선언되어 있다.
src_t *sp;
dest_t *dp;
src_t와 dest_t는 typedef로 선언된 자료형들이다. 우리는 적당한 두 개의 데이터 이동 인스트럭션을 이용해서 다음의 연산을 구현하고자 한다.
*dp = (dest_t) *sp;
sp와 dp 값들이 레지스터 %rdi와 %rsi에 저장되어 있다고 가정한다. 다음 표의 각 항목에 대해 지정된 데이터 이동을 구현하는 두 개의 인스트럭션을 보이시오. 첫 번째 인 스트럭션은 메모리에서 읽어서 적절한 변환을 하고, 레지스터 %rax의 적절한 부분을 설정 해야 한다. 두 번째 인스트럭션은 %rax의 적절한 부분을 메모리에 써야 한다. 두 경우 모두에서 이 부분들은 %rax, %eax, %ax 또는 %al일 수 있으며, 이들은 서로 다를 수 있다.
src_t | dest_t | Instruction | Comments |
long | long | movq (%rdi), %rax | Read 8 bytes |
movq %rax, (%rsi) | Store 8 bytes | ||
char | int | movsbl (%rdi), %eax | Convert char to int |
movl %eax, (%rsi) | Store 4 bytes | ||
char | unsigned | movsbl (%rdi), %eax | Convert char to int |
movl %eax, (%rsi) | Store 4 bytes | ||
unsigned char | long | movzbl (%rdi), %eax | Read byte and zero-extend |
movq %rax, (%rsi) | Store 8 bytes | ||
int | char | movl (%rdi), %eax | Read 4 bytes |
movb %al, (%rsi) | Store low-order byte | ||
unsigned | unsigned char | movl (%rdi), %eax | Read 4 bytes |
movb %al, (%rsi) | Store low-order byte | ||
char | short | movsbw (%rdi), %ax | Read byte and sign-extend |
movw %ax, (%rsi) | Store 2 bytes |
C언어에서 크기를 바꾸고, 부호화된 것을 변경하는 것과 관련된 캐스팅을 수행할 때 에는 해당 연산이 크기를 먼저 변경해야 한다는 점을 기억해야 한다(2.2.6절 참조) drag ㄱ
연습문제 3.5
여러분에게 다음의 정보가 주어졌다. 다음과 같은 프로토타입을 갖는 함수
void decodel(long *xp, long *yp, long *zp);
가 어셈블리 코드로 컴파일되어 다음의 결과를 생성하였다.
void decode1(long *xp, long *yp, long *zp)
xp in %rdi, yp in %rsi, zp in %rdx
decode1:
movq (%rdi), %r8
movq (%rsi), %rcx
movq (%rdx), %rax
movq %r8, (%rsi)
movq %rcx, (%rdx)
movq %rax, (%rdi)
ret
매개변수 xp, yp, zp들은 레지스터 %rdi, %rsi, %rdx에 각각 저장되어 있다.
위의 어셈블리 코드와 동일한 효과를 갖는 decode1을 C 코드로 작성하시오.
연습문제 3.5 해답
역엔지니어링은 시스템을 이해하는 데 매우 좋은 방법이다. 이 경우에 어떤 c 코드가 이 어셈블리 코드를 만드는지 결정하기 위해 C 컴파일러의 효과를 거꾸로 돌리고 싶어진다. 가장 좋은 방법은 포인터 xp, yp, zp가 가리키는 위치에 x, y, z 값으로 시작하는 “시뮬레이션”을 돌리는 것이다. 그러면 다음과 같은 동작을 얻을 수 있다:
void decode1(long *xp, long *yp, long *zp)
xp in %rdi, yp in %rsi, zp in %rdx
decode1:
movq (%rdi), %r8 Get x = *xp
movq (%rsi), %rcx Get y = *yp
movq (%rdx), %rax Get z = *zp
movq %r8, (%rsi) Store x at yp
movq %rcx, (%rdx) Store y at zp
movq %rax, (%rdi) Store z at xp
ret
이것으로부터 다음과 같은 C 코드를 작성할 수 있다:
void decode1(long *xp, long *yp, long *zp)
{
long x = *xp;
long y = *yp;
long z = *zp;
*yp = x;
*zp = y;
*xp = z;
}
'CS:APP' 카테고리의 다른 글
[CS:APP] 3.11 부동소수점 프로그램 (Floating Point Programming) (0) | 2025.04.03 |
---|---|
[CS:APP] 3.10 기계수준 프로그램에서 제어와 데이터의 종합 적용 (0) | 2025.04.03 |
[CS:APP] 3.9 이종 자료구조 (Heterogeneous Data Structures) (0) | 2025.04.03 |
[CS:APP] 3.8 배열의 할당과 접근 (Arrays: Allocation and Access) (0) | 2025.04.03 |
[CS:APP] 3.7 프로시저 (Procedures) (0) | 2025.04.03 |