gpt4 book ai didi

assembly - 链接两个或多个程序集文件

转载 作者:行者123 更新时间:2023-12-02 19:22:12 24 4
gpt4 key购买 nike

我正在开发一个简单且小型的 64 位操作系统。到目前为止,我一直使用单个文件并使用 NASM 对其进行编译:

nasm -f bin os.asm -o os.bin

然后使用 qemu 测试 .bin 文件。
现在我需要在我的 os.bin 文件中使用多个文件。我插入了这一行:

extern helper_func

然后在代码中调用它。在另一个 .asm 文件中,我创建了这个函数或过程。问题是bin格式不支持extern,所以我尝试使用ELF格式创建.obj文件,然后将它们与gcc链接:

gcc -m32 -nostdlib -nodefaultlibs -lgcc os.obj helper.obj -t linker.ld

使用此链接器文件:

ENTRY(_start)

SECTIONS
{
. = 0x7C00;

.text :
{
*(.text);
}
}

但是当我尝试运行已创建的 .bin 时,qemu 无法识别该文件。我做错了什么?

(我使用了 gcc,因为我计划将来使用 C 代码)

实际上,我什至不知道 gcc 中所有标志的作用;我是从网上复制的XD。

这是我到目前为止所做的:

nasm -f elf os.asm -o os.obj
nasm -f elf helper.asm -o helper.obj
gcc -m32 -nostdlib -nodefaultlibs -lgcc os.obj helper.obj -t linker.ld -o myos.bin
objcopy --input-target=elf32-little --output-target=binary myos.bin myos.bin.new
qemu-system-x86_64 myos.bin.new

这些编译都没有错误。但是当我运行 qemu 时我得到这个:

enter image description here

os.asm:

[bits 16]

section .text

global _start

_start:

; Zero segment
cli
jmp 0x0000:.zero_seg
.zero_seg:
xor ax, ax
mov ss, ax
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov sp, _start
cld
sti

; Reset disk
call reset_disk

; Load disk sectors
mov al, 2 ; sectors to read
mov cl, 2 ; start sector
mov bx, second_sector ; offset to load
call read_disk

; Enable A20 line
call enable_a20

jmp second_sector

_end1:
jmp $

%include "liba/disk.asm"
%include "liba/a20.asm"

; padding and magic number
times 510-($-$$) db 0
dw 0xaa55

second_sector:

call check_long
call switch_long

_hang:
jmp $

%include "liba/long.asm"
%include "liba/gdt.asm"

[bits 64]

extern helper_func

long_mode:

jmp kernel_code

_end2:
jmp $

times 512-($-$$-512) db 0

kernel_code:

; two byte
call helper_func

helper.asm:

[bits 64]

section .text

global helper_func

helper_func:

kernel_end:
hlt
jmp .kernel_end

ret

在 os.asm 中我使用了这个库:

磁盘.asm:

read_disk:
pusha

mov ah, 0x02
mov dl, 0x80 ; 0x00 Floppy/FlashDrive -- 0x80 HardDisk
mov ch, 0 ; cylinder
mov dh, 0 ; head

int 0x13

jc .disk_err
popa
ret

.disk_err:
jmp $

reset_disk:
xor ax, ax
mov bx, second_sector
mov dl, 0x80
int 0x13
ret

a20.asm:

test_a20:
pusha

mov ax, [0x7dfe]

push bx
mov bx, 0xffff
mov es, bx
pop bx

mov bx, 0x7e0e

mov dx, [es:bx]

cmp ax, dx
je .cont

popa
mov ax, 1
ret

.cont:
mov ax, [0x7dff]

push bx
mov bx, 0xffff
mov es, bx
pop bx

mov bx, 0x7e0f
mov dx, [es:bx]

cmp ax, dx
je .exit

popa
mov ax, 1
ret

.exit:
popa
xor ax, ax
ret

enable_a20:
pusha

;BIOS
mov ax, 0x2401
int 0x15

call test_a20
cmp ax, 1
je .done

;Keyboard
sti

call wait_c
mov al, 0xad
out 0x64, al

call wait_c
mov al, 0xd0
out 0x64, al

call wait_d
in al, 0x60
push ax

call wait_d
mov al, 0xd1
out 0x64, al

