GAS (GNU Assembler) Linker Script와 Long Mode -> Real Mode 로 전환할때의 문제....
안녕하세요, 취미로 OS 공부해보고 있는 직딩입니다.
GAS, gcc로 개발 진행 중인데요.. Long mode에서 Real mode 전환한 후에 문제가 생겼습니다.
일단 Bootloader -> Second bootloader -> Kernel 식으로 로드하고 Kernel에 들어갈땐 Long mode전환된 상태로 들어갑니다.
메모리 0x7C00 0x500 0x20000
Kernel 링크할 때 스크립트를 사용하는데 스크립트는 다음과 같습니다.
SECTIONS { . = 0x20000; .text ALIGN(0x1000) : { *(.text) } .rodata ALIGN(0x1000) : { start_ctors = .; *(.ctor*) end_ctors = .; start_dtors = .; *(.dtor*) end_dtors = .; *(.rodata*) } .data ALIGN(0x1000) : { *(.data) } .bss ALIGN(0x1000) : { *(.bss) } }
그냥 웹에서 긁어와서 조금 수정했습니다.. 뭔가 많이 부족한 링크 스크립트 같습니다.
문제는 여기입니다.
Kernel에서 .code16으로 Real mode전환 후 16bit 코딩을 하는데
저 위에 locator가 처음에 0x20000으로 셋팅을 해놓으니 (0x20000에 불러오니 이렇게 해야할 것 같아서 했는데 다른 방법이 있으면 좀 알려주세요)
모든 Address를 0x20000을 기준으로 하는겁니다.
.code64
.intel_syntax noprefix
.text
.org 0x0
Label:
jmp Label
이러면 Label에 0x20000을 더한 address로 점프를 하더라구요 (맞습니다 flat 메모리 구조에서는 가능합니다만)
문제는 Real-mode 전환 시 16비트 코드에서 생깁니다...
.code16
.intel_syntax noprefix
.text
.org 0x0
Label:
jmp far 0x2000:Label
에러납니다... 왜냐하면 0x20000 어드레스가 16비트에서는 표현 불가능 하기 때문인 것 같습니다.
0x2000:0x0 으로 표현 가능해야 하는데
링커가 세그먼트는 모르는지 0x0에다가 그냥 0x20000을 더해서 0x2000:0x20000으로 바꿔버리는 것 같습니다.
그렇다고 jmp far 0x0:Label 하면
relocation truncated to fit: R_X86_64_16 against `.text'
이런 링커 에러가 납니다.
그렇다고 jmp far 0x2000:Label - 0x20000 꼼수를 써봐도
Error: value of fffffffffffe002b too large for field of 2 bytes at 000000000000002a
어셈블러 컴파일 에러가 납니다.
한가지 더 해 본 시도는
section을 16/64비트 코드를 나눠서
--section-start 옵션을 사용해 봤는데
그러면 .bin 출력 파일 자체가 굉장히 커집니다. ( 0x0: 16비트 코드 | 이 사이는 모두 0로 채워짐 | 0x20000: 64비트 코드)
링커 스크립트를 고쳐서 특정 파일이나 구간만 relocation(??이라고 부르는게 맞을까요)을 하지 않도록 하는 방법은 없을까요...
혹은 아예 다른 방법은 없을까요
저의 접근 방법이 잘못됬다면 어떤 방법이 좋을까요
댓글 달기