gpt4 book ai didi

assembly - 了解引导加载程序汇编代码和内存位置

转载 作者:行者123 更新时间:2023-12-02 18:55:32 24 4
gpt4 key购买 nike

我想检查我对以下引导加载程序代码的理解:

BITS 16

start:
mov ax, 07C0h ; Set up 4K stack space after this bootloader
add ax, 288 ; (4096 + 512) / 16 bytes per paragraph
mov ss, ax
mov sp, 4096

mov ax, 07C0h ; Set data segment to where we're loaded
mov ds, ax

mov si, text_string ; Put string position into SI
call print_string ; Call our string-printing routine

jmp $ ; Jump here - infinite loop!

text_string db 'This is my cool new OS!', 0

print_string: ; Routine: output string in SI to screen
mov ah, 0Eh ; int 10h 'print char' function

.repeat:
lodsb ; Get character from string
cmp al, 0
je .done ; If char is zero, end of string
int 10h ; Otherwise, print it
jmp .repeat

.done:
ret

times 510-($-$$) db 0 ; Pad remainder of boot sector with 0s
dw 0xAA55 ; The standard PC boot signature

这是我对代码的理解:

mov ax, 07C0h:

  • 内存地址可以从堆栈段值(存储在 ss 寄存器中)和偏移量(存储在 sp 寄存器中)获得。您可以通过执行以下操作获得地址:堆栈段值 x 16 + 偏移值。
  • 我们使用段 07C0h 在代码中设置空间。因此,当07C0h偏移0时,它将引用地址0x7C00。 BIOS 尝试从 0x7C00 启动代码。 0x7C00 中复制的代码示例是 MBR。
  • 每个段以 16 字节为单位递增,因此 07C0h 将为您提供地址范围 0x7C00-0x7C0F。下一段 07C1h 将为您提供地址 0x7C10-0x7C1F。

add ax, 288

  • 为了在引导加载程序之后设置 4K 堆栈空间,我们需要添加从每段 (4096 + 512)/16 字节获得的 288。十进制值 288 等于 120h。
  • 现在存储在 ax 寄存器中的值是 08e0h,我通过以下方式获得:07c0h + 120h = 08e0h(120h 是十进制的 288)。

mov ss, ax

  • 将寄存器 ax 中的值复制到 ss 寄存器中。偏移量现在包含段:08e0h。

mov sp, 4096

  • 偏移值为 4096,即 0x1000h。 ss:sp 对给出的值是 08e0:1000。
  • 堆栈底部从内存地址 0x8e00 开始,堆栈顶部位于 0x9e00(从 0x8e00 + 0x1000 = 0x9e00)。

这是内存中的代码和分配的空间的图表,如下所示。

enter image description here

注意:此图中的引导加载程序和内存引用很可能是不正确的,我假设它不会是连续的,并且汇编器将以不同的方式编译机器代码。但是,代码的开头将从较低的内存地址(0x7C00)开始,引导签名将从较高的地址开始(0xaa55磁盘签名从0x7c0:0x1fe开始(物理地址0x7c0*16 + 0x1fe=0x7dfe),它们是第一个 512 字节扇区的最后两个字节,从 0x7c0:0x0000 到 0x7c0:0x200(0x7C32 是 512 字节的末尾)。

奇怪的是,分配的空间是两个 4096 字节的 block :一个用于堆栈,另一个包含代码和数据。我怀疑我在这里遗漏了一些东西。

最佳答案

following bootloader code:

它缺少如何设置汇编代码的相对地址的信息,即如何计算本地偏移量。通常引导加载程序以 org 0x7C00 开头,以明确代码期望从 cs:ip = 0000:7C00 启动。但是如果您这样做的话,ds=07C0 将会是错误的,这表明代码期望偏移量被组装,就好像它从 07C0:0000 开始,而不是 0000:7C00。虽然两个地址都指向相同的物理内存地址,但段:偏移量对是不同的。

Each segment increments in blocks of 16 bytes, so 07C0h will give you address range 0x7C00-0x7C0F. The next segment 07C1h will give you address 0x7C10-0x7C1F.

每个段为您提供 64kiB 范围,尽管起始地址仅前进 16 个字节,因此段之间有很多重叠,您可以通过多种组合来寻址相同的物理地址。 IE。 ds=07C0 为您提供物理内存范围 07C00-17BFF 的窗口。

<小时/>

那么你将值转换为十六进制是错误的(另请参阅迈克尔评论),288 = 0x120,并且4096 = 0x1000,但你正确地得出结论,有512B的引导加载程序代码( block 设备的单个扇区),4096B的备用空间,然后是 4096B 的堆栈空间。如果您通过向堆栈中压入超过 4096 个字节来填充堆栈,它不会命中代码后的空闲空间,但会回绕到 08E0:FFFE (远高于堆栈的原始开头)。

I am assuming that it won't be sequential and the assembler will compile the machine code differently.

恰恰相反,源代码中的指令和定义的字节在生成的机器代码中按顺序发出。使用“listing”命令行开关来查看汇编器如何为特定行发出机器代码。例如,您是否会将 text_string db 'This is my Cool new OS!', 0 行移到 BITS 16 指令之后的开头,该文本将位于开头机器代码,由 BIOS 在 0000:7C00 地址处加载并执行,将文本字节作为指令执行。

关于assembly - 了解引导加载程序汇编代码和内存位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52127149/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com