【发布时间】:2021-01-15 03:42:43
【问题描述】:
我有两种用于引导加载程序的代码变体(它应该在引导加载程序代码的 512b 之后移动 1kb 堆栈)。 起始物理地址始终为 0x7c00(标签“start”)。 BIOS 将引导加载程序代码复制到 RAM 中。 当我使用“MOV SP,开始+1024+512”时:
- SP 将是 0x7c00 + 1024 + 512,因为物理地址应该是 SS:SP = 0
- SP 将是 0 + 1024 + 512,因为物理地址应该是 SS:SP = 0x07c0
但是如果我写“jmp start”处理器将总是去地址0x7c00。它会计算
- 0 + 0x07c0
- 0x07c0
为什么'start'在MOV和LMP中返回不同的值?还是一样,但在 MOV 处理器中不添加段,而在 JMP 中添加?在这种情况下,“开始”是否会根据 DS:SI 而不是 CS:IP 计算,这是否也是真的? 另一个例子。如果我最后添加代码
mov SI, main
lodsb ;write data from main to AL
处理器将始终转到完整的物理地址段+偏移量,并在寄存器 AL 中获取值“S”。 SI 将仅等于偏移量吗?并且处理器会在 lodsb 执行期间添加段?
补充问题:
处理器如何执行“jmp main”?该指令位于“mov ds, ax”之上。因此 2 变体中的代码有错误,但它可以工作。
BIOS加载bootloader时CS寄存器的默认值是多少?显然 CS:IP 应该是 0x7c00。
1 个变种
[bits 16]
[org 0x7c00]
start: ;offset= 0x7c00
jmp main
db "Some data" ;actually fake BIOS Parameter Block(BPB)
main:
mov ax, 0
mov ds, ax ; data segment =0.
mov ss, ax ; stack segment = 0
mov sp, start+1024+512 ;stack pointer = 0x7c00+1024+512
2 个变种
[bits 16]
[org 0x0000]
start: ;offset= 0x0000
jmp main
db "Some data" ;actually fake BIOS Parameter Block(BPB)
main:
mov ax, 0x07c0
mov ds, ax ; data segment =0x07c0.
mov ss, ax ; stack segment =0x07c0.
mov sp, start+1024+512 ;stack pointer = 0+1024+512
【问题讨论】:
-
你能多关注一下吗?这里似乎至少有 10 个问题,大约 9 个太多了,如果不写一整本关于 8086 内存架构的书,我什至不知道如何开始回答。
-
但也许stackoverflow.com/a/43397557/634919 会有所帮助。一些 BIOS 将 CS:IP 设置为
0000:7c00,其他设置为07c0:0000。标签start发生的情况与此无关,取决于您在源代码中为org选择的值。您确实需要在脑海中将段和偏移量分开,因为这就是 CPU 所做的;它只会在最后阶段将它们转换为物理地址。 -
而
jmp main很可能是相对或“短”的跳跃。汇编器计算jmp main指令本身和标签main之间的字节数,并将差值编码到地址中。执行时,CPU 将该值添加到程序计数器 IP,并让 CS 保持不变。因此,无论段寄存器如何设置,无论代码在内存中加载到什么位置,它都能正常工作。 -
谢谢@NateEldredge 您回答了我所有的问题=) 额外感谢 jmp。我忘记了这个机制。
-
更正:它是
jmp main之后的next指令与标签main之间的字节数。短直接跳转和近直接跳转都是这种情况,只是差异是否适合 8 位符号扩展立即数或 16 位的问题。
标签: assembly x86 nasm bootloader real-mode