본문 바로가기

CS:APP

[CS:APP] 3 프로그램의 기계수준 표현(Machinne-Level Representation of Programs) 연습문제 ①

연습문제 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)
  • %eax: 32비트 (4바이트)
  • (%rsp): 메모리
  • 메모리에 4바이트를 저장하겠다는 의미 → movl
 정답: movl
2. mov__ (%rax), %dx
  • %dx : 16비트 (2바이트)
  • 메모리에서 2바이트를 읽어와서 %dx에 저장 → movw
 정답: movw
3. mov__ $0xFF, %bl
  • %bl : 8비트 레지스터 (1바이트)
  • Immediate → 1바이트 저장 → movb
 정답: movb
4. mov__ (%rsp, %rdx, 4), %dl
  • %dl → 8비트 레지스터 (1바이트) → movb
 정답: movb
5. mov__ (%rdx), %rax
  • %rax : 64비트 (8바이트)
  • 메모리에서 8바이트 읽기 → movq
 정답: movq
6. mov__ %dx, (%rax)
  • %dx : 16비트 레지스터 (2바이트)
  • %dx 값을 (%rax)가 가리키는 위치에 저장  movw
 정답: movw

 


연습문제 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;
}