xref: /llvm-project-15.0.7/lld/ELF/Symbols.cpp (revision f4bf4227)
1 //===- Symbols.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 "Symbols.h"
11 #include "InputFiles.h"
12 #include "InputSection.h"
13 #include "OutputSections.h"
14 #include "Strings.h"
15 #include "SyntheticSections.h"
16 #include "Target.h"
17 #include "Writer.h"
18 
19 #include "lld/Common/ErrorHandler.h"
20 #include "llvm/ADT/STLExtras.h"
21 #include "llvm/Support/Path.h"
22 #include <cstring>
23 
24 using namespace llvm;
25 using namespace llvm::object;
26 using namespace llvm::ELF;
27 
28 using namespace lld;
29 using namespace lld::elf;
30 
31 Defined *ElfSym::Bss;
32 Defined *ElfSym::Etext1;
33 Defined *ElfSym::Etext2;
34 Defined *ElfSym::Edata1;
35 Defined *ElfSym::Edata2;
36 Defined *ElfSym::End1;
37 Defined *ElfSym::End2;
38 Defined *ElfSym::GlobalOffsetTable;
39 Defined *ElfSym::MipsGp;
40 Defined *ElfSym::MipsGpDisp;
41 Defined *ElfSym::MipsLocalGp;
42 
43 static uint64_t getSymVA(const Symbol &Sym, int64_t &Addend) {
44   switch (Sym.kind()) {
45   case Symbol::DefinedKind: {
46     auto &D = cast<Defined>(Sym);
47     SectionBase *IS = D.Section;
48     if (auto *ISB = dyn_cast_or_null<InputSectionBase>(IS))
49       IS = ISB->Repl;
50 
51     // According to the ELF spec reference to a local symbol from outside
52     // the group are not allowed. Unfortunately .eh_frame breaks that rule
53     // and must be treated specially. For now we just replace the symbol with
54     // 0.
55     if (IS == &InputSection::Discarded)
56       return 0;
57 
58     // This is an absolute symbol.
59     if (!IS)
60       return D.Value;
61 
62     uint64_t Offset = D.Value;
63 
64     // An object in an SHF_MERGE section might be referenced via a
65     // section symbol (as a hack for reducing the number of local
66     // symbols).
67     // Depending on the addend, the reference via a section symbol
68     // refers to a different object in the merge section.
69     // Since the objects in the merge section are not necessarily
70     // contiguous in the output, the addend can thus affect the final
71     // VA in a non-linear way.
72     // To make this work, we incorporate the addend into the section
73     // offset (and zero out the addend for later processing) so that
74     // we find the right object in the section.
75     if (D.isSection()) {
76       Offset += Addend;
77       Addend = 0;
78     }
79 
80     const OutputSection *OutSec = IS->getOutputSection();
81 
82     // In the typical case, this is actually very simple and boils
83     // down to adding together 3 numbers:
84     // 1. The address of the output section.
85     // 2. The offset of the input section within the output section.
86     // 3. The offset within the input section (this addition happens
87     //    inside InputSection::getOffset).
88     //
89     // If you understand the data structures involved with this next
90     // line (and how they get built), then you have a pretty good
91     // understanding of the linker.
92     uint64_t VA = (OutSec ? OutSec->Addr : 0) + IS->getOffset(Offset);
93 
94     if (D.isTls() && !Config->Relocatable) {
95       if (!Out::TlsPhdr)
96         fatal(toString(D.getFile()) +
97               " has an STT_TLS symbol but doesn't have an SHF_TLS section");
98       return VA - Out::TlsPhdr->p_vaddr;
99     }
100     return VA;
101   }
102   case Symbol::SharedKind: {
103     auto &SS = cast<SharedSymbol>(Sym);
104     if (SS.CopyRelSec)
105       return SS.CopyRelSec->getParent()->Addr + SS.CopyRelSec->OutSecOff;
106     if (SS.NeedsPltAddr)
107       return Sym.getPltVA();
108     return 0;
109   }
110   case Symbol::UndefinedKind:
111     return 0;
112   case Symbol::LazyArchiveKind:
113   case Symbol::LazyObjectKind:
114     assert(Sym.IsUsedInRegularObj && "lazy symbol reached writer");
115     return 0;
116   }
117   llvm_unreachable("invalid symbol kind");
118 }
119 
120 // Returns true if this is a weak undefined symbol.
121 bool Symbol::isUndefWeak() const {
122   // See comment on Lazy in Symbols.h for the details.
123   return !isLocal() && isWeak() && (isUndefined() || isLazy());
124 }
125 
126 InputFile *Symbol::getFile() const {
127   if (isLocal()) {
128     const SectionBase *Sec = cast<Defined>(this)->Section;
129     // Local absolute symbols actually have a file, but that is not currently
130     // used. We could support that by having a mostly redundant InputFile in
131     // Symbol, or having a special absolute section if needed.
132     return Sec ? cast<InputSectionBase>(Sec)->File : nullptr;
133   }
134   return File;
135 }
136 
137 // Overwrites all attributes with Other's so that this symbol becomes
138 // an alias to Other. This is useful for handling some options such as
139 // --wrap.
140 void Symbol::copyFrom(Symbol *Other) {
141   Symbol Sym = *this;
142   memcpy(this, Other, sizeof(SymbolUnion));
143 
144   Binding = Sym.Binding;
145   VersionId = Sym.VersionId;
146   Visibility = Sym.Visibility;
147   IsUsedInRegularObj = Sym.IsUsedInRegularObj;
148   ExportDynamic = Sym.ExportDynamic;
149   CanInline = Sym.CanInline;
150   Traced = Sym.Traced;
151   InVersionScript = Sym.InVersionScript;
152 }
153 
154 uint64_t Symbol::getVA(int64_t Addend) const {
155   uint64_t OutVA = getSymVA(*this, Addend);
156   return OutVA + Addend;
157 }
158 
159 uint64_t Symbol::getGotVA() const { return InX::Got->getVA() + getGotOffset(); }
160 
161 uint64_t Symbol::getGotOffset() const {
162   return GotIndex * Target->GotEntrySize;
163 }
164 
165 uint64_t Symbol::getGotPltVA() const {
166   if (this->IsInIgot)
167     return InX::IgotPlt->getVA() + getGotPltOffset();
168   return InX::GotPlt->getVA() + getGotPltOffset();
169 }
170 
171 uint64_t Symbol::getGotPltOffset() const {
172   return GotPltIndex * Target->GotPltEntrySize;
173 }
174 
175 uint64_t Symbol::getPltVA() const {
176   if (this->IsInIplt)
177     return InX::Iplt->getVA() + PltIndex * Target->PltEntrySize;
178   return InX::Plt->getVA() + Target->PltHeaderSize +
179          PltIndex * Target->PltEntrySize;
180 }
181 
182 uint64_t Symbol::getSize() const {
183   if (const auto *DR = dyn_cast<Defined>(this))
184     return DR->Size;
185   if (const auto *S = dyn_cast<SharedSymbol>(this))
186     return S->Size;
187   return 0;
188 }
189 
190 OutputSection *Symbol::getOutputSection() const {
191   if (auto *S = dyn_cast<Defined>(this)) {
192     if (S->Section)
193       return S->Section->getOutputSection();
194     return nullptr;
195   }
196 
197   if (auto *S = dyn_cast<SharedSymbol>(this)) {
198     if (S->CopyRelSec)
199       return S->CopyRelSec->getParent();
200     return nullptr;
201   }
202 
203   return nullptr;
204 }
205 
206 // If a symbol name contains '@', the characters after that is
207 // a symbol version name. This function parses that.
208 void Symbol::parseSymbolVersion() {
209   StringRef S = getName();
210   size_t Pos = S.find('@');
211   if (Pos == 0 || Pos == StringRef::npos)
212     return;
213   StringRef Verstr = S.substr(Pos + 1);
214   if (Verstr.empty())
215     return;
216 
217   // Truncate the symbol name so that it doesn't include the version string.
218   Name = {S.data(), Pos};
219 
220   // If this is not in this DSO, it is not a definition.
221   if (!isDefined())
222     return;
223 
224   // '@@' in a symbol name means the default version.
225   // It is usually the most recent one.
226   bool IsDefault = (Verstr[0] == '@');
227   if (IsDefault)
228     Verstr = Verstr.substr(1);
229 
230   for (VersionDefinition &Ver : Config->VersionDefinitions) {
231     if (Ver.Name != Verstr)
232       continue;
233 
234     if (IsDefault)
235       VersionId = Ver.Id;
236     else
237       VersionId = Ver.Id | VERSYM_HIDDEN;
238     return;
239   }
240 
241   // It is an error if the specified version is not defined.
242   // Usually version script is not provided when linking executable,
243   // but we may still want to override a versioned symbol from DSO,
244   // so we do not report error in this case.
245   if (Config->Shared)
246     error(toString(getFile()) + ": symbol " + S + " has undefined version " +
247           Verstr);
248 }
249 
250 InputFile *Lazy::fetch() {
251   if (auto *S = dyn_cast<LazyArchive>(this))
252     return S->fetch();
253   return cast<LazyObject>(this)->fetch();
254 }
255 
256 ArchiveFile *LazyArchive::getFile() {
257   return cast<ArchiveFile>(Symbol::getFile());
258 }
259 
260 InputFile *LazyArchive::fetch() {
261   std::pair<MemoryBufferRef, uint64_t> MBInfo = getFile()->getMember(&Sym);
262 
263   // getMember returns an empty buffer if the member was already
264   // read from the library.
265   if (MBInfo.first.getBuffer().empty())
266     return nullptr;
267   return createObjectFile(MBInfo.first, getFile()->getName(), MBInfo.second);
268 }
269 
270 LazyObjFile *LazyObject::getFile() {
271   return cast<LazyObjFile>(Symbol::getFile());
272 }
273 
274 InputFile *LazyObject::fetch() { return getFile()->fetch(); }
275 
276 uint8_t Symbol::computeBinding() const {
277   if (Config->Relocatable)
278     return Binding;
279   if (Visibility != STV_DEFAULT && Visibility != STV_PROTECTED)
280     return STB_LOCAL;
281   if (VersionId == VER_NDX_LOCAL && isDefined())
282     return STB_LOCAL;
283   if (Config->NoGnuUnique && Binding == STB_GNU_UNIQUE)
284     return STB_GLOBAL;
285   return Binding;
286 }
287 
288 bool Symbol::includeInDynsym() const {
289   if (!Config->HasDynSymTab)
290     return false;
291   if (computeBinding() == STB_LOCAL)
292     return false;
293   if (!isDefined())
294     return true;
295   return ExportDynamic;
296 }
297 
298 // Print out a log message for --trace-symbol.
299 void elf::printTraceSymbol(Symbol *Sym) {
300   std::string S;
301   if (Sym->isUndefined())
302     S = ": reference to ";
303   else if (Sym->isLazy())
304     S = ": lazy definition of ";
305   else if (Sym->isShared())
306     S = ": shared definition of ";
307   else if (dyn_cast_or_null<BssSection>(cast<Defined>(Sym)->Section))
308     S = ": common definition of ";
309   else
310     S = ": definition of ";
311 
312   message(toString(Sym->File) + S + Sym->getName());
313 }
314 
315 // Returns a symbol for an error message.
316 std::string lld::toString(const Symbol &B) {
317   if (Config->Demangle)
318     if (Optional<std::string> S = demangle(B.getName()))
319       return *S;
320   return B.getName();
321 }
322