[yummyHitOS] 5 day (2017.07.06)

4 분 소요

이제 7장으로 넘어왔어요.. C언어로 커널을 만들 수 있대요!! 넘나 기쁜것~ㅜㅠ

은 꿈.. 링커 스크립트가 뭐죠? 먹는건가요? 우걱우걱

(우분투 환경에서는 /usr/lib/ldscripts/elf_i386.x 경로이며 윈7 환경에서는 C:\cygwin\usr\cross\x86_64-pc-linux\lib\ldscripts\elf_i386.x경로에 링커 스크립트가 위치해있습니다!! 이 파일을 복사하여 01.Kernel32 디렉터리에 붙여넣으시면 링커 스크립트 수정 준비 끗!!!)


혹시 아직 제 블로그 좌측 Author 부분의 github 링크를 못찾으신 분께서는..(여기에 소스파일 전부 다 있거든용 ㅎㅎ 책과 상이한 부분이 많다보니 열심히 삽질한 결과를 저의 github에서 훔쳐가도록 하세요!!) yummyHit's Github 를 참고해주세요!


이곳에 방문하셔서 소스파일을 전~부 뜯고 씹고 맛보고 즐기실 수 있습니다!

Linker Script

왜 무엇이 어떻게 바뀌었는가.. 하면 우선 elf_i386.x 링커 스크립트에서


. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .);


이렇게 작성되어 있는 곳이 있는데, 이 부분이 있으면 make할 때 에러가 나더라구요!! 이러한 이유들 때문~에~ 소스파일을 올려드리게 되었습니다(절대 저의 소스를 자랑하기위함이 아니예여!!)

(참, 그리고 위에 . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .); 부분은 주석처리 해주어야 해요!!

/* . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .); */ 이렇게 해주시면 됩니다~!!)


Type.h

7.2장으로 넘어가면 드디어 C언어가.... Type.h 라는 헤더파일이... 하아 감격T^T

이 헤더파일의 중요한 점은 이제부터 쓸 중요한 함수들의 모든 자료형 타입을 거의 여기에 정의해둡니다. 특히 Java 이후의 언어에는 있을 BOOL타입과 BYTE타입을 정의합니다!! Visual Studio나 GCC 어느 라이브러리에도 없는 타입을 이렇~게 선언해줍니다.



그냥 unsigned char로 사용하면 되지 않냐구요? 뭐... 되긴 하겠지만... 편리함이 아닐까요?! BOOLEAN 이라는 단어와 BYTE 라는 단어를 보면 "아! 이거 TRUE와 FALSE로 나누는 자료형이구나!" 같은 생각이 들텐데 같은 unsigned char를 쓰면 헷갈리니까요 ㅎㅎ

편리함을 위해 만들었으니 편리하게 쓰면 그만입니다! 그리고 그 아래 패킹하는 것이 보이는데.. 수학 잘하시나요? 저도 참 좋아했는데요.. 자 그럼 한 번 만나러 가보시죠!



위와 같은 두 개의 구조체가 있다고 가정해봅시다. 두 구조체 멤버는 똑같은데.. 도대체 뭐가 다르다는 건가요!?

메모리 저장 방식이 문제가 됩니다. 현재 우리의 개성파 OS는 32bit 보호모드이기 때문에 32bit를 기준으로 설명드리겠습니다.

32bit 운영체제는 메모리를 4byte씩 끊어 읽는다는 사실을 알고 계신가요!? 이 두 개의 구조체가 메모리에 할당되는 방식은 바로!!



참.. 제가 이제서야 커밍아웃을 하는건데 저 보라색 쬲이에여 나으 맥뿍도 보라보라하구 침대도 보라보라 가방도 보라보라.. 보라색이 마음에 평안을 주는 색이라고 하더라구여 야미님의 말에 의하면 ㅎㅎㅎ헿헤헿

위 그림을 보시면 이해가 되시나요? 구조체 A는 먼저 4byte를 할당한 후, 차례대로 a1, a2, a3 순서로 넣다보니 char와 short 사이에 1byte의 빈 공간이 생깁니다!

이어서 구조체 B는 4byte를 할당한 후, a1을 넣고보니 a3가 4byte짜리 변수네? 그럼 3byte는 비워야징~ ㅎㅎㅎ우왕 마니 비었다 난 사람 별로 없는게좋더라~ 처럼 기분 좋게 다 empty가 됩니다. 기분이 좋긴요.. 낭비죠 낭비 지갑에서 돈이 비어있는 느낌이랄까요?

구조체 B보다는 구조체 A가 더 효율적이지만, 양쪽 전부 empty가 생겨버리니.. 이를 방지하기 위해 있는 것이 패킹입니다!

실질적으로 구조체 A나 B 둘 다 7byte만큼의 크기이니, 32bit를 기준으로 메모리를 저장하는 것이 아닌, 우리가 직접 메모리 저장 방식을 정해주는 것입니다!


indicator

pack 지시자는 구조체의 바이트 정렬 값을 지정해주기 위해 사용한다

pack과 함께 사용되는 키워드로 push와 pop이 있다

push는 현재 값을 저장하면서 정렬 값을 바꾸고 싶을 때 사용한다

pop은 push에 의해 저장된 값을 다시 불러오고 싶을 때 사용한다


즉, #pragma pakc(push, 1) ... #pragma pack(pop) 을 한다면 1바이트를 기준으로 메모리에 push를 할 것이고, pop을 기준으로 다시 운영체제에 맞게 저장하겠다!! 라는 것이 됩니다! 우리의 OS에서 정의된 것과 함께 볼까요?



