본문 바로가기

운영체제 정리/64비트 OS 만들기 실습

[64비트 멀티코어 OS 원리와 구조] 7장 - C언어로 코드를 작성하자

이번 장에서 해야 할 일

1. C소스 파일 추가

2. 1을 빌드하여 보호 모드 커널 이미지에 통합

 

실제로 하는 일은 C언어로 작성한 커널을 보호 모드 엔트리 포인트의 뒷부분에 연결하고 엔트리 포인트에서는 C 커널의 시작부분으로 이동하는 것이 전부

 

 

7.1 실행 가능한 C 코드 커널 생성 방법

- C코드는 컴파일과 링크 과정을 거쳐서 최종 결과물이 생성된다.

- 컴파일 과정은 소스 파일을 중간 단계인 오브젝트 파일로 변환하는 과정으로 소스 파일을 해석하여 코드 영역과 데이터 영역으로 나누고, 이러한 메모리 영역에 대한 정보를 생성하는 단계다.

 

- 링크 단계는 오브젝트 파일들의 정보를 취합하여 실행 파일에 통합하며, 필요한 라이브러리 등을 연결해주는 역할을 하는 단계.

 

엔트리 포인트가 C 코드를 실행하기 위한 최소 세 가지 제약 조건

1. C 라이브러리를 사용하지 않게 빌드해야 한다.

2. 0x10200 위치에서 실행하게끔 빌드해야 한다.

3. 순수한 바이너리 파일 형태여야 한다.

 

소스 파일 컴파일 - 명령어를 이용해서 간단하게 진행 가능 (책 p198 참조)

오브젝트 파일 링크

- 소스 파일 컴파일보다 까다로움. 왜냐면 실행 파일을 구성하는 섹션 배치, 로딩될 어드레스, 코드 내에서 가장 먼저 실행될 코드인 엔트리 포인트를 지정해줘야 하기 때문.

- 섹션 배치를 다시 하는 이유는 실행 파일이 링크될 떄 코드나 데이터 이외에 디버깅 관련 정보와 심볼 정보 등이 포함되기 떄문. 최종 바이너리 파일을 생성할 떄 이를 제거하려고 섹션을 재배치 하는것임.

 

섹션 배치와 링커 스크립트, 라이브러리를 사용하지 않는 링크

섹션 - 실행 파일 또는 오브젝트 파일에 있으며 공통된 속성을 담는 영역. 핵심 역할을 하는 세션은 3가지.

1. 실행 가능한 코드가 들어 있는 .text 섹션. 실제 코드가 저장되는 영역. 일반적으로 읽기 전용

2. 초기화 된 데이터가 들어 있는 .data 섹션. 일반적으로 읽기/쓰기 속성

3. 초기화되지 않은 데이터가 들어 있는 .bss 섹션. 초기화되지 않은 변수만 포함한다는 것이 차이점. (데이터와 거의 같음) 정상적으로 프로그램을 실행하려면 메모리에 로딩할 때, .bss 영역을 모두 0으로 초기화해야 한다.

 

합쳐지는 순서에 따라서 섹션의 어드레스는 얼마든지 바뀔 수 있음!

 

링커 - 오브젝트 파일들을 결합하여 정리하고 실제 메모리에 로딩될 위치를 결정하는 것

주된 역할은 오브젝트 파일 모아 섹션을 통합하고 그에 따라 어드레스를 조정하며, 외부 라이브러리에 있는 함수를 연결해주는 것.

링커가 실행 파일을 만들려면 파일 구성에 대한 정보가 필요한데, 이떄 사용하는 것이 링커 스크립트.

 

- 링커 스크립트에 대한 자세한 내용: https://sourceware.org/binutils/docs/ld/

 

Top (LD)

This document is distributed under the terms of the GNU Free Documentation License version 1.3. A copy of the license is included in the section entitled “GNU Free Documentation License”.

sourceware.org

 

섹션의 재배치는 코드 및 데이터에 관련된 섹션(.text, .data, .bss, .rodata)을 가장 앞으로 이동함으로써 처리할 수 있다.

 

스크립트 파일이 복잡한데, 저자가 친절하게 올려주셔서 그걸 참고하면 된다.

 

로딩할 메모리 어드레스와 엔트리 포인트 지정

만약 이미지를 로딩할 어드레스에 맞춰서 생성하지 않는다면 전역 변수와 같이 선형 어드레스를 직접 참고하는 코드는 모두 잘못된 어드레스에 접근하기 때문.

 

여기서는 0x10000 어드레스에 존재하는 보호 모드 엔트리 포인트가 0x10200 어드레스로 이동하므로, C 코드의 엔트리 포인트를 해당 어드레스에 강제로 위치시킬 필요가 있음.

 

특정 함수를 실행 파일의 가장 앞쪽에 두는 방법 2가지

1. 오브젝트 파일 내의 함수 간의 순서. C 소스 파일을 수정해서 엔트리 포인트 함수를 가장 상위로 옮겨준다.

2. 실행 파일 내의 함수 간의 순서. 엔트리 포인트가 포함된 오브젝트 파일을 가장 앞쪽으로 옮겨줌으로써 C 코드의 엔트리 포인트를 0x10200에 위치시킬 수 있다.

 

실행 파일을 바이너리 파일로 변환

objcopy 프로그램을 사용해서 꼭 필요한 코드 섹션과 데이터 섹션만 추출하자.

 

 

7.2 C 소스 파일 추가와 보호 모드 엔트리 포인트 통합

1. C 소스 파일 추가

여러 소스 파일에서 공통으로 사용할 헤더 파일부터 생성한다. (책 참고 p212)

C 코드 엔트리 포인트 파일을 생성한다.

 

2. 보호 모드 엔트리 포인트 코드 수정

jmp 명령어로 0x10200으로 이동한다.

3. makefile 수정

.c 확장자의 파일만 추가하면 자동으로 포함하여 빌드하게 수정한다. (파일 검색하는 와일드카드 이용)

파일 패턴에 대해 동일한 룰을 적용해서 컴파일 하자.

검색된 C 파일을 이용해서 링크할 파일 목록을 생성하자.

  - 일반적으로 오브젝트 파일은 소스 파일과 같은 이름이며, 확장자만 .o로 변경되므로 소스 파일 목록에 포함된 파일의 확장자를 .c에서 .o로만 수정하면 된다.

엔트리 포인트 오브젝트 파일을 COBJECTFILES에서 맨 앞에 두어야 한다.

헤더 파일을 수정해도 소스 파일을 다시 빌드해야 한다. 포함하는 헤더 파일을 모두 makefile Dependency에 기록하자.

  - gcc 옵션중에 -MM을 사용하면 stdio.h와 같은 시스템 헤더 파일을 제외한 나머지 헤더 파일에 대한 의존 관계를 출력한다.

  - 생성한 dep 파일을 include 지시어로 포함해야 한다. (단, include 명령어는 해당 파일이 없으면 에러를 발생시키기 때문에 파일 존재 여부에 따라서 실행해야 함)

7.3 커널 빌드와 실행

부트로더에 커널의 총 섹터 수를 업데이트 하는 이미지 메이커 프로그램 작성

  - 부트로더 이미지 파일에 있는 TOTALSECTORCOUNT의 오프셋 확인

  - makefile을 작성하여 make를 실행하자.

 

Imagemaker 프로그램을 사용하도록 루트의 makefile을 수정한다.