간단 지식/System Programming

02. 시스템의 컴파일 과정

납작한돌맹이 2020. 10. 29. 22:42
반응형

적정한 크기의 소스코드를 컴파일하면 수 초 안에 결과물을 볼 수 있다. 그 수 초 안에는 어떤 과정들이 담겨있는 걸까?

총 4단계로 이뤄지며 각 단계에서 산출한 파일이 순차 처리된다. 가상의 파일 hello.c가 있다고 가정해보자.

 

1단계, 전처리(Preprocessing)

text형식의 c언어 파일(hello.c)를 받아서 modified source program(hello.i)으로 변환한다.

 

2단계, C언어로 어셈블리 코드 생성(Compilation)

text형식의 modifed source program(hello.i)를 assembly code(hello.s)로 변환한다.

 

3단계, 기계어로 object파일 생성(Assembly)

text형식의 assembly code(hello.s)를 relocatable object program(hello.o)로 변환한다.

 

4단계, library 파일 참조(Linking)

binary형식의 relocatable object program(hello.o)를 받아 printf, string 등 library로 존재하는 심볼들을 합친다.

 

5단계, 컴파일 완료

binary 형식의 executable object program(hello)이 산출된다.


시스템 프로그램이니 컴파일 단계에서 가장 집중해서 볼 단계는 바로 2단계, assembly코드를 생성하는 compilation 단계이다. 컴파일이란, 여태까지 사람이 이해할 수 있는 고급언어를 저급언어인 기계어로 바꿔주는 단계를 말한다. 여기서 말하는 기계어란 무엇일까? 01010101110011 처럼 0과 1로 이뤄진 코드 역시 기계어이다. 하지만 이는 컴퓨터의 입장이고, 시스템 입장에서 와 닿는 기계어는 좀 다르다.

store:
	pushq %rbx
        movq %rdx, %rbx
        movq %rax, (%rbx)
        popq %rbx
        ret

위 코드가 바로 c코드를 컴파일 했을 때 생성되는 어셈블리 코드이다. 간단하게 설명하자면 %rbx, %rdx 처럼 %가 붙은 것들은 전부 다 레지스터를 의미한다. pushq, popq는 그런 레지스터들을 시스템 스택에 넣고 빼는 명령어들이다. 이 레지스터들이 갖는 값은 주소인데, 메모리 공간의 주소를 말하는 것이지 그 내부에 저장된 값을 말하는 것이 아니다. 따라서 메모리 데이터에 접근하고 싶다면 (%rbx)처럼 괄호로 묶어줘야 한다. 특이한 점은 movq 명령어인데, 일반적으로 값의 대입은 <- 방향으로 이뤄지지만 movq는 -> 방향으로 이뤄진다. 예를 들어 movq %rdx, %rbx의 의미는 '레지스터 %rdx가 갖는 값을 %rbx에 대입'이라는 의미이다.


컴파일에서 어셈블리 코드를 생성하는 과정이 필요한 이유는 바로 그 특성에 있다. 어셈블리의 특징은 여러 가지가 있지만 그중에서 2가지를 알아두자.

1. 데이터 타입의 최소화

2. 원시적인 조작

 

c언어에서는 short, long, int, char 등 다양한 데이터타입이 있지만 어셈블리에서는 모두 int 타입으로 통일한다. 또한 배열, 구조체 등과 같은 집합적 데이터가 존재하지 않는다. 물론 이를 대신하여 메모리 안에서 연속적인 바이트들이 할당될 수 있다. 

어셈블리 코드에서 잘 드러나듯, 레지스터 혹은 메모리 데이터에 대한 산수기능을 할 수 있다. 같은 의미로 메모리에서 레지스터로, 레지스터에서 메모리로 데이터를 옮기고 저장할 수 있다.

 

 

(이 글이 도움이 됐다면 광고 한번씩만 클릭 해주시면 감사드립니다, 더 좋은 정보글 작성하도록 노력하겠습니다 :) )

반응형