오호.. 요로코롬 패킹을 해주는군요... 패킹을 안해주면 2byte만큼의 empty가 발생할 뻔 했습니다 ㅎㅎ

참 이 구조체로 말씀드리자면 이제부터 OS Image 로딩부터 각 기법 및 인터럽트 등을 qemu를 통해 출력시키기 위한 구조체예요!! 넘나 중요한 것!! character 멤버에 글자를, color 멤버에 색을 지정할 수 있답니다!!

이제 우리는 EntryPoint.s 파일을 수정해 0x10200 위치에서부터 커널을 수행할 거예요! 우리가 작성한 Main.c 등의 C언어 소스파일을 수행할 수 있도록 하기 위해서죠! 이얏호우 내사랑 C언어가 드디어 실행된다니 둑흔둑흔..


책을 천천~히 따라가며 C언어를 음미하다가... 음마 이게 뭐야... 7.3장에서 깜!짝 놀랐네요..

현재 우리는 GCC 컴파일러를 빌려 컴파일을 하고있지만, 실질적으로 윈도우 7 자체에는 C언어의 어느 라이브러리도 존재하지 않아요!

그런데 갑자기 등장한 디스크 이미지를 만드는 ImageMaker.c 소스파일..


#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
/*리눅스는 io.h 대신 sys/uio.h 입니다!! */
#include <unistd.h>
/* Unix 기반만 추가하라고 되어있던데.. 전 이게 없으면 open(), close(), write() 함수 오류가 나더라구요!! */
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>


위 전처리기가 원하는 헤더파일들은 아직 우리가 받아들일 수 없습니다!!(참고로 리눅스에서는 GCC 컴파일러 기반으로 돌아가기 때문에 별로 걱정안하시고 그냥 진행해주셔도 됩니다!)

우리의 이클립스에게 라이브러리 경로를 적어줘야할 것 같아요ㅜㅠ 이클립스라곤 자바를 독학할 때만 써봤는데... ㅂㄷㅂㄷ


이클립스 내에서 프로젝트 탐색기 -> 현재 프로젝트 명(우리의 개성파 OS 이름 폴더) 마우스 우클릭

-> Properties -> C/C++ General -> Paths and Symbols 탭 -> Includes GNU C에서 Add버튼 클릭

-> File System... 클릭 -> C:\cygwin\usr\include 와 C:\cygwin\usr\cross\lib\gcc\x86_64-pc-linux\version\include 추가 후 Apply


이러한 과정을 거치시면 드디어 저 헤더파일들을 읽을 수가 있습니다.

그리고 최근 GCC 컴파일러 업데이트로 약간 변동된 부분이 있더군요! 모든 것은 저의 소스파일을 참고하시기...(너 이런식으로 나오면 사람들이 악플단다? 조심하자?) 제가 직접 삽질을 해보며 무엇이 무엇이 문제일까~ 하여 찾아보았습니다!


1. open() 함수에 들어갈 파라미터 중 O_BINARY 가 없습니다!! 이 소스파일에서 open() 함수를 총 4개 사용하는데, 4개의 O_BINARY와 앞에 있는 pipe(|), 뒤에 있는 comma(,) 둘 다 지워주시면 됩니다.

즉, 첫번째 open() 함수부터 나열하자면


open("Disk.img", O_RDWR | O_CREAT | O_TRUNC)
open(argv[1], O_RDONLY)
open(argv[2], O_RDONLY)
open(argv[3], O_RDONLY)


이렇게 해주시면 됩니다!!(argv[2]는 32비트 보호모드시, argv[3]은 64비트 IA-32e모드시 변환하는 open()함수이기 때문에 아직 책에 나와있지 않으시다면 있는 것만 이렇게 바꿔주시면 됩니다~)

그보다... O_BINARY가 O_TEXT와 함께 GNU C 에서 사라졌다고 하기는 하는데...

~Path\sys\fcntl.h 에선 ~Path\sys\_default_fcntl.h 에 있다고하고, _default_fcntl.h 파일엔 분명히 O_BINARY와 _FBINARY를 정의하고 있는데 왜 없다고 하는것인지.. 이클립스 나뿐놈들..(외국인이니까 못읽을거야.. 그럴거야..)


2. 저의 오타 문제였지만, 혹시나 해서 주의!! 이클립스 글자 크기가 작다보니 %랑 &가 헷갈려 보이더라구요.. 포맷을 위한 %와 주소를 위한 &가 잘못 쓰이면 완벽히 잘못된 것이기 때문에 참고하시면 좋을 것 같습니다!!


이렇게 ImageMaker.c 파일까지 완성시켰으면 당연히 makefile을 만들텐데, 이 makefile에 한 줄의 명령을 추가하시면 편합니다!



ImageMaker.exe 규칙에 정의된 명령인 "cp $@ ../" 요것을 추가해주시면 좋아영!! 두번조아여 세번조아여!!


이 한 줄을 추가해주시면 프로젝트 빌드 후 qemu를 실행시켰을 때 아무 문제 없이 잘 실행 되실겁니다!!


드디어 C언어를 이용한 커널 빌드를... 저희가 성공시켰습니다 쨖쨖쨖~~ 이제 다음엔 뭔지 모를 A20게이트와 페이징기능을 한 번 다뤄보겠습니다!! 그럼 to be continue..


Check out the yummyhit’s website for more info on who am i. If you have questions, you can ask them on E-mail.

카테고리:

업데이트:

댓글남기기