Search code examples
assemblylinkernasmbootgnu-assembler

GNU GAS: Label is not relatively referenced


I am writing a little bootsector for learning purpose.

Here is boot.S

.code16
.text
    movw    $0xB800, %ax    /* 0xB000 is the text screen video memory */
    movw    %ax, %es       /* set it as the %es segment */

    movb    label, %al
    movb    %al, %es:0x0    /* screen[0] = 'A' */
    movb    $0x07, %es:0x1  /* white on black */
    jmp .

label:  
    .byte 'A

    .=510
    .byte 0x55
    .byte 0xAA

and here is the Makefile I use to compile it to a raw binary file

hdd.img: boot.S
    as $< -o boot.o
    ld --oformat binary -Ttext 0x7c00 boot.o -o hdd.img

I face the problem that the label is not relatively referenced: when loading the byte 'A', it uses the absolute address, say 0x7c14).

So I cannot relocate this bootsector at runtime (for example by copying it further in memory). It would be better if the label was simply referenced trough an offset from the current instruction.

Is it possible to do this ?


Solution

  • Of course it is possible to relocate strings.

    First of all, your -Ttext 0x7C00 is correct. Do not change it. At the beginning of your bootloader you should zero the segment registers (%ds, %es, %fs, %gs and %ss):

    mov $0, %ax         // xor %ax, %ax would be more space efficient
    mov %ax, %ds
    mov %ax, %es
    mov %ax, %fs
    mov %ax, %gs
    mov %ax, %ss
    

    Next, you should set up a stack. Read: osdev wiki about stacks

    Now to your question: It is usual to address strings using segmentation in the form of %ds:%si. When relocating the bootloader, just change %ds properly.
    Assuming you call your string label:

    mov $label, %si     // Always prefix a label address with a $
    

    You can get a character from a string using the lodsb instruction (LOaD String Byte, which automatically increments %si for you:

    lodsb               // Character is stored in `%al` now
    

    Another recommendation is not to address the video memory manually. Use BIOS Interrupt 0x10.

    Good luck with your bootloader!