본문 바로가기

EXE 파일의 생성

1. 컴퓨터는 네이티브 코드만 실행할 수 있다

 

<Example.c>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <Windows.h>
 
int add(int a, int b);
 
int main()
{
    int a = 5, b = 9;
    char buffer[20];
    char title[] = "Add";
 
    sprintf_s(buffer, sizeof buffer, "%d + %d = %d", a, b, add(a, b));
    
    MessageBox(NULL, buffer, title, MB_OK);
 
    return 0;
}
 
int add(int a, int b)
{
    return (a + b);
}
cs

 

 

위와 같이 특정 프로그래밍 언어로 작성된 프로그램을 소스 코드(source code)라 하고, 소스 코드를 파일로 보존한 것을 소스 파일(source file)이라 한다. 이 때 소스 파일의 확장자명은 언어마다 다르다(C: .c / Java: .java / Python: .py / PHP: .php). 소스 파일은 단순한 텍스트 파일이므로 Visual Studio나 Dev C++ 등의 개발 환경이 없어도 메모장이나 notepad++등의 텍스트 편집기로도 작성할 수 있다. 

 

다만 Example.c를 그대로 실행할 수는 없다. 소스 코드는 컴파일 과정을 거쳐 네이티브 코드(native code)로 변환되어야 비로소 CPU가 실행할 수 있기 때문이다. native의 사전적 의미를 빌리자면, CPU의 모국어인 native code로 변환되어야 CPU가 이해할 수 있다고 생각할 수 있다. 서로 다른 프로그래밍 언어로 작성된 소스 코드라도 네이티브 코드로 변환되면 같은 언어(기계어)의 형태를 갖게 된다.

 

 

 

 

2. 네이티브 코드

 

다음은 Example.c를 네이티브 코드로 번역한 파일(Example.exe)을 메모장으로 읽은 것이다.

 

 

 

네이티브 코드는 CPU의 언어기 때문에 사람은 이해할 수 없다. 따라서 사람이 이해할 수 있는 C언어 등의 고급 언어로 소스 코드를 작성한 후 CPU가 이해할 수 있는 네이티브 코드로 번역하는 방법을 사용하게 된 것이다.

 

 

다음은 같은 파일을 HxD를 이용해 ⒜덤프한 것이다.

 

여러가지 숫자가 반복됨을 알 수 있는데, 이 숫자들은 어떤 명령, 또는 데이터를 나타낸다. 컴퓨터는 모든 정보를 0과 1, 그러니까 비트의 집합으로 나타내기 때문에 모든 데이터를 숫자로 취급할 수 있다. 예를 들어 문자 A는 숫자 65로 나타내어진다. 결국 명령어도 숫자가 나열된 것이고, 이것이 바로 네이티브 코드인 것이다.

 

 

 

 

3. 컴파일러

 

고급 언어로 작성된 소스 코드를 네이티브로 번역하는 프로그램을 컴파일러(compiler)라고 한다. 컴파일러는 소스 코드를 작성한 언어에 따라 다른 것이 필요하다. 예를 들어 C언어의 컴파일러는 C 컴파일러라 한다. C나 C++로 소스 코드를 작성할 때 사용하는 Visual Studio나 Java로 소스 코드를 작성할 때 사용하는 Eclipse 등의 툴에는 각각의 전용 컴파일러가 포함되어 있다.

 

컴파일러가 소스 코드의 내용을 네이티브 코드로 번역하는 작업은 일종의 대응표에 따라 이루어진다고 생각하면 된다. 소스 코드와 네이티브 코드가 어떻게 대응되는지 나타내는 표가 있고, 이 표에 따라 번역이 이루어지는 것이다. 물론 이 표만으로 번역하는 것은 사실상 불가능하고, 실제로는 문자 해석, 구문 해석, 의미 해석 등의 다양한 해석 과정을 거쳐 이루어진다. 

 

CPU에 따라 기계어가 다르므로, CPU가 다르면 네이티브 코드도 달라진다. 때문에 프로그래밍 언어 뿐만 아니라 CPU에 따라서도 컴파일러가 달라져야 한다. 예를 들어 x86 계열 전용 C 컴파일러와 PowerPC CPU 전용 C 컴파일러는 다르다. 같은 소스 코드를 다른 CPU 전용 네이티브 코드로 번역할 수 있다. 

 

컴파일러 자체도 하나의 프로그램이기 때문에 특정한 작동 환경(OS, CPU)을 요구하기도 한다. Windows용 C 컴파일러와 Linux용 컴파일러가 그 예다. 또한 현재 사용되는 CPU와 다른 종류의 CPU 전용 네이티브 코드를 생성하는 크로스 컴파일러(cross compiler)도 있다. 예를 들어 ⒝Pentium과 Windows 환경에서 MIPS를 탑재한 Windows CE용 프로그램을 작성하는 경우 크로스 컴파일러를 사용하게 된다.

 

