Подтвердить что ты не робот

Тройная ошибка в стеке в коде C

Я пишу игрушечное ядро ​​для учебных целей, и у меня проблемы с ним. Я сделал простой загрузчик, который загружает сегмент с гибкого диска (который написан на 32-битном коде), тогда загрузчик включает A20-ворот и включает защищенный режим. Я могу перейти к 32-разрядному коду, если я напишу его на ассемблере, но если я напишу его на C, я получу тройную ошибку. Когда я разбираю код C, я вижу, что первые две команды включают в себя создание нового фрейма стека. Это ключевое различие между действующим кодом ASM и неисправным кодом C. Я использую NASM v2.10.05 для кода ASM и GCC из коллекции DJGPP 4.72 для кода C.

Это код загрузчика:

org 7c00h
BITS 16

entry:
mov [drive], dl         ;Save the current drive


cli
mov ax,cs               ; Setup segment registers
mov ds,ax               ; Make DS correct
mov ss,ax               ; Make SS correct        

mov bp,0fffeh
mov sp,0fffeh           ;Setup a temporary stack
sti

;Set video mode to text
;===================
mov ah, 0
mov al, 3
int 10h
;===================

;Set current page to 0
;==================
mov ah, 5
mov al, 0
int 10h
;==================

;Load the sector
;=============
call load_image
;=============

;Clear interrupts
;=============
cli
;=============

;Disable NMIs
;============
in ax, 70h
and ax, 80h ;Set the high bit to 1
out 70h, ax
;============

;Enable A20:
;===========
mov ax, 02401h
int 15h
;===========

;Load the GDT
;===========
lgdt [gdt_pointer]
;===========

;Clear interrupts
;=============
cli
;=============

;Enter protected mode
;==================
mov eax, cr0
or eax, 1       ;Set the low bit to 1
mov cr0, eax
;==================

jmp 08h:clear_pipe  ;Far jump to clear the instruction queue


;======================================================
load_image:
reset_drive:
    mov ah, 00h
    ; DL contains *this* drive, given to us by the BIOS
    int 13h
    jc reset_drive

read_sectors:
    mov ah, 02h
    mov al, 01h
    mov ch, 00h
    mov cl, 02h
    mov dh, 00h
    ; DL contains *this* drive, given to us by the BIOS

    mov bx, 7E0h
    mov es, bx
    mov bx, 0

    int 13h
    jc read_sectors

ret
;======================================================

BITS 32 ;Protected mode now!
clear_pipe:

mov ax, 10h             ; Save data segment identifier
mov ds, ax              ; Move a valid data segment into the data segment register
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax              ; Move a valid data segment into the stack segment register
mov esp, 90000h        ; Move the stack pointer to 90000h
mov ebp, esp

jmp 08h:7E00h           ;Jump to the kernel proper

;===============================================
;========== GLOBAL DESCRIPTOR TABLE ==========
;===============================================

gdt:                    ; Address for the GDT

gdt_null:               ; Null Segment
    dd 0
    dd 0

gdt_code:               ; Code segment, read/execute, nonconforming
    dw 0FFFFh       ;   LIMIT, low 16 bits
    dw 0            ;   BASE, low 16 bits           
    db 0            ;   BASE, middle 8 bits
    db 10011010b    ;   ACCESS byte
    db 11001111b    ;   GRANULARITY byte
    db 0            ;   BASE, low 8 bits

gdt_data:               ; Data segment, read/write, expand down
    dw 0FFFFh
    dw 0
    db 0
    db 10010010b
    db 11001111b
    db 0

gdt_end:                ; Used to calculate the size of the GDT



gdt_pointer:                       ; The GDT descriptor
    dw gdt_end - gdt - 1    ; Limit (size)
    dd gdt                  ; Address of the GDT
;===============================================
;===============================================

drive: db 00    ;A byte to store the current drive in
times 510-($-$$) db 00
db 055h
db 0AAh

И это код ядра:

void main()
{
    asm("mov byte ptr [0x8000], 'T'");
    asm("mov byte ptr [0x8001], 'e'");
    asm("mov byte ptr [0x8002], 's'");
    asm("mov byte ptr [0x8003], 't'");
}

Ядро просто вставляет эти четыре байта в память, которые я могу проверить, когда я запускаю код в виртуальной машине VMPlayer. Если появляются байты, я знаю, что код работает. Если я напишу код в ASM, который выглядит так, то программа работает:

org 7E00h
BITS 32

main:
mov byte [8000h], 'T'
mov byte [8001h], 'e'
mov byte [8002h], 's'
mov byte [8003h], 't'

hang:
    jmp hang

Единственными отличиями являются поэтому две операции стека, которые я нашел в дизассемблированном C-коде, которые следующие:

push ebp
mov ebp, esp

Любая помощь по этому вопросу была бы весьма признательна. Я полагаю, что мне не хватает чего-то относительно незначительного, но важного здесь, поскольку я знаю, что это возможно.

4b9b3361

Ответ 2

Я бы попытался переместить адрес стека защищенного режима на что-то другое - скажем 0x80000 - который (в соответствии с этим: http://wiki.osdev.org/Memory_Map_(x86)) - это оперативная память, которая гарантирована бесплатно для использования (в отличие от используемого вами адреса - 0x90000 - что, по-видимому, может отсутствовать) в зависимости от того, что вы используете в качестве тестовой среды).

Ответ 3

Я выполнил инструкции в ссылке Майкла, извлек секцию .text в двоичный файл, и теперь у меня есть загрузочный C-код. Таким образом, похоже, что проблема не в стеке, а в дополнительной информации внутри файла C. Я лаял неправильное дерево со стеком! Спасибо всем за ваши предложения здесь, я ценю это.