[C] C언어 컴파일 3/4단계: 어셈블러(Assembler)

Yongjun Park·2022년 1월 31일
0
post-thumbnail

커맨드

$ as main.s -o main.o
$ as sum.s -o sum.o

또는 다음의 명령어도 사용 가능하다.

$ gcc -c main.s -o main.o
$ gcc -c sum.s -o sum.o

gcc -c 옵션에 대한 자세한 내용은 gcc 기본 옵션 정리를 참고하시기 바랍니다.


위의 명령어를 통해 산출된 main.o는 다음과 같다.

이미 눈치챘겠지만, .o 파일은 텍스트 파일이 아니라 이진 파일이다.

사실 어셈블러의 역할은 매우 단순하다.

어셈블러의 역할

작성된 어셈블리어를 기계어로 바꿔 주는 프로그램. 요즘은 C언어로 입문하는 이가 많다보니 어셈블러의 특수성을 제대로 이해하지 못하고 어셈블러와 타 컴파일러간의 차이를 제대로 인식하지 못하는 경우도 있다.

어셈블리어는 기본적으로는 기계어와 1:1 대응이기 때문에 어셈블러에는 인스트럭션 테이블만 내장해 두고 각 구문을 테이블에 맞게 치환만 하면 된다. (출처)

과정을 체험해보기 위해 함께 직접 변환해보자. (출처 : CS:APP 연습문제 4.2)

Y86-64를 이용한 어셈블러 역할 체험

irmovq $-4, %rbx
rmmovq %rsi, 0x800(%rbx)
halt

위의 커맨드는 실제 어셈블리어는 아니지만 매우 흡사하다.

irmovq $-4, %rbx

  1. irmovq : 30
  2. $-4 : 4의 2진수 표현인 0000 0100를 1의 보수로 바꾸면 1111 1011이고, 여기에 1을 더한 2의 보수는 1111 1100fc로 표현할 수도 있다.
    irmovq에서 Imm값은 8바이트로 표현되어야 하므로, $-4ff ff ff ff ff ff ff fc이다.
    여기서 Imm값 표현을 리틀 엔디안으로 한다면, fc ff ff ff ff ff ff ff로 저장된다.
  3. %rbx : 3
  4. 종합 : 30 f3 fc ff ff ff ff ff ff ff

rmmovq %rsi, 0x800(%rbx)

  1. rmmovq : 40
  2. %rsi : 6
  3. 0x800 : 00 00 00 00 00 00 08 00을 리틀 엔디안으로 바꾸면, 00 08 00 00 00 00 00 00
  4. %rbx : 3
  5. 종합 : 40 63 00 08 00 00 00 00 00 00

halt : 00


따라서

irmovq $-4, %rbx
rmmovq %rsi, 0x800(%rbx)
halt

를 어셈블러를 통해 기계어로 변환하면, 다음과 같은 결과를 얻을 수 있다.

30 f3 fc ff ff ff ff ff ff ff
40 63 00 08 00 00 00 00 00 00
00

하지만, 이것 역시 우리가 보기 편하게 잘라 놓은 것이고 실제 컴퓨터는 다음과 같은 이진 코드를 보게 된다.

30 f3 fc ff ff ff ff ff ff ff 40 63 00 08 00 00 00 00 00 00 00

위의 두 사진에 나온 것처럼, 인스트럭션 코드 번호, 인스트럭션별 바이트 수, 레지스터 번호 등을 어셈블러가 이미 내장하고 있기 때문에 텍스트 코드를 이진 코드로 아주 쉽게 바꿀 수 있다.

그리고 그 정보를 컴퓨터도 이미 가지고 있기 때문에, 인스트럭션을 계속 이어서 나열해도 (우리만 보기 힘들어할 뿐) 컴퓨터가 이해하는 데에는 전혀 문제가 없다.

오해하지 말아야 할 것은, .s 파일의 텍스트만을 이진으로 바꾼 것이 .o는 아니라는 점이다. 곧 알게 되겠지만, .s 내용에 추가하여 몇몇 섹션들이 들어간다.

더 중요한 사실은, 우리도 .o 파일을 역으로 대응시켜 텍스트화시킬 수 있다는 점이다.

objdump를 이용한 역어셈블

profile
추상화되었던 기술을 밑단까지 이해했을 때의 쾌감을 잊지 못합니다

0개의 댓글