- // Scan dynamic table.
- for (Elf_Dyn_Iter DynI = dynamic_table_begin(), DynE = dynamic_table_end();
- DynI != DynE; ++DynI) {
- switch (DynI->d_tag) {
- case ELF::DT_RELA: {
- uint64_t VBase = 0;
- const uint8_t *FBase = nullptr;
- for (Elf_Phdr_Iter PhdrI = program_header_begin(),
- PhdrE = program_header_end();
- PhdrI != PhdrE; ++PhdrI) {
- if (PhdrI->p_type != ELF::PT_LOAD)
- continue;
- if (DynI->getPtr() >= PhdrI->p_vaddr &&
- DynI->getPtr() < PhdrI->p_vaddr + PhdrI->p_memsz) {
- VBase = PhdrI->p_vaddr;
- FBase = base() + PhdrI->p_offset;
- break;
- }
- }
- if (!VBase)
- return;
- DynRelaRegion.Addr = FBase + DynI->getPtr() - VBase;
+ auto toMappedAddr = [&](uint64_t VAddr) -> const uint8_t * {
+ const Elf_Phdr **I = std::upper_bound(
+ LoadSegments.begin(), LoadSegments.end(), VAddr, compareAddr<ELFT>);
+ if (I == LoadSegments.begin())
+ report_fatal_error("Virtual address is not in any segment");
+ --I;
+ const Elf_Phdr &Phdr = **I;
+ uint64_t Delta = VAddr - Phdr.p_vaddr;
+ if (Delta >= Phdr.p_filesz)
+ report_fatal_error("Virtual address is not in any segment");
+ return this->base() + Phdr.p_offset + Delta;
+ };
+
+ for (const Elf_Dyn &Dyn : dynamic_table()) {
+ switch (Dyn.d_tag) {
+ case ELF::DT_HASH:
+ if (HashTable)
+ continue;
+ HashTable =
+ reinterpret_cast<const Elf_Hash *>(toMappedAddr(Dyn.getPtr()));
+ break;
+ case ELF::DT_STRTAB:
+ if (!DynStrRegion.Addr)
+ DynStrRegion.Addr = toMappedAddr(Dyn.getPtr());
+ break;
+ case ELF::DT_STRSZ:
+ if (!DynStrRegion.Size)
+ DynStrRegion.Size = Dyn.getVal();
+ break;
+ case ELF::DT_RELA:
+ if (!DynRelaRegion.Addr)
+ DynRelaRegion.Addr = toMappedAddr(Dyn.getPtr());