I am trying to find where global variables are stored in a binary exec (ELF).
In my final context, my exec is not executed directly, but called from another program that dlopens it, so I cannot use __data_start and _end.
I looked at this post here: How to determine the address range of global variables in a shared library at runtime? Which is indeed very interesting, but some of my shared variables are not in the range returned by Employed Russian's approach.
If put everything in a single reproducer:
#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;
}
And I compile it with gcc -o myexec myexec.c -fPIC, I get something like:
$ ./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
A few observations:
- the array is beyond the first range
data_startis at the beginning of the fourth rangedata_endis just after the end of the fourth range
Is it because of some relocation that was not disabled by -fPIC? Can I disable it, or find the true location?
RWLOADsegment, but there is no guarantee that there is only one such segment (although usually there is only one).&& p_flags == PF_R|PF_Wdoesn't do what you think it does.taband&tabare exactly the same.begin/endfrom DSOs, but you are only interested in the main executable.&data_startbut probably you meant to printdata_startinstead.0thdlpi_phdrwhen you should be usingjth one.Correcting these mistakes, I get all the addresses in the expected range:
The code: