这个问题是我在x86保护模式下使用GDT下的选择器定义了一个数据和堆栈段。当jmp到保护模式时,似乎我可以访问数据部分但是当推送eax时崩溃。请参阅以下代码:
%include "../inc/descriptor.asm"
%include "../inc/define.asm"
org 7c00h
jmp begin
; -----------------------------------------------------------------------
; Const variable
STACK_BASE EQU 1000000h ; 16M
DATA_BASE EQU 2000000h ; 32M
STACK_SIZE EQU 8000h ; 32K
STACK_LIMIT EQU 1008000h ; 16M + 32K
DATA_SIZE EQU 100000h ; 1M
; GDT and LDT
; Descriptor base limit property
[SECTION .gdt]
GDT: Descriptor 0, 0, 0
LDT_CODE32: Descriptor 0, SEG_CODE32_LEN - 1, DA_C + DA_32
LDT_VIDEO: Descriptor 0B8000h, 0ffffh, DA_DRW
LDT_STACK: Descriptor STACK_BASE, STACK_SIZE - 1, DA_DRWA + DA_B
LDT_DATA: Descriptor DATA_BASE, DATA_SIZE - 1, DA_DRW
GDTLEN EQU $ - GDT
GDTPTR DW GDTLEN - 1
DD 0
; Selectors
SLT_CODE32 EQU LDT_CODE32 - GDT
SLT_VIDEO EQU LDT_VIDEO - GDT
SLT_STACK EQU LDT_STACK - GDT
SLT_DATA EQU LDT_DATA - GDT
; -----------------------------------------------------------------------
; Real mode code
[SECTION .s16]
[BITS 16]
begin:
mov ax, cs
mov ds, ax
; init 32 bits code section descriptor
xor eax, eax
mov ax, cs
shl eax, 4
add eax, code32
mov word [LDT_CODE32 + 2], ax
shr eax, 16
mov byte [LDT_CODE32 + 4], al
mov byte [LDT_CODE32 + 7], ah
; prepare for loading gdtr
xor eax, eax
mov ax, ds
shl eax, 4
add eax, GDT
mov dword [GDTPTR + 2], eax
lgdt [GDTPTR]
cli
in al, 92h
or al, 10b
out 92h, al
mov eax, cr0
or eax, 1
mov cr0, eax
jmp dword SLT_CODE32:0
; protected mode code
[SECTION .s32]
[BITS 32]
code32:
mov ax, SLT_VIDEO
mov gs, ax
mov ax, SLT_STACK
mov ss, ax
mov esp, STACK_LIMIT - 16
mov ax, SLT_DATA
mov ds, ax
mov eax, 012345678h
xor edx, edx
mov [edx], eax
mov edx, [edx]
push eax ; **<= crashed here.**
; ---------------------------------
; PREPARE DEBUG CHAR
mov ax, SLT_VIDEO
mov gs, ax
mov bh, 0ch
mov bl, 'B'
mov esi, (80 * 1 + 1) * 2
mov [gs:esi], bx
jmp $
; ; END OF PREPARE DEBUG CHAR
; ---------------------------------
push eax
pop ebx
mov eax, DATA_BASE
mov dword [eax], ebx
mov edi, 0
mov esi, (80 * 1 + 1) * 2
call PRINT_DWORD
jmp $
; ---------------------------------
; ; PREPARE DEBUG CHAR
; mov ax, SLT_VIDEO
; mov gs, ax
; mov bh, 0ch
; mov bl, 'B'
; mov esi, (80 * 1 + 1) * 2
; mov [gs:esi], bx
; jmp $
; ; END OF PREPARE DEBUG CHAR
; ---------------------------------
SEG_CODE32_LEN EQU $ - code32
times 290 - ($ - $$) db 0
dw 0xaa55
; command reference:
; nasm protected_mode.asm -o pm.bin
; dd if=pm.bin of=pm.img bs=512 count=1
Descriptor.asm:
;
; Descriptor base, limit, attr
; base: dd
; limit: dd low 20 bits available
; attr: dw low nibble of higher byte always 0
;
%macro Descriptor 3
dw %2 & 0FFFFh
dw %1 & 0FFFFh
db (%1 >> 16) & 0FFh
dw ((%2 >> 8) & 0F00h) | (%3 & 0F0FFh)
db (%1 >> 24) & 0FFh
%endmacro
;
DEFINE.ASM:
;
DA_32 EQU 4000h
DA_DRW EQU 92h
DA_DRWA EQU 93h
DA_C EQU 98h
DA_B EQU DA_32
DA_ELEMENT_4K EQU 8000h
;
; Paging Entry Attribute
PG_P EQU 1
PG_RW_W EQU 2
PG_US_U EQU 4
答案 0 :(得分:2)
由于您将段基数设置为STACK_BASE
,因此不能将其添加到堆栈指针中。因此,mov esp, STACK_LIMIT - 16
应为mov esp, STACK_SIZE - 16
。
PS:您从未设置cs
,因此您的代码可能会在不为零的系统上中断。
答案 1 :(得分:0)
最后,我root导致了push指令导致崩溃的原因。谢谢Jester的帮助。我在这里写的是其他人可能会遗漏评论。
当定义一个堆栈段时,GDT的属性总是应设置为向下增长,类型为6/7。并且段基STACK_BASE定义最高 使用STACK_SIZE的那个段的地址。所以范围应该是从STACK_BASE - STACK_SIZE到STACK_BASE。
然后使用STACK_BASE设置esp,您现在可以使用堆栈。 感谢你的帮助。 :)