我正在尝试查找全局变量在二进制 exec (ELF) 中的存储位置。
在我的最终上下文中,我的 exec 不是直接执行的,而是从另一个程序调用的,所以我不能使用
dlopen
和 __data_start
。我在这里看了这篇文章:如何在运行时确定共享库中全局变量的地址范围?这确实很有趣,但是我的一些共享变量不在 Employed Russian 的方法返回的范围内。 如果将所有内容放在一个复制器中:
_end
我用
#define _GNU_SOURCE
#include <link.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdint.h>
#define N 16
static int tab[N];
uintmax_t data_start;
uintmax_t data_end;
static int smpi_global_callback( struct dl_phdr_info *info, size_t size, void *data ){
int p_type, p_flags;
for (size_t j = 0; j < info->dlpi_phnum; j++) {
p_type = info->dlpi_phdr[j].p_type;
p_flags = info->dlpi_phdr[j].p_flags;
if( p_type == PT_LOAD && p_flags == PF_R|PF_W ){
data_start = info->dlpi_addr + info->dlpi_phdr->p_vaddr;
data_end = info->dlpi_addr + info->dlpi_phdr->p_vaddr + info->dlpi_phdr->p_memsz;
printf( "begin = %2zu ; end = %2zu\n", data_start, data_end );
return 0; /* always the same values so return after the first one */
}
}
return 0;
}
int main(){
int i = getpid();
dl_iterate_phdr(smpi_global_callback, NULL);
tab[0] = i;
printf( "ptr: %p %2zu\n", &tab, (uintmax_t)&tab );
printf( "ptr: %p %2zu\n", tab, (uintmax_t)tab );
printf( "ptr: %p %2zu\n", &data_start, (uintmax_t)data_start );
printf( "ptr: %p %2zu\n", &data_end, (uintmax_t)data_end );
return EXIT_SUCCESS;
}
编译它,我得到类似的东西:
gcc -o myexec myexec.c -fPIC
一些观察:
数组超出第一个范围
$ ./myexec
begin = 93878406574144 ; end = 93878406574872
begin = 140732748611584 ; end = 140732748615005
begin = 140256805367872 ; end = 140256805368656
begin = 140256807493632 ; end = 140256807497096
tab ptr: 0x5561c513b080 93878406590592
&tab ptr: 0x5561c513b080 93878406590592
data_start ptr: 0x5561c513b060 140256807493632
data_end ptr: 0x5561c513b068 140256807497096
data_start
data_end
禁用的搬迁?我可以禁用它,或者找到真实位置吗?
-fPIC
RW
段后,您将从回调中返回,但不能保证只有一个这样的段(尽管 通常只有一个)。 这个表达:
LOAD
&& p_flags == PF_R|PF_W
tab
完全相同。 您正在从 DSO 打印
&tab
begin/end
可能您本来想打印
&data_start
。当您应该使用第 data_start
0
。
纠正这些错误,我得到了预期范围内的所有地址:
dlpi_phdr
代码:
j