【发布时间】:2020-05-13 09:30:07
【问题描述】:
我想我已经阅读了十几个基本上与这个问题重复的问题,但我仍然没有找到解决方案。
期望的结果是进入保护模式并停止而没有故障。我遇到的问题是使用 6 字节立即值执行段间jmp 后出现三重错误。
这是我在 DOSBox 和运行 MS-DOS 7 的 Pentium II PC 中产生错误的代码。 汇编器是 MASM 5.10
single segment stack
assume cs:single,ds:single
gdt dq 0
c_limit_lo dw 0ffffh
c_base_lo dw 0
c_base_mid db 0
c_priv db 10011110b ;present set, highest priv, type set, conforming, read
c_limit_hi db 11001111b ;granularity set, operand size 32
c_base_hi db 0
d_limit_lo dw 0ffffh
d_base_lo dw 0
d_base_mid db 0
d_priv db 10010010b ;present set, highest priv, type clr, expand dn, write
d_limit_hi db 11001111b ;granularity set, big set
d_base_hi db 0
gdt_end:
gdt_limit dw gdt_end-offset gdt-1
gdt_addr dd ?
start:
mov ax, cs
mov ds, ax
;calc phys address of current code segment and
;insert it into code and data descriptors
.386p
xor eax, eax
mov ax, cs
mov cl, 4
shl eax, cl ;multiply cs by 16 to get phys address of seg
mov edx, eax
mov c_base_lo, ax
mov d_base_lo, ax ;low word
mov cl, 16
shr eax, cl
mov c_base_mid, al
mov d_base_mid, al ;middle byte
mov c_base_hi, ah
mov d_base_hi, ah ;high byte
add edx, offset gdt ;add offset of gdt
mov gdt_addr, edx ;gdt address set
;attempt to enter protected mode
cli ;disable interrupts
in al, 70h
or al, 80h
out 70h, al ;turn off nonmasked interrupts
in al, 92h
or al, 2
out 92h, al ;enable A20 line
lgdt [gdt_limit]
mov eax, cr0
or eax, 1
mov cr0, eax ;enter protected mode
db 66h ;specify 32-bit operand
jmp_op db 0eah ;manually encoded "jmp 8h:enter_32" TRIPLE FAULT
jmp_loc_lo dw offset enter_32
jmp_loc_hi dw 0
jmp_sel dw 8
enter_32:
mov eax, 0ffffffffh ;sometimes doesn't triple fault on infinite jump or hlt instruction
back:jmp back ;but always triple faults on mov
the_stack db 64 dup (0ffh) ;64 byte stack
single ends
end start
三重错误在某种程度上似乎是“运气”。远跳转后 0x67 前缀和 nops 的某些配置会导致 cpu 表现得好像它已停止。不是很懂。
我认为我生成了错误的跳转目标。
更新:单字节指令(无论 cpu 模式如何,单编码指令)都不会出错。我想我会尝试跳入 USE32 定义的细分市场。
此代码没有错误:
jmp_op db 0eah
jmp_loc_lo dw offset enter_32
jmp_loc_hi dw 0
jmp_sel dw 8
enter_32:
aaa
daa
cmc
cld
cli
stc
nop
aaa
daa
cmc
cld
cli
stc
nop
hlt
【问题讨论】:
-
注意,在汇编32位代码时,需要将汇编器设置为32位模式。
mov eax, 0ffffffffh的编码在 16 位模式下具有66h前缀,但在 32 位模式下没有。jmp back指令也是如此。 -
添加到 fuz 的评论中。您确实需要创建对实模式代码使用 16 位编码和对保护模式使用 32 位编码的段。您可以通过使用 USE16 和 USE32 选项创建自己的分段来更改行为来做到这一点。我想知道这样的代码是否适合您:pastebin.com/Ce2BXqdd(这是一个小时前我发布的与堆栈相关的更改稍作修改的版本)
-
还应注意,如果您尝试在已处于保护模式的情况下运行此代码,它将失败。在尝试更改为保护模式之前,检查您是否已经处于保护模式通常是一个好主意。如果您已加载 EMM386、正在运行 VM8086 任务等,则会发生这种情况。
-
我假设 5.10 至少是 5.10a。
标签: assembly x86 dos masm protected-mode