1 //===- SymbolTable.cpp ----------------------------------------------------===//
2 //
3 //                             The LLVM Linker
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "SymbolTable.h"
11 #include "Config.h"
12 #include "Error.h"
13 #include "Symbols.h"
14 
15 using namespace llvm;
16 using namespace llvm::object;
17 
18 using namespace lld;
19 using namespace lld::elf2;
20 
21 SymbolTable::SymbolTable() {}
22 
23 void SymbolTable::addFile(std::unique_ptr<InputFile> File) {
24   File->parse();
25   InputFile *FileP = File.release();
26   if (auto *AF = dyn_cast<ArchiveFile>(FileP)) {
27     ArchiveFiles.emplace_back(AF);
28     for (Lazy &Sym : AF->getLazySymbols())
29       addLazy(&Sym);
30     return;
31   }
32   addELFFile(cast<ELFFileBase>(FileP));
33 }
34 
35 template <class ELFT> void SymbolTable::init() {
36   if (Config->Shared)
37     return;
38   EntrySym = new (Alloc) Undefined<ELFT>("_start", Undefined<ELFT>::Synthetic);
39   resolve<ELFT>(EntrySym);
40 }
41 
42 template <class ELFT> void SymbolTable::addELFFile(ELFFileBase *File) {
43   if (const ELFFileBase *Old = getFirstELF()) {
44     if (!Old->isCompatibleWith(*File))
45       error(Twine(Old->getName() + " is incompatible with " + File->getName()));
46   } else {
47     init<ELFT>();
48   }
49 
50   if (auto *O = dyn_cast<ObjectFileBase>(File)) {
51     ObjectFiles.emplace_back(O);
52     for (SymbolBody *Body : O->getSymbols())
53       resolve<ELFT>(Body);
54   }
55 
56   if (auto *S = dyn_cast<SharedFile<ELFT>>(File)) {
57     SharedFiles.emplace_back(S);
58     for (SharedSymbol<ELFT> &Body : S->getSharedSymbols())
59       resolve<ELFT>(&Body);
60   }
61 }
62 
63 void SymbolTable::addELFFile(ELFFileBase *File) {
64   switch (File->getELFKind()) {
65   case ELF32LEKind:
66     addELFFile<ELF32LE>(File);
67     break;
68   case ELF32BEKind:
69     addELFFile<ELF32BE>(File);
70     break;
71   case ELF64LEKind:
72     addELFFile<ELF64LE>(File);
73     break;
74   case ELF64BEKind:
75     addELFFile<ELF64BE>(File);
76     break;
77   }
78 }
79 
80 // This function resolves conflicts if there's an existing symbol with
81 // the same name. Decisions are made based on symbol type.
82 template <class ELFT> void SymbolTable::resolve(SymbolBody *New) {
83   Symbol *Sym = insert(New);
84   if (Sym->Body == New)
85     return;
86 
87   SymbolBody *Existing = Sym->Body;
88 
89   if (Lazy *L = dyn_cast<Lazy>(Existing)) {
90     if (New->isUndefined()) {
91       addMemberFile(L);
92       return;
93     }
94 
95     // Found a definition for something also in an archive. Ignore the archive
96     // definition.
97     Sym->Body = New;
98     return;
99   }
100 
101   // compare() returns -1, 0, or 1 if the lhs symbol is less preferable,
102   // equivalent (conflicting), or more preferable, respectively.
103   int comp = Existing->compare<ELFT>(New);
104   if (comp < 0)
105     Sym->Body = New;
106   if (comp == 0)
107     error(Twine("duplicate symbol: ") + Sym->Body->getName());
108 }
109 
110 Symbol *SymbolTable::insert(SymbolBody *New) {
111   // Find an existing Symbol or create and insert a new one.
112   StringRef Name = New->getName();
113   Symbol *&Sym = Symtab[Name];
114   if (!Sym) {
115     Sym = new (Alloc) Symbol(New);
116     New->setBackref(Sym);
117     return Sym;
118   }
119   New->setBackref(Sym);
120   return Sym;
121 }
122 
123 void SymbolTable::addLazy(Lazy *New) {
124   Symbol *Sym = insert(New);
125   if (Sym->Body == New)
126     return;
127   SymbolBody *Existing = Sym->Body;
128   if (Existing->isDefined() || Existing->isLazy())
129     return;
130   Sym->Body = New;
131   assert(Existing->isUndefined() && "Unexpected symbol kind.");
132   addMemberFile(New);
133 }
134 
135 void SymbolTable::addMemberFile(Lazy *Body) {
136   std::unique_ptr<InputFile> File = Body->getMember();
137 
138   // getMember returns nullptr if the member was already read from the library.
139   if (!File)
140     return;
141 
142   addFile(std::move(File));
143 }
144