Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking two or more assembly files

I am developing a simple and small 64bit OS. Until now I've used a single file and compile it with NASM:

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

Then tested the .bin file with qemu.
Now I need to use multiple files so in my os.bin file. I've inserted this line:

extern helper_func

Then called it in the code. In another .asm file i've created this function or procedure. The problem is that the bin format does not support extern, so I've tried to use the ELF format to create the .obj files and then link them with gcc:

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

with this linker file:

ENTRY(_start)

SECTIONS
{
    . = 0x7C00;

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

But when I try to run the .bin that has been created, qemu does not recognize the file. What have I done wrong?

(I've used gcc because I plan to use C code in the future)

Actually, I don't even know what all the flags do in gcc; I've copied them from the internet XD.

This is what i've done so far:

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

No errors from any of those compilation. But when i run qemu i get this:

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

Inside os.asm i've used this libs:

disk.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

long.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
like image 469
Mimmo Avatar asked Jun 01 '19 18:06

Mimmo


1 Answers

I don't know anything about the environment you are building with. I strongly recommend building an x86-64 cross compiler.

I can make a reasonable guess at some of the possible problems. Using GCC to link will generate a .note.gnu.build-id section and place it before all other sections in your binary. This will have the effect of moving your disk boot signature (0xaa55) to a location beyond the last 2 bytes in the first sector. It is the only reason I can think that your disk wouldn't be identified as bootable which appears to be the case in your screenshots. You need to add -Wl,build-id=none to your GCC link options to prevent this section from being generated.

To build a custom 64-bit bootloader in the fashion you are you should be generating everything as 64-bit objects and not 32-bit objects. Use -m64 when compiling/linking with GCC, and -felf64 when assembling with NASM (--64 if assembling with as GNU Assembler).

Ensure that you aren't generating relocatable code with -static and I recommend eliminating the .eh_frame sections with the option -fno-asynchronous-unwind-tables.

The linker script is passed using the -T option, not the -t option. In your linking options you have-t linker.ldand it should be -T linker.ld

You can simplify OBJCOPY arguments by letting it determine the source object/executable type. You can do objcopy -O binary myos.bin myos.bin.new instead.

The commands that I think you should use could look like:

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

Observations and Notes

  • In disk.asm you hard code the drive number. You can reuse/save the value of the DL register when your bootloader first starts. The BIOS passes the boot drive number in DL for you. If you reuse that value you don't need to change your code depending on the drive type you boot as (floppy, hard drive etc.)

  • I have some General Bootloader Tips that may be of value.

  • In the future when you start compiling C files I recommend these options:

    gcc -m64 -ffreestanding -mcmodel=kernel -mno-red-zone \
        -mno-mmx -mno-sse -mno-sse2 -c filename.c -o filename.o
    
like image 64
Michael Petch Avatar answered Sep 22 '22 14:09

Michael Petch