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));
当我打开GDB单步执行这段代码时,我通过执行print &gdt_raw[0]
得到了gdb_raw
数组的地址,并得到了0x380
的输出。我用gdb中的x命令检查了0x380处的内存,确认了这是数组的实际地址,而不是指向数组的指针的地址。
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
现在,当我在GDB中逐步执行上面的汇编代码时,我希望函数的第一个参数[esp + 4]处的值是gdt_raw
(0x380
)的地址。然而,它不是。它的值是0x106000。出于对为什么会出现这种情况的好奇,我在调用gdt_load后直接进入了汇编:通过layout asm
和stepi
,我看到的是:
push 0x18
push 0x106000
call 0x10806e
这些是传递给函数的参数。0x18是有意义的,这是gdt的大小,也是我所期望的。但是,为什么另一个参数是0x106000而不是0x380呢?
这是否与符号表中gdt_raw
的地址0x380有关,但一旦文件Map到内存,我们在汇编代码中看到的地址就是gdt_raw在内存中的真实的地址?这是我的猜测,但我希望有人能证实或否认。
而且,如果以上是真的,那么当我在GDB中使用x命令查看内存位置的字节时,这些字节不是真实的的内存,而是对象文件中的偏移吗?
更新:Makefile和linker script
1条答案
按热度按时间8ljdwjyq1#
问题是我正在从可重定位对象文件的符号表中提取调试符号。
我生成了一个可重定位的对象文件
build/kernelfull.o
。然后,我把这个文件转换成了一个二进制文件,并在0x100000
处加载到内存中。在GDB中,当执行这个二进制文件时,我用add-symbol-file build/kernelfull.o 0x100000
从可重定位文件中拉入了符号表。因此,GDB只知道
gdt_raw
相对于0
的地址。为了纠正这个问题,我必须创建一个ELF可执行文件(与ELF可重定位文件相对),然后将其转换为二进制文件(objcopy
)。通过使用这个ELF可执行文件的调试符号,GDB可以看到gdt_raw
确实位于地址0x106000
感谢@MichaelPetch发现了这一点。