wrong memory locations when debugging in qemu with gdb

后端 未结 1 2011
情话喂你
情话喂你 2021-01-24 18:19

I\'m writing a little kernel in assembler. I\'m running it in QEMU and have some problems with some bugs. Now I want to debug the kernel with dbg. So I assembled it like so:

相关标签:
1条回答
  • 2021-01-24 19:03

    Explanation

    • qemu-system-i386 loads the first byte of an x86 boot sector image file at address 0x7c00 at run time.
    • Your ELF files (myos.elf, myos.sym) mistakenly inform GDB that the code would be loaded at address 0. Thus GDB thinks welcome is at 0x1e while it's actually at 0x7c1e.
    • Adding 0x7c00 to all addresses in GDB would work but is clumsy: x/32xb (welcome + 0x7c00)
    • A better solution is to create an ELF file with the right addresses.

    Solution

    boot.asm

    ; 'boot.asm'
    ; loaded by BIOS
    
    [bits 16]
    
    global main
    main:
    mov di, welcome
    print_welcome:
    mov ah, 0x0e
    mov al, [di]
    int 0x10
    inc di
    cmp byte [di], 0
    jne print_welcome
    hlt
    
    db "XXXXXXXXXXXXXX" ; some padding to make welcome appear at 0x1e
    welcome: db "System started. Happy hacking!", 10, 0
    
    ; x86 boot sector padding and signature
    ; NOTE: intentionally commented out. Will be added by linker script
    ;times 510 - ($ - $$) db 0x00
    ;db 0x55, 0xAA
    

    x86-boot.ld

    ENTRY(main);
    SECTIONS
    {
        . = 0x7C00;
        .text : AT(0x7C00)
        {
            _text = .;
            *(.text);
            _text_end = .;
        }
        .data :
        {
            _data = .;
            *(.bss);
            *(.bss*);
            *(.data);
            *(.rodata*);
            *(COMMON)
            _data_end = .;
        }
        .sig : AT(0x7DFE)
        {
            SHORT(0xaa55);
        }
        /DISCARD/ :
        {
            *(.note*);
            *(.iplt*);
            *(.igot*);
            *(.rel*);
            *(.comment);
    /* add any unwanted sections spewed out by your version of gcc and flags here */
        }
    }
    

    Build the code with:

    nasm -g -f elf -F dwarf boot.asm -o boot.o
    cc -nostdlib -m32 -T x86-boot.ld -Wl,--build-id=none  boot.o -o boot
    objcopy -O binary boot boot.good.bin
    

    dump-welcome.gdb

    target remote localhost:1234
    symbol-file boot
    monitor system_reset
    # run until hlt instruction, address obtained through disassembly
    until *0x7c0f
    x/32xb welcome
    
    monitor quit
    disconnect
    quit
    

    Sample session:

    $ qemu-system-x86_64 -s -S boot.good.bin &
    $ gdb -q -x dump-welcome.gdb
    0x0000fff0 in ?? ()
    main () at boot.asm:16
    16  hlt
    0x7c1e :   0x53    0x79    0x73    0x74    0x65    0x6d    0x20    0x73
    0x7c26: 0x74    0x61    0x72    0x74    0x65    0x64    0x2e    0x20
    0x7c2e: 0x48    0x61    0x70    0x70    0x79    0x20    0x68    0x61
    0x7c36: 0x63    0x6b    0x69    0x6e    0x67    0x21    0x0a    0x00
    

    Thought Process

    Most of the 32 bytes you dumped have values ≥ 0x80, i.e. they're not printable ASCII characters. This raises the question: Am I really dumping the right address?

    The hex dump of your welcome message should be:

    $ python -c 's = "System started. Happy hacking!"; print [hex(ord(x)) for x in s ]'
    ['0x53', '0x79', '0x73', '0x74', '0x65', '0x6d', '0x20', '0x73', '0x74', '0x61', '0x72', '0x74', '0x65', '0x64', '0x2e', '0x20', '0x48', '0x61', '0x70', '0x70', '0x79', '0x20', '0x68', '0x61', '0x63', '0x6b', '0x69', '0x6e', '0x67', '0x21']
    

    Using GDB to search for the welcome message in memory would have revealed the right address as well:

    (gdb) find 0, 0xffff, 'S', 'y', 's', 't'
    0x7c1e
    

    Further Reading

    • GNU LD: Basic Linker Script Concepts: see discussion on LMA vs. VMA
    • Real mode in C with gcc : writing a bootloader: source of the linker script above. Shows some cool GNU toolchain tricks for x86 real mode development.
    0 讨论(0)
提交回复
热议问题