gpt4 book ai didi

c - 为什么每次在 GDB 中构建 + 反汇编函数时都会得到相同的地址?

转载 作者:行者123 更新时间:2023-12-01 08:59:44 25 4
gpt4 key购买 nike

为什么每次反汇编一个函数,总是得到相同的指令地址和常量地址?

例如,执行以下命令后,

gcc -o hello hello.c -ggdb
gdb hello
(gdb) disassemble main

转储代码将是:

dump code

当我退出 gdb 并重新反汇编 main 函数时,我会得到和以前一样的结果。对于 gdb 中的每个反汇编命令,指令地址甚至常量地址总是相同的。这是为什么?编译后的文件 hello 是否包含关于每条汇编指令的地址以及常量地址的某些信息?

最佳答案

如果您创建了一个与位置无关的可执行文件(例如,使用 gcc -fpie -pie, which is the default for gcc in many recent Linux distros ),内核将随机化它映射您的可执行文件的地址。 (在 GDB 下运行时除外:GDB disables ASLR by default,即使对于共享库和 PIE 可执行文件也是如此。)


但是您正在制作一个位置相关可执行文件,它可以利用静态地址作为链接时常量(通过将它们用作立即数等等,而不需要运行时重定位修复)。例如您或编译器可以使用 mov $msg, %edi (如您的代码)而不是 lea msg, %rdi (使用 -fpie) .

常规(位置相关)可执行文件在 ELF header 中设置了加载地址:使用 readelf -a ./a.out 查看 ELF 元数据。

即使不在 GDB 下运行,非 PIE 可执行文件也会在每次同时加载,位于 ELF 程序头中指定的地址。 (gcc/ld 在 x86-64-linux-elf 上默认选择 0x400000;您可以使用链接器脚本更改此设置)。硬编码到代码+数据中的所有静态地址的重定位信息不可用,因此加载程序即使想要修复地址也无法修复。

例如在一个简单的可执行文件中(只有一个文本段,没有数据或 bss)我用 -no-pie 构建(这似乎是你的 gcc 中的默认值):

Program Headers:
Type Offset VirtAddr PhysAddr
FileSiz MemSiz Flags Align
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
0x00000000000000c5 0x00000000000000c5 R E 0x200000

Section to Segment mapping:
Segment Sections...
00 .text

所以 ELF 头请求将文件中的偏移量 0 映射到虚拟地址 0x0000000000400000。 (并且 ELF 入口点是 0x400080;这就是 _start 所在的位置。)我不确定 PhysAddr = VirtAddr 的相关性是什么;用户空间可执行文件不知道也不能轻易找出内核用于支持其虚拟内存的 RAM 页面的物理地址,并且它可以在页面换入/换出时随时更改。

注意 readelf 会自动换行;注意有两行列标题。 0x200000 是那个 LOADed 段的对齐列。

关于c - 为什么每次在 GDB 中构建 + 反汇编函数时都会得到相同的地址?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48366077/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com