@@ -, +, @@ address $ dumpelf ia64_bug_gcc/cc1plus /* Dynamic tag #25 'DT_RELA' 0x2099518 */ { .d_tag = 0x7 , .d_un = { .d_val = 0x4000000000104B08 , .d_ptr = 0x4000000000104B08 , }, }, /* Section Header #8 '.rela.dyn' 0x20AA610 */ { .sh_type = 4 , /* [SHT_RELA] */ .sh_addr = 0x4000000000104B08 , .sh_offset = 1067784 , /* (bytes) */ }, /* Program Header #2 0xB0 */ { .p_type = 1 , /* [PT_LOAD] */ .p_offset = 0 , /* (bytes into file) */ .p_vaddr = 0x4000000000000000 , /* (virtual addr at runtime) */ .p_paddr = 0x4000000000000000 , /* (physical addr at runtime) */ }, --- scanelf.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) --- a/scanelf.c +++ a/scanelf.c @@ -579,6 +579,8 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun Elf ## B ## _Rela *rela; \ Elf ## B ## _Dyn *dyn, *drel, *drelsz, *drelent, *dpltrel; \ uint32_t pltrel; \ + Elf ## B ## _Addr load_address = 0; \ + Elf ## B ## _Addr file_offset; \ \ /* Walk all the dynamic tags to find relocation info */ \ drel = drelsz = drelent = dpltrel = NULL; \ @@ -605,27 +607,40 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun warnf("ELF is missing relocation information"); \ break; \ } \ + phdr = PHDR ## B(elf->phdr); \ + /* Lookup load base: byte 0 is mapped at load_address */ \ + for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ + /* Only care about loadable segments. */ \ + if (EGET(phdr[i].p_type) != PT_LOAD) \ + continue; \ + /* We search for the first program header to map into memory */ \ + if (EGET(phdr[i].p_offset) != 0) \ + continue; \ + load_address = EGET(phdr[i].p_vaddr); \ + } \ switch (EGET(dpltrel->d_un.d_val)) { \ case DT_REL: \ - if (!VALID_RANGE(elf, EGET(drel->d_un.d_val), sizeof (drel->d_un.d_val))) { \ + file_offset = EGET(drel->d_un.d_val) - load_address; \ + if (!VALID_RANGE(elf, file_offset, sizeof (drel->d_un.d_val))) { \ rel = NULL; \ rela = NULL; \ warn("%s: DT_REL is out of file range", elf->filename); \ break; \ } \ - rel = REL##B(elf->vdata + EGET(drel->d_un.d_val)); \ + rel = REL##B(elf->vdata + file_offset); \ rela = NULL; \ pltrel = DT_REL; \ break; \ case DT_RELA: \ - if (!VALID_RANGE(elf, EGET(drel->d_un.d_val), sizeof (drel->d_un.d_val))) { \ + file_offset = EGET(drel->d_un.d_val) - load_address; \ + if (!VALID_RANGE(elf, file_offset, sizeof (drel->d_un.d_val))) { \ rel = NULL; \ rela = NULL; \ warn("%s: DT_RELA is out of file range", elf->filename); \ break; \ } \ rel = NULL; \ - rela = RELA##B(elf->vdata + EGET(drel->d_un.d_val)); \ + rela = RELA##B(elf->vdata + file_offset); \ pltrel = DT_RELA; \ break; \ default: \ @@ -639,7 +654,6 @@ static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *foun rmax = EGET(drelsz->d_un.d_val) / EGET(drelent->d_un.d_val); \ \ /* search the program segments for relocations */ \ - phdr = PHDR ## B(elf->phdr); \ for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \ uint ## B ## _t memsz = EGET(phdr[i].p_memsz); \ --