【问题标题】:How to setup Stack segment in protected mode?如何在保护模式下设置堆栈段?
【发布时间】:2015-09-25 02:38:46
【问题描述】:

这个问题是我在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

描述符.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
;

定义.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

【问题讨论】:

  • 无需定义单独的数据、堆栈和视频段,您可以通过只创建一个引用所有内存的数据段来简化事情,就像您的代码段一样。
  • 是的,我只是想尝试一下独立的堆栈段选择器。按照惯例,应该按照你说的做。

标签: assembly x86 operating-system nasm protected-mode


【解决方案1】:

由于您将段基数设置为STACK_BASE,因此您不能将其添加到堆栈指针中。因此,mov esp, STACK_LIMIT - 16 应该是 mov esp, STACK_SIZE - 16

PS:您从未设置过cs,因此您的代码可能会在它不为零的系统上中断。

【讨论】:

  • 谢谢,但是堆栈 esp 应该是指向段最高地址的指针,以便向下增长。还有一个关于cs的问题,我怎样才能让cs处于保护模式?
  • 是的,esp 将是相对于段基础的最高 偏移量,即 GDT 中已设置的 STACK_BASE。我不明白你关于cs 的问题。
  • 你在那段代码中说我从未设置过cs寄存器。看来我对此一无所知,您能帮忙解释一下吗?提前致谢!
  • 使用远跳转到你的入口点,而不是jmp begin do jmp 0:begin
  • 我仍然对设置此段的 esp 有疑问。该段从 16M 开始,到 16M + 32K 结束。如果将 esp 设置为 STACK_BASE,它是一个完整的堆栈?或者你的意思是STACK_BASE是堆栈段的最高地址,范围应该是16M-32K到16M?提前致谢!
【解决方案2】:

最后,我根源导致了为什么该推送指令会导致崩溃。感谢小丑的帮助。我在这里写它是为了其他人可能会缺少 cmets。

当定义一个堆栈段时,GDT 的属性总是应该设置为向下增长 TYPE 6/7。而段基 STACK_BASE 定义了最高 该段的地址与 STACK_SIZE。所以范围应该是从 STACK_BASE - STACK_SIZE 到 STACK_BASE。

然后用STACK_BASE设置esp,现在就可以使用stack了。 感谢你的帮助。 :)

【讨论】:

    猜你喜欢
    • 2021-10-01
    • 2011-10-02
    • 1970-01-01
    • 2016-04-06
    • 1970-01-01
    • 2011-07-30
    • 2017-08-28
    • 2017-02-24
    • 2015-10-16
    相关资源
    最近更新 更多