Search code examples
assemblyldbootstrappingatt

How to locate a variable correctly in AT&T assembly?


I am practicing to write a bootstrap using assembly (in AT&T syntax, and gnu/gas). The small program is assembled and linked, then copied to the first sector of a virtual disk. BIOS will load it into 0000:7c00, and here comes the problem. The call hello will be translated from call 0010 to call 7c10 during running. But the movw $message, %as doesn't get relocated. The ax is still 0026, not 7c26. The result is that I can't make the Hello World on the screen. Instead, some random data at 0000:0026 will be displayed on the screen.

How can I make it correct during booting? Should I change the asm source code using some directives? Or should I change my link script?

Thank you!

.text
.global     _start
.code16

_start:
movw    %cs, %ax
movw    %ax, %ds
movw    %ax, %es
call    hello
jmp     .

.org    0x10

hello:
movw    $message, %ax
movw    %ax, %bp
movw    $13, %cx
movw    $0x1301, %ax
movw    $0x000c, %bx
movb    $0, %dl
int     $0x10
ret

message:    
.ascii  "Hello, World!"

.org    0x01fe
.byte   0x55
.byte   0xaa

I use the following assemble and link scripts

as -o boot.o boot.s  
    //generate object code

ld -Ttext 0x0 -e _start -s -o boot.out boot.o  
    //relocate .text to 0x0
    //entry is _start

objcopy -O binary -j .text boot.out boot
    //copy .text section to boot

vboxmanage convertfromraw boot boot.vdi --format VDI
    //create vdi for virtual box

Solution

  • I see that the main problem is in the way you are compiling your code.

    The correct steps to get your code working should be:

    as boot.s -c -o boot.o
    ld --oformat binary --Ttext 0x7C00 -o boot.bin boot.o
    

    Please note, as others have said, that I'm passing the --Ttext 0x7C00 parameter to ld, to force it relocating your code at that address.

    As an additional suggestion, try to structure your code like this:

    .text
    .global     _start
    .code16
    
    _start:
    jmp stage1_start
    
    ...
    
    stage1_start:
    
    <your bootloader here>
    

    Note that this is compiant with how BIOS code looks at hard drives, since after 2 bytes (the length of the first jump instruction) you should place the Disk Description Table.

    Additionally, you can refactor your last instructions in a more as-like syntax like this:

    . = _start + 0x0200 - 2
    .short 0x0AA55
    

    Where the . variable is the location counter. Look at this page for further information on how this counter works (in the context of ld, not as).

    Hope this helps!