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"); }