从 x64 系统交叉编译 c 内核到 x32 二进制文件
Cross-compiling c kernel from x64 system to x32 binary
我正在尝试创建一个用于教育目的的 OS 内核。
使用 this 指南,我在 fasm 中编写了一个引导加载程序:
use16
org 0x7c00
start:
jmp kernel_start
KERNEL_OFFSET equ 0x1000
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0000
db 0x00
db 10011010b
db 11001111b
db 0x00
gdt_data:
dw 0xffff
dw 0x0000
db 0x00
db 10010010b
db 11001111b
db 0x00
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
read_disk:
pusha
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
jc .disk_error
pop dx
cmp dh, al
jne .disk_error
jmp .done
.disk_error:
mov bx, ERROR_MSG
call write_string
stc
.done:
popa
ret
write_string:
pusha
mov ah, 0x0e
.repeat:
lodsb
cmp al, 0x00
je .done
int 0x10
jmp .repeat
.done:
popa
ret
kernel_start:
mov [BOOT_DRIVE], dl
cli
mov ax, cs
mov ss, ax
mov sp, start
mov bp, start
sti
mov ds, ax
mov es, ax
mov si, BOOT_MSG
call write_string
mov dh, 15
mov dl, [BOOT_DRIVE]
mov bx, KERNEL_OFFSET
call read_disk
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x01
mov cr0, eax
jmp CODE_SEG:kernel_launch
use32
kernel_launch:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, start
mov esp, start
call KERNEL_OFFSET
jmp $
variables:
BOOT_DRIVE db 0
KERNEL_LEN file "kernel_info.bb": 0x0, 1
BOOT_MSG db "Booted in real mode...", 0x0d, 0x0a, 0
ERROR_MSG db "Could not load second boot loader!", 0x0d, 0x0a, 0
magic_numbers:
times 510-($-$$) db 0
dw 0xaa55
我用 fasm loader.asm
编译了它并用 dd
制作了一个 iso。它可以在 OracleVM 中很好地打印消息。
现在是时候将它与 c 部分结合起来了。但问题是:我无法在目标 (x32) 设备上构建。我被迫使用 x64。
根据 this 手册,我找到了一种编译 elf
可执行文件和 link 使用多重启动的方法。但我不想使用多重引导标准 - 我宁愿使用自己编写的引导加载程序(上面那个)。
我应该使用哪些工具、参数和配置来将 c 代码编译为 x32,link 它带有汇编程序部分并创建一个二进制文件?
或者,也许我应该分别编译 assempler-part 二进制文件和 c-part,然后将它们一个接一个地写入磁盘映像?
到目前为止,我在互联网上找不到任何答案。 是否可以将这两个内核部分放在一起?
这是我的 C 代码:
void main() {
char* video_memory = 0xb8000;
*video_memory = ’X’;
}
更新:
我尝试了以下命令:
$nasm loader.asm -f bin -o loader.bin
$gcc -m32 -fno-pie -ffreestanding -c kernel.c -o kernel.o
$ld -m -elf_i386 -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary
$cat loader.bin kernel.bin > os-image
将引导加载程序和内核编译为二进制文件,然后将它们写入磁盘映像。引导加载程序按预期工作,但没有显示来自内核的消息。
我发现了一个错误(以防有人遇到同样的问题),构建脚本有问题,我应该使用:
$ gcc -m32 -ffreestanding -c kernel.c -o kernel.o
而不是:
$ gcc -m32 -fno-pie -ffreestanding -c kernel.c -o kernel.o
(不需要 -fno-pie
标志)。
还有命令:
$ ld -m -elf_i386 -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary
应该分成两部分:
$ ld -m -elf_i386 -o kernel.elf -Ttext 0x1000 kernel.o
$ objcopy -O binary kernel.elf kernel.bin
就是这样!
我正在尝试创建一个用于教育目的的 OS 内核。
使用 this 指南,我在 fasm 中编写了一个引导加载程序:
use16
org 0x7c00
start:
jmp kernel_start
KERNEL_OFFSET equ 0x1000
gdt_start:
gdt_null:
dd 0x0
dd 0x0
gdt_code:
dw 0xffff
dw 0x0000
db 0x00
db 10011010b
db 11001111b
db 0x00
gdt_data:
dw 0xffff
dw 0x0000
db 0x00
db 10010010b
db 11001111b
db 0x00
gdt_end:
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
read_disk:
pusha
push dx
mov ah, 0x02
mov al, dh
mov ch, 0x00
mov dh, 0x00
mov cl, 0x02
int 0x13
jc .disk_error
pop dx
cmp dh, al
jne .disk_error
jmp .done
.disk_error:
mov bx, ERROR_MSG
call write_string
stc
.done:
popa
ret
write_string:
pusha
mov ah, 0x0e
.repeat:
lodsb
cmp al, 0x00
je .done
int 0x10
jmp .repeat
.done:
popa
ret
kernel_start:
mov [BOOT_DRIVE], dl
cli
mov ax, cs
mov ss, ax
mov sp, start
mov bp, start
sti
mov ds, ax
mov es, ax
mov si, BOOT_MSG
call write_string
mov dh, 15
mov dl, [BOOT_DRIVE]
mov bx, KERNEL_OFFSET
call read_disk
cli
lgdt [gdt_descriptor]
mov eax, cr0
or eax, 0x01
mov cr0, eax
jmp CODE_SEG:kernel_launch
use32
kernel_launch:
mov ax, DATA_SEG
mov ds, ax
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, start
mov esp, start
call KERNEL_OFFSET
jmp $
variables:
BOOT_DRIVE db 0
KERNEL_LEN file "kernel_info.bb": 0x0, 1
BOOT_MSG db "Booted in real mode...", 0x0d, 0x0a, 0
ERROR_MSG db "Could not load second boot loader!", 0x0d, 0x0a, 0
magic_numbers:
times 510-($-$$) db 0
dw 0xaa55
我用 fasm loader.asm
编译了它并用 dd
制作了一个 iso。它可以在 OracleVM 中很好地打印消息。
现在是时候将它与 c 部分结合起来了。但问题是:我无法在目标 (x32) 设备上构建。我被迫使用 x64。
根据 this 手册,我找到了一种编译 elf
可执行文件和 link 使用多重启动的方法。但我不想使用多重引导标准 - 我宁愿使用自己编写的引导加载程序(上面那个)。
我应该使用哪些工具、参数和配置来将 c 代码编译为 x32,link 它带有汇编程序部分并创建一个二进制文件?
或者,也许我应该分别编译 assempler-part 二进制文件和 c-part,然后将它们一个接一个地写入磁盘映像?
到目前为止,我在互联网上找不到任何答案。 是否可以将这两个内核部分放在一起?
这是我的 C 代码:
void main() {
char* video_memory = 0xb8000;
*video_memory = ’X’;
}
更新: 我尝试了以下命令:
$nasm loader.asm -f bin -o loader.bin
$gcc -m32 -fno-pie -ffreestanding -c kernel.c -o kernel.o
$ld -m -elf_i386 -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary
$cat loader.bin kernel.bin > os-image
将引导加载程序和内核编译为二进制文件,然后将它们写入磁盘映像。引导加载程序按预期工作,但没有显示来自内核的消息。
我发现了一个错误(以防有人遇到同样的问题),构建脚本有问题,我应该使用:
$ gcc -m32 -ffreestanding -c kernel.c -o kernel.o
而不是:
$ gcc -m32 -fno-pie -ffreestanding -c kernel.c -o kernel.o
(不需要 -fno-pie
标志)。
还有命令:
$ ld -m -elf_i386 -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary
应该分成两部分:
$ ld -m -elf_i386 -o kernel.elf -Ttext 0x1000 kernel.o
$ objcopy -O binary kernel.elf kernel.bin
就是这样!