对于共享库文件,如何在文件偏移量和符号定义的虚拟地址之间进行转换?
在ELF文档中,对于符号表中的符号,
在可执行文件和共享对象文件中,
st_value
包含虚拟地址。为了使这些文件的符号对动态链接器更有用,段偏移(文件解释)让位于与第二个数字无关的虚拟地址(内存解释)。
但是如何在文件中获得相应的偏移?或者给出一个偏移量,我该如何计算虚拟地址(文件解释到内存解释)?
想象一下这样的场景。在执行进程期间,假设它正在使用在共享库中实现的函数,比如libx.so,并且库文件被映射到由vma
表示的区域。
//addr holds the value of PC
offset = (vma->vm_pgoff << PAGE_SIZE) + addr -vma->vm_start;
据我了解,现在offset
保存了库文件中指令的偏移量。鉴于此偏移,我想知道函数名称。一种方法是计算与offset
对应的虚拟地址,并将虚拟地址与符号表中的st_value
进行比较。如果st_value
被处理为按升序存储,则st_value_1 < virtual_address < st_value_2
表示st_name_1是我正在寻找的。所以问题在于转换
作为参考,符号表条目的数据结构是:
typedef struct{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
}Elf32_Sym;
答案 0 :(得分:0)
程序头表PT_LOAD
条目定义了加载器/链接器如何映射虚拟地址空间中ELF文件的部分内容。如果要在文件偏移量和(相对)虚拟内存地址之间进行转换,则应使用此选项:
~$ readelf -l /lib/i386-linux-gnu/libc-2.24.so Elf file type is DYN (Shared object file) Entry point 0x18400 There are 10 program headers, starting at offset 52 Program Headers: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align PHDR 0x000034 0x00000034 0x00000034 0x00140 0x00140 R E 0x4 INTERP 0x166374 0x00166374 0x00166374 0x00013 0x00013 R 0x4 [Requesting program interpreter: /lib/ld-linux.so.2] LOAD 0x000000 0x00000000 0x00000000 0x1b01c8 0x1b01c8 R E 0x1000 LOAD 0x1b0260 0x001b1260 0x001b1260 0x02c74 0x0579c RW 0x1000 DYNAMIC 0x1b1db0 0x001b2db0 0x001b2db0 0x000f0 0x000f0 RW 0x4 NOTE 0x000174 0x00000174 0x00000174 0x00044 0x00044 R 0x4 TLS 0x1b0260 0x001b1260 0x001b1260 0x00008 0x00048 R 0x4 GNU_EH_FRAME 0x166388 0x00166388 0x00166388 0x061ec 0x061ec R 0x4 GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x10 GNU_RELRO 0x1b0260 0x001b1260 0x001b1260 0x01da0 0x01da0 R 0x1
例如,考虑此符号
Num: Value Size Type Bind Vis Ndx Name 188: 0005df80 35 FUNC GLOBAL DEFAULT 13 fopen@@GLIBC_2.1
它的(相对)虚拟地址是0x0005df80。它属于第一个PT_LOAD
条目,其范围在从0x00000000
到0x00000000 + 0x1b01c8
的相对虚拟内存中。它在该细分中的偏移量为Value - VirtAddr = 0x00000000
。因此,它在文件中的偏移量为PhysAddr + (Value - VirtAddr) = 0005df80
。