call wait_c
pop ax
or al, 2
out 0x60, al

call wait_c
mov al, 0xae
out 0x64, al

call wait_c

sti

call test_a20
cmp ax, 1
je .done

;FastA20
in al, 0x92
or al, 2
out 0x92, al

call test_a20
cmp al, 1
je .done

jmp $

.done:
popa
ret

wait_c:
in al, 0x64
test al, 2

jnz wait_c
ret

wait_d:
in al, 0x64
test al, 1

jz wait_d
ret

长.asm:

enable_long:
cli

call check_long

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

mov dword [edi], 0x2003
add edi, 0x1000
mov dword [edi], 0x3003
add edi, 0x1000
mov dword [edi], 0x4003
add edi, 0x1000

mov dword ebx, 3
mov ecx, 512

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

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
or eax, 1 << 0
mov cr0, eax

ret

switch_long:

call enable_long

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

ret

check_long:
pusha

pushfd
pop eax
mov ecx, eax

xor eax, 1 << 21

push eax
popfd

pushfd
pop eax

xor eax, ecx
jz .done

mov eax, 0x80000000
cpuid
cmp eax, 0x80000001
jb .done

mov eax, 0x80000001
cpuid
test edx, 1 << 29
jz .done

popa
ret

.done:
popa
jmp $

gdt.asm:

GDT:
.Null: equ $ - GDT
dw 0
dw 0
db 0
db 0
db 0
db 0

.Code: equ $ - GDT
dw 0
dw 0
db 0
db 10011000b
db 00100000b
db 0

.Data: equ $ -GDT
dw 0
dw 0
db 0
db 10000000b
db 0
db 0

.Pointer:
dw $ - GDT - 1
dq GDT

最佳答案

我对您正在构建的环境一无所知。我强烈建议构建一个 x86-64 cross compiler .

我可以对一些可能出现的问题做出合理的猜测。使用GCC链接会生成.note.gnu.build-id节并将其放在二进制文件中所有其他节之前。这会将磁盘启动签名 ( 0xaa55 ) 移动到第一个扇区最后 2 个字节之外的位置。这是我认为您的磁盘不会被识别为可引导的唯一原因,这在您的屏幕截图中似乎是这种情况。您需要添加-Wl,build-id=none添加到您的 GCC 链接选项以防止生成此部分。

要按照您的方式构建自定义 64 位引导加载程序,您应该将所有内容生成为 64 位对象而不是 32 位对象。使用-m64使用 GCC 编译/链接时,以及 -felf64当使用 NASM 进行汇编时(--64 如果使用 as GNU 汇编器进行汇编)。

确保您没有使用 -static 生成可重定位代码我建议消除 .eh_frame带有选项 -fno-asynchronous-unwind-tables 的部分.

链接器脚本使用 -T 传递选项,而不是-t选项。在您的链接选项中,您有 -t linker.ld它应该是 -T linker.ld

您可以通过让它确定源对象/可执行文件类型来简化 OBJCOPY 参数。你可以做objcopy -O binary myos.bin myos.bin.new相反。

我认为您应该使用的命令可能如下所示:

nasm -f elf64 os.asm -o os.obj
nasm -f elf64 helper.asm -o helper.obj
gcc -m64 -wl,--build-id=none -static -fno-asynchronous-unwind-tables \
-nostdlib -nodefaultlibs -lgcc os.obj helper.obj -T linker.ld -o myos.bin
objcopy -O binary myos.bin myos.bin.new
<小时/>

观察和注释

  • disk.asm您对驱动器号进行硬编码。当引导加载程序首次启动时,您可以重用/保存DL寄存器的值。 BIOS 会在DL 中为您传递启动驱动器号。如果您重复使用该值,则无需根据启动的驱动器类型(软盘、硬盘驱动器等)更改代码。

  • 我有一些General Bootloader Tips这可能很有值(value)。

  • 将来当您开始编译 C 文件时,我建议使用以下选项:

    gcc -m64 -ffreestanding -mcmodel=kernel -mno-red-zone \
    -mno-mmx -mno-sse -mno-sse2 -c filename.c -o filename.o

关于assembly - 链接两个或多个程序集文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56409250/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com