x86 NASM 实模式下的间接远跳转
x86 NASM Indirect Far Jump In Real Mode
我一直在摆弄多阶段引导加载程序,我的所有代码都可以工作,除了最后一部分:The Jump。我之前已经得到了这段代码,但我想通过替换这一行使其更加模块化:
jmp 0x7E0:0
有了这个:
jmp far [Stage2Read + SectorReadParam.bufoff]
我不想在加载代码的地方进行硬编码,而是想间接跳转到它。这是我的其余代码:
; This is stage 1 of a multi-stage bootloader
bits 16
org 0x7C00
jmp 0:boot_main
%include "io16.inc"
boot_main:
; setup the new stack
cli
mov ax, 0x100
mov ss, ax
mov bp, 0x4000
mov sp, bp
sti
; Setup data segment
xor ax, ax
mov ds, ax
; Save which drive we booted from
mov [Stage2Read + SectorReadParam.drive], dl
; Home-made BIOS wrapper to read sectors into memory
mov si, Stage2Read
call ReadSectors
; Change to new data segment
mov ax, [Stage2Read + SectorReadParam.bufseg]
mov ds, ax
;jmp 0x7E0:0 ; THIS WORKS
jmp far [Stage2Read + SectorReadParam.bufoff] ; BUT THIS DOES NOT
; Used as the parameters for ReadSectors
Stage2Read: ISTRUC SectorReadParam
AT SectorReadParam.bufoff, dd 0
AT SectorReadParam.bufseg, dw 0x07E0
AT SectorReadParam.numsecs, db 1
AT SectorReadParam.track, db 0
AT SectorReadParam.sector, db 2
AT SectorReadParam.head, db 0
AT SectorReadParam.drive, db 0 ; needs to be initialized!
IEND
; Ending
times 510-($-$$) db 0
dw 0xAA55
记住所有这些代码都已经过测试并且可以工作,除了间接远跳转可以工作。这就是我需要让它工作的全部。我想知道间接远跳转是否隐含地使用了例如 ds
以便地址 Stage2Read + SectorReadParam.bufoff
不正确。这真的让我很烦恼,因为它看起来很简单。我需要帮助!
您期望 jmp far
从 Stage2Read + SectorReadParam.bufoff
读取其目标地址,这实际上是 0x0000:Stage2Read + SectorReadParam.bufoff
(ds
= 0x0000)。
然而,就在跳转之前,ds
被设置为 0x07e0,所以在我看来,您的代码正在从 0x07e0:Stage2Read + SectorReadParam.bufoff
.
读取其目标地址
您的原始代码中有几个错误。第一个事实是您使用 DD(32 位 DWORD)而不是 16 位 来获得偏移量字。这一行:
AT SectorReadParam.bufoff, dd 0
应该是:
AT SectorReadParam.bufoff, dw 0
默认情况下(在您的情况下)为 FAR JMP 指定内存操作数时,它是相对于 DS(数据分割)。在 FAR JMP 之前,您将 DS 设置为一个新值,因此 JMP 内存操作数将读取来自错误段的内存地址(0x07e0 而不是 0x0000)。
您可以在 JMP 之后设置 DS 或者您可以将内存操作数更改为相对于 CS (仍然是包含数据的段)使用覆盖。它可能看起来像这样:
jmp far [CS:Stage2Read + SectorReadParam.bufoff]
我一直在摆弄多阶段引导加载程序,我的所有代码都可以工作,除了最后一部分:The Jump。我之前已经得到了这段代码,但我想通过替换这一行使其更加模块化:
jmp 0x7E0:0
有了这个:
jmp far [Stage2Read + SectorReadParam.bufoff]
我不想在加载代码的地方进行硬编码,而是想间接跳转到它。这是我的其余代码:
; This is stage 1 of a multi-stage bootloader
bits 16
org 0x7C00
jmp 0:boot_main
%include "io16.inc"
boot_main:
; setup the new stack
cli
mov ax, 0x100
mov ss, ax
mov bp, 0x4000
mov sp, bp
sti
; Setup data segment
xor ax, ax
mov ds, ax
; Save which drive we booted from
mov [Stage2Read + SectorReadParam.drive], dl
; Home-made BIOS wrapper to read sectors into memory
mov si, Stage2Read
call ReadSectors
; Change to new data segment
mov ax, [Stage2Read + SectorReadParam.bufseg]
mov ds, ax
;jmp 0x7E0:0 ; THIS WORKS
jmp far [Stage2Read + SectorReadParam.bufoff] ; BUT THIS DOES NOT
; Used as the parameters for ReadSectors
Stage2Read: ISTRUC SectorReadParam
AT SectorReadParam.bufoff, dd 0
AT SectorReadParam.bufseg, dw 0x07E0
AT SectorReadParam.numsecs, db 1
AT SectorReadParam.track, db 0
AT SectorReadParam.sector, db 2
AT SectorReadParam.head, db 0
AT SectorReadParam.drive, db 0 ; needs to be initialized!
IEND
; Ending
times 510-($-$$) db 0
dw 0xAA55
记住所有这些代码都已经过测试并且可以工作,除了间接远跳转可以工作。这就是我需要让它工作的全部。我想知道间接远跳转是否隐含地使用了例如 ds
以便地址 Stage2Read + SectorReadParam.bufoff
不正确。这真的让我很烦恼,因为它看起来很简单。我需要帮助!
您期望 jmp far
从 Stage2Read + SectorReadParam.bufoff
读取其目标地址,这实际上是 0x0000:Stage2Read + SectorReadParam.bufoff
(ds
= 0x0000)。
然而,就在跳转之前,ds
被设置为 0x07e0,所以在我看来,您的代码正在从 0x07e0:Stage2Read + SectorReadParam.bufoff
.
您的原始代码中有几个错误。第一个事实是您使用 DD(32 位 DWORD)而不是 16 位 来获得偏移量字。这一行:
AT SectorReadParam.bufoff, dd 0
应该是:
AT SectorReadParam.bufoff, dw 0
默认情况下(在您的情况下)为 FAR JMP 指定内存操作数时,它是相对于 DS(数据分割)。在 FAR JMP 之前,您将 DS 设置为一个新值,因此 JMP 内存操作数将读取来自错误段的内存地址(0x07e0 而不是 0x0000)。
您可以在 JMP 之后设置 DS 或者您可以将内存操作数更改为相对于 CS (仍然是包含数据的段)使用覆盖。它可能看起来像这样:
jmp far [CS:Stage2Read + SectorReadParam.bufoff]