gcc 当我使用全局变量时,它会使内核崩溃

3zwtqj6y  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(131)

我以前也遇到过这种情况,并解决了一段时间,但现在它慢慢变得越来越不可避免,因为现在我需要它们。由于某种奇怪的原因,当我试图在代码中使用全局变量时,我的内核崩溃了。
这是可行的:

int global;

void kmain()
{
    //do some stuff...
}

这不起作用:

int global;

void kmain()
{
    global = 1;
    
    //do some stuff...
}

我不知道为什么会发生这种情况。作为一些额外的资源,这里是我的链接器脚本:

OUTPUT_FORMAT(binary)

phys = 0x0500;

SECTIONS
{
    .text phys : AT(phys) {
        code = .;
        *(.text)
        *(.rodata)
        . = ALIGN(4096);
    }

    .data : AT(phys + (data - code))
    {
        data = .;
        *(.data)
        . = ALIGN(4096);
    }

    .bss : AT(phys + (bss - code)) {
        bss = .;
        *(.bss)
        . = ALIGN(4096);
    }

    end = .;

    /DISCARD/
     : {
        *(.comment)
        *(.eh_frame)
        *(.note.gnu.build-id)
    }
}

和我makefile:

bin/UmbrellaOS.img: bin/boot.bin bin/kernel.bin bin/zeros.bin
    cat $^ > $@

bin/kernel.bin: tmp/kernel_entry.o tmp/kernel.o
    x86_64-elf-ld -o $@ -T link.ld $^

tmp/kernel.o: src/kernel/main.c
    x86_64-elf-gcc -ffreestanding -m64 -g -c $^ -o $@

编辑:更具体地说,我使用QEMU来测试我的操作系统,当启动QEMU时,它会立即关闭。还应该注意的是,如果我尝试这样做:

int global;

void kmain()
{
    return;
    global = 0;
}

它的工作出于某种原因。我可以看到一个绿色的L打印到屏幕上,这是我的引导加载程序在进入长模式后将控制传递给内核之前所做的最后一件事。
顺便说一句,这是我的引导程序:

[bits 16]
[org 0x7C00]

KERNEL_LOC equ 0x0500

_start:
    mov [_BootDisk], dl
    
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax

    mov bp, 0x7BFF
    mov sp, bp

    push 0x7E00         ; buffer
    push 1              ; sectors to read
    push 2              ; sector num
    call DiskRead
    jc .error

    push ebx
    pushfd
    pop eax
    mov ebx, eax
    xor eax, 0x200000
    push eax
    popfd
    pushfd
    pop eax
    cmp eax, ebx
    jnz .supported
    push _CpuErrorString
    call Print
    jmp .error
    .supported:

    mov eax, 0x80000000
    cpuid
    cmp eax, 0x80000001
    jb .no64
    mov eax, 0x80000001
    cpuid
    test edx, 1 << 29
    jnz .is64
    .no64:
    push _64ErrorString
    call Print
    jmp .error
    .is64:
    
    push 0x8000
    call MapMem
    
    push KERNEL_LOC     ; buffer
    push 8              ; sectors to read
    push 3              ; sector num
    call DiskRead
    jc .error
    
    cli
    lgdt [GDT_descriptor]
    mov eax, cr0
    or eax, 1
    mov cr0, eax
    jmp CODE_SEG:protected_mode

    .error:
    jmp $

Print:
    push bp
    mov bp, sp
    mov bx, [bp+4]
    mov ah, 0x0E
    .loop:
    mov al, [bx]
    cmp al, 0
    je .end
    int 0x10
    inc bx
    jmp .loop
    .end:
    mov sp, bp
    pop bp
    ret 2

DiskRead:
    push bp
    mov bp, sp
    mov ah, 0x02
    mov al, [bp+6]
    mov ch, 0
    mov cl, [bp+4]
    mov dh, 0
    mov dl, [_BootDisk]
    mov bx, [bp+8]
    int 0x13
    cmp al, [bp+6]
    je .end
    jnc .end
    push _DiskErrorString
    call Print
    .end:
    mov sp, bp
    pop bp
    ret 6

MapMem:
    push bp
    mov bp, sp
    mov si, [bp+4]
    mov di, [bp+4]
    add di, 4
    xor ebx, ebx
    mov edx, 0x0534D4150
    mov eax, 0xE820
    mov [di+20], dword 1
    mov ecx, 24
    int 0x15
    jc .failed

    mov edx, 0x0534D4150
    cmp eax, edx
    jne .failed
    test ebx, ebx
    je .failed

    .loop:
        mov eax, 0xE820
        mov [di+20], dword 1
        mov ecx, 24
        int 0x15
        jc .finish
        mov edx, 0x0534D4150

        .jmpin:
        jcxz .skip
        cmp cl, 20
        jbe .notext
        test byte [di+20], 1
        je .skip
        
        .notext:
        mov ecx, [di+8]
        or ecx, [di+12]
        jz .skip
        inc dword [si]
        add di, 24
        
        .skip:
        test ebx, ebx
        jne .loop
        
        .finish:
        clc
        jmp .end
    .failed:
    push _MemErrorString
    call Print
    stc
    jmp .end
    .end:
    mov sp, bp
    pop bp
    ret 2

