void InputSection::copyRelocations(uint8_t *Buf, ArrayRef<RelTy> Rels) { InputSectionBase *Sec = getRelocatedSection(); for (const RelTy &Rel : Rels) { RelType Type = Rel.getType(Config->IsMips64EL); Symbol &Sym = getFile<ELFT>()->getRelocTargetSym(Rel); auto *P = reinterpret_cast<typename ELFT::Rela *>(Buf); Buf += sizeof(RelTy); if (Config->IsRela) P->r_addend = getAddend<ELFT>(Rel); // Output section VA is zero for -r, so r_offset is an offset within the // section, but for --emit-relocs it is an virtual address. P->r_offset = Sec->getOutputSection()->Addr + Sec->getOffset(Rel.r_offset); P->setSymbolAndType(InX::SymTab->getSymbolIndex(&Sym), Type, Config->IsMips64EL); if (Sym.Type == STT_SECTION) { // We combine multiple section symbols into only one per // section. This means we have to update the addend. That is // trivial for Elf_Rela, but for Elf_Rel we have to write to the // section data. We do that by adding to the Relocation vector. // .eh_frame is horribly special and can reference discarded sections. To // avoid having to parse and recreate .eh_frame, we just replace any // relocation in it pointing to discarded sections with R_*_NONE, which // hopefully creates a frame that is ignored at runtime. auto *D = dyn_cast<Defined>(&Sym); if (!D) { error("STT_SECTION symbol should be defined"); continue; } SectionBase *Section = D->Section; if (Section == &InputSection::Discarded) { P->setSymbolAndType(0, 0, false); continue; } if (Config->IsRela) { P->r_addend = Sym.getVA(getAddend<ELFT>(Rel)) - Section->getOutputSection()->Addr; } else if (Config->Relocatable) { const uint8_t *BufLoc = Sec->Data.begin() + Rel.r_offset; Sec->Relocations.push_back({R_ABS, Type, Rel.r_offset, Target->getImplicitAddend(BufLoc, Type), &Sym}); } } } }
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { switch (Sym.kind()) { case Symbol::DefinedKind: { auto &D = cast<Defined>(Sym); SectionBase *IS = D.Section; // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule // and must be treated specially. For now we just replace the symbol with // 0. if (IS == &InputSection::Discarded) return 0; // This is an absolute symbol. if (!IS) return D.Value; IS = IS->Repl; uint64_t Offset = D.Value; // An object in an SHF_MERGE section might be referenced via a // section symbol (as a hack for reducing the number of local // symbols). // Depending on the addend, the reference via a section symbol // refers to a different object in the merge section. // Since the objects in the merge section are not necessarily // contiguous in the output, the addend can thus affect the final // VA in a non-linear way. // To make this work, we incorporate the addend into the section // offset (and zero out the addend for later processing) so that // we find the right object in the section. if (D.isSection()) { Offset += Addend; Addend = 0; } // In the typical case, this is actually very simple and boils // down to adding together 3 numbers: // 1. The address of the output section. // 2. The offset of the input section within the output section. // 3. The offset within the input section (this addition happens // inside InputSection::getOffset). // // If you understand the data structures involved with this next // line (and how they get built), then you have a pretty good // understanding of the linker. uint64_t VA = IS->getVA(Offset); // MIPS relocatable files can mix regular and microMIPS code. // Linker needs to distinguish such code. To do so microMIPS // symbols has the `STO_MIPS_MICROMIPS` flag in the `st_other` // field. Unfortunately, the `MIPS::relocateOne()` method has // a symbol value only. To pass type of the symbol (regular/microMIPS) // to that routine as well as other places where we write // a symbol value as-is (.dynamic section, `Elf_Ehdr::e_entry` // field etc) do the same trick as compiler uses to mark microMIPS // for CPU - set the less-significant bit. if (Config->EMachine == EM_MIPS && isMicroMips() && ((Sym.StOther & STO_MIPS_MICROMIPS) || Sym.NeedsPltAddr)) VA |= 1; if (D.isTls() && !Config->Relocatable) { // Use the address of the TLS segment's first section rather than the // segment's address, because segment addresses aren't initialized until // after sections are finalized. (e.g. Measuring the size of .rela.dyn // for Android relocation packing requires knowing TLS symbol addresses // during section finalization.) if (!Out::TlsPhdr || !Out::TlsPhdr->FirstSec) fatal(toString(D.File) + " has an STT_TLS symbol but doesn't have an SHF_TLS section"); return VA - Out::TlsPhdr->FirstSec->Addr; } return VA; } case Symbol::SharedKind: case Symbol::UndefinedKind: return 0; case Symbol::LazyArchiveKind: case Symbol::LazyObjectKind: assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer"); return 0; case Symbol::PlaceholderKind: llvm_unreachable("placeholder symbol reached writer"); } llvm_unreachable("invalid symbol kind"); }
static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) { switch (Sym.kind()) { case Symbol::DefinedKind: { auto &D = cast<Defined>(Sym); SectionBase *IS = D.Section; // According to the ELF spec reference to a local symbol from outside // the group are not allowed. Unfortunately .eh_frame breaks that rule // and must be treated specially. For now we just replace the symbol with // 0. if (IS == &InputSection::Discarded) return 0; // This is an absolute symbol. if (!IS) return D.Value; IS = IS->Repl; uint64_t Offset = D.Value; // An object in an SHF_MERGE section might be referenced via a // section symbol (as a hack for reducing the number of local // symbols). // Depending on the addend, the reference via a section symbol // refers to a different object in the merge section. // Since the objects in the merge section are not necessarily // contiguous in the output, the addend can thus affect the final // VA in a non-linear way. // To make this work, we incorporate the addend into the section // offset (and zero out the addend for later processing) so that // we find the right object in the section. if (D.isSection()) { Offset += Addend; Addend = 0; } // In the typical case, this is actually very simple and boils // down to adding together 3 numbers: // 1. The address of the output section. // 2. The offset of the input section within the output section. // 3. The offset within the input section (this addition happens // inside InputSection::getOffset). // // If you understand the data structures involved with this next // line (and how they get built), then you have a pretty good // understanding of the linker. uint64_t VA = IS->getVA(Offset); if (D.isTls() && !Config->Relocatable) { if (!Out::TlsPhdr) fatal(toString(D.File) + " has an STT_TLS symbol but doesn't have an SHF_TLS section"); return VA - Out::TlsPhdr->p_vaddr; } return VA; } case Symbol::SharedKind: case Symbol::UndefinedKind: return 0; case Symbol::LazyArchiveKind: case Symbol::LazyObjectKind: llvm_unreachable("lazy symbol reached writer"); } llvm_unreachable("invalid symbol kind"); }