부트스트랩 코드의 cs 관련 질문

Reper의 이미지

%include "init.inc"
 
[org 0]
[bits 16]
	jmp 0x07C0:start
 
start:
	mov ax, cs
	mov ds, ax
 
write:
	mov ax, 0xB800
	mov es, ax
 
	lea si, [msgBoot]
	mov di, 0
 
write_loop:
	mov al, byte [si]
	mov byte [es:di], al
	or al, al
	jz read
	inc di
	mov byte [es:di], 0x07
	inc di
	inc si
	jmp write_loop
 
read:
	mov ax, 0x1000
	mov es, ax
	xor bx, bx			; es:bx = 0x1000:0000
 
	mov ah, 2
	mov al, 1
	mov ch, 0
	mov cl, 2
	mov dh, 0
	mov dl, 0
	int 0x13
 
	jc read
 
prepare_pm:
	cli
 
	lgdt[gdtr]
 
	mov eax, cr0
	or eax, 0x00000001
	mov cr0, eax
 
	jmp dword CodeSelector:0000
 
 
; Global Descriptor Table (GDT)
gdtr:
	dw gdt_end - gdt - 1
	dd 0x7C00 + gdt
 
gdt:
	dd 0x00000000, 0x00000000
	dd 0x0000FFFF, 0x00CF9A01		; Code Segment Descriptor
	dd 0x0000FFFF, 0x00CF9201		; Data Segment Descriptor
	dd 0x8000FFFF, 0x0040920B		; Video Segment Descriptor
 
gdt_end:
 
 
msgBoot db "I am in Boot !" , 0
 
times 510-($-$$) db 0
dw 0xAA55

안녕하세요. 커널 공부를 하고 있는 학생입니다. 지금 16비트 실제 모드에서 32비트 보호 모드로 넘어가는 코드를 작성 중인데요.
위의 코드는 아무 이상 없이 잘 동작 합니다. 그런데 cs에 0x07C0의 값을 넣어주기 귀찮아서,

[org 0]
[bits 16]
jmp 0x07C0:start
start:
...

이 코드를

[org 0x7C00]
[bits 16]

start:
...

이렇게 고쳤는데 무한 재부팅이 됩니다. BIOS가 부트 코드를 메모리의 0x0000:07C0 주소에 적재 하면서 cs에는 0000이 들어가게 되는데,
이 0의 값을 고쳐 주지 않으면 무슨 문제가 있나요 ..? 기계어로 디스어셈블 해봐도 오프셋이나 여러 코드가 정상적으로 작동하기 위한
내용에는 아무 이상이 없어보이는 데요 ... 우선 문제의 요점은, 제 생각엔 cs(code segment) 레지스터의 값인 것 같습니다.

혹시 아시는 분 계시다면, 답변 해주시면 정말 감사하겠습니다.

Reper의 이미지

참고로 init.inc 에는 단순히 CodeSelector, DataSelector, VideoSelector 가 equ를 통해 GDT의 인덱스 값으로 상수화 되어있습니다.

익명 사용자의 이미지

첨부한 부트로더 코드의 실제 부팅시 적재될 메모리 주소가 0x7c00이기 때문에 정도로 이해하시면 되겠군요.
http://kkamagui.tistory.com/14

위에서 jmp 0x07c0:start 코드를 볼 수 있는데, 이 코드는 CS 세그먼트 레지스터에 0x07c0을 설정하고 IP 레지스터에 start의 주소를 설정하는 코드이다.
CS 세그먼트 레지스터에 0x07c0을 설정하면 어떤 일이 발생하는 것일까? 16bit 모드에서 세그먼트 레지스터의 역할은 32bit 모드의 역할과 다르다.
 
16bit 모드의 세그먼트 레지스터의 역할은 Base 주소 역할만 하는데, 주소 계산 방식은 아래와 같다.
 
  실제 주소 = 세그먼트 레지스터의 값 << 4 + 레지스터의 값
 
즉 start 코드가 위치하는 실제 주소는 0x7c00  + start의 주소가 되는 것이다.
 
그렇다면 0x7c00 주소는 무엇일까? 0x7c00의 주소는 BIOS가 디스크로부터 한 섹터를 읽어들여 메모리에 복사하는 위치이다.
다시말해 부트 코드가 0x7c00에 위치하며 BIOS가 0x7c00의 주소로 jump해서 부트 코드를 실행한다.
부트 코드가 정상적으로 실행되기 위해서는 0x7c00에서 실행되도록 컴파일 되어야 함은 두말할 필요도 없다.
익명 사용자의 이미지

아 죄송합니다. 원 질문을 대충 읽었네요. 이미 알고 계신 내용이겠네요.

질문내용중에 "BIOS가 부트 코드를 메모리의 0x0000:07C0 주소에 적재 하면서 cs에는 0000이 들어가게 되는데,"
부분이 있는데요, 의도하신대로라면 메모리의 0x07c0:0000 주소에 적대하면서 cs에는 0x07c0 이 들어가야 하지 않을까요.
혹시 org 0x7c0 하신건 아닌지요.

익명 사용자의 이미지

잘 살펴보면 원질문자께서 "BIOS가 부트 코드를 메모리의 0x0000:7C00 주소에 적재 하면서 cs에는 0000이 들어가게 되는데," 라고 적으실려다 오타낸거 같습니다.
0x7c00, 0x07c0:0000, 0x0000:7c00 이 같은 주소니까요.

