Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 跳转到保护模式时重置_Assembly_X86_Nasm_Bootloader_Osdev - Fatal编程技术网

Assembly 跳转到保护模式时重置

Assembly 跳转到保护模式时重置,assembly,x86,nasm,bootloader,osdev,Assembly,X86,Nasm,Bootloader,Osdev,我正在开发一个引导加载程序来加载我没有使用GRUB的操作系统,因为我想学习汇编程序,我的代码会出现三次错误并重置QEMU。以下是相关代码: 引导加载程序 基于BOCHS debugger并尝试使用jmp$在不同点停止程序,我推断问题在于这一行: jmp 0x8:Init32 另外,我没有包括函数文件,因为我认为它们在这里没有用处。您没有显示磁盘加载函数,但最终它必须执行与以下操作等效的操作: mov ax, 0201h mov cx, 0002h mov dh, 0

我正在开发一个引导加载程序来加载我没有使用GRUB的操作系统,因为我想学习汇编程序,我的代码会出现三次错误并重置QEMU。以下是相关代码:

引导加载程序

基于BOCHS debugger并尝试使用jmp$在不同点停止程序,我推断问题在于这一行:

jmp 0x8:Init32

另外,我没有包括函数文件,因为我认为它们在这里没有用处。

您没有显示磁盘加载函数,但最终它必须执行与以下操作等效的操作:

    mov ax, 0201h
    mov cx, 0002h
    mov dh, 0
    mov bx, 7e00h
    int 13h
这将把CHS=0,0,2加载到引导加载程序后面的ES:BX 0x0000:0x7e00。或者,您可以将ES:BX设置为0x07e0:0x0000。由于您声称问题似乎是跳转到保护模式,我将假设磁盘负载正在工作

这实际上只剩下GDT可能是问题,而不是潜在的堆栈问题1。我确实看到了一个严重的问题,它可能导致远JMP进入保护模式失败:

.desc:
    dw .end - GDT - 1
    db GDT
应该是一个长度为-1的单词dw,后面跟一个DWORD dd。您已经将基定义为单字节db!您需要将其更改为dd。它应该如下所示:

.desc:
    dw .end - GDT - 1
    dd GDT
不幸的是,NASM不会试图告诉您它填充到字节中的值是从另一个值截取的。此问题可能导致您的问题,因为代码描述符无效,导致jmp 0x8:Init32出现三重故障并导致重新启动

如果使用BOCHS进行调试,则可以将断点设置为0x7c00,并逐条执行指令,直到指令位于lgdt[GDT.desc]之后。您本来可以使用信息GDT查看GDT。您可能会发现基数错误,并且所有条目都不正确

附加说明 1您已将堆栈指针SS:SP设置为0x0000:0x0500。堆栈从该地址向下扩展。0x0000:0x0500包含的数据,其正下方是。你应该把这堆东西放在更安全的地方。0x0000:0x7c00在引导加载程序下方向下生长,在它撞击BDA之前会留下大量的堆栈空间

您需要在进入受保护模式之前关闭中断,这样您就可以在代码开始时简单地执行CLI,避免所有CLI/STI指令。或者,您可以一直启用它们,并在进入保护模式之前执行CLI

通常情况下,通过首先将SS更新为新的值和SP,使中断能够同时更新SS:SP。这是因为更新SS的副作用是在执行以下指令之前禁用中断。如果更新SP是以下指令,则操作将以原子方式完成,并且更新SS和SP之间不会发生中断。在某些8088处理器上,存在一个缺陷,该缺陷没有发生,但此处不适用,因为您的代码需要386+

在实模式代码中设置BP没有任何效果,因为您没有在任何地方使用堆栈帧,也没有调用任何需要将BP设置为特定值的BIOS例程。您也不需要设置GS和FS,因为您的代码没有在实际模式中使用它们

代码的开头可能显示为:

Start:
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax     ; Set SS:SP to grow down beneath bootloader at 0x0000:0x7c00
    mov sp, 7c00h
    cld
我有额外的引导程序提示,在这可能是有用的


您没有显示磁盘加载功能,但最终它必须执行以下等效操作:

    mov ax, 0201h
    mov cx, 0002h
    mov dh, 0
    mov bx, 7e00h
    int 13h
这将把CHS=0,0,2加载到引导加载程序后面的ES:BX 0x0000:0x7e00。或者,您可以将ES:BX设置为0x07e0:0x0000。由于您声称问题似乎是跳转到保护模式,我将假设磁盘负载正在工作

这实际上只剩下GDT可能是问题,而不是潜在的堆栈问题1。我确实看到了一个严重的问题,它可能导致远JMP进入保护模式失败:

.desc:
    dw .end - GDT - 1
    db GDT
应该是一个长度为-1的单词dw,后面跟一个DWORD dd。您已经将基定义为单字节db!您需要将其更改为dd。它应该如下所示:

.desc:
    dw .end - GDT - 1
    dd GDT
不幸的是,NASM不会试图告诉您它填充到字节中的值是从另一个值截取的。此问题可能导致您的问题,因为代码描述符无效,导致jmp 0x8:Init32出现三重故障并导致重新启动

如果使用BOCHS进行调试,则可以将断点设置为0x7c00,并逐条执行指令,直到指令位于lgdt[GDT.desc]之后。您本来可以使用信息GDT查看GDT。您可能会发现基数错误,并且所有条目都不正确

附加说明 1您已将堆栈指针SS:SP设置为0x0000:0x0500。堆栈从该地址向下扩展。0x0000:0x0500包含的数据,其正下方是。你应该把这堆东西放在更安全的地方。0x0000:0x7c00向下生长在引导加载程序下面,在它撞击B之前会留下大量的堆栈空间 爸爸

您需要在进入受保护模式之前关闭中断,这样您就可以在代码开始时简单地执行CLI,避免所有CLI/STI指令。或者,您可以一直启用它们,并在进入保护模式之前执行CLI

通常情况下,通过首先将SS更新为新的值和SP,使中断能够同时更新SS:SP。这是因为更新SS的副作用是在执行以下指令之前禁用中断。如果更新SP是以下指令,则操作将以原子方式完成,并且更新SS和SP之间不会发生中断。在某些8088处理器上,存在一个缺陷,该缺陷没有发生,但此处不适用,因为您的代码需要386+

在实模式代码中设置BP没有任何效果,因为您没有在任何地方使用堆栈帧,也没有调用任何需要将BP设置为特定值的BIOS例程。您也不需要设置GS和FS,因为您的代码没有在实际模式中使用它们

代码的开头可能显示为:

Start:
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax     ; Set SS:SP to grow down beneath bootloader at 0x0000:0x7c00
    mov sp, 7c00h
    cld
我有额外的引导程序提示,在这可能是有用的


GDT记录GDTR应该是一个长度为-1的DWORD dw,后面跟一个DWORD dd-对dw的引用应该读字。GDT记录GDTR应该是一个长度为-1的DWORD dw,后面跟一个DWORD dd-对dw的引用应该读字。