assembly x86为什么C函数反汇编在推送到调用堆栈时显示不同的指针值

acruukt9  于 2022-11-13  发布在  其他
关注(0)|答案(1)|浏览(129)

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_raw0x380)的地址。然而,它不是。它的值是0x106000。出于对为什么会出现这种情况的好奇,我在调用gdt_load后直接进入了汇编:通过layout asmstepi,我看到的是:

push 0x18
push 0x106000
call 0x10806e

这些是传递给函数的参数。0x18是有意义的,这是gdt的大小,也是我所期望的。但是,为什么另一个参数是0x106000而不是0x380呢?
这是否与符号表中gdt_raw的地址0x380有关,但一旦文件Map到内存,我们在汇编代码中看到的地址就是gdt_raw在内存中的真实的地址?这是我的猜测,但我希望有人能证实或否认。
而且,如果以上是真的,那么当我在GDB中使用x命令查看内存位置的字节时,这些字节不是真实的的内存,而是对象文件中的偏移吗?
更新:Makefilelinker script

8ljdwjyq

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发现了这一点。

相关问题