컴퓨터 구조 - 빌드 과정

Translating and Starting a Program

JVM이 java파일을 어떻게 실행하는 지 알기 전에 C언어로 작성된 코드가 어떻게 실행되는지 알아보자. Java보다 20년 정도 먼저 개발된 C 언어의 개념들이 Java 개발에 영향을 안 주었을 리 없다고 생각하기 때문이다.

디스크에 저장된 C언어로 작성된 파일을 실행 가능한 프로그램으로 만드는 과정은 크게 네 단계로 구성된다.

번역 계층

High-level 언어(C)로 작성된 파일이 assembly language로 번역되고 assembly 파일이 machine language로 이루어진 object 모듈로 조립된다(assembled). 마지막으로 linker가 여러 object 모듈들을 library routine과 조합(combine)하여 모든 참조들을 환원(resolve)한다.

일반적으로 object 파일은 바로 실행할 수 없다.

Compiler

컴파일러는 C언어로 작성된 파일을 assembly language 프로그램으로 번역한다. Assembly 프로그램은 기계가 이해할 수 있는 추상적인 기호로 작성된 형태(symbolic form)이다. Assembly의 symbol들은 나중에 cpu가 인식할 수 있는 형태로 대체된다.

Assembler

Assembler는 assembly 코드의 pseudoinstruction을 cpu가 이해할 수 있는 instruction으로 번역한다. pseudoinstruction은 machine language(instruction)를 추상화 한 것이다. Assembler의 주된 작업은 assembly를 machine 코드로 바꾸는 것이다. Assembler는 assembly code program을 object file로 변환한다. Object 파일은 machine language instruction, data(변수의 값)과 instruction을 메모리에 로드하기 위한 정보의 조합이다. assembly instruction을 binary version(machin code)으로 바꾸려면 assembler는 모든 label(symbol)에 대한 주소값을 결정해야 한다. Assembler는 분기(branch)와 data transfer instruction(mov 등)에 사용된 모든 label에 대해 추적한다. Symbol table에는 symbol과 그에 대응되는 주소값이 저장되어 있다.

linker

이번 단계는 assemble된 routine들(예를 들면 라이브러리 루틴)을 서로 연결하는 것이다. Library routine이란 일반적으로 라이브러리 내에 정의된 함수를 의미한다.

하나의 프로그램을 여러 파일로 나누어 작성한 뒤 개별적으로 컴파일하고 assembler로 object 파일을 만든 뒤 하나의 실행파일로 합치는 이유는 반복을 피하기 위함이다. 예를 들어 내가 정의한 foo()라는 함수를 수정하여 실행파일을 빌드하려는데, 하나의 파일에 모든 코드가 존재한다면 다시 컴파일할 필요가 없는 코드들까지 모두 빌드 과정을 거치게 된다. Standard library는 거의 변할 일이 없는데 항상 다시 빌드되어야 하는 것이다. 이는 컴퓨팅 자원의 심각한 낭비이다.

Linker는 독립적으로 생성된 object file들을 연결하여 하나의 실행 파일을 만든다.
Linking이 진행되는 방식은 두 가지이다.

Static Linking

Linker가 object file들을 연결하는 단계에서 library routine들이 실행 프로그램에 포함된다. 이는 실행 파일의 용량을 증가시키고 실행 시에는 메인 메모리를 낭비하게 된다. 예를 들어 의 `printf` 함수만 사용했더라도 의 모든 routine이 실행 파일에 연결되고 를 사용한 프로그램을 여러 개 실행시킨다면 똑같은 명령어()가 메모리에 계속 로드된다.

Dynamic Linking

Static Linking의 단점을 보완하기 위해 실행 중에 library routine이 메모리에 로드되고 여러 프로세스가 공유한다.

class file symbol table

Class 파일은 javac에 의해 생성되며 세 가지 모드로 실행될 수 있다.

  • standalone mode - main 메서드를 실행한다.
  • 다른 클래스들과 JAR, EAR, WAR 파일로 묶일 수 있다. (C의 .o 파일과 비슷하다.)
  • jlink와 같은 툴을 사용하여 module로 묶일(bundled) 수 있다. (.so 파일과 비슷하다.)

.so 파일과 .o 파일의 차이

Object 파일(.o)은 컴파일러가 생성한 파일이며 전체 프로그램에서의 중간 결과물이다. Linker에 의해 완성된 하나의 실행 파일이 된다.

Shared object 파일(.so)여러 프로그램이 공유해서 사용할 수 있는 동적 라이브러리 파일이다. Windows의 .dll 파일과 유사하다. 프로그램이 실행될 때 필요에 따라 동적으로 메모리에 로드된다. 여러 프로그램에 링크되어있어도 메모리에는 한 번만 로드되어 여러 프로그램들이 같은 메모리 주소를 참조하여 해당 라이브러리의 기능을 사용한다. 코드의 재사용성을 높이고 메모리 사용을 최적화한다.

references

Comments