error("no input files.");
}
-template <class ELFT> static void initSymbols() {
- ElfSym<ELFT>::Etext.setBinding(STB_GLOBAL);
- ElfSym<ELFT>::Edata.setBinding(STB_GLOBAL);
- ElfSym<ELFT>::End.setBinding(STB_GLOBAL);
- ElfSym<ELFT>::Ignored.setBinding(STB_WEAK);
- ElfSym<ELFT>::Ignored.setVisibility(STV_HIDDEN);
-}
-
template <class ELFT> void LinkerDriver::link(opt::InputArgList &Args) {
- initSymbols<ELFT>();
-
SymbolTable<ELFT> Symtab;
std::unique_ptr<TargetInfo> TI(createTarget());
Target = TI.get();
Config->EMachine != EM_AMDGPU)
Config->Entry = Config->EMachine == EM_MIPS ? "__start" : "_start";
- // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
- // is magical and is used to produce a R_386_GOTPC relocation.
- // The R_386_GOTPC relocation value doesn't actually depend on the
- // symbol value, so it could use an index of STN_UNDEF which, according
- // to the spec, means the symbol value is 0.
- // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
- // the object file.
- // The situation is even stranger on x86_64 where the assembly doesn't
- // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
- // an undefined symbol in the .o files.
- // Given that the symbol is effectively unused, we just create a dummy
- // hidden one to avoid the undefined symbol error.
- if (!Config->Relocatable)
- Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
-
if (!Config->Entry.empty()) {
// Set either EntryAddr (if S is a number) or EntrySym (otherwise).
StringRef S = Config->Entry;
}
if (Config->EMachine == EM_MIPS) {
- // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
- // start of function and 'gp' pointer into GOT.
- Config->MipsGpDisp = Symtab.addIgnored("_gp_disp");
- // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
- // pointer. This symbol is used in the code generated by .cpload pseudo-op
- // in case of using -mno-shared option.
- // https://sourceware.org/ml/binutils/2004-12/msg00094.html
- Config->MipsLocalGp = Symtab.addIgnored("__gnu_local_gp");
-
// Define _gp for MIPS. st_value of _gp symbol will be updated by Writer
// so that it points to an absolute address which is relative to GOT.
// See "Global Data Symbols" in Chapter 6 in the following document:
// ftp://www.linux-mips.org/pub/linux/mips/doc/ABI/mipsabi.pdf
- Symtab.addAbsolute("_gp", ElfSym<ELFT>::MipsGp);
+ ElfSym<ELFT>::MipsGp = Symtab.addAbsolute("_gp", STV_DEFAULT);
}
for (std::unique_ptr<InputFile> &F : Files)
// Returns true if Sec is subject of ICF.
template <class ELFT> bool ICF<ELFT>::isEligible(InputSectionBase<ELFT> *Sec) {
- if (!Sec || Sec == InputSection<ELFT>::Discarded || !Sec->Live)
+ if (!Sec || Sec == &InputSection<ELFT>::Discarded || !Sec->Live)
return false;
auto *S = dyn_cast<InputSection<ELFT>>(Sec);
if (!S)
auto *DB = dyn_cast<DefinedRegular<ELFT>>(&SB);
if (!DA || !DB)
return false;
- if (DA->Sym.st_value != DB->Sym.st_value)
+ if (DA->Value != DB->Value)
return false;
InputSection<ELFT> *X = dyn_cast<InputSection<ELFT>>(DA->Section);
InputSection<ELFT> *Y = dyn_cast<InputSection<ELFT>>(DB->Section);
const ELFFile<ELFT> &Obj = this->ELFObj;
for (const Elf_Shdr &Sec : Obj.sections()) {
++I;
- if (Sections[I] == InputSection<ELFT>::Discarded)
+ if (Sections[I] == &InputSection<ELFT>::Discarded)
continue;
switch (Sec.sh_type) {
case SHT_GROUP:
- Sections[I] = InputSection<ELFT>::Discarded;
+ Sections[I] = &InputSection<ELFT>::Discarded;
if (ComdatGroups.insert(getShtGroupSignature(Sec)).second)
continue;
for (uint32_t SecIndex : getShtGroupEntries(Sec)) {
if (SecIndex >= Size)
fatal("invalid section index in group");
- Sections[SecIndex] = InputSection<ELFT>::Discarded;
+ Sections[SecIndex] = &InputSection<ELFT>::Discarded;
}
break;
case SHT_SYMTAB:
// Strictly speaking, a relocation section must be included in the
// group of the section it relocates. However, LLVM 3.3 and earlier
// would fail to do so, so we gracefully handle that case.
- if (Target == InputSection<ELFT>::Discarded)
+ if (Target == &InputSection<ELFT>::Discarded)
return nullptr;
if (!Target)
// is controlled only by the command line option (-z execstack) in LLD,
// .note.GNU-stack is ignored.
if (Name == ".note.GNU-stack")
- return InputSection<ELFT>::Discarded;
+ return &InputSection<ELFT>::Discarded;
if (Name == ".note.GNU-split-stack")
error("objects using splitstacks are not supported");
if (Index >= Sections.size() || !Sections[Index])
fatal("invalid section index");
InputSectionBase<ELFT> *S = Sections[Index];
- if (S == InputSectionBase<ELFT>::Discarded)
+ if (S == &InputSectionBase<ELFT>::Discarded)
return S;
return S->Repl;
}
template <class ELFT>
SymbolBody *elf::ObjectFile<ELFT>::createSymbolBody(const Elf_Sym *Sym) {
+ uint32_t NameOffset = Sym->st_name;
unsigned char Binding = Sym->getBinding();
InputSectionBase<ELFT> *Sec = getSection(*Sym);
if (Binding == STB_LOCAL) {
- if (Sec == InputSection<ELFT>::Discarded)
- Sec = nullptr;
- return new (Alloc) DefinedRegular<ELFT>("", *Sym, Sec);
+ if (Sym->st_shndx == SHN_UNDEF)
+ return new (Alloc) UndefinedElf<ELFT>(NameOffset, *Sym);
+ return new (Alloc) DefinedRegular<ELFT>(NameOffset, *Sym, Sec);
}
StringRef Name = check(Sym->getName(this->StringTable));
case SHN_UNDEF:
return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
case SHN_COMMON:
- return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value,
- Sym->getBinding() == llvm::ELF::STB_WEAK,
- Sym->getVisibility());
+ return new (Alloc) DefinedCommon(Name, Sym->st_size, Sym->st_value, Binding,
+ Sym->st_other, Sym->getType());
}
switch (Binding) {
case STB_GLOBAL:
case STB_WEAK:
case STB_GNU_UNIQUE:
- if (Sec == InputSection<ELFT>::Discarded)
+ if (Sec == &InputSection<ELFT>::Discarded)
return new (Alloc) UndefinedElf<ELFT>(Name, *Sym);
return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, Sec);
}
uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
SymbolBodies.reserve(NumSymbols);
for (const Elf_Sym &Sym : Syms) {
+ // FIXME: We should probably just err if we get a local symbol in here.
+ if (Sym.getBinding() == STB_LOCAL)
+ continue;
StringRef Name = check(Sym.getName(this->StringTable));
if (Sym.isUndefined())
Undefs.push_back(Name);
const DataLayout &DL = M.getDataLayout();
uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
Body = new (Alloc)
- DefinedCommon(NameRef, Size, GV->getAlignment(), IsWeak, Visibility);
+ DefinedCommon(NameRef, Size, GV->getAlignment(),
+ IsWeak ? STB_WEAK : STB_GLOBAL, Visibility, /*Type*/ 0);
} else {
Body = new (Alloc) DefinedBitcode(NameRef, IsWeak, Visibility);
}
- Body->IsTls = GV->isThreadLocal();
+ if (GV->isThreadLocal())
+ Body->Type = STT_TLS;
return Body;
}
// The number is the offset in the string table. It will be used as the
// st_name of the symbol.
- std::vector<std::pair<const Elf_Sym *, unsigned>> KeptLocalSyms;
+ std::vector<std::pair<const DefinedRegular<ELFT> *, unsigned>> KeptLocalSyms;
private:
void initializeSections(llvm::DenseSet<StringRef> &ComdatGroups);
}
template <class ELFT>
-typename ELFT::uint InputSectionBase<ELFT>::getOffset(const Elf_Sym &Sym) {
- return getOffset(Sym.st_value);
+typename ELFT::uint
+InputSectionBase<ELFT>::getOffset(const DefinedRegular<ELFT> &Sym) {
+ return getOffset(Sym.Value);
}
// Returns a section that Rel relocation is pointing to.
SymVA = getMipsGotVA<ELFT>(Body, SymVA, BufLoc);
else
SymVA = Body.getGotVA<ELFT>() + A;
- if (Body.IsTls)
+ if (Body.isTls())
Type = Target->getTlsGotRel(Type);
} else if (Target->isSizeRel(Type) && Body.isPreemptible()) {
// A SIZE relocation is supposed to set a symbol size, but if a symbol
namespace elf {
template <class ELFT> class ICF;
+template <class ELFT> class DefinedRegular;
template <class ELFT> class ObjectFile;
template <class ELFT> class OutputSection;
template <class ELFT> class OutputSectionBase;
enum Kind { Regular, EHFrame, Merge, MipsReginfo };
Kind SectionKind;
+ InputSectionBase() : Repl(this) {}
+
InputSectionBase(ObjectFile<ELFT> *File, const Elf_Shdr *Header,
Kind SectionKind);
OutputSectionBase<ELFT> *OutSec = nullptr;
// Returns the size of this section (even if this is a common or BSS.)
size_t getSize() const;
- static InputSectionBase<ELFT> *Discarded;
+ static InputSectionBase<ELFT> Discarded;
StringRef getSectionName() const;
const Elf_Shdr *getSectionHdr() const { return Header; }
ObjectFile<ELFT> *getFile() const { return File; }
- uintX_t getOffset(const Elf_Sym &Sym);
+ uintX_t getOffset(const DefinedRegular<ELFT> &Sym);
// Translate an offset in the input section to an offset in the output
// section.
const RelTy *Rel, const RelTy *End);
};
-template <class ELFT>
-InputSectionBase<ELFT> *
- InputSectionBase<ELFT>::Discarded = (InputSectionBase<ELFT> *)-1ULL;
+template <class ELFT> InputSectionBase<ELFT> InputSectionBase<ELFT>::Discarded;
// Usually sections are copied to the output as atomic chunks of data,
// but some special types of sections are split into small pieces of data
// script KEEP command.
for (const std::unique_ptr<ObjectFile<ELFT>> &F : Symtab->getObjectFiles())
for (InputSectionBase<ELFT> *Sec : F->getSections())
- if (Sec && Sec != InputSection<ELFT>::Discarded)
+ if (Sec && Sec != &InputSection<ELFT>::Discarded)
if (isReserved(Sec) || Script->shouldKeep<ELFT>(Sec))
Enqueue(Sec);
// Iterate over all input object files to copy their local symbols
// to the output symbol table pointed by Buf.
for (const std::unique_ptr<ObjectFile<ELFT>> &File : Table.getObjectFiles()) {
- for (const std::pair<const Elf_Sym *, size_t> &P : File->KeptLocalSyms) {
- const Elf_Sym *Sym = P.first;
-
+ for (const std::pair<const DefinedRegular<ELFT> *, size_t> &P :
+ File->KeptLocalSyms) {
+ const DefinedRegular<ELFT> &Body = *P.first;
+ InputSectionBase<ELFT> *Section = Body.Section;
auto *ESym = reinterpret_cast<Elf_Sym *>(Buf);
- if (Sym->st_shndx == SHN_ABS) {
+
+ if (!Section) {
ESym->st_shndx = SHN_ABS;
- ESym->st_value = Sym->st_value;
+ ESym->st_value = Body.Value;
} else {
- InputSectionBase<ELFT> *Section = File->getSection(*Sym);
const OutputSectionBase<ELFT> *OutSec = Section->OutSec;
ESym->st_shndx = OutSec->SectionIndex;
- ESym->st_value = OutSec->getVA() + Section->getOffset(*Sym);
+ ESym->st_value = OutSec->getVA() + Section->getOffset(Body);
}
ESym->st_name = P.second;
- ESym->st_size = Sym->st_size;
- ESym->setBindingAndType(Sym->getBinding(), Sym->getType());
+ ESym->st_size = Body.template getSize<ELFT>();
+ ESym->setBindingAndType(Body.Binding, Body.Type);
Buf += sizeof(*ESym);
}
}
SymbolBody *Body = P.first;
size_t StrOff = P.second;
- uint8_t Type = STT_NOTYPE;
- uintX_t Size = 0;
- if (const Elf_Sym *InputSym = Body->getElfSym<ELFT>()) {
- Type = InputSym->getType();
- Size = InputSym->st_size;
- } else if (auto *C = dyn_cast<DefinedCommon>(Body)) {
- Type = STT_OBJECT;
- Size = C->Size;
- }
+ uint8_t Type = Body->Type;
+ uintX_t Size = Body->getSize<ELFT>();
ESym->setBindingAndType(getSymbolBinding(Body), Type);
ESym->st_size = Size;
uint8_t Visibility = Body->getVisibility();
if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
return STB_LOCAL;
- if (const Elf_Sym *ESym = Body->getElfSym<ELFT>())
- return ESym->getBinding();
if (isa<DefinedSynthetic<ELFT>>(Body))
return STB_LOCAL;
- return Body->isWeak() ? STB_WEAK : STB_GLOBAL;
+ return Body->Binding;
}
template <class ELFT>
}
template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addAbsolute(StringRef Name, Elf_Sym &ESym) {
+DefinedRegular<ELFT> *SymbolTable<ELFT>::addAbsolute(StringRef Name,
+ uint8_t Visibility) {
// Pass nullptr because absolute symbols have no corresponding input sections.
- auto *Sym = new (Alloc) DefinedRegular<ELFT>(Name, ESym, nullptr);
+ auto *Sym = new (Alloc) DefinedRegular<ELFT>(Name, STB_GLOBAL, Visibility);
resolve(Sym);
return Sym;
}
}
// Add Name as an "ignored" symbol. An ignored symbol is a regular
-// linker-synthesized defined symbol, but it is not recorded to the output
-// file's symbol table. Such symbols are useful for some linker-defined symbols.
+// linker-synthesized defined symbol, but is only defined if needed.
template <class ELFT>
-SymbolBody *SymbolTable<ELFT>::addIgnored(StringRef Name) {
- return addAbsolute(Name, ElfSym<ELFT>::Ignored);
+DefinedRegular<ELFT> *SymbolTable<ELFT>::addIgnored(StringRef Name,
+ uint8_t Visibility) {
+ if (!find(Name))
+ return nullptr;
+ return addAbsolute(Name, Visibility);
}
// Rename SYM as __wrap_SYM. The original symbol is preserved as __real_SYM.
return;
}
- if (New->IsTls != Existing->IsTls) {
+ if (New->isTls() != Existing->isTls()) {
error("TLS attribute mismatch for symbol: " + conflictMsg(Existing, New));
return;
}
// symbols and copy information to reduce how many special cases are needed.
if (Undef->isWeak()) {
L->setUsedInRegularObj();
- L->setWeak();
+ L->Binding = Undef->Binding;
+ L->Type = Undef->Type;
// FIXME: Do we need to copy more?
- L->IsTls |= Undef->IsTls;
return;
}
SymbolBody *addUndefined(StringRef Name);
SymbolBody *addUndefinedOpt(StringRef Name);
- SymbolBody *addAbsolute(StringRef Name, Elf_Sym &ESym);
+ DefinedRegular<ELFT> *addAbsolute(StringRef Name,
+ uint8_t Visibility = llvm::ELF::STV_HIDDEN);
SymbolBody *addSynthetic(StringRef Name, OutputSectionBase<ELFT> &Section,
uintX_t Value, uint8_t Visibility);
- SymbolBody *addIgnored(StringRef Name);
+ DefinedRegular<ELFT> *addIgnored(StringRef Name,
+ uint8_t Visibility = llvm::ELF::STV_HIDDEN);
void scanShlibUndefined();
SymbolBody *find(StringRef Name);
void wrap(StringRef Name);
InputFile *findFile(SymbolBody *B);
+ void resolve(SymbolBody *Body);
private:
Symbol *insert(SymbolBody *New);
void addLazy(Lazy *New);
void addMemberFile(Undefined *Undef, Lazy *L);
- void resolve(SymbolBody *Body);
std::string conflictMsg(SymbolBody *Old, SymbolBody *New);
// The order the global symbols are in is not defined. We can use an arbitrary
template <class ELFT>
static typename ELFT::uint getSymVA(const SymbolBody &Body,
typename ELFT::uint &Addend) {
- typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
switch (Body.kind()) {
auto &D = cast<DefinedRegular<ELFT>>(Body);
InputSectionBase<ELFT> *SC = 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 (SC == &InputSection<ELFT>::Discarded)
+ return 0;
+
// This is an absolute symbol.
if (!SC)
- return D.Sym.st_value;
+ return D.Value;
- const Elf_Sym &Sym = D.Sym;
- uintX_t Offset = Sym.st_value;
- if (Sym.getType() == STT_SECTION) {
+ uintX_t Offset = D.Value;
+ if (D.isSection()) {
Offset += Addend;
Addend = 0;
}
uintX_t VA = SC->OutSec->getVA() + SC->getOffset(Offset);
- if (Sym.getType() == STT_TLS)
+ if (D.isTls())
return VA - Out<ELFT>::TlsPhdr->p_vaddr;
return VA;
}
auto &SS = cast<SharedSymbol<ELFT>>(Body);
if (!SS.NeedsCopyOrPltAddr)
return 0;
- if (SS.IsFunc)
+ if (SS.isFunc())
return Body.getPltVA<ELFT>();
return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
}
llvm_unreachable("invalid symbol kind");
}
+SymbolBody::SymbolBody(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type)
+ : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
+ Type(Type), Binding(STB_LOCAL), Other(Other), NameOffset(NameOffset) {
+ IsUsedInRegularObj =
+ K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
+}
+
// Returns true if a symbol can be replaced at load-time by a symbol
// with the same name defined in other ELF executable or DSO.
bool SymbolBody::isPreemptible() const {
return false;
if (getVisibility() != STV_DEFAULT)
return false;
- if (Config->Bsymbolic || (Config->BsymbolicFunctions && IsFunc))
+ if (Config->Bsymbolic || (Config->BsymbolicFunctions && isFunc()))
return false;
return true;
}
}
template <class ELFT> typename ELFT::uint SymbolBody::getSize() const {
- if (const typename ELFT::Sym *Sym = getElfSym<ELFT>())
- return Sym->st_size;
+ if (const auto *C = dyn_cast<DefinedCommon>(this))
+ return C->Size;
+ if (const auto *DR = dyn_cast<DefinedRegular<ELFT>>(this))
+ return DR->Size;
+ if (const auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
+ return S->Sym.st_size;
+ if (const auto *U = dyn_cast<UndefinedElf<ELFT>>(this))
+ return U->Size;
return 0;
}
-template <class ELFT> const typename ELFT::Sym *SymbolBody::getElfSym() const {
- if (auto *S = dyn_cast<DefinedRegular<ELFT>>(this))
- return &S->Sym;
- if (auto *S = dyn_cast<SharedSymbol<ELFT>>(this))
- return &S->Sym;
- if (auto *S = dyn_cast<UndefinedElf<ELFT>>(this))
- return &S->Sym;
- return nullptr;
-}
-
static uint8_t getMinVisibility(uint8_t VA, uint8_t VB) {
if (VA == STV_DEFAULT)
return VB;
if (L > R)
return -Other->compare<ELFT>(this);
- Visibility = Other->Visibility =
- getMinVisibility(Visibility, Other->Visibility);
+ uint8_t V = getMinVisibility(getVisibility(), Other->getVisibility());
+ setVisibility(V);
+ Other->setVisibility(V);
if (IsUsedInRegularObj || Other->IsUsedInRegularObj)
IsUsedInRegularObj = Other->IsUsedInRegularObj = true;
return isCommon() ? -1 : 1;
}
-Defined::Defined(Kind K, StringRef Name, bool IsWeak, bool IsLocal,
- uint8_t Visibility, uint8_t Type)
- : SymbolBody(K, Name, IsWeak, IsLocal, Visibility, Type) {}
+Defined::Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t Visibility,
+ uint8_t Type)
+ : SymbolBody(K, Name, Binding, Visibility, Type) {}
+
+Defined::Defined(Kind K, uint32_t NameOffset, uint8_t Visibility, uint8_t Type)
+ : SymbolBody(K, NameOffset, Visibility, Type) {}
DefinedBitcode::DefinedBitcode(StringRef Name, bool IsWeak, uint8_t Visibility)
- : Defined(DefinedBitcodeKind, Name, IsWeak, false, Visibility,
- 0 /* Type */) {}
+ : Defined(DefinedBitcodeKind, Name, IsWeak ? STB_WEAK : STB_GLOBAL,
+ Visibility, 0 /* Type */) {}
bool DefinedBitcode::classof(const SymbolBody *S) {
return S->kind() == DefinedBitcodeKind;
}
-Undefined::Undefined(SymbolBody::Kind K, StringRef N, bool IsWeak,
+Undefined::Undefined(SymbolBody::Kind K, StringRef N, uint8_t Binding,
+ uint8_t Other, uint8_t Type)
+ : SymbolBody(K, N, Binding, Other, Type), CanKeepUndefined(false) {}
+
+Undefined::Undefined(SymbolBody::Kind K, uint32_t NameOffset,
uint8_t Visibility, uint8_t Type)
- : SymbolBody(K, N, IsWeak, false, Visibility, Type),
- CanKeepUndefined(false) {}
+ : SymbolBody(K, NameOffset, Visibility, Type), CanKeepUndefined(false) {}
Undefined::Undefined(StringRef N, bool IsWeak, uint8_t Visibility,
bool CanKeepUndefined)
- : Undefined(SymbolBody::UndefinedKind, N, IsWeak, Visibility, 0 /* Type */) {
+ : Undefined(SymbolBody::UndefinedKind, N, IsWeak ? STB_WEAK : STB_GLOBAL,
+ Visibility, 0 /* Type */) {
this->CanKeepUndefined = CanKeepUndefined;
}
template <typename ELFT>
UndefinedElf<ELFT>::UndefinedElf(StringRef N, const Elf_Sym &Sym)
- : Undefined(SymbolBody::UndefinedElfKind, N,
- Sym.getBinding() == llvm::ELF::STB_WEAK, Sym.getVisibility(),
+ : Undefined(SymbolBody::UndefinedElfKind, N, Sym.getBinding(), Sym.st_other,
Sym.getType()),
- Sym(Sym) {}
+ Size(Sym.st_size) {}
+
+template <typename ELFT>
+UndefinedElf<ELFT>::UndefinedElf(uint32_t NameOffset, const Elf_Sym &Sym)
+ : Undefined(SymbolBody::UndefinedElfKind, NameOffset, Sym.st_other,
+ Sym.getType()),
+ Size(Sym.st_size) {
+ assert(Sym.getBinding() == STB_LOCAL);
+}
template <typename ELFT>
DefinedSynthetic<ELFT>::DefinedSynthetic(StringRef N, uintX_t Value,
OutputSectionBase<ELFT> &Section,
uint8_t Visibility)
- : Defined(SymbolBody::DefinedSyntheticKind, N, false, false, Visibility,
+ : Defined(SymbolBody::DefinedSyntheticKind, N, STB_GLOBAL, Visibility,
0 /* Type */),
Value(Value), Section(Section) {}
DefinedCommon::DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment,
- bool IsWeak, uint8_t Visibility)
- : Defined(SymbolBody::DefinedCommonKind, N, IsWeak, false, Visibility,
- 0 /* Type */),
+ uint8_t Binding, uint8_t Visibility, uint8_t Type)
+ : Defined(SymbolBody::DefinedCommonKind, N, Binding, Visibility, Type),
Alignment(Alignment), Size(Size) {}
std::unique_ptr<InputFile> Lazy::getMember() {
template uint64_t SymbolBody::template getSize<ELF64LE>() const;
template uint64_t SymbolBody::template getSize<ELF64BE>() const;
-template const ELF32LE::Sym *SymbolBody::template getElfSym<ELF32LE>() const;
-template const ELF32BE::Sym *SymbolBody::template getElfSym<ELF32BE>() const;
-template const ELF64LE::Sym *SymbolBody::template getElfSym<ELF64LE>() const;
-template const ELF64BE::Sym *SymbolBody::template getElfSym<ELF64BE>() const;
-
template uint32_t SymbolBody::template getThunkVA<ELF32LE>() const;
template uint32_t SymbolBody::template getThunkVA<ELF32BE>() const;
template uint64_t SymbolBody::template getThunkVA<ELF64LE>() const;
Kind kind() const { return static_cast<Kind>(SymbolKind); }
- bool isWeak() const { return IsWeak; }
+ bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
bool isUndefined() const {
return SymbolKind == UndefinedKind || SymbolKind == UndefinedElfKind;
}
bool isCommon() const { return SymbolKind == DefinedCommonKind; }
bool isLazy() const { return SymbolKind == LazyKind; }
bool isShared() const { return SymbolKind == SharedKind; }
- bool isLocal() const { return IsLocal; }
+ bool isLocal() const { return Binding == llvm::ELF::STB_LOCAL; }
bool isUsedInRegularObj() const { return IsUsedInRegularObj; }
bool isPreemptible() const;
// Returns the symbol name.
- StringRef getName() const { return Name; }
+ StringRef getName() const {
+ assert(!isLocal());
+ return Name;
+ }
+ uint32_t getNameOffset() const {
+ assert(isLocal());
+ return NameOffset;
+ }
- uint8_t getVisibility() const { return Visibility; }
+ uint8_t getVisibility() const { return Other & 0x3; }
unsigned DynsymIndex = 0;
uint32_t GlobalDynIndex = -1;
template <class ELFT> typename ELFT::uint getPltVA() const;
template <class ELFT> typename ELFT::uint getThunkVA() const;
template <class ELFT> typename ELFT::uint getSize() const;
- template <class ELFT> const typename ELFT::Sym *getElfSym() const;
// A SymbolBody has a backreference to a Symbol. Originally they are
// doubly-linked. A backreference will never change. But the pointer
template <class ELFT> int compare(SymbolBody *Other);
protected:
- SymbolBody(Kind K, StringRef Name, bool IsWeak, bool IsLocal,
- uint8_t Visibility, uint8_t Type)
- : SymbolKind(K), IsWeak(IsWeak), IsLocal(IsLocal), Visibility(Visibility),
- MustBeInDynSym(false), NeedsCopyOrPltAddr(false), Name(Name) {
- IsFunc = Type == llvm::ELF::STT_FUNC;
- IsTls = Type == llvm::ELF::STT_TLS;
- IsGnuIFunc = Type == llvm::ELF::STT_GNU_IFUNC;
+ SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t Other,
+ uint8_t Type)
+ : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
+ Type(Type), Binding(Binding), Other(Other), Name(Name) {
+ assert(!isLocal());
IsUsedInRegularObj =
K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
}
+ SymbolBody(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type);
+
const unsigned SymbolKind : 8;
- unsigned IsWeak : 1;
- unsigned IsLocal : 1;
- unsigned Visibility : 2;
// True if the symbol was used for linking and thus need to be
// added to the output file's symbol table. It is usually true,
// symbol or if the symbol should point to its plt entry.
unsigned NeedsCopyOrPltAddr : 1;
- unsigned IsTls : 1;
- unsigned IsFunc : 1;
- unsigned IsGnuIFunc : 1;
+ uint8_t Type;
+ uint8_t Binding;
+ uint8_t Other;
+ bool isSection() const { return Type == llvm::ELF::STT_SECTION; }
+ bool isTls() const { return Type == llvm::ELF::STT_TLS; }
+ bool isFunc() const { return Type == llvm::ELF::STT_FUNC; }
+ bool isGnuIFunc() const { return Type == llvm::ELF::STT_GNU_IFUNC; }
+ bool isObject() const { return Type == llvm::ELF::STT_OBJECT; }
+ bool isFile() const { return Type == llvm::ELF::STT_FILE; }
+ void setVisibility(uint8_t V) { Other = (Other & ~0x3) | V; }
protected:
- StringRef Name;
+ union {
+ StringRef Name;
+ uint32_t NameOffset;
+ };
Symbol *Backref = nullptr;
};
// The base class for any defined symbols.
class Defined : public SymbolBody {
public:
- Defined(Kind K, StringRef Name, bool IsWeak, bool IsLocal, uint8_t Visibility,
- uint8_t Type);
+ Defined(Kind K, StringRef Name, uint8_t Binding, uint8_t Other, uint8_t Type);
+ Defined(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type);
static bool classof(const SymbolBody *S) { return S->isDefined(); }
};
// The defined symbol in LLVM bitcode files.
class DefinedBitcode : public Defined {
public:
- DefinedBitcode(StringRef Name, bool IsWeak, uint8_t Visibility);
+ DefinedBitcode(StringRef Name, bool IsWeak, uint8_t Other);
static bool classof(const SymbolBody *S);
};
class DefinedCommon : public Defined {
public:
- DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, bool IsWeak,
- uint8_t Visibility);
+ DefinedCommon(StringRef N, uint64_t Size, uint64_t Alignment, uint8_t Binding,
+ uint8_t Other, uint8_t Type);
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedCommonKind;
// Regular defined symbols read from object file symbol tables.
template <class ELFT> class DefinedRegular : public Defined {
typedef typename ELFT::Sym Elf_Sym;
+ typedef typename ELFT::uint uintX_t;
public:
DefinedRegular(StringRef Name, const Elf_Sym &Sym,
InputSectionBase<ELFT> *Section)
- : Defined(SymbolBody::DefinedRegularKind, Name,
- Sym.getBinding() == llvm::ELF::STB_WEAK,
- Sym.getBinding() == llvm::ELF::STB_LOCAL,
- Sym.getVisibility(), Sym.getType()),
- Sym(Sym), Section(Section ? Section->Repl : NullInputSection) {}
+ : Defined(SymbolBody::DefinedRegularKind, Name, Sym.getBinding(),
+ Sym.st_other, Sym.getType()),
+ Value(Sym.st_value), Size(Sym.st_size),
+ Section(Section ? Section->Repl : NullInputSection) {}
+
+ DefinedRegular(uint32_t NameOffset, const Elf_Sym &Sym,
+ InputSectionBase<ELFT> *Section)
+ : Defined(SymbolBody::DefinedRegularKind, NameOffset, Sym.st_other,
+ Sym.getType()),
+ Value(Sym.st_value), Size(Sym.st_size),
+ Section(Section ? Section->Repl : NullInputSection) {
+ assert(isLocal());
+ }
+
+ DefinedRegular(StringRef Name, uint8_t Binding, uint8_t Other)
+ : Defined(SymbolBody::DefinedRegularKind, Name, Binding, Other,
+ llvm::ELF::STT_NOTYPE),
+ Value(0), Size(0), Section(NullInputSection) {}
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedRegularKind;
}
- const Elf_Sym &Sym;
+ uintX_t Value;
+ uintX_t Size;
// The input section this symbol belongs to. Notice that this is
// a reference to a pointer. We are using two levels of indirections
// takes an output section to calculate output VA, etc.
template <class ELFT> class DefinedSynthetic : public Defined {
public:
- typedef typename ELFT::Sym Elf_Sym;
typedef typename ELFT::uint uintX_t;
DefinedSynthetic(StringRef N, uintX_t Value, OutputSectionBase<ELFT> &Section,
- uint8_t Visibility);
+ uint8_t Other);
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::DefinedSyntheticKind;
bool CanKeepUndefined;
protected:
- Undefined(Kind K, StringRef N, bool IsWeak, uint8_t Visibility, uint8_t Type);
+ Undefined(Kind K, StringRef N, uint8_t Binding, uint8_t Other, uint8_t Type);
+ Undefined(Kind K, uint32_t NameOffset, uint8_t Other, uint8_t Type);
public:
- Undefined(StringRef N, bool IsWeak, uint8_t Visibility,
- bool CanKeepUndefined);
+ Undefined(StringRef N, bool IsWeak, uint8_t Other, bool CanKeepUndefined);
static bool classof(const SymbolBody *S) { return S->isUndefined(); }
};
template <class ELFT> class UndefinedElf : public Undefined {
+ typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Sym Elf_Sym;
public:
UndefinedElf(StringRef N, const Elf_Sym &Sym);
- const Elf_Sym &Sym;
+ UndefinedElf(uint32_t NameOffset, const Elf_Sym &Sym);
+
+ uintX_t Size;
static bool classof(const SymbolBody *S) {
return S->kind() == SymbolBody::UndefinedElfKind;
}
SharedSymbol(SharedFile<ELFT> *F, StringRef Name, const Elf_Sym &Sym)
- : Defined(SymbolBody::SharedKind, Name,
- Sym.getBinding() == llvm::ELF::STB_WEAK,
- Sym.getBinding() == llvm::ELF::STB_LOCAL,
- Sym.getVisibility(), Sym.getType()),
+ : Defined(SymbolBody::SharedKind, Name, Sym.getBinding(), Sym.st_other,
+ Sym.getType()),
File(F), Sym(Sym) {}
SharedFile<ELFT> *File;
// OffsetInBss is significant only when needsCopy() is true.
uintX_t OffsetInBss = 0;
- bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->IsFunc; }
+ bool needsCopy() const { return this->NeedsCopyOrPltAddr && !this->isFunc(); }
};
// This class represents a symbol defined in an archive file. It is
class Lazy : public SymbolBody {
public:
Lazy(ArchiveFile *F, const llvm::object::Archive::Symbol S)
- : SymbolBody(LazyKind, S.getName(), false, false, llvm::ELF::STV_DEFAULT,
- /* Type */ 0),
+ : SymbolBody(LazyKind, S.getName(), llvm::ELF::STB_GLOBAL,
+ llvm::ELF::STV_DEFAULT, /* Type */ 0),
File(F), Sym(S) {}
static bool classof(const SymbolBody *S) { return S->kind() == LazyKind; }
// was already returned.
std::unique_ptr<InputFile> getMember();
- void setWeak() { IsWeak = true; }
-
private:
ArchiveFile *File;
const llvm::object::Archive::Symbol Sym;
};
// Some linker-generated symbols need to be created as
-// DefinedRegular symbols, so they need Elf_Sym symbols.
-// Here we allocate such Elf_Sym symbols statically.
+// DefinedRegular symbols.
template <class ELFT> struct ElfSym {
- typedef typename ELFT::Sym Elf_Sym;
-
- // Used to represent an undefined symbol which we don't want to add to the
- // output file's symbol table. It has weak binding and can be substituted.
- static Elf_Sym Ignored;
-
// The content for _etext and etext symbols.
- static Elf_Sym Etext;
+ static DefinedRegular<ELFT> *Etext;
+ static DefinedRegular<ELFT> *Etext2;
// The content for _edata and edata symbols.
- static Elf_Sym Edata;
+ static DefinedRegular<ELFT> *Edata;
+ static DefinedRegular<ELFT> *Edata2;
// The content for _end and end symbols.
- static Elf_Sym End;
+ static DefinedRegular<ELFT> *End;
+ static DefinedRegular<ELFT> *End2;
// The content for _gp symbol for MIPS target.
- static Elf_Sym MipsGp;
+ static DefinedRegular<ELFT> *MipsGp;
// __rel_iplt_start/__rel_iplt_end for signaling
// where R_[*]_IRELATIVE relocations do live.
- static Elf_Sym RelaIpltStart;
- static Elf_Sym RelaIpltEnd;
+ static DefinedRegular<ELFT> *RelaIpltStart;
+ static DefinedRegular<ELFT> *RelaIpltEnd;
};
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::Ignored;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::Etext;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::Edata;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::End;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::MipsGp;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::RelaIpltStart;
-template <class ELFT> typename ELFT::Sym ElfSym<ELFT>::RelaIpltEnd;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Etext2;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::Edata2;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::End2;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::MipsGp;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::RelaIpltStart;
+template <class ELFT> DefinedRegular<ELFT> *ElfSym<ELFT>::RelaIpltEnd;
} // namespace elf
} // namespace lld
}
bool TargetInfo::canRelaxTls(uint32_t Type, const SymbolBody *S) const {
- if (Config->Shared || (S && !S->IsTls))
+ if (Config->Shared || (S && !S->isTls()))
return false;
// We know we are producing an executable.
auto *SS = dyn_cast<SharedSymbol<ELFT>>(&S);
if (!SS)
return false;
- return SS->Sym.getType() == STT_OBJECT;
+ return SS->isObject();
}
template <class ELFT>
TargetInfo::PltNeed TargetInfo::needsPlt(uint32_t Type,
const SymbolBody &S) const {
- if (S.IsGnuIFunc)
+ if (S.isGnuIFunc())
return Plt_Explicit;
if (S.isPreemptible() && needsPltImpl(Type))
return Plt_Explicit;
// plt. That is identified by special relocation types (R_X86_64_JUMP_SLOT,
// R_386_JMP_SLOT, etc).
if (S.isShared())
- if (!Config->Pic && S.IsFunc && !refersToGotEntry(Type))
+ if (!Config->Pic && S.isFunc() && !refersToGotEntry(Type))
return Plt_Implicit;
return Plt_No;
}
bool X86TargetInfo::needsGot(uint32_t Type, const SymbolBody &S) const {
- if (S.IsTls && Type == R_386_TLS_GD)
+ if (S.isTls() && Type == R_386_TLS_GD)
return Target->canRelaxTls(Type, &S) && S.isPreemptible();
if (Type == R_386_TLS_GOTIE || Type == R_386_TLS_IE)
return !canRelaxTls(Type, &S);
// LA25 is required if target file has PIC code
// or target symbol is a PIC symbol.
return (D->Section->getFile()->getObj().getHeader()->e_flags & EF_MIPS_PIC) ||
- (D->Sym.st_other & STO_MIPS_MIPS16) == STO_MIPS_PIC;
+ (D->Other & STO_MIPS_MIPS16) == STO_MIPS_PIC;
}
template <class ELFT>
return 1;
}
- if (!Body.IsTls)
+ if (!Body.isTls())
return 0;
if (Target->isTlsGlobalDynamicRel(Type)) {
Out<ELFT>::Plt->addEntry(Body);
uint32_t Rel;
- if (Body.IsGnuIFunc)
+ if (Body.isGnuIFunc())
Rel = Preemptible ? Target->PltRel : Target->IRelativeRel;
else
Rel = Target->UseLazyBinding ? Target->PltRel : Target->GotRel;
!Target->isSizeRel(Type);
if (Preemptible || Dynrel) {
uint32_t DynType;
- if (Body.IsTls)
+ if (Body.isTls())
DynType = Target->TlsGotRel;
else if (Preemptible)
DynType = Target->GotRel;
}
template <class ELFT>
-static bool shouldKeepInSymtab(const elf::ObjectFile<ELFT> &File,
- StringRef SymName,
- const typename ELFT::Sym &Sym) {
- if (Sym.getType() == STT_FILE)
+static bool shouldKeepInSymtab(InputSectionBase<ELFT> *Sec, StringRef SymName,
+ const SymbolBody &B) {
+ if (B.isFile())
return false;
// We keep sections in symtab for relocatable output.
- if (Sym.getType() == STT_SECTION)
+ if (B.isSection())
return Config->Relocatable;
- // No reason to keep local undefined symbol in symtab.
- if (Sym.st_shndx == SHN_UNDEF)
- return false;
-
- InputSectionBase<ELFT> *Sec = File.getSection(Sym);
// If sym references a section in a discarded group, don't keep it.
- if (Sec == InputSection<ELFT>::Discarded)
+ if (Sec == &InputSection<ELFT>::Discarded)
return false;
if (Config->DiscardNone)
return;
for (const std::unique_ptr<elf::ObjectFile<ELFT>> &F :
Symtab.getObjectFiles()) {
+ const char *StrTab = F->getStringTable().data();
for (SymbolBody *B : F->getLocalSymbols()) {
- const Elf_Sym &Sym = cast<DefinedRegular<ELFT>>(B)->Sym;
- StringRef SymName = check(Sym.getName(F->getStringTable()));
- if (!shouldKeepInSymtab<ELFT>(*F, SymName, Sym))
+ auto *DR = dyn_cast<DefinedRegular<ELFT>>(B);
+ // No reason to keep local undefined symbol in symtab.
+ if (!DR)
+ continue;
+ StringRef SymName(StrTab + B->getNameOffset());
+ InputSectionBase<ELFT> *Sec = DR->Section;
+ if (!shouldKeepInSymtab<ELFT>(Sec, SymName, *B))
continue;
- if (Sym.st_shndx != SHN_ABS && !F->getSection(Sym)->Live)
+ if (Sec && !Sec->Live)
continue;
++Out<ELFT>::SymTab->NumLocals;
if (Config->Relocatable)
B->DynsymIndex = Out<ELFT>::SymTab->NumLocals;
- F->KeptLocalSyms.push_back(std::make_pair(
- &Sym, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
+ F->KeptLocalSyms.push_back(
+ std::make_pair(DR, Out<ELFT>::SymTab->StrTabSec.addString(SymName)));
}
}
}
uintX_t Align = getAlignment(SS);
Off = alignTo(Off, Align);
SS->OffsetInBss = Off;
- Off += SS->Sym.st_size;
+ Off += SS->template getSize<ELFT>();
MaxAlign = std::max(MaxAlign, Align);
}
Out<ELFT>::Bss->setSize(Off);
template <class ELFT>
bool Writer<ELFT>::isDiscarded(InputSectionBase<ELFT> *S) const {
- return !S || S == InputSection<ELFT>::Discarded || !S->Live ||
+ return !S || S == &InputSection<ELFT>::Discarded || !S->Live ||
Script->isDiscarded(S);
}
if (isOutputDynamic() || !Out<ELFT>::RelaPlt)
return;
StringRef S = Config->Rela ? "__rela_iplt_start" : "__rel_iplt_start";
- if (Symtab.find(S))
- Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltStart);
+ ElfSym<ELFT>::RelaIpltStart = Symtab.addIgnored(S);
S = Config->Rela ? "__rela_iplt_end" : "__rel_iplt_end";
- if (Symtab.find(S))
- Symtab.addAbsolute(S, ElfSym<ELFT>::RelaIpltEnd);
+ ElfSym<ELFT>::RelaIpltEnd = Symtab.addIgnored(S);
}
template <class ELFT> static bool includeInSymtab(const SymbolBody &B) {
return false;
if (auto *D = dyn_cast<DefinedRegular<ELFT>>(&B)) {
- // Don't include synthetic symbols like __init_array_start in every output.
- if (&D->Sym == &ElfSym<ELFT>::Ignored)
- return false;
// Exclude symbols pointing to garbage-collected sections.
if (D->Section && !D->Section->Live)
return false;
// The linker is expected to define some symbols depending on
// the linking result. This function defines such symbols.
template <class ELFT> void Writer<ELFT>::addReservedSymbols() {
+ if (Config->EMachine == EM_MIPS) {
+ // On MIPS O32 ABI, _gp_disp is a magic symbol designates offset between
+ // start of function and 'gp' pointer into GOT.
+ Config->MipsGpDisp = Symtab.addIgnored("_gp_disp");
+ // The __gnu_local_gp is a magic symbol equal to the current value of 'gp'
+ // pointer. This symbol is used in the code generated by .cpload pseudo-op
+ // in case of using -mno-shared option.
+ // https://sourceware.org/ml/binutils/2004-12/msg00094.html
+ Config->MipsLocalGp = Symtab.addIgnored("__gnu_local_gp");
+ }
+
+ // In the assembly for 32 bit x86 the _GLOBAL_OFFSET_TABLE_ symbol
+ // is magical and is used to produce a R_386_GOTPC relocation.
+ // The R_386_GOTPC relocation value doesn't actually depend on the
+ // symbol value, so it could use an index of STN_UNDEF which, according
+ // to the spec, means the symbol value is 0.
+ // Unfortunately both gas and MC keep the _GLOBAL_OFFSET_TABLE_ symbol in
+ // the object file.
+ // The situation is even stranger on x86_64 where the assembly doesn't
+ // need the magical symbol, but gas still puts _GLOBAL_OFFSET_TABLE_ as
+ // an undefined symbol in the .o files.
+ // Given that the symbol is effectively unused, we just create a dummy
+ // hidden one to avoid the undefined symbol error.
+ if (!Config->Relocatable)
+ Symtab.addIgnored("_GLOBAL_OFFSET_TABLE_");
+
// __tls_get_addr is defined by the dynamic linker for dynamic ELFs. For
// static linking the linker is required to optimize away any references to
// __tls_get_addr, so it's not defined anywhere. Create a hidden definition
if (!isOutputDynamic())
Symtab.addIgnored("__tls_get_addr");
- auto Define = [this](StringRef S, Elf_Sym &Sym) {
- if (Symtab.find(S))
- Symtab.addAbsolute(S, Sym);
+ auto Define = [this](StringRef S, DefinedRegular<ELFT> *&Sym,
+ DefinedRegular<ELFT> *&Sym2) {
+ Sym = Symtab.addIgnored(S, STV_DEFAULT);
// The name without the underscore is not a reserved name,
// so it is defined only when there is a reference against it.
S = S.substr(1);
if (SymbolBody *B = Symtab.find(S))
if (B->isUndefined())
- Symtab.addAbsolute(S, Sym);
+ Sym2 = Symtab.addAbsolute(S, STV_DEFAULT);
};
- Define("_end", ElfSym<ELFT>::End);
- Define("_etext", ElfSym<ELFT>::Etext);
- Define("_edata", ElfSym<ELFT>::Edata);
+ Define("_end", ElfSym<ELFT>::End, ElfSym<ELFT>::End2);
+ Define("_etext", ElfSym<ELFT>::Etext, ElfSym<ELFT>::Etext2);
+ Define("_edata", ElfSym<ELFT>::Edata, ElfSym<ELFT>::Edata2);
}
// Sort input sections by section name suffixes for
// to beginning or ending of .rela.plt section, respectively.
if (Out<ELFT>::RelaPlt) {
uintX_t Start = Out<ELFT>::RelaPlt->getVA();
- ElfSym<ELFT>::RelaIpltStart.st_value = Start;
- ElfSym<ELFT>::RelaIpltEnd.st_value = Start + Out<ELFT>::RelaPlt->getSize();
+ if (ElfSym<ELFT>::RelaIpltStart)
+ ElfSym<ELFT>::RelaIpltStart->Value = Start;
+ if (ElfSym<ELFT>::RelaIpltEnd)
+ ElfSym<ELFT>::RelaIpltEnd->Value = Start + Out<ELFT>::RelaPlt->getSize();
}
// Update MIPS _gp absolute symbol so that it points to the static data.
if (Config->EMachine == EM_MIPS)
- ElfSym<ELFT>::MipsGp.st_value = getMipsGpAddr<ELFT>();
+ ElfSym<ELFT>::MipsGp->Value = getMipsGpAddr<ELFT>();
// _etext is the first location after the last read-only loadable segment.
// _edata is the first location after the last read-write loadable segment.
Elf_Phdr &H = P.H;
if (H.p_type != PT_LOAD)
continue;
- ElfSym<ELFT>::End.st_value = H.p_vaddr + H.p_memsz;
- uintX_t Val = H.p_vaddr + H.p_filesz;
- if (H.p_flags & PF_W)
- ElfSym<ELFT>::Edata.st_value = Val;
- else
- ElfSym<ELFT>::Etext.st_value = Val;
+ uintX_t Val = H.p_vaddr + H.p_memsz;
+ if (ElfSym<ELFT>::End)
+ ElfSym<ELFT>::End->Value = Val;
+ if (ElfSym<ELFT>::End2)
+ ElfSym<ELFT>::End2->Value = Val;
+
+ Val = H.p_vaddr + H.p_filesz;
+ if (H.p_flags & PF_W) {
+ if (ElfSym<ELFT>::Edata)
+ ElfSym<ELFT>::Edata->Value = Val;
+ if (ElfSym<ELFT>::Edata2)
+ ElfSym<ELFT>::Edata2->Value = Val;
+ } else {
+ if (ElfSym<ELFT>::Etext)
+ ElfSym<ELFT>::Etext->Value = Val;
+ if (ElfSym<ELFT>::Etext2)
+ ElfSym<ELFT>::Etext2->Value = Val;
+ }
}
}
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
-// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
// CHECK-NEXT: Section: Absolute
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
-// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
// CHECK-NEXT: Section: Absolute
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
# CHECK-NEXT: Section: Undefined (0x0)
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: _gp
-# CHECK-NEXT: Value: 0x0
+# CHECK-NEXT: Name: __start
+# CHECK-NEXT: Value: 0x20000
# CHECK-NEXT: Size: 0
-# CHECK-NEXT: Binding: Local (0x0)
+# CHECK-NEXT: Binding: Global (0x1)
# CHECK-NEXT: Type: None (0x0)
# CHECK-NEXT: Other: 0
-# CHECK-NEXT: Section: Absolute (0xFFF1)
+# CHECK-NEXT: Section: .text
# CHECK-NEXT: }
# CHECK-NEXT: Symbol {
-# CHECK-NEXT: Name: __start
-# CHECK-NEXT: Value: 0x20000
+# CHECK-NEXT: Name: _gp
+# CHECK-NEXT: Value: 0x0
# CHECK-NEXT: Size: 0
-# CHECK-NEXT: Binding: Global (0x1)
+# CHECK-NEXT: Binding: Global
# CHECK-NEXT: Type: None (0x0)
# CHECK-NEXT: Other: 0
-# CHECK-NEXT: Section: .text
+# CHECK-NEXT: Section: Absolute (0xFFF1)
# CHECK-NEXT: }
# CHECK-NEXT: ]
# CHECK-NEXT: ProgramHeaders [
// RUN: llvm-readobj -t %t2 | FileCheck %s
.long _GLOBAL_OFFSET_TABLE_
-// CHECK-NOT: Name: _GLOBAL_OFFSET_TABLE_
+// CHECK: Name: _GLOBAL_OFFSET_TABLE_
+// CHECK-NEXT: Value:
+// CHECK-NEXT: Size: 0
+// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
-// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
// CHECK-NEXT: Section: Absolute
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
-// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
// CHECK-NEXT: Section: Absolute
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
-// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
// CHECK-NEXT: Section: Absolute
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
// CHECK-NEXT: Size: 0
// CHECK-NEXT: Binding: Local
// CHECK-NEXT: Type: None
-// CHECK-NEXT: Other: 0
+// CHECK-NEXT: Other [
+// CHECK-NEXT: STV_HIDDEN
+// CHECK-NEXT: ]
// CHECK-NEXT: Section: Absolute
// CHECK-NEXT: }
// CHECK-NEXT: Symbol {
# REQUIRES: mips
-# INT-SO-NOT: Name: _gp_disp
+# INT-SO: Name: _gp_disp
+# INT-SO-NEXT: Value:
+# INT-SO-NEXT: Size:
+# INT-SO-NEXT: Binding: Local
# EXT-SO: Name: _gp_disp
# EXT-SO-NEXT: Value: 0x20010
# ^-- %lo(0x37ff0-0x20004+4)
# EXE: SYMBOL TABLE:
-# EXE: 00037ff0 *ABS* 00000000 _gp
# EXE: 00020000 .text 00000000 __start
+# EXE: 00037ff0 *ABS* 00000000 _gp
# EXE: 00020010 .text 00000000 _foo
# SO: Disassembly of section .text: