gpt4 book ai didi

assembly - 是什么导致此引导加载程序在硬件上失败但在 DOSBOX 中没有?它显示所有寄存器

转载 作者:行者123 更新时间:2023-12-04 01:13:27 32 4
gpt4 key购买 nike

我最近编写了一个 x86“引导加载程序”程序,它在 BIOS 跳转到我的程序后显示硬件寄存器的值。出于测试的目的,我将AX寄存器设置为一个已知值,以确保程序正确运行。

BITS 16
%macro pad 1-2 0
times %1 - ($ - $$) db %2
%endmacro
[org 0x7C00]
CLD ; clear direction flag (forward direction)
CLI ; clear interrupt flag (disable interrupts, opposite of 65xx)

MOV [0x8000], AX ; display all registers,
MOV [0x8004], BX ; including stack,
MOV [0x8008], CX ; segment, & extra
MOV [0x800C], DX ; registers

MOV [0x8010], SP
MOV [0x8014], BP
MOV [0x8018], SI
MOV [0x801C], DI

MOV [0x8020], CS
MOV [0x8024], SS ; we also display DS register,
MOV [0x8028], ES ; so we can't modify it or
MOV [0x802C], DS ; we'll loose our data

MOV [0x8030], FS
MOV [0x8034], GS

MOV AX, 0x0123 ; write 0x0123 to [0x8000]
MOV [0x8000], AX ; for debugging

MOV DI, 0x804C ; DI is pointer to address 0x804C
; (temporary data)
MOV AH, 0x02
MOV BH, 0x00 ; video page 0?
MOV DX, 0x0401
INT 0x10 ; move cursor to XY:($01, $04)

; display register data
MOV AL, 'A'
CALL printXl ; print 'AX:'
MOV DX, [0x8000] ; recall value of AX register
; (set to 0x0123 for test)
CALL printascii ; print 16-bit value @ [0x8000]

;... ; omitted code: display other registers

MOV AH, 0x00 ; wait for keyboard press
INT 0x16

INT 0x18 ; boot Windows

printXl:
MOV AH, 0x0E
XOR BX, BX
INT 0x10 ; display character in 'AL'
MOV AL, 'X'
; falls through
prnt: ; referenced in omitted code
MOV AH, 0x0E
INT 0x10 ; display character 'X'/'S'
MOV AL, ':'
INT 0x10 ; display character ':'
RET

printascii:
MOV [DI], DX ; store value for later recall
MOV AH, 0x0E ; INT 10,E

MOV SI, hexascii ; load address of 'hexascii'
AND DX, 0xF000
SHR DX, 0x0C ; shift high nibble to lowest 4 bits
ADD SI, DX
CS LODSB ; AL = CS:[0x1EE + DX >> 12];
INT 0x10 ; display high nibble of character value

MOV SI, hexascii
MOV DX, [DI]
AND DX, 0x0F00
SHR DX, 0x08
ADD SI, DX
CS LODSB
INT 0x10 ; display low nibble of character value

MOV SI, hexascii
MOV DX, [DI]
AND DX, 0x00F0
SHR DX, 0x04
ADD SI, DX
CS LODSB
INT 0x10 ; display high nibble of character value

MOV SI, hexascii ;
MOV DX, [DI]
AND DX, 0x000F
ADD SI, DX
CS LODSB
INT 0x10 ; display low nibble of character value

RET
pad 0x01EE
hexascii:
db "0123456789ABCDEF" ;

pad 0x01FE ; pad to end of bootsector
dw 0xAA55 ; bootsector signature

当从 DOSBOX 运行时,我正确地看到 AX:0123,但是当从我的软盘启动时,我看到 AX:FFFF。我不知道我做错了什么。作为引用,我的 PC 是 Intel Core 2 Quad

最佳答案

不可能在保证 100% 安全的情况下做自己想做的事情。

问题是要将数据存储在任何地方你必须知道你正在将它存储在一个安全的地方(不覆盖你的堆栈,不被堆栈覆盖,不写入 ROM 或其他不是 RAM 的东西而不是损坏 RAM 中的任何其他内容,如 BIOS 数据或您的代码);并且您必须先修改寄存器(主要是段寄存器),然后才能知道将数据存储在安全的地方,因此您无法安全地将这些寄存器的原始值存储在任何地方。请注意,这是导致(至少一个)您最初问题的原因 - 不想更改 DS(因为您想打印其原始值)并最终不知道使用 DS 是否安全。

“最不安全”的替代方法是(暂时)使用 BIOS 留下的堆栈。很可能 BIOS 在某个地方留下了一个有足够空间的堆栈,以确保如果在 BIOS 跳转到您的代码之后但在您可以执行单个指令(或自己设置安全堆栈)之前发生 IRQ,它不会导致问题,因此您可能可以在该堆栈上存储少量数据。然而;无法保证任何中断(包括 IRQ 和 BIOS 函数)消耗的堆栈不会比您消耗一些后剩余的堆栈更多(因此您不想在堆栈上存储大量数据);理想情况下,您应该在启用 IRQ 或调用任何 BIOS 函数之前将存储在堆栈中的数据传输到其他地方。

这会导致如下内容(NASM 语法,未经测试):

    org 0x7C00

start:
cli
push ds
push ax
xor ax,ax
mov ds,ax

call far [.fixCSIP] ;Push CS and IP then set CS and IP to known values
.fixCSIP:
dw 0x0000, .here ;Values to load into CS and IP
.here:

pop word [0x8020] ;Move original value of CS

pop ax ;ax = original value of "IP + (.fixCSIP - start)"
sub ax,.fixCSIP-start ;ax = original value of IP
mov [0x8038],ax ;Store original value of IP

pop word [0x8000] ;Move original value of AX
pop word [0x802C] ;Move original value of DS

;SP is now back to the value it originally had

mov [0x8010],sp
mov [0x8024],ss

xor ax,ax
mov ss,ax
mov sp,0x7C00

;Now CS:IP, DS and SS:SP are all "known safe" values, so we can start being normal

sti

mov [0x8004], bx
mov [0x8008], cx
mov [0x800C], dx

...

关于assembly - 是什么导致此引导加载程序在硬件上失败但在 DOSBOX 中没有?它显示所有寄存器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64069732/

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