임베디드 OS 개발 프로젝트 따라하기 2일차
어제부터 임베디드 OS 개발 프로젝트를 따라하면서 OS개발을 해보고 있다.
벌써 3장인데 이제부터 본격적으로 어려워질 것이다! 제목부터 일단 시작하기
라니 ㅋㅋㅋㅋㅋㅋㅋㅋ
시작하자마자 알 수 없는 코드를 입력하라고 한다.
Entry.S
sohn@DESKTOP-BUET9V4:~/boot$ cat Entry.S
.text
.code 32
.global vector_start
.global vector_end
vector_start:
MOV R0, R1
vector_end:
.space 1024, 0
.end
간단히 설명하자면 위의 .text부터 .end까지를 text섹션
이라고 부른다.
code 32는 32bit가 한 명령어를 구성하는 것을 의미하고 global은
C언어의 extern
과 같다고 한다.
한 마디로 R0 레지스터에 R1 을 붙여넣고 이후 1024바이트를 0으로 채우라는 명령이다. 결과를 살펴보자
-
arm-none-eabi-as -march=armv7-a -mcpu=cortex-a8 -o Entry.o ./Entry.S
-
arm-none-eabi-objcopy -O binary Entry.o Entry.bin
-
hexdump Entry.bin
0000000 0001 e1a0 0000 0000 0000 0000 0000 0000
0000010 0000 0000 0000 0000 0000 0000 0000 0000
*
0000404
요렇게 결과가 나왔다면 성공이다. GCC로 처음 Compile
했을 때처럼 당최 하나도 모르겠는 기분이다.
Compile
명령을 뜯어보자면 우리가 처음 설치한 Compiler
는 gcc-arm-none-eabi였다. 그리고
ARM 코어가 cortex-a8이어서 아키텍처를 armv7-a로 설정 & Cpu를 cortex-a8로 설정한 것이다.(정신 가출직전…)
그 다음 Object 파일에서 바이너리만 뽑아내어 Entry.bin을 만들고 이를 출력한 것이 저 3줄의 내용이다. 후…
참고로 *은 0000404번지 까지 0만 나왔다는 의미이며 0x0000404 = 1028이다.
이제 QEMU로 읽어보자. QEMU는 ELF라는 파일 형식밖에 읽지 못한다고 한다. ELF파일을 만들기 위해선 링커의 도움이 필요하다.
링커? 어디서 들어보지 않았던가? 우리가 처음 언어를 배울 때를 기억해보자.
Source Code -> Compile -> Object File -> Link -> Execute File
위 작업의 Link가 바로 그 Link이다. 이 Link 작업을 하기 위해 링커 스크립트라는 파일이 필요하다.
그런데 잘 생각해보면 링커 스크립트는 작성해본 적이 없는 것 같다. 경험 부족 때문도 있지만 운영체제의 라이브러리에
링커 스크립트가 기본값으로 포함되어 있어서라고 한다. (그런데 펌웨어를 개발할 거면 이것도 만질 줄 알아야 한다는 거…)
그런 의미에서 같이 작성해보자
navilos.ld
sohn@DESKTOP-BUET9V4:~$ cat navilos.ld
ENTRY(vector_start)
SECTIONS
{
. = 0X0;
.text :
{
*(vector_start)
*(.text .rodata)
}
.data :
{
*(.data)
}
.bss :
{
*(.bss)
}
}
으… 조금만 더 버텨보자! 대충 보면 SECTIONS
이라는 블록이 핵심 역할인 것 같다.
0x0번지에 위치하고 text 섹션의 배치 순서를 지정한다. 우리는 vector_start가 0번지에 있었으면 좋겠으니
vector_start를 적고 이후에 text, data, bss 섹션을 적어서 연속된 메모리에 배치하였다. 이제 이걸 실행파일로 바꿔보자
-
arm-none-eabi-ld -n -T ./navilos.ld -nostdlib -o navilos.axf boot/Entry.o
-
arm-none-eabi-objdump -D navilos.axf
navilos.axf: file format elf32-littlearm
Disassembly of section .text:
00000000 <vector_start>:
0: e1a00001 mov r0, r1
00000004 <vector_end>:
...
Disassembly of section .ARM.attributes:
00000000 <.ARM.attributes>:
0: 00002441 andeq r2, r0, r1, asr #8
4: 61656100 cmnvs r5, r0, lsl #2
8: 01006962 tsteq r0, r2, ror #18
c: 0000001a andeq r0, r0, sl, lsl r0
10: 726f4305 rsbvc r4, pc, #335544320 ; 0x14000000
14: 2d786574 cfldr64cs mvdx6, [r8, #-464]! ; 0xfffffe30
18: 06003841 streq r3, [r0], -r1, asr #16
1c: 0841070a stmdaeq r1, {r1, r3, r8, r9, sl}^
20: 44020901 strmi r0, [r2], #-2305 ; 0xfffff6ff
24: Address 0x0000000000000024 is out of bounds.
뭔가 나왔다!!!!!!! 일단 방금 작성한 명령어가 무슨 의미인지부터 알아보자. 첫 번째 명령어의 -n 옵션은 링커에 섹션의 정렬을
자동으로 맞추지 말라는 의미라고 한다. 두 번째 명령의 -T 옵션은 링커 스크립트의 파일명을 알려주는 옵션이다.
무슨 소리인지는 하나도 모르겠지만 지금 가장 중요한 것은 이것이다.
00000000 <vector_start>:
0: e1a00001 mov r0, r1
제일 처음에 vector_start가 들어가게 되었다. 이제 다 했다.
마지막으로 실행해보자. 과정이 아무리 힘들었어도 결과물이 잘 나오면 기분이 좋은 것이
이쪽 분야의 매력인 것 같다..
Finally!!!
sohn@DESKTOP-BUET9V4:~$ ./navilos.axf
-bash: ./navilos.axf: cannot execute binary file: Exec format error
What? Are you kiddin…읍읍
잠시 흥분했다. 책의 저자는 에러가 뜨는 것을 알고 있었다. 그리고 두 가지 해결방법을 제시하기까지(당신은 대체…)
-
“ARM 개발 보드에 다운로드해서 동작을 확인해 보세요 >_O”
-
“QEMU로 실행해 보세요 O_<”
물론 저런 이모티콘은 없었지만 왠지 놀리는 기분이 들었다…
보드가 없으니 우리는 2번 방법을 택해보자
- qemu-system-arm -M realview-pb-a8 -kernel navilos.axf -S -gdb tcp::1234,ipv4
여기서 -M 옵션은 머신을 지정하는 것이고 -kernel 옵션으로 ELF파일 이름을 지정한다. -S 옵션과 -gdb는 디버깅을 위한 옵션이라고 한다.
그런데…
왜
왜
왜!!!!!!
또 에러냐구여!!!!!
- “아, 이런. gdb를 따로 설치해야 하는군요.”
네^^ 당신도 사람인데 실수할 수도 있져. 그럼요.. 그렇구말고요…
- sudo apt install gdb-arm-none-eabi
그런데 여기서 또 문제가 발생하네요. 제가 사용하는게 Ubuntu 18.04버전인데
18.04에서는 gdb-arm-none-eabi 자동설치가 안 되나봐요. 그래서 구글링을 해보았습니다.
- sudo apt-get update -y
- sudo apt-get install -y gdb-multiarch
- gdb-multiarch
요거를 하면 gdb-arm-none-eabi를 설치하지 않아도 gdb를 사용할 수 있어요
역시 쉽지만은 않은 운영체제… 계속 화이팅해봐요!!