assemblyx86objdumpbochs

Why same lgdt opCode display difference on objdump and bochs


I write boot.asm kernel.asm main.c three file. kernel.asm and main.c compile into kernel file. boot.asm loader kernel into 0x10000.

the question is kernel file, the code 0f 01 15 22 00 00 00, on objdump display lgdtl 0x22, but when i run it on bochs, display lgdt ds:[di]

here are kernel.asm

global _start:
jmp _start
;====== gdt start
LABEL_GDT:      dd  0,0
LABEL_DESC_CODE32:
    dw 0xFFFF       ;segment limit first 0-15 bits
    dw 0x0000       ;base first 0-15 bits
    db 0x00         ;base 16-23 bits
    db 0b10011010   ;access byte
    db 0b11001111   ;high 4 bits (flags) low 4 bits (limit 4 last bits)(limit is 20 bit wide)
    db 0x00         ;base 24-31 bits
LABEL_DESC_DATA32:
    dw 0xFFFF       ;segment limit first 0-15 bits
    dw 0x0000       ;base first 0-15 bits
    db 0x00         ;base 16-23 bits
    db 0b10010010   ;access byte
    db 0b11001111   ;high 4 bits (flags) low 4 bits (limit 4 last bits)(limit is 20 bit wide)
    db 0x00         ;base 24-31 bits
LABEL_DESC_VIDEO:
    dw 0xFFFF       ;segment limit first 0-15 bits
    dw 0x8000       ;base first 0-15 bits
    db 0x0B         ;base 16-23 bits
    db 0b10010010           ;access byte
    db 0b11001111   ;high 4 bits (flags) low 4 bits (limit 4 last bits)(limit is 20 bit wide)
    db 0x00         ;base 24-31 bits

LABEL_GDT_END:

GdtPtr  dw  LABEL_GDT_END - LABEL_GDT - 1
    dd  LABEL_GDT

SelectorCode    equ LABEL_DESC_CODE32 - LABEL_GDT
SelectorData    equ LABEL_DESC_DATA32 - LABEL_GDT

SelectorVideo   equ LABEL_DESC_VIDEO - LABEL_GDT
;======gdt end
_start:
Kernel_Start:
    mov ax, cs
    mov ds, ax
    mov es, ax
    mov ss, ax

    lgdt [GdtPtr]
    cli

    mov eax,    cr0
    or  eax,    1
    mov cr0,    eax

    jmp dword SelectorCode:Kernel_Start32

;kernel entry protected
[BITS 32]
extern main
Kernel_Start32:
    mov ax, SelectorVideo
    mov gs, ax          

    mov edi, (80 * 11 + 10) * 2 
    mov ah, 0Ch         
    mov al, 'P'
    mov [gs:edi], ax

    call main
    jmp $

main.c

int main() {
    char *video = (char*)0x8b00;
    int offset = 1440*10;
    for (int i=0;i<20;i++) {
        *(video+offset+i*4+0) = 0xff;
        *(video+offset+i*4+1) = 0x00;
        *(video+offset+i*4+2) = 0x00;
        *(video+offset+i*4+2) = 0x00;
    }

    while (1) {
    };

    return 0;
}

compile command is

gcc -c main.c -o main.o -std=c99 -m32
nasm kernel.asm -f elf -o kernel.o
ld kernel.o main.o -e _start -o kernel -m elf_i386 -Ttext 0x10000 --oformat binary

result objdump -d kernel.o is

enter image description here

result bochs run is

enter image description here


Solution

  • This is because your code is assembled for 32 bit mode (which objdump disassembles as, too) whereas you are still in 16 bit mode when _start is executed. Bochs correctly disassembles for the current operation mode. As the addressing modes in 16 and 32 bit mode differ, the instruction's behaviour differs, too.

    To fix this, temporarily switch the assembler to 16 bit mode with a bits 16 directive in the stub that switches to protected mode. You already have a bits 32 directive after that, so I'm not sure why you forgot the other one. Maybe you originally tested with a bin format file which defaults to 16 bit mode. elf format files default to 32 bit mode instead.