_BootDisk: db 0
_DiskErrorString: db "Disk read error!", 13, 10, 0
_MemErrorString: db "Memory mapping failed!", 13, 10, 0
_CpuErrorString: db "CPUID not supported!", 13, 10, 0
_64ErrorString: db "x64 bits not supported!", 13, 10, 0

CODE_SEG equ GDT_code - GDT_start
DATA_SEG equ GDT_data - GDT_start

GDT_start:
    GDT_null:
        dd 0x0
        dd 0x0
    GDT_code:
        dw 0xffff
        dw 0x0
        db 0x0
        db 0b10011010
        db 0b11001111
        db 0x0
    GDT_data:
        dw 0xffff
        dw 0x0
        db 0x0
        db 0b10010010
        db 0b11001111
        db 0x0
GDT_end:

GDT_descriptor:
    dw GDT_end - GDT_start - 1
    dd GDT_start

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

[bits 32]
protected_mode:
    mov ax, DATA_SEG
    mov ds, ax
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000
    mov esp, ebp

    call Clear
    
    mov ebx, VGA_MEM
    mov byte [ebx], 'P'
    inc ebx
    mov byte [ebx], 14

    mov eax, cr0
    and eax, ~(1 << 31)
    mov cr0, eax

    mov edi, 0x1000
    mov cr3, edi
    xor eax, eax
    mov ecx, 4096
    rep stosd
    mov edi, cr3

    mov dword [edi], 0x2003
    add edi, 0x1000
    mov dword [edi], 0x3003
    add edi, 0x1000
    mov dword [edi], 0x4003
    add edi, 0x1000
    mov ebx, 0x00000003
    mov ecx, 512

    .set_entry:
    mov dword [edi], ebx
    add ebx, 0x1000
    add edi, 8
    loop .set_entry

    mov eax, cr4
    or eax, 1 << 5
    mov cr4, eax

    mov ecx, 0xC0000080
    rdmsr
    or eax, 1 << 8
    wrmsr

    mov eax, cr0
    or eax, 1 << 31
    mov cr0, eax

    lgdt [GDT.Pointer]
    jmp GDT.Code:long_mode

    jmp $

Clear:
    push ebp
    mov ebp, esp
    mov ecx, VGA_SIZE
    mov eax, VGA_MEM
    .loop:
    mov byte [eax], 0
    inc eax
    loop .loop
    mov esp, ebp
    pop ebp
    ret

PRESENT         equ 1 << 7
NOT_SYS         equ 1 << 4
EXEC            equ 1 << 3
RW              equ 1 << 1
ACCESSED        equ 1 << 0

GRAN_4K         equ 1 << 7
SZ_32           equ 1 << 6
LONG_MODE       equ 1 << 5

GDT:
    .Null: equ $ - GDT
        dq 0
    .Code: equ $ - GDT
        dd 0xFFFF
        db 0
        db PRESENT | NOT_SYS | EXEC | RW
        db GRAN_4K | LONG_MODE | 0xF
        db 0
    .Data: equ $ - GDT
        dd 0xFFFF
        db 0
        db PRESENT | NOT_SYS | RW
        db GRAN_4K | SZ_32 | 0xF
        db 0
    .TSS: equ $ - GDT
        dd 0x00000068
        dd 0x00CF8900
    .Pointer:
        dw $ - GDT - 1
        dq GDT

[bits 64]
long_mode:
    cli
    mov ax, GDT.Data
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    
    mov rbp, 0x0007FFFF
    mov rsp, rbp

    mov rbx, VGA_MEM
    mov byte [rbx], 'L'
    inc rbx
    mov byte [rbx], 2

    jmp KERNEL_LOC

VGA_MEM equ 0xB8000
VGA_WIDTH equ 80
VGA_HEIGHT equ 25
VGA_STRIDE equ 2
VGA_SIZE equ VGA_WIDTH * VGA_STRIDE * VGA_HEIGHT
VGA_LENGTH equ VGA_WIDTH * VGA_HEIGHT

times 1024-($-$$) db 0

对于任何想看到大画面的人,这里是我做的Github repository

xhv8bpkk

xhv8bpkk1#

问题是我忘记了我把页表结构放在0x1000,当我在0x0500加载内核时意外地覆盖了它们。我最终把结构留在0x1000,并把内核移到0x5000
这是一个相当简单的问题,但我建议你还是看一看评论,因为仍然有很多有用的信息和事情要考虑。

lf5gs5x2

lf5gs5x22#

第一个:* 总是 * 初始化变量,尤其是全局变量。
第二个:这个问题肯定是从你的引导程序,你能编辑后,告诉我们你如何加载你的内核?

尝试objdump以查看是否声明了变量,使用-monitor stdio和QEMU并检查CR2寄存器的值,这可能是由于 second 问题导致的页面错误。
下面是一个检查变量是否真的有一个有效指针的解决方案:
您可以在一切就绪后移除这些编辑。而不是:

jmp KERNEL_LOC

执行:

call KERNEL_LOC ; RAX Has the pointer of the global variable
jmp $

kmain中,只需键入:

return &global

然后在QEMU上运行它,并在控制台中键入info registers,RAX应包含名为global的变量的指针。

相关问题