2장 도구
컴파일러는 헤더 파일이 존재하는지 모른다. C++ 전처리기가 컴파일에 앞서 모든 #include
구문을 헤더 파일의 내용으로 교체해 넣기 때문이다.
번역 단위 1개가(소스 파일 1개) 컴파일된 결과물인 기계어는 목적 파일에 저장된다(윈도우에서 .obj). 목적 파일 안의 기계어는 다음과 같은 특성이 있다.
- 재배치 가능: 코드가 위치할 메모리 주소가 아직 결정되지 않은 상태이다.
- 링크되지 않음: 번역 단위 안에 들어 있지 않은 외부 참조 함수나 전역 데이터가 아직 확정되지 않았다.
링커는 다음과 같은 역할을 한다.
- 모든 기계어 명령어의 최종 상대 주소를 계산한다. 프로그램이 실행될 떄 메모리에 올라갈 모양이 된다.
- 각 번역 단위(목적 파일)에서 확정하지 못했던 외부 함수와 전역 데이터의 값을 확정한다.
동적 링크 라이브러리(DLL, Dynamic Link Library) p102
3장 게임을 위한 소프트웨어 엔지니어링 기초
관리인과 RAII p134
어썰션
선언과 정의의 차이
- 선언: 데이터 객체나 함수의 형태를 나타낸다. 컴파일러에 ‘이름’과 데이터 타입 또는 함수의 서명(리턴 타입과 인자타입, 시그니처)을 알려준다.
- 정의: 프로그램 안에 고유한 저장 공간을 나타낸다. 이 저장 공간 안에는 변수, 구조체 및 클래스의 인스턴스, 함수의 기계어 등이 들어갈 수 있다.
실행 파일 이미지
- 실행 파일 이미지는 세그먼트 또는 섹션이라 불리는 연속적인 구획으로 나뉜다. 운영체제마다 세부적인 방식은 조금씩 다르고 같은 운영체제라고 실행 파일에 따라 서로 미세하게 다를 수 있다. 하지만 실행 파일 이미지는 최소한 다음의 네 가지 세그먼트로 구성된다.
- 텍스트 세그먼트: 코드 세그먼트라고도 불린다. 프로그램에서 정의한 모든 함수의 기계어를 담고 있다.
- 데이터 세그먼트: 모든 초기 값을 가진 전역 및 정적 변수가 자리한다. 이 형태대로 프로그램이 실행될 때 메모리에 배치되고 값들은 지정한 대로 초기화돼 있다. 따라서 실행 파일이 메모리에 로드될 때 전역 변수와 정적 변수는 바로 사용할 수 있다.
- BSS 세그먼트: BSS는 ‘Block Started by Symbol’를 나타내는데, 지금은 거의 사용되지 않은 용어다. 여기에 초기화되지 않은 모든 전역 변수와 정적 변수가 자리한다. 몇 개가 될지 모르는 0의 값들을 무작정 들고 있기보다는 링커는 얼마나 많은 바이트의 0이 있는지만 기록한다. 운영체제는 실행 파일이 메모리에 로드돼 시작점(
main()
함수는 WinMain()
함수)이 불리기 직전에 이 값을 보고 공간을 할당하고 0으로 채운다.
- 읽기 전용 데이터 세그먼트: rodata 세그먼트라고 불리기도 하는데, 여기에는 읽기 전용인 전역 데이터가 자리한다. 부동소수인 상수나 const 키워드로 정의된 전역 인스턴스 등이 여기에 해당한다. 이와 달리 정수 타입인 상수는 매니페스트 상수처럼 취급돼 사용되는 기계어 코드 위치에 직접 삽입되는 경우가 대부분이다. 이런 상수들은 텍스트 세그먼트의 공간을 차지하고 읽기 전용 데이터 세그먼트에는 존재하지 않는다.