blob: 7270bbf94de6f9d58707a13fae222d6859b82382 [file] [log] [blame]
Martin Storsjoe84a0b52018-12-19 07:24:38 +00001//===- Reader.cpp ---------------------------------------------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Martin Storsjoe84a0b52018-12-19 07:24:38 +00006//
7//===----------------------------------------------------------------------===//
8
9#include "Reader.h"
10#include "Object.h"
11#include "llvm-objcopy.h"
12#include "llvm/ADT/ArrayRef.h"
13#include "llvm/ADT/StringRef.h"
Martin Storsjof9e14342019-01-19 19:42:35 +000014#include "llvm/BinaryFormat/COFF.h"
Martin Storsjoe84a0b52018-12-19 07:24:38 +000015#include "llvm/Object/COFF.h"
16#include "llvm/Support/ErrorHandling.h"
17#include <cstddef>
18#include <cstdint>
19
20namespace llvm {
21namespace objcopy {
22namespace coff {
23
24using namespace object;
Martin Storsjof9e14342019-01-19 19:42:35 +000025using namespace COFF;
Martin Storsjoe84a0b52018-12-19 07:24:38 +000026
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000027Error COFFReader::readExecutableHeaders(Object &Obj) const {
Martin Storsjoe84a0b52018-12-19 07:24:38 +000028 const dos_header *DH = COFFObj.getDOSHeader();
29 Obj.Is64 = COFFObj.is64();
30 if (!DH)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000031 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000032
33 Obj.IsPE = true;
34 Obj.DosHeader = *DH;
35 if (DH->AddressOfNewExeHeader > sizeof(*DH))
36 Obj.DosStub = ArrayRef<uint8_t>(reinterpret_cast<const uint8_t *>(&DH[1]),
37 DH->AddressOfNewExeHeader - sizeof(*DH));
38
39 if (COFFObj.is64()) {
40 const pe32plus_header *PE32Plus = nullptr;
41 if (auto EC = COFFObj.getPE32PlusHeader(PE32Plus))
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000042 return errorCodeToError(EC);
Martin Storsjoe84a0b52018-12-19 07:24:38 +000043 Obj.PeHeader = *PE32Plus;
44 } else {
45 const pe32_header *PE32 = nullptr;
46 if (auto EC = COFFObj.getPE32Header(PE32))
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000047 return errorCodeToError(EC);
Martin Storsjoe84a0b52018-12-19 07:24:38 +000048 copyPeHeader(Obj.PeHeader, *PE32);
49 // The pe32plus_header (stored in Object) lacks the BaseOfData field.
50 Obj.BaseOfData = PE32->BaseOfData;
51 }
52
53 for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) {
54 const data_directory *Dir;
55 if (auto EC = COFFObj.getDataDirectory(I, Dir))
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000056 return errorCodeToError(EC);
Martin Storsjoe84a0b52018-12-19 07:24:38 +000057 Obj.DataDirectories.emplace_back(*Dir);
58 }
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000059 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000060}
61
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000062Error COFFReader::readSections(Object &Obj) const {
Martin Storsjof9e14342019-01-19 19:42:35 +000063 std::vector<Section> Sections;
Martin Storsjoe84a0b52018-12-19 07:24:38 +000064 // Section indexing starts from 1.
65 for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) {
66 const coff_section *Sec;
67 if (auto EC = COFFObj.getSection(I, Sec))
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000068 return errorCodeToError(EC);
Martin Storsjof9e14342019-01-19 19:42:35 +000069 Sections.push_back(Section());
70 Section &S = Sections.back();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000071 S.Header = *Sec;
Martin Storsjo12b6b802019-01-23 08:25:28 +000072 ArrayRef<uint8_t> Contents;
73 if (auto EC = COFFObj.getSectionContents(Sec, Contents))
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000074 return errorCodeToError(EC);
Martin Storsjo12b6b802019-01-23 08:25:28 +000075 S.setContentsRef(Contents);
Martin Storsjoe84a0b52018-12-19 07:24:38 +000076 ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000077 for (const coff_relocation &R : Relocs)
Martin Storsjo4c1c4fc2019-01-10 21:59:41 +000078 S.Relocs.push_back(R);
Martin Storsjoe84a0b52018-12-19 07:24:38 +000079 if (auto EC = COFFObj.getSectionName(Sec, S.Name))
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000080 return errorCodeToError(EC);
Martin Storsjoe84a0b52018-12-19 07:24:38 +000081 if (Sec->hasExtendedRelocations())
Martin Storsjo8010c6be2019-01-22 10:57:59 +000082 return createStringError(object_error::parse_failed,
83 "Extended relocations not supported yet");
Martin Storsjoe84a0b52018-12-19 07:24:38 +000084 }
Martin Storsjof9e14342019-01-19 19:42:35 +000085 Obj.addSections(Sections);
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000086 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000087}
88
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000089Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const {
Martin Storsjo10b72962019-01-10 21:28:24 +000090 std::vector<Symbol> Symbols;
91 Symbols.reserve(COFFObj.getRawNumberOfSymbols());
Martin Storsjof9e14342019-01-19 19:42:35 +000092 ArrayRef<Section> Sections = Obj.getSections();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000093 for (uint32_t I = 0, E = COFFObj.getRawNumberOfSymbols(); I < E;) {
94 Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(I);
95 if (!SymOrErr)
Martin Storsjo0a5d5b12018-12-30 20:35:43 +000096 return SymOrErr.takeError();
Martin Storsjoe84a0b52018-12-19 07:24:38 +000097 COFFSymbolRef SymRef = *SymOrErr;
98
Martin Storsjo10b72962019-01-10 21:28:24 +000099 Symbols.push_back(Symbol());
100 Symbol &Sym = Symbols.back();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000101 // Copy symbols from the original form into an intermediate coff_symbol32.
102 if (IsBigObj)
103 copySymbol(Sym.Sym,
104 *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr()));
105 else
106 copySymbol(Sym.Sym,
107 *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr()));
108 if (auto EC = COFFObj.getSymbolName(SymRef, Sym.Name))
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000109 return errorCodeToError(EC);
Martin Storsjo1be91952019-01-23 11:54:51 +0000110
111 ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(SymRef);
112 size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16);
113 assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols());
114 // The auxillary symbols are structs of sizeof(coff_symbol16) each.
115 // In the big object format (where symbols are coff_symbol32), each
116 // auxillary symbol is padded with 2 bytes at the end. Copy each
117 // auxillary symbol to the Sym.AuxData vector. For file symbols,
118 // the whole range of aux symbols are interpreted as one null padded
119 // string instead.
120 if (SymRef.isFileRecord())
121 Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()),
122 AuxData.size())
123 .rtrim('\0');
124 else
125 for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++)
126 Sym.AuxData.push_back(AuxData.slice(I * SymSize, sizeof(AuxSymbol)));
127
Martin Storsjof9e14342019-01-19 19:42:35 +0000128 // Find the unique id of the section
129 if (SymRef.getSectionNumber() <=
130 0) // Special symbol (undefined/absolute/debug)
131 Sym.TargetSectionId = SymRef.getSectionNumber();
132 else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) <
133 Sections.size())
134 Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId;
135 else
Martin Storsjo8010c6be2019-01-22 10:57:59 +0000136 return createStringError(object_error::parse_failed,
137 "Section number out of range");
Martin Storsjof9e14342019-01-19 19:42:35 +0000138 // For section definitions, check if it is comdat associative, and if
139 // it is, find the target section unique id.
140 const coff_aux_section_definition *SD = SymRef.getSectionDefinition();
Martin Storsjo9ec18a32019-01-22 10:58:09 +0000141 const coff_aux_weak_external *WE = SymRef.getWeakExternal();
Martin Storsjof9e14342019-01-19 19:42:35 +0000142 if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) {
143 int32_t Index = SD->getNumber(IsBigObj);
144 if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size())
Martin Storsjo8010c6be2019-01-22 10:57:59 +0000145 return createStringError(object_error::parse_failed,
146 "Unexpected associative section index");
Martin Storsjof9e14342019-01-19 19:42:35 +0000147 Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId;
Martin Storsjo9ec18a32019-01-22 10:58:09 +0000148 } else if (WE) {
149 // This is a raw symbol index for now, but store it in the Symbol
150 // until we've added them to the Object, which assigns the final
151 // unique ids.
152 Sym.WeakTargetSymbolId = WE->TagIndex;
Martin Storsjof9e14342019-01-19 19:42:35 +0000153 }
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000154 I += 1 + SymRef.getNumberOfAuxSymbols();
155 }
Martin Storsjo10b72962019-01-10 21:28:24 +0000156 Obj.addSymbols(Symbols);
157 return Error::success();
158}
159
Martin Storsjo9ec18a32019-01-22 10:58:09 +0000160Error COFFReader::setSymbolTargets(Object &Obj) const {
Martin Storsjo10b72962019-01-10 21:28:24 +0000161 std::vector<const Symbol *> RawSymbolTable;
162 for (const Symbol &Sym : Obj.getSymbols()) {
163 RawSymbolTable.push_back(&Sym);
164 for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++)
165 RawSymbolTable.push_back(nullptr);
166 }
Martin Storsjo9ec18a32019-01-22 10:58:09 +0000167 for (Symbol &Sym : Obj.getMutableSymbols()) {
168 // Convert WeakTargetSymbolId from the original raw symbol index to
169 // a proper unique id.
170 if (Sym.WeakTargetSymbolId) {
171 if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size())
172 return createStringError(object_error::parse_failed,
173 "Weak external reference out of range");
174 const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId];
175 if (Target == nullptr)
176 return createStringError(object_error::parse_failed,
177 "Invalid SymbolTableIndex");
178 Sym.WeakTargetSymbolId = Target->UniqueId;
179 }
180 }
Martin Storsjof9e14342019-01-19 19:42:35 +0000181 for (Section &Sec : Obj.getMutableSections()) {
Martin Storsjo10b72962019-01-10 21:28:24 +0000182 for (Relocation &R : Sec.Relocs) {
183 if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size())
Martin Storsjo8010c6be2019-01-22 10:57:59 +0000184 return createStringError(object_error::parse_failed,
185 "SymbolTableIndex out of range");
Martin Storsjo10b72962019-01-10 21:28:24 +0000186 const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex];
187 if (Sym == nullptr)
Martin Storsjo8010c6be2019-01-22 10:57:59 +0000188 return createStringError(object_error::parse_failed,
189 "Invalid SymbolTableIndex");
Martin Storsjo10b72962019-01-10 21:28:24 +0000190 R.Target = Sym->UniqueId;
191 R.TargetName = Sym->Name;
192 }
193 }
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000194 return Error::success();
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000195}
196
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000197Expected<std::unique_ptr<Object>> COFFReader::create() const {
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000198 auto Obj = llvm::make_unique<Object>();
199
200 const coff_file_header *CFH = nullptr;
201 const coff_bigobj_file_header *CBFH = nullptr;
202 COFFObj.getCOFFHeader(CFH);
203 COFFObj.getCOFFBigObjHeader(CBFH);
204 bool IsBigObj = false;
205 if (CFH) {
206 Obj->CoffFileHeader = *CFH;
207 } else {
208 if (!CBFH)
Martin Storsjo8010c6be2019-01-22 10:57:59 +0000209 return createStringError(object_error::parse_failed,
210 "No COFF file header returned");
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000211 // Only copying the few fields from the bigobj header that we need
212 // and won't recreate in the end.
213 Obj->CoffFileHeader.Machine = CBFH->Machine;
214 Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp;
215 IsBigObj = true;
216 }
217
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000218 if (Error E = readExecutableHeaders(*Obj))
219 return std::move(E);
220 if (Error E = readSections(*Obj))
221 return std::move(E);
222 if (Error E = readSymbols(*Obj, IsBigObj))
223 return std::move(E);
Martin Storsjo9ec18a32019-01-22 10:58:09 +0000224 if (Error E = setSymbolTargets(*Obj))
Martin Storsjo10b72962019-01-10 21:28:24 +0000225 return std::move(E);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000226
Martin Storsjo0a5d5b12018-12-30 20:35:43 +0000227 return std::move(Obj);
Martin Storsjoe84a0b52018-12-19 07:24:38 +0000228}
229
230} // end namespace coff
231} // end namespace objcopy
232} // end namespace llvm