首页 > 解决方案 > 如何在准系统上正确执行 C 代码?

问题描述

我正在尝试制作一个没有 GRUB 的操作系统。现在我想从保护模式执行 C 代码,但我不知道如何。

我尝试了这些命令(pm.bin 是编译的 ASM 代码,我想在其中调用 C 代码,而 bootloader.bin 是第一阶段的引导加载程序,它可以正常工作):

nasm -f bin bootloader.asm -o bootloader.bin
nasm -f bin pm.asm -o pm.bin

gcc -ffreestanding -c kernel.c -o kernel.o
ld -o kernel.bin -Ttext 0x0 --oformat binary kernel.o
cat pm.bin kernel.bin > fin.bin

sudo dd if=bootloader.bin ibs=512 count=1 of=boot.img obs=512
sudo dd if=fin.bin ibs=1024 count=1 of=boot.img obs=512 seek=1
sudo qemu-system-x86_64 boot.img -monitor stdio

好的,使用“cat”命令我将在我的二进制 ASM 代码之后得到二进制 C 代码,但我怎样才能跳转到 C 代码?

C 代码(kernel.c):

void main() {
   char* vga = (char*)0xb8000;
   vga[0] = 'y';
   vga[1] = 0x4;
}

引导加载程序.asm:

bits 16
org 0x7c00

jmp start

%include "print_hex.asm"

; ================================================

start:
    cli
    mov ah, 0x00              ; clearing the screen
    mov al, 0x03
    int 0x10

    xor ax, ax                ; segment reg. init
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x07c0            ; stack init


    mov [bootdisk], dl
    jmp reset

reset:
    ; reset the disk
    xor ax, ax
    mov dl, [bootdisk]
    int 0x13
    jc error

load_disk:
    mov bx, 0x07e0            ; загружаем код по адресу 0x7e00
    mov es, bx
    xor bx, bx                ; обнуляем bx, получается 0x07e0:0x0000

    mov ah, 0x02              ; функция
    mov dl, [bootdisk]        ; номер накопителя
    mov al, 0x1               ; количество читаемых секторов
    mov ch, 0x0
    mov cl, 0x2               ; номер сектора
    mov dh, 0x0               ; head

    int 0x13                  ; читаем, используя все параметры

    jc error                  ; если ошибка

    jmp 0x07e0:0x0000

error:
    mov dx, ax
    call print_hex_dx

    jmp $


bootdisk: db 0 ; for boot disk number

times 510 - ($ - $$) db 0
dw 0xaa55

pm.asm(我需要从这个文件中调用 C):

bits 16
org 0x7e00

jmp mainf

%include "gdt.inc"

mainf:
    cli                       ; disable interrupts
    xor ax, ax                ; null segments
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x07c0            ; the stack is under 0x7c00
    sti                       ; enable interrupts

    call installGDT           ; installing GDT

    ; entering PM
    cli
    mov eax, cr0
    or eax, 1
    mov cr0, eax

    jmp 0x8:final_stage


; =============================================================
[bits 32]

%include "driver_print_string.asm"
%include "color_clear_screen.asm"

; maybe I'll need "extern main" here

final_stage:
    cli

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov ss, ax

    mov esp, 0x07c0

disable_cursor:
    mov dx, 0x3d4
    mov al, 0xa
    out dx, al

    inc dx
    mov al, 0x20    
    out dx, al

ccode:
    ; here I want my code to call C, but I don't know how to link it correctly!

jmp $

times 1024 - ($ - $$) db 0

gdt.inc:

installGDT:
    cli
    pusha
    lgdt [toc]
    sti
    popa
    ret

;*******************************************
; Global Descriptor Table (GDT)
;*******************************************

gdt_data:
    dd 0                ; null descriptor
    dd 0

; gdt code:             ; code descriptor
    dw 0FFFFh           ; limit low
    dw 0                ; base low
    db 0                ; base middle
    db 10011010b            ; access
    db 11001111b            ; granularity
    db 0                ; base high

; gdt data:             ; data descriptor
    dw 0FFFFh           ; limit low (Same as code)
    dw 0                ; base low
    db 0                ; base middle
    db 10010010b            ; access
    db 11001111b            ; granularity
    db 0                ; base high

end_of_gdt:
toc:
    dw end_of_gdt - gdt_data - 1    ; limit (Size of GDT)
    dd gdt_data             ; base of GDT

那么如何正确编译和链接 C 和 ASM 代码并跳转到第一个?

标签: cassemblyx86bootloaderosdev

解决方案


推荐阅读