问题
I have been messing around with a multi-stage bootloader and I have got all of my code to work, except for the last part: The Jump. I have gotten this code to work out before now but I wanted to make it more modular by replacing this line:
jmp 0x7E0:0
With this one:
jmp far [Stage2Read + SectorReadParam.bufoff]
Instead of hard coding where the code will load in, I wanted to do an indirect jump to it. Here's the rest of my code:
; 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
Remember all this code has been tested and works except for the indirect far jump to work. That's all I need to get this to work. I was wondering if maybe the indirect far jump implicitly is using for example ds
so that the address Stage2Read + SectorReadParam.bufoff
would be incorrect. This is really bugging me because it is so seemingly simple. I would like help!
回答1:
You had a couple of bugs in your original code. The first was the fact that you had the offset using a DD (32-bit DWORD) instead of a 16-bit WORD. This line:
AT SectorReadParam.bufoff, dd 0
Should have been:
AT SectorReadParam.bufoff, dw 0
When you specify the memory operand for the FAR JMP by default (in your case) it is relative to the DS (data segment). Before the FAR JMP you set DS to a new value, so the JMP memory operand will read the memory address from the wrong segment (0x07e0 instead of 0x0000).
You can either set DS after you JMP or you can change the memory operand to be relative to CS (which is still the segment with the data) using an override. It could look like this:
jmp far [CS:Stage2Read + SectorReadParam.bufoff]
回答2:
You're expecting jmp far
to read its destination address from Stage2Read + SectorReadParam.bufoff
, which is essentially 0x0000:Stage2Read + SectorReadParam.bufoff
(ds
= 0x0000).
However, just before the jump, ds
is set to 0x07e0, so it seems to me that your code is reading its destination address from 0x07e0:Stage2Read + SectorReadParam.bufoff
.
来源:https://stackoverflow.com/questions/36783568/x86-nasm-indirect-far-jump-in-real-mode