uint32_t Flags = Sym.getFlags();
bool IsWeak = Flags & BasicSymbolRef::SF_Weak;
if (Flags & BasicSymbolRef::SF_Undefined) {
- Body = new (Alloc) Undefined(NameRef, IsWeak, Visibility, false);
+ Body = new (Alloc) UndefinedBitcode(NameRef, IsWeak, Visibility);
} else if (Flags & BasicSymbolRef::SF_Common) {
const DataLayout &DL = M.getDataLayout();
uint64_t Size = DL.getTypeAllocSize(GV->getValueType());
return Out<ELFT>::Bss;
break;
case SymbolBody::UndefinedElfKind:
- case SymbolBody::UndefinedKind:
+ case SymbolBody::UndefinedBitcodeKind:
case SymbolBody::LazyKind:
break;
case SymbolBody::DefinedBitcodeKind:
// Add an undefined symbol.
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefined(StringRef Name) {
- auto *Sym = new (Alloc) Undefined(Name, false, STV_DEFAULT, false);
+ auto *Sym = new (Alloc)
+ UndefinedElf<ELFT>(Name, STB_GLOBAL, STV_DEFAULT, /*Type*/ 0, false);
resolve(Sym);
return Sym;
}
// doesn't have to be resolved, thus "opt" (optional).
template <class ELFT>
SymbolBody *SymbolTable<ELFT>::addUndefinedOpt(StringRef Name) {
- auto *Sym = new (Alloc) Undefined(Name, false, STV_HIDDEN, true);
+ auto *Sym = new (Alloc)
+ UndefinedElf<ELFT>(Name, STB_GLOBAL, STV_HIDDEN, /*Type*/ 0, true);
resolve(Sym);
return Sym;
}
SymbolBody *Existing = Sym->Body;
if (auto *L = dyn_cast<Lazy>(Existing)) {
- if (auto *Undef = dyn_cast<Undefined>(New)) {
- addMemberFile(Undef, L);
+ if (New->isUndefined()) {
+ addMemberFile(New, L);
return;
}
// Found a definition for something also in an archive.
template <class ELFT> void SymbolTable<ELFT>::addLazy(Lazy *L) {
Symbol *Sym = insert(L);
- if (Sym->Body == L)
+ SymbolBody *Cur = Sym->Body;
+ if (Cur == L)
return;
- if (auto *Undef = dyn_cast<Undefined>(Sym->Body)) {
+ if (Cur->isUndefined()) {
Sym->Body = L;
- addMemberFile(Undef, L);
+ addMemberFile(Cur, L);
}
}
template <class ELFT>
-void SymbolTable<ELFT>::addMemberFile(Undefined *Undef, Lazy *L) {
+void SymbolTable<ELFT>::addMemberFile(SymbolBody *Undef, Lazy *L) {
if (Undef->isUsedInRegularObj())
L->setUsedInRegularObj();
// Weak undefined symbols should not fetch members from archives.
class Lazy;
template <class ELFT> class OutputSectionBase;
struct Symbol;
-class Undefined;
// SymbolTable is a bucket of all known symbols, including defined,
// undefined, or lazy symbols (the last one is symbols in archive
private:
Symbol *insert(SymbolBody *New);
void addLazy(Lazy *New);
- void addMemberFile(Undefined *Undef, Lazy *L);
+ void addMemberFile(SymbolBody *Undef, Lazy *L);
void resolve(SymbolBody *Body);
std::string conflictMsg(SymbolBody *Old, SymbolBody *New);
return Out<ELFT>::Bss->getVA() + SS.OffsetInBss;
}
case SymbolBody::UndefinedElfKind:
- case SymbolBody::UndefinedKind:
+ case SymbolBody::UndefinedBitcodeKind:
return 0;
case SymbolBody::LazyKind:
assert(Body.isUsedInRegularObj() && "lazy symbol reached writer");
uint8_t Type)
: SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
Type(Type), Binding(STB_LOCAL), StOther(StOther), NameOffset(NameOffset) {
- IsUsedInRegularObj =
- K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
+ init();
+}
+
+SymbolBody::SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
+ uint8_t Type)
+ : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
+ Type(Type), Binding(Binding), StOther(StOther),
+ Name({Name.data(), Name.size()}) {
+ assert(!isLocal());
+ init();
+}
+
+void SymbolBody::init() {
+ Kind K = kind();
+ IsUsedInRegularObj = K == DefinedRegularKind || K == DefinedCommonKind ||
+ K == DefinedSyntheticKind || K == UndefinedElfKind;
}
// Returns true if a symbol can be replaced at load-time by a symbol
return S->kind() == DefinedBitcodeKind;
}
-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 StOther, uint8_t Type)
- : SymbolBody(K, NameOffset, StOther, Type), CanKeepUndefined(false) {}
-
-Undefined::Undefined(StringRef N, bool IsWeak, uint8_t StOther,
- bool CanKeepUndefined)
- : Undefined(SymbolBody::UndefinedKind, N, IsWeak ? STB_WEAK : STB_GLOBAL,
- StOther, 0 /* Type */) {
- this->CanKeepUndefined = CanKeepUndefined;
-}
+UndefinedBitcode::UndefinedBitcode(StringRef N, bool IsWeak, uint8_t StOther)
+ : SymbolBody(SymbolBody::UndefinedBitcodeKind, N,
+ IsWeak ? STB_WEAK : STB_GLOBAL, StOther, 0 /* Type */) {}
template <typename ELFT>
UndefinedElf<ELFT>::UndefinedElf(StringRef N, const Elf_Sym &Sym)
- : Undefined(SymbolBody::UndefinedElfKind, N, Sym.getBinding(), Sym.st_other,
- Sym.getType()),
+ : SymbolBody(SymbolBody::UndefinedElfKind, N, Sym.getBinding(),
+ Sym.st_other, Sym.getType()),
Size(Sym.st_size) {}
template <typename ELFT>
+UndefinedElf<ELFT>::UndefinedElf(StringRef Name, uint8_t Binding,
+ uint8_t StOther, uint8_t Type,
+ bool CanKeepUndefined)
+ : SymbolBody(SymbolBody::UndefinedElfKind, Name, Binding, StOther, Type),
+ CanKeepUndefined(CanKeepUndefined) {}
+
+template <typename ELFT>
UndefinedElf<ELFT>::UndefinedElf(const Elf_Sym &Sym)
- : Undefined(SymbolBody::UndefinedElfKind, Sym.st_name, Sym.st_other,
- Sym.getType()),
+ : SymbolBody(SymbolBody::UndefinedElfKind, Sym.st_name, Sym.st_other,
+ Sym.getType()),
Size(Sym.st_size) {
assert(Sym.getBinding() == STB_LOCAL);
}
// The base class for real symbol classes.
class SymbolBody {
+ void init();
+
public:
enum Kind {
DefinedFirst,
DefinedSyntheticKind,
DefinedLast = DefinedSyntheticKind,
UndefinedElfKind,
- UndefinedKind,
+ UndefinedBitcodeKind,
LazyKind
};
bool isWeak() const { return Binding == llvm::ELF::STB_WEAK; }
bool isUndefined() const {
- return SymbolKind == UndefinedKind || SymbolKind == UndefinedElfKind;
+ return SymbolKind == UndefinedBitcodeKind || SymbolKind == UndefinedElfKind;
}
bool isDefined() const { return SymbolKind <= DefinedLast; }
bool isCommon() const { return SymbolKind == DefinedCommonKind; }
protected:
SymbolBody(Kind K, StringRef Name, uint8_t Binding, uint8_t StOther,
- uint8_t Type)
- : SymbolKind(K), MustBeInDynSym(false), NeedsCopyOrPltAddr(false),
- Type(Type), Binding(Binding), StOther(StOther),
- Name({Name.data(), Name.size()}) {
- assert(!isLocal());
- IsUsedInRegularObj =
- K != SharedKind && K != LazyKind && K != DefinedBitcodeKind;
- }
+ uint8_t Type);
SymbolBody(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
const OutputSectionBase<ELFT> &Section;
};
-// Undefined symbol.
-class Undefined : public SymbolBody {
- typedef SymbolBody::Kind Kind;
- bool CanKeepUndefined;
-
-protected:
- Undefined(Kind K, StringRef N, uint8_t Binding, uint8_t StOther,
- uint8_t Type);
- Undefined(Kind K, uint32_t NameOffset, uint8_t StOther, uint8_t Type);
-
+class UndefinedBitcode : public SymbolBody {
public:
- Undefined(StringRef N, bool IsWeak, uint8_t StOther, bool CanKeepUndefined);
+ UndefinedBitcode(StringRef N, bool IsWeak, uint8_t StOther);
- static bool classof(const SymbolBody *S) { return S->isUndefined(); }
-
- bool canKeepUndefined() const { return CanKeepUndefined; }
+ static bool classof(const SymbolBody *S) {
+ return S->kind() == UndefinedBitcodeKind;
+ }
};
-template <class ELFT> class UndefinedElf : public Undefined {
+template <class ELFT> class UndefinedElf : public SymbolBody {
typedef typename ELFT::uint uintX_t;
typedef typename ELFT::Sym Elf_Sym;
+ bool CanKeepUndefined = false;
public:
UndefinedElf(StringRef N, const Elf_Sym &Sym);
UndefinedElf(const Elf_Sym &Sym);
+ UndefinedElf(StringRef Name, uint8_t Binding, uint8_t StOther, uint8_t Type,
+ bool CanKeepUndefined);
+
+ bool canKeepUndefined() const { return CanKeepUndefined; }
uintX_t Size;
std::vector<DefinedCommon *> CommonSymbols;
for (auto &P : Symtab.getSymbols()) {
SymbolBody *Body = P.second->Body;
- if (auto *U = dyn_cast<Undefined>(Body))
- if (!U->isWeak() && !U->canKeepUndefined())
+ if (Body->isUndefined() && !Body->isWeak()) {
+ auto *U = dyn_cast<UndefinedElf<ELFT>>(Body);
+ if (!U || !U->canKeepUndefined())
reportUndefined<ELFT>(Symtab, Body);
+ }
if (auto *C = dyn_cast<DefinedCommon>(Body))
CommonSymbols.push_back(C);
--- /dev/null
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define void @f() {
+ ret void
+}
--- /dev/null
+; REQUIRES: x86
+; RUN: llvm-as %s -o %t.o
+; RUN: llvm-as %p/Inputs/internalize-undef.ll -o %t2.o
+; RUN: ld.lld -m elf_x86_64 %t.o %t2.o -o %t -save-temps
+; RUN: llvm-dis < %t.lto.bc | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+declare void @f()
+define void @_start() {
+ call void @f()
+ ret void
+}
+
+; CHECK: define internal void @f()