]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/llvm-objcopy/COFF/Reader.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / llvm-objcopy / COFF / Reader.cpp
1 //===- Reader.cpp ---------------------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "Reader.h"
10 #include "Object.h"
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/ADT/StringRef.h"
13 #include "llvm/BinaryFormat/COFF.h"
14 #include "llvm/Object/COFF.h"
15 #include "llvm/Support/ErrorHandling.h"
16 #include <cstddef>
17 #include <cstdint>
18
19 namespace llvm {
20 namespace objcopy {
21 namespace coff {
22
23 using namespace object;
24 using namespace COFF;
25
26 Error COFFReader::readExecutableHeaders(Object &Obj) const {
27   const dos_header *DH = COFFObj.getDOSHeader();
28   Obj.Is64 = COFFObj.is64();
29   if (!DH)
30     return Error::success();
31
32   Obj.IsPE = true;
33   Obj.DosHeader = *DH;
34   if (DH->AddressOfNewExeHeader > sizeof(*DH))
35     Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
36                                     DH->AddressOfNewExeHeader - sizeof(*DH));
37
38   if (COFFObj.is64()) {
39     const pe32plus_header *PE32Plus = nullptr;
40     if (auto EC = COFFObj.getPE32PlusHeader(PE32Plus))
41       return errorCodeToError(EC);
42     Obj.PeHeader = *PE32Plus;
43   } else {
44     const pe32_header *PE32 = nullptr;
45     if (auto EC = COFFObj.getPE32Header(PE32))
46       return errorCodeToError(EC);
47     copyPeHeader(Obj.PeHeader, *PE32);
48     // The pe32plus_header (stored in Object) lacks the BaseOfData field.
49     Obj.BaseOfData = PE32->BaseOfData;
50   }
51
52   for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
53     const data_directory *Dir;
54     if (auto EC = COFFObj.getDataDirectory(I, Dir))
55       return errorCodeToError(EC);
56     Obj.DataDirectories.emplace_back(*Dir);
57   }
58   return Error::success();
59 }
60
61 Error COFFReader::readSections(Object &Obj) const {
62   std::vector<Section> Sections;
63   // Section indexing starts from 1.
64   for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
65     const coff_section *Sec;
66     if (auto EC = COFFObj.getSection(I, Sec))
67       return errorCodeToError(EC);
68     Sections.push_back(Section());
69     Section &S = Sections.back();
70     S.Header = *Sec;
71     ArrayRef<uint8_t> Contents;
72     if (Error E = COFFObj.getSectionContents(Sec, Contents))
73       return E;
74     S.setContentsRef(Contents);
75     ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
76     for (const coff_relocation &R : Relocs)
77       S.Relocs.push_back(R);
78     if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec))
79       S.Name = *NameOrErr;
80     else
81       return NameOrErr.takeError();
82     if (Sec->hasExtendedRelocations())
83       return createStringError(object_error::parse_failed,
84                                "extended relocations not supported yet");
85   }
86   Obj.addSections(Sections);
87   return Error::success();
88 }
89
90 Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
91   std::vector<Symbol> Symbols;
92   Symbols.reserve(COFFObj.getRawNumberOfSymbols());
93   ArrayRef<Section> Sections = Obj.getSections();
94   for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
95     Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
96     if (!SymOrErr)
97       return SymOrErr.takeError();
98     COFFSymbolRef SymRef = *SymOrErr;
99
100     Symbols.push_back(Symbol());
101     Symbol &Sym = Symbols.back();
102     // Copy symbols from the original form into an intermediate coff_symbol32.
103     if (IsBigObj)
104       copySymbol(Sym.Sym,
105                  *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
106     else
107       copySymbol(Sym.Sym,
108                  *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
109     if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name))
110       return errorCodeToError(EC);
111
112     ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
113     size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
114     assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
115     // The auxillary symbols are structs of sizeof(coff_symbol16) each.
116     // In the big object format (where symbols are coff_symbol32), each
117     // auxillary symbol is padded with 2 bytes at the end. Copy each
118     // auxillary symbol to the Sym.AuxData vector. For file symbols,
119     // the whole range of aux symbols are interpreted as one null padded
120     // string instead.
121     if (SymRef.isFileRecord())
122       Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
123                               AuxData.size())
124                         .rtrim('\0');
125     else
126       for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
127         Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
128
129     // Find the unique id of the section
130     if (SymRef.getSectionNumber() <=
131         0) // Special symbol (undefined/absolute/debug)
132       Sym.TargetSectionId = SymRef.getSectionNumber();
133     else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
134              Sections.size())
135       Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
136     else
137       return createStringError(object_error::parse_failed,
138                                "section number out of range");
139     // For section definitions, check if it is comdat associative, and if
140     // it is, find the target section unique id.
141     const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
142     const coff_aux_weak_external *WE = SymRef.getWeakExternal();
143     if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
144       int32_t Index = SD->getNumber(IsBigObj);
145       if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
146         return createStringError(object_error::parse_failed,
147                                  "unexpected associative section index");
148       Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
149     } else if (WE) {
150       // This is a raw symbol index for now, but store it in the Symbol
151       // until we've added them to the Object, which assigns the final
152       // unique ids.
153       Sym.WeakTargetSymbolId = WE->TagIndex;
154     }
155     I += 1 + SymRef.getNumberOfAuxSymbols();
156   }
157   Obj.addSymbols(Symbols);
158   return Error::success();
159 }
160
161 Error COFFReader::setSymbolTargets(Object &Obj) const {
162   std::vector<const Symbol *> RawSymbolTable;
163   for (const Symbol &Sym : Obj.getSymbols()) {
164     RawSymbolTable.push_back(&Sym);
165     for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
166       RawSymbolTable.push_back(nullptr);
167   }
168   for (Symbol &Sym : Obj.getMutableSymbols()) {
169     // Convert WeakTargetSymbolId from the original raw symbol index to
170     // a proper unique id.
171     if (Sym.WeakTargetSymbolId) {
172       if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
173         return createStringError(object_error::parse_failed,
174                                  "weak external reference out of range");
175       const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
176       if (Target == nullptr)
177         return createStringError(object_error::parse_failed,
178                                  "invalid SymbolTableIndex");
179       Sym.WeakTargetSymbolId = Target->UniqueId;
180     }
181   }
182   for (Section &Sec : Obj.getMutableSections()) {
183     for (Relocation &R : Sec.Relocs) {
184       if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
185         return createStringError(object_error::parse_failed,
186                                  "SymbolTableIndex out of range");
187       const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
188       if (Sym == nullptr)
189         return createStringError(object_error::parse_failed,
190                                  "invalid SymbolTableIndex");
191       R.Target = Sym->UniqueId;
192       R.TargetName = Sym->Name;
193     }
194   }
195   return Error::success();
196 }
197
198 Expected<std::unique_ptr<Object>> COFFReader::create() const {
199   auto Obj = llvm::make_unique<Object>();
200
201   const coff_file_header *CFH = nullptr;
202   const coff_bigobj_file_header *CBFH = nullptr;
203   COFFObj.getCOFFHeader(CFH);
204   COFFObj.getCOFFBigObjHeader(CBFH);
205   bool IsBigObj = false;
206   if (CFH) {
207     Obj->CoffFileHeader = *CFH;
208   } else {
209     if (!CBFH)
210       return createStringError(object_error::parse_failed,
211                                "no COFF file header returned");
212     // Only copying the few fields from the bigobj header that we need
213     // and won't recreate in the end.
214     Obj->CoffFileHeader.Machine = CBFH->Machine;
215     Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
216     IsBigObj = true;
217   }
218
219   if (Error E = readExecutableHeaders(*Obj))
220     return std::move(E);
221   if (Error E = readSections(*Obj))
222     return std::move(E);
223   if (Error E = readSymbols(*Obj, IsBigObj))
224     return std::move(E);
225   if (Error E = setSymbolTargets(*Obj))
226     return std::move(E);
227
228   return std::move(Obj);
229 }
230
231 } // end namespace coff
232 } // end namespace objcopy
233 } // end namespace llvm