Search code examples
cassemblyx86gdbdisassembly

x86 Why does C function disassembly show different value for pointer when pushed to call stack


gdt.h:

void gdt_load(struct segment_descriptor_raw *gdt, uint16_t size);

gdt.c:

struct segment_descriptor_raw gdt_raw[TOTAL_GDT_SEGMENTS];
gdt_load(gdt_raw, sizeof(gdt_raw));

When I open GDB to step through this code, I get the address of the gdb_raw array by executing print &gdt_raw[0] and I get an output of 0x380. I confirmed that this is the actual address of the array, and not the address of the pointer to the array, by examining the memory at 0x380 with the x command in gdb.

gdt.asm:

gdt_load:
    mov eax, [esp + 4]              
    mov [gdt_descriptor + 2], eax   
    mov ax, [esp + 8]               
    mov [gdt_descriptor], ax        
    lgdt [gdt_descriptor]           
    ret

Now, as I step through the above assembly code in GDB, I expect the value at [esp + 4], the first argument to the function, to be the address of gdt_raw (0x380). However, it's not. It's the value 0x106000. Curious as to why this is the case, I stepped into the assembly directly after calling gdt_load: via layout asm and stepi and this is what I see:

push 0x18
push 0x106000
call 0x10806e

These are the arguments getting passed to the function. 0x18 makes sense, this is the size of the gdt and what I expect. However, why is the other argument 0x106000 and not 0x380?

Does this have something to do with 0x380 being the address of gdt_raw in the symbol table, but once the file is mapped to memory, the address we're seeing in the assembly code is the real address of gdt_raw in memory? This is my guess but I'm hoping someone can confirm or deny.

And, if the above is true, then when I use the x command in GDB to view the bytes at a memory location, are those bytes not the real memory, but instead only the offset within the object file?

Update: Makefile and linker script


Solution

  • The issue was that I was pulling debug symbols from the symbol table of a relocatable object file.

    I was generating a relocatable object file, build/kernelfull.o. Then, I converted this file into a binary that was loaded into memory at 0x100000. In GDB, when executing the binary, I pulled in the symbol table from the relocatable file with add-symbol-file build/kernelfull.o 0x100000.

    Thus, GDB only knew an address for gdt_raw that was relative to 0. To correct this, I had to create an ELF Executable (as opposed to ELF Relocatable) which I then converted into a binary (objcopy). By using the debugging symbols of this ELF Executable, GDB could see that gdt_raw was indeed at the address 0x106000

    Thanks to @MichaelPetch for figuring this out.