You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

操作系统项目:从Boot Loader加载ELF内C函数的方式是否正确?

Troubleshooting ELF Kernel Loading & C Function Call in Your Bootloader

Let's walk through your setup and pinpoint where things might be going wrong with loading the ELF kernel and calling your kmain function.

First: Is Your Entry Address Calculation Correct?

Your current code tries to compute the entry point like this:

xor edx, edx
mov edx, 24
add edx, IMAGE_PMODE_BASE
add ebx, dword[edx]
add ebx, IMAGE_PMODE_BASE
call ebx

This has a critical mistake: you're double-adding IMAGE_PMODE_BASE to the entry address.

In a 32-bit ELF executable, the e_entry field (at offset 24 in the ELF header) already represents the linear address of the entry point (start in your case) if you linked the kernel correctly to load at IMAGE_PMODE_BASE. Adding the base address again will point you to an invalid memory location, which explains why the call fails.

Key Fixes to Get It Working

1. Fix Your Linker Script

Your current linker script only sets ENTRY(start)—it doesn't specify where the kernel should be loaded in memory. This means ld will use a default base address (like 0x08048000), which almost certainly doesn't match your IMAGE_PMODE_BASE.

Update your linker script to explicitly set the load address to IMAGE_PMODE_BASE (replace with your actual base address, e.g., 0x100000 for 1MB):

ENTRY(start)
SECTIONS {
    . = IMAGE_PMODE_BASE;  /* Set base address to where you'll load the kernel */
    .text ALIGN(4) : { *(.text) }  /* Code section, aligned to 4 bytes */
    .data ALIGN(4) : { *(.data) }  /* Initialized data */
    .bss ALIGN(4) : {              /* Uninitialized data */
        __bss_start = .;
        *(.bss)
        *(COMMON)
        __bss_end = .;
    }
}

This ensures the linker sets e_entry to the correct linear address (e.g., IMAGE_PMODE_BASE + offset of start if start is at the top of .text).

2. Correct the Entry Point Call in Your Bootloader

Once the linker script is fixed, you can directly use the e_entry value from the ELF header as the call address. Assuming ebx points to the start of the ELF file in memory (i.e., IMAGE_PMODE_BASE), simplify your code to:

; ebx = IMAGE_PMODE_BASE (start of ELF file in memory)
mov eax, dword[ebx + 24]  ; Load e_entry from ELF header offset 24
call eax                  ; Call the kernel entry point (start)

No need to add IMAGE_PMODE_BASE again—e_entry is already the full linear address.

3. Ensure Proper Stack Setup Before Calling C Code

Your kmain function uses a local variable (int a = 5), which requires a valid stack. If you haven't set up the stack pointer (ESP) in 32-bit protected mode, the C code will crash when trying to access the stack.

Add this code right after entering 32-bit protected mode (before calling the kernel entry point):

mov esp, 0x90000  ; Set stack to a safe location (e.g., 576KB mark)
                  ; Make sure this doesn't overlap with your kernel's loaded address

4. Verify Protected Mode Segment Configuration

Double-check your GDT (Global Descriptor Table) setup. Your code segment descriptor should allow full access to the 4GB address space, with the correct privilege level (0, since this is kernel code). A minimal valid GDT might look like:

gdt_start:
gdt_null:  ; Mandatory null descriptor
    dd 0x0
    dd 0x0
gdt_code:  ; Kernel code segment
    dw 0xFFFF       ; Limit (low 16 bits)
    dw 0x0          ; Base (low 16 bits)
    db 0x0          ; Base (middle 8 bits)
    db 0x9A         ; Access: Present, Ring 0, Code segment, Readable
    db 0xCF         ; Flags: 4KB granularity, 32-bit mode, Limit (high 8 bits)
    db 0x0          ; Base (high 8 bits)
gdt_data:  ; Kernel data segment
    dw 0xFFFF
    dw 0x0
    db 0x0
    db 0x92         ; Access: Present, Ring 0, Data segment, Writable
    db 0xCF
    db 0x0
gdt_end:

gdt_descriptor:
    dw gdt_end - gdt_start - 1  ; GDT size
    dd gdt_start                ; GDT base address

When entering protected mode, load the GDTR and set CS to the code segment selector (e.g., 0x08), and DS, ES, SS to the data segment selector (e.g., 0x10).

Final Checks

  • Recompile all components with the updated linker script:
    cc -m32 -nostdlib -nostdinc -fno-builtin -fno-stack-protector -c -o kmain.o kmain.c
    nasm -f elf loader.asm -o loader.o
    ld -m elf_i386 -T link.ld -o kernel loader.o kmain.o
    
  • Confirm your bootloader correctly loads the entire ELF file into memory at IMAGE_PMODE_BASE (not just the header—make sure you parse the program headers to load all segments to their correct addresses).

With these fixes, your bootloader should correctly call start, which in turn calls kmain without issues.

内容的提问来源于stack exchange,提问作者snehm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:03:11