정리하면, 컴파일러를 선택할 때는 다음의 세 가지 사항을 고려해야 한다는 것이다.

 

① 어떤 프로그래밍 언어로 작성된 소스를 컴파일할 것인가?

② 어떤 CPU용 네이티브 코드를 생성할 것인가?

③ 어떤 환경(OS 등)에서 사용할 것인가?

 

 

 

 

4. 실행 파일

 

컴파일러가 소스 코드를 번역해 얻어지는 것이 네이티브 코드지만, 이 상태로 바로 실행할 수는 없다. 링크(link)라는 과정을 거쳐야 비로소 실행할 수 있는 *.exe 파일이 얻어진다.

 

Example.c를 컴파일하면 Example.obj라는 ⒞오브젝트 파일이 생성된다. 오브젝트 파일의 내용은 네이티브 코드로 있고, 역시 실행할 수 없다. 아직 프로그램이 미완성 상태기 때문이다.

 

Example.c의 내용을 잘 보자.  main  함수와  add  함수는 직접 정의했지만  sprintf_s  함수와  MessageBox  함수는 처리 코드가 정의되어 있지 않다. 따라서 이 함수들의 처리 코드가 포함되어 컴파일된 오브젝트 파일을 Example.obj와 결합해야 제대로된 실행파일이 생성되는 것이다.

 

이처럼 여러 개의 오브젝트 파일을 결합해 하나의 실행 파일을 생성하는 과정을 링크라고 한다. 링크 작업을 수행하는 프로그램을 링커 또는 링크 에디터(link editor), 결합 프로그램이라고 한다.

 

 

 

 

5. 라이브러리

 

링크할 때 sprintf 함수나 MessageBox 함수 등의 함수는 소스 코드가 아니라, 컴파일러와 함께 라이브러리 파일로 제공된다. 라이브러리 파일은 여러 개의 오브젝트 파일을 묶은 파일로, 이런 방식으로 제공되는 함수를 표준 함수(standard function)라고 한다. 예를 들어 MessageBoxA 함수의 경우 user32.dll이라는 동적 연결 라이브러리(DLL) 파일에 저장된다.

 

함수를 오브젝트 파일이나 이를 통합한 라이브러리 파일의 형태로 제공하면 두 가지의 장점이 있다. 먼저, 기본적인 기능을 갖는 함수를 매번 컴파일할 필요가 없어진다는 장점이 있다. 그리고 표준 함수의 소스 코드가 노출되지 않는다는 장점도 있다. 표준 함수의 소스 코드는 컴파일러 판매 업체의 귀중한 자산이기 때문이다.

 

 

 

 

6. 컴파일과 링크

 

윈도우는 애플리케이션에서 이용할 수 있는 여러가지 기능을 함수의 집합으로 제공하고 있는데, 이를 API(Application Programming Interface)라 한다. 예를 들어 Example.c에서 호출한 함수인 

 MessageBox) 는 메시지 상자를 표시하는 기능을 제공하는 함수로, C언어가 기본적으로 갖추고 있는 함수가 아니라 윈도우에서 제공하는 API의 일종이다.

 

윈도우에서 API의 오브젝트 파일은 일반적인 라이브러리 파일이 아닌 동적 연결 라이브러리(DLL, Dynamic Link Library)라는 특수한 라이브러리 파일에 기록된다. 이 파일은 동적이라는 이름대로 프로그램이 실행될 때 EXE 파일에 결합되며, 확장자명은 .dll이다. 

 

이에 비해 정적 연결 라이브러리(static link library - .lib)는 컴파일 할 때 EXE 파일에 결합된다. 확장자명은 .lib다.

 

정리하면 Example.c와 같은 소스 코드가 컴파일될 때는 Exmaple.obj에 다른 정적 연결 라이브러리 파일(.lib)이 결합되고, 이렇게 만들어진 EXE 파일을 실행할 때 동적 연결 라이브러리가 결합되는 것이다.

 

 

 

 

 

 

 

 

 

 

 

⒜덤프(dump): 1바이트씩 두 자리의 16진수 단위로 나타내는 작업. 또는 나타낸 것.

   Hex dump라고도 하며, 덤프뜬다 또는 덤프한다고 표현한다.

⒝Pentium: Intel 사의 PC용 CPU 중 하나.

⒞오브젝트 파일(object file, 목적 파일): 컴파일로 인해 생성되는 파일.

                 참고로 ⒟OOP에서 말하는 객체(object)와는 무관하다.

⒟OOP(Object-Oriented Programming): 객체 지향 프로그래밍.

'Programming > Basis' 카테고리의 다른 글

OS의 의의  (0) 2019.06.02
EXE 파일의 실행  (0) 2019.05.13
부트 스트랩  (0) 2019.04.08
프로그램의 이식  (0) 2019.04.08
Ports  (0) 2019.04.04