• Wonhyuk Yang

[Practice] WAIOS 제작 (1)

최종 수정일: 2021년 12월 1일

이론을 공부하고 커널 코드를 분석하여 완전히 이해하면 너무나 좋겠지만, 완전히 이해하기 힘든 부분이 존재하는 것 같아요. 저는 커널 코드를 분석하는 입장과, 커널 코드를 개발하는 입장의 차이는 생각보다 꽤 크다고 봐요. 그렇기 때문에 직접 OS를 개발하거나 커널 코드를 작성하는 것은 코드 분석에 많이 도움이 된다고 생각해요. 그래서 이번 시리즈에서는 WhoamI OS를 만들면서 Training에서 공부했던 내용을 복습하고, 부족한 부분들을 발견하고, 놓친 부분들을 있는지 체크하려고 해요.


Series


  1. Linux kernel head.S 찍어먹기(1)

  2. Linux kernel head.S 찍어먹기(2)

  3. Linux kernel head.S 찍어먹기(3)

  4. Linux kernel head.S, main.c 분석하기 (1) (GDB + QEMU + BUILDROOT)

해당 Practice 시리즈는 Training에서 배운 내용을 직접 실습하는 내용을 담고 있습니다. 필요한 이론을 Training을 통해 학습하신 후, 해당 Practice를 진행하길 권장해요.
해당 포스트는 Arm v8 architecture을 Target으로 합니다.

1. Plan

빌드된 커널 이미지를 QEMU를 통해 실행하고 디버깅을 진행한 적이 있었는데 기억나시나요? QEMU는 -kernel 옵션으로 커널 이미지들을 인자로 받아요. 이때 인자로 받은 이미지가 elf 형식이 아닌 binary 포맷이라면 리눅스 커널 이미지라 가정해요. 조금 더 자세히 이야기하면, 커널 이미지 헤더만 제대로 작성하면 custom binary 파일도 qemu를 통해 실행시킬 수 있다는 것이지요. 그럼 정말로 그런지 아래에서 확인해 볼게요. 이제 우리의 WAIOS의 head.S를 작성해야 하는데요, 너무 막연하다고 생각하실 수 있으니 몇 가지 가이드 라인을 제공해드릴게요.

  1. Kernel Image header를 작성한다. (어셈블리가 약하시면, Linux kernel의 표현 방식을 참고하세요)

  2. Kernel Image header가 이미지 제일 앞에 올 수 있도록 배치한다.(Linker script를 사용하세요)

  3. Binary format으로 Image 파일을 만드세요. (elf 헤더들을 모두 제거하세요

이제 해당 가이드라인을 베이스로 직접 커널 이미지를 제작해보세요. 다 작성하셨다면 참고하는 차원에서 제가 작성한 코드를 살펴보도록 해요.

 

2. 구현

제가 작성한 head.S는 아래와 같아요. Linux 커널과 유사하도록 naming을 그대로 따왔어요.

Linux처럼 이미지 헤더의 정보는 링크 과정에서 전해주도록 외부 심볼들을 사용했어요. 또한 다른 코드들과 구분하기 위해 독자적인 Section에 배치했어요. text에서는 스택을 설정하고, loop를 계속 돌게 되는 단순한 코드에요. 이제 제가 작성한 linker script를 살펴볼까요?


head.S와 마찬가지로, 링커 스크립터도 Linux에서 사용하는 방식을 그대로 유지했어요. 매크로를 통해 가상 주소의 시작점과 text_offset, 이미지 헤더의 플래그를 정했어요. 그리고 stack으로 사용할 영역을 커널 이미지에 잡아주고, head.S에서 사용하는 심볼들에 값을 넣어줬어요. 위의 파일은 전처리가 필요하기 때문에 추가적인 명령을 실행해야 해요. 이와 같이 커널 이미지를 빌드하기 위해서 여러가지 명령들을 하나의 쉘 스크립트에 담아서 build.sh이란 파일을 만들었어요.


  • Line 1의 커맨드를 통해, vmlinux.lds.S 파일은 온전한 링커 스크립트인 vmlinux.lds가 생성돼요.

  • Line 2~3을 통해 오브젝트 파일을 생성, 재배치를 하여 vmlinux라는 elf 형식의 바이너리 파일을 생성해요.

  • Line 4를 통해 elf 형식의 vmlinux를 binary 형식으로 변환해서 Image라는 파일을 생성해요.

소스 코드를 준비하고 build.sh을 실행하면 Image가 나타나겠지요? 이렇게 만든 이미지를 이제 qemu를 통해 부팅을 하고 그 과정을 디버깅해볼게요.

우선, TEXT_OFFSET대로 우리의 커널 이미지가 로딩된 것을 확인할 수 있어요. 커널 이미지 부분을 읽었을 때 만든 대로 나오는 것을 확인할 수 있지요? 그리고 text로 jump를 하면 스택 포인터를 조정하고, 무한 루프를 도는 부분도 확인할 수 있어요.


정리


이렇게 생각보다 쉽게 OS의 기반을 만들었어요. 이것을 바탕으로 이것 저것 해볼 건데요, 다음 포스트에서는 Hello world!를 출력하도록 코드를 작성해 볼게요! 드라이브를 한 번도 짜본 적이 없으신 분이라면 해당 포스트에서 어떤 insight를 얻을 수 있을 것 같네요. 만약 코드를 작성하는데 어려움을 겪었다면 어느 부분에서 부족한지 확인하시고, 그 부족한 부분을 채우시면 실력이 빠르게 늘 거라 생각해요. 제가 작성한 코드를 보고싶다면 아래의 링크를 참고하시면 됩니다


참고 링크: https://github.com/YWHyuk/WAIOS/tree/base_template


조회수 91회댓글 0개

관련 게시물

전체 보기