익명 사용자의 이미지

    dd 0x7C00 + gdt

이 부분에 의심이 갑니다. 말씀하신 상황에서 그냥 dd gdt 해야 하지 않을까요.

org 0에서는 gdt 값이 offset이기 때문에 0x7c00을 더해주었지만, org 0x7c00에서는 gdt값이 온전한 주소값이 되기 때문에 0x7c00을 더해줄 필요가 없어 보입니다.

Reper의 이미지

예, 제가 오타를 적었네요; 그런데 [org 0] jmp 0x07C0:start 와 [org 0x7C00]으로 소스를 어셈블러를 통해 기계어로 변환한 후, 디스어셈블 결과를 살펴봤을때 gdt의 위치의 오프셋을 살펴봤는데 아무 이상이 없었습니다. 그래서 이렇게 질문을 드리는 거구요 ...

익명 사용자의 이미지

-   0:  ea 05 00 c0 07          ljmp   $0x7c0,$0x5
+   0:  ea 05 7c c0 07          ljmp   $0x7c0,$0x7c05
    5:  8c c8                   mov    %cs,%ax
    7:  8e d8                   mov    %ax,%ds
    9:  b8 00 b8                mov    $0xb800,%ax
    c:  8e c0                   mov    %ax,%es
-   e:  8d 36 7c 00             lea    0x7c,%si
+   e:  8d 36 7c 7c             lea    0x7c7c,%si
   12:  bf 00 00                mov    $0x0,%di
   15:  8a 04                   mov    (%si),%al
   17:  26 88 05                mov    %al,%es:(%di)
@@ -33,14 +33,14 @@
   3a:  cd 13                   int    $0x13
   3c:  72 e9                   jb     0x27
   3e:  fa                      cli
-  3f:  0f 01 16 56 00          lgdtw  0x56       <=== gdtr의 오프셋은 0x56, 이때 CS가 0x07c0이기 때문에 gdtr의 실제주소는 0x7c56
+  3f:  0f 01 16 56 7c          lgdtw  0x7c56     <=== CS가 0x0000이기 때문에 바로 오프셋이 실주소. gdtr의 주소는 그대로 0x7c56
   44:  0f 20 c0                mov    %cr0,%eax
   47:  66 83 c8 01             or     $0x1,%eax
   4b:  0f 22 c0                mov    %eax,%cr0
   4e:  66 ea 00 00 00 00 08    ljmpl  $0x8,$0x0
   55:  00
   56:  1f                      pop    %ds            <=== 이후 어셈코드는 무시 데이터값이 중요. 
-  57:  00 5c 7c                add    %bl,0x7c(%si)
+  57:  00 5c f8                add    %bl,-0x8(%si)                     
        ...
   62:  00 00                   add    %al,(%bx,%si)
   64:  ff                      (bad)

실제로는 처음 jmp 0x07c0:start 라인이 없어지기 때문에 쉽게 비교하기 어렵기 때문에,
코드분석을 쉽게 하기 위해서 (잘못된 코드이지만) jmp 0x07c0:start 라인은 그대로 두고, [org 0] 을 [org 0x7c00]으로만 바꾼 코드를 어셈블 후 디스어셈블한 결로를 diff한 것입니다. org 값을 변경했을 때, 코드가 어떻게 해석되는지를 알 수 있을겁니다.

오프셋 0: 은 테스트를 쉽게 하려고 첫 jmp라인을 남긴 것이니 무시하면 됩니다. [org 0x7c05]하고 jmp 0x07c0:start라인을 없앴다고 생각하면 됩니다.

오프셋 0x0e, ox3f의 경우 앞의 것은 CS가 0x07c0이고 뒤에것은 CS가 0x0000인 경우라서 실제 실행에서는 문제가 되지 않습니다.

문제는 오프셋 0x57 부분에 있는데요.
lgdt[gdtr] 할때 gdtr에 있는 값이 다르다는데 문제가 있습니다. 두 경우 모두 gdt의 오프셋(0x5c)은 같은데 말이죠.
실제 실행하였을 경우 메모리에서 gdt의 위치는 0x7c5c = 0x07c0:005c = 0x0000:7c5c 입니다.

따라서 [org 0x7c00]에서는 앞에서 이야기했듯이 gdtr:에서 dd 0x7c00 + gdt를 dd gdt로 바꾸어야 합니다.
이 부분 그대로 두었기 때문에 0x7c00 + 0x7c5c = 0xf85c가 들어가면서 잘못된 gdt 주소값이 들어가게 되는 문제가 생기게 되는 것입니다.

말로할게 하니라 실제로 실행해 보면 알수 있겠죠. 저는 분석만 한 것이기에, 틀릴수도 있습니다만 도움이 되었으면 좋겠습니다.

Reper의 이미지

헛.. dd gdt 로 변경하니 정상 작동을 하는군요 ! 제가 보고 있는 서적에 GDTR 레지스터에 GDT의 크기를 명시한 후, GDT의 물리 주소를 채워야 한다고 하길래 순간 오프셋 기준을 생각치 못하고 헤맸군요. 답변 감사드립니다. ㅎㅎ

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.