1 //===- InputFiles.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 "InputFiles.h"
11 #include "Chunks.h"
12 #include "Error.h"
13 #include "Symbols.h"
14 #include "llvm/ADT/STLExtras.h"
15 
16 using namespace llvm::ELF;
17 
18 using namespace lld;
19 using namespace lld::elf2;
20 
21 template <class ELFT>
22 bool ObjectFile<ELFT>::isCompatibleWith(const ObjectFileBase &Other) const {
23   if (kind() != Other.kind())
24     return false;
25   return getObj()->getHeader()->e_machine ==
26          cast<ObjectFile<ELFT>>(Other).getObj()->getHeader()->e_machine;
27 }
28 
29 template <class ELFT> void elf2::ObjectFile<ELFT>::parse() {
30   // Parse a memory buffer as a ELF file.
31   std::error_code EC;
32   ELFObj = llvm::make_unique<ELFFile<ELFT>>(MB.getBuffer(), EC);
33   error(EC);
34 
35   // Read section and symbol tables.
36   initializeChunks();
37   initializeSymbols();
38 }
39 
40 template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
41   uint64_t Size = ELFObj->getNumSections();
42   Chunks.reserve(Size);
43   for (const Elf_Shdr &Sec : ELFObj->sections()) {
44     if (Sec.sh_type == SHT_SYMTAB) {
45       Symtab = &Sec;
46       continue;
47     }
48     if (Sec.sh_flags & SHF_ALLOC) {
49       auto *C = new (Alloc) SectionChunk<ELFT>(this->getObj(), &Sec);
50       Chunks.push_back(C);
51     }
52   }
53 }
54 
55 template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
56   ErrorOr<StringRef> StringTableOrErr =
57       ELFObj->getStringTableForSymtab(*Symtab);
58   error(StringTableOrErr.getError());
59   StringRef StringTable = *StringTableOrErr;
60 
61   Elf_Sym_Range Syms = ELFObj->symbols(Symtab);
62   uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
63   uint32_t FirstNonLocal = Symtab->sh_info;
64   if (FirstNonLocal > NumSymbols)
65     error("Invalid sh_info in symbol table");
66   Syms = llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
67   SymbolBodies.reserve(NumSymbols);
68   for (const Elf_Sym &Sym : Syms)
69     SymbolBodies.push_back(createSymbolBody(StringTable, &Sym));
70 }
71 
72 template <class ELFT>
73 SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
74                                                      const Elf_Sym *Sym) {
75   ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
76   error(NameOrErr.getError());
77   StringRef Name = *NameOrErr;
78   switch (Sym->getBinding()) {
79   default:
80     error("unexpected binding");
81   case STB_GLOBAL:
82     if (Sym->isUndefined())
83       return new (Alloc) Undefined(Name);
84     return new (Alloc) DefinedRegular(Name);
85   case STB_WEAK:
86     if (Sym->isUndefined())
87       return new (Alloc) UndefinedWeak(Name);
88     return new (Alloc) DefinedWeak(Name);
89   }
90 }
91 
92 namespace lld {
93 namespace elf2 {
94 template class elf2::ObjectFile<llvm::object::ELF32LE>;
95 template class elf2::ObjectFile<llvm::object::ELF32BE>;
96 template class elf2::ObjectFile<llvm::object::ELF64LE>;
97 template class elf2::ObjectFile<llvm::object::ELF64BE>;
98 }
99 }
100