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     switch (Sec.sh_type) {
45     case SHT_SYMTAB:
46       Symtab = &Sec;
47       break;
48     case SHT_STRTAB:
49     case SHT_NULL:
50     case SHT_RELA:
51     case SHT_REL:
52       break;
53     default:
54       auto *C = new (Alloc) SectionChunk<ELFT>(this->getObj(), &Sec);
55       Chunks.push_back(C);
56       break;
57     }
58   }
59 }
60 
61 template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
62   ErrorOr<StringRef> StringTableOrErr =
63       ELFObj->getStringTableForSymtab(*Symtab);
64   error(StringTableOrErr.getError());
65   StringRef StringTable = *StringTableOrErr;
66 
67   Elf_Sym_Range Syms = ELFObj->symbols(Symtab);
68   uint32_t NumSymbols = std::distance(Syms.begin(), Syms.end());
69   uint32_t FirstNonLocal = Symtab->sh_info;
70   if (FirstNonLocal > NumSymbols)
71     error("Invalid sh_info in symbol table");
72   Syms = llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
73   SymbolBodies.reserve(NumSymbols);
74   for (const Elf_Sym &Sym : Syms)
75     SymbolBodies.push_back(createSymbolBody(StringTable, &Sym));
76 }
77 
78 template <class ELFT>
79 SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
80                                                      const Elf_Sym *Sym) {
81   ErrorOr<StringRef> NameOrErr = Sym->getName(StringTable);
82   error(NameOrErr.getError());
83   StringRef Name = *NameOrErr;
84   switch (Sym->getBinding()) {
85   default:
86     error("unexpected binding");
87   case STB_GLOBAL:
88     if (Sym->isUndefined())
89       return new (Alloc) Undefined(Name);
90     return new (Alloc) DefinedRegular(Name);
91   case STB_WEAK:
92     if (Sym->isUndefined())
93       return new (Alloc) UndefinedWeak(Name);
94     return new (Alloc) DefinedWeak(Name);
95   }
96 }
97 
98 namespace lld {
99 namespace elf2 {
100 template class elf2::ObjectFile<llvm::object::ELF32LE>;
101 template class elf2::ObjectFile<llvm::object::ELF32BE>;
102 template class elf2::ObjectFile<llvm::object::ELF64LE>;
103 template class elf2::ObjectFile<llvm::object::ELF64BE>;
104 }
105 }
106