简体   繁体   中英

JMP not working

Okay, so I've been trying to make a two-step bootloader in assembly/C but I haven't been able to get the JMP working. At first I thought the read was failing, but, after the following test I ruled that out:

__asm__ __volatile__(
    "xorw %ax, %ax;"
    "movw %ax, %ds;"
    "movw %ax, %es;"
    "movb $0x02, %ah;"
    "movb $0x01, %al;"
    "movw $0x7E00, %bx;"
    "movw $0x0003, %cx;"
    "xorb %dh, %dh;"
    "int $0x13;"
    "movb 0x7E00, %al;"
    "movb $0x0e, %ah;"
    "int $0x10;"
    //"jmp 0x7E00"
);

This printed 'f' as expected (the first byte of the sector is 0x66 which is the ASCII code for 'f') proving that the read is successful and the jmp is the problem. This is my code:

__asm__(".code16\n");
__asm__(".code16gcc\n");
__asm__("jmpl $0x0000, $main\n");
void main(){
    __asm__ __volatile__(
        "xorw %ax, %ax;"
        "movw %ax, %ds;"
        "movw %ax, %es;"
        "movb $0x02, %ah;"
        "movb $0x01, %al;"
        "movw $0x7E00, %bx;"
        "movw $0x0003, %cx;"
        "xorb %dh, %dh;"
        "int $0x13;"
        "jmp $0x200;"
    );
}

When run, my program simply hangs, this means that the program is probably jumping to the wrong location in memory. By the way, I am obviously running this in real mode under VMWare player. I am compiling this with the following commands:

gcc -c -0s -march=i686 -ffreestanding -Wall -Werror boot.c -o boot.o
ld -static -Ttest.ld -nostdlib --nmagic -o boot.elf boot.o --no-check-sections
objcopy -0 binary boot.elf boot.bin

and this is test.ld :

ENTRY(main);
SECTIONS
{
    . = 0x7C00;
    .text : AT(0x7C00)
    {
        *(.test);
    }
    .sig : AT(0x7DFE)
    {
        SHORT(0xAA55);
    }
}

Note: I have confirmed this is not a problem with the inline asm - I have tried a pure assembly implementation too with the same results - the only reason I am using C is because I plan on expanding this a bit and I am much more comfortable with C loops and functions...

EDIT: I've uploaded the first three sectors of my floppy drive here

EDIT 2: I have been unable to get my boot loader working using any of the suggestions and, based on advice from @RossRidge I have written an assembly version of the same program and a simple assembly program to echo input. Sadly these aren't working either..

Bootloader:

org 0x7c00
xor ax, ax
mov ds, ax
mov es, ax
mov ah, 0x02
mov al, 0x01
mov bx, 0x7E00
mov cx, 0x0003
xor dh, dh
int 0x13
jmp 0x7E00

Program in sector 3:

xor ax, ax
int 0x16
mov ah, 0xe
int 0x10

These are both compiled with: nasm Linux/boot.S -o Linux/asm.bin and behave the same as their C counterparts..

I am pretty sure your assembler is generating the wrong jump offset, it's probably interpreting the 0x7e00 as relative in the current text section, but that's mapped at 0x7c00 by the linker script so your jump probably goes to 0x7c00+0x7e00=0xfa00 instead. As an ugly workaround you could try jmp 0x200 instead or use an indirect jump to hide it from your tools such as mov $0x7e00, %ax; jmp *%ax mov $0x7e00, %ax; jmp *%ax . Alternatively jmp .text+0x200 could also work.

Also note that writing 16 bit asm in a 32 bit C compiler will generate wrong code, which is also hinted by the first byte of the loaded sector being 0x66 which is the operand size override prefix. Since the compiler assumes 32 bit mode, it will generate your 16 bit code with prefixes, which when run in 16 bit mode will switch back to 32 bits. In general, it's not a good idea to abuse inline asm for such purpose, you should use a separate asm file and make sure you tell your assembler that the code is intended for 16 bit real mode.

PS: learn to use a debugger.


Update: The following code when assembled using nasm boot.asm -o boot.bin works fine in qemu and bochs :

org 0x7c00
xor ax, ax
mov ds, ax
mov es, ax
mov ah, 0x02
mov al, 0x01
mov bx, 0x7E00
mov cx, 0x0003
xor dh, dh
int 0x13
jmp 0x7E00

times 510-($-$$) db 0
dw 0xaa55
; second sector
times 512 db 0
; Program in sector 3:
xor ax, ax
int 0x16
mov ah, 0xe
int 0x10
jmp $
times 1536-($-$$) db 0

You can download an image here (limited offer ;)).

I have written many boot loaders.

There needs to be two(2) separate executables,

1) the boot loader
2) the main code

so the loaded code (the main program) can be updated without doing anything to the boot loader.

The boot loader, when done needs to jump to a known location.

The main program needs to place a jump instruction at the known location, that jumps to a function in the librt library. (usually start())

start() will set I/O, heap, etc and call main()

Both the linker command file for the boot loader and the linker command file for the main program must agreed on the address of the known location

The known location is usually the only thing in a unique section of both linker command files.

The boot loader must be smart enough to place all the parts of the main program in the right areas in memory.

It is best if the main program is in motorola S1 (or similar) format rather than a raw .elf or .coff format; otherwise the boot loader can get very big very quickly.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM