1 | //===- COFFReader.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 "COFFReader.h" |
10 | #include "COFFObject.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::(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 | Obj.PeHeader = *COFFObj.getPE32PlusHeader(); |
40 | } else { |
41 | const pe32_header *PE32 = COFFObj.getPE32Header(); |
42 | copyPeHeader(Dest&: Obj.PeHeader, Src: *PE32); |
43 | // The pe32plus_header (stored in Object) lacks the BaseOfData field. |
44 | Obj.BaseOfData = PE32->BaseOfData; |
45 | } |
46 | |
47 | for (size_t I = 0; I < Obj.PeHeader.NumberOfRvaAndSize; I++) { |
48 | const data_directory *Dir = COFFObj.getDataDirectory(index: I); |
49 | if (!Dir) |
50 | return errorCodeToError(EC: object_error::parse_failed); |
51 | Obj.DataDirectories.emplace_back(args: *Dir); |
52 | } |
53 | return Error::success(); |
54 | } |
55 | |
56 | Error COFFReader::readSections(Object &Obj) const { |
57 | std::vector<Section> Sections; |
58 | // Section indexing starts from 1. |
59 | for (size_t I = 1, E = COFFObj.getNumberOfSections(); I <= E; I++) { |
60 | Expected<const coff_section *> SecOrErr = COFFObj.getSection(index: I); |
61 | if (!SecOrErr) |
62 | return SecOrErr.takeError(); |
63 | const coff_section *Sec = *SecOrErr; |
64 | Sections.push_back(x: Section()); |
65 | Section &S = Sections.back(); |
66 | S.Header = *Sec; |
67 | S.Header.Characteristics &= ~COFF::IMAGE_SCN_LNK_NRELOC_OVFL; |
68 | ArrayRef<uint8_t> Contents; |
69 | if (Error E = COFFObj.getSectionContents(Sec, Res&: Contents)) |
70 | return E; |
71 | S.setContentsRef(Contents); |
72 | ArrayRef<coff_relocation> Relocs = COFFObj.getRelocations(Sec); |
73 | llvm::append_range(C&: S.Relocs, R&: Relocs); |
74 | if (Expected<StringRef> NameOrErr = COFFObj.getSectionName(Sec)) |
75 | S.Name = *NameOrErr; |
76 | else |
77 | return NameOrErr.takeError(); |
78 | } |
79 | Obj.addSections(NewSections: Sections); |
80 | return Error::success(); |
81 | } |
82 | |
83 | Error COFFReader::readSymbols(Object &Obj, bool IsBigObj) const { |
84 | std::vector<Symbol> Symbols; |
85 | Symbols.reserve(n: COFFObj.getNumberOfSymbols()); |
86 | ArrayRef<Section> Sections = Obj.getSections(); |
87 | for (uint32_t I = 0, E = COFFObj.getNumberOfSymbols(); I < E;) { |
88 | Expected<COFFSymbolRef> SymOrErr = COFFObj.getSymbol(index: I); |
89 | if (!SymOrErr) |
90 | return SymOrErr.takeError(); |
91 | COFFSymbolRef SymRef = *SymOrErr; |
92 | |
93 | Symbols.push_back(x: Symbol()); |
94 | Symbol &Sym = Symbols.back(); |
95 | // Copy symbols from the original form into an intermediate coff_symbol32. |
96 | if (IsBigObj) |
97 | copySymbol(Dest&: Sym.Sym, |
98 | Src: *reinterpret_cast<const coff_symbol32 *>(SymRef.getRawPtr())); |
99 | else |
100 | copySymbol(Dest&: Sym.Sym, |
101 | Src: *reinterpret_cast<const coff_symbol16 *>(SymRef.getRawPtr())); |
102 | auto NameOrErr = COFFObj.getSymbolName(Symbol: SymRef); |
103 | if (!NameOrErr) |
104 | return NameOrErr.takeError(); |
105 | Sym.Name = *NameOrErr; |
106 | |
107 | ArrayRef<uint8_t> AuxData = COFFObj.getSymbolAuxData(Symbol: SymRef); |
108 | size_t SymSize = IsBigObj ? sizeof(coff_symbol32) : sizeof(coff_symbol16); |
109 | assert(AuxData.size() == SymSize * SymRef.getNumberOfAuxSymbols()); |
110 | // The auxillary symbols are structs of sizeof(coff_symbol16) each. |
111 | // In the big object format (where symbols are coff_symbol32), each |
112 | // auxillary symbol is padded with 2 bytes at the end. Copy each |
113 | // auxillary symbol to the Sym.AuxData vector. For file symbols, |
114 | // the whole range of aux symbols are interpreted as one null padded |
115 | // string instead. |
116 | if (SymRef.isFileRecord()) |
117 | Sym.AuxFile = StringRef(reinterpret_cast<const char *>(AuxData.data()), |
118 | AuxData.size()) |
119 | .rtrim(Char: '\0'); |
120 | else |
121 | for (size_t I = 0; I < SymRef.getNumberOfAuxSymbols(); I++) |
122 | Sym.AuxData.push_back(x: AuxData.slice(N: I * SymSize, M: sizeof(AuxSymbol))); |
123 | |
124 | // Find the unique id of the section |
125 | if (SymRef.getSectionNumber() <= |
126 | 0) // Special symbol (undefined/absolute/debug) |
127 | Sym.TargetSectionId = SymRef.getSectionNumber(); |
128 | else if (static_cast<uint32_t>(SymRef.getSectionNumber() - 1) < |
129 | Sections.size()) |
130 | Sym.TargetSectionId = Sections[SymRef.getSectionNumber() - 1].UniqueId; |
131 | else |
132 | return createStringError(EC: object_error::parse_failed, |
133 | S: "section number out of range" ); |
134 | // For section definitions, check if it is comdat associative, and if |
135 | // it is, find the target section unique id. |
136 | const coff_aux_section_definition *SD = SymRef.getSectionDefinition(); |
137 | const coff_aux_weak_external *WE = SymRef.getWeakExternal(); |
138 | if (SD && SD->Selection == IMAGE_COMDAT_SELECT_ASSOCIATIVE) { |
139 | int32_t Index = SD->getNumber(IsBigObj); |
140 | if (Index <= 0 || static_cast<uint32_t>(Index - 1) >= Sections.size()) |
141 | return createStringError(EC: object_error::parse_failed, |
142 | S: "unexpected associative section index" ); |
143 | Sym.AssociativeComdatTargetSectionId = Sections[Index - 1].UniqueId; |
144 | } else if (WE) { |
145 | // This is a raw symbol index for now, but store it in the Symbol |
146 | // until we've added them to the Object, which assigns the final |
147 | // unique ids. |
148 | Sym.WeakTargetSymbolId = WE->TagIndex; |
149 | } |
150 | I += 1 + SymRef.getNumberOfAuxSymbols(); |
151 | } |
152 | Obj.addSymbols(NewSymbols: Symbols); |
153 | return Error::success(); |
154 | } |
155 | |
156 | Error COFFReader::setSymbolTargets(Object &Obj) const { |
157 | std::vector<const Symbol *> RawSymbolTable; |
158 | for (const Symbol &Sym : Obj.getSymbols()) { |
159 | RawSymbolTable.push_back(x: &Sym); |
160 | for (size_t I = 0; I < Sym.Sym.NumberOfAuxSymbols; I++) |
161 | RawSymbolTable.push_back(x: nullptr); |
162 | } |
163 | for (Symbol &Sym : Obj.getMutableSymbols()) { |
164 | // Convert WeakTargetSymbolId from the original raw symbol index to |
165 | // a proper unique id. |
166 | if (Sym.WeakTargetSymbolId) { |
167 | if (*Sym.WeakTargetSymbolId >= RawSymbolTable.size()) |
168 | return createStringError(EC: object_error::parse_failed, |
169 | S: "weak external reference out of range" ); |
170 | const Symbol *Target = RawSymbolTable[*Sym.WeakTargetSymbolId]; |
171 | if (Target == nullptr) |
172 | return createStringError(EC: object_error::parse_failed, |
173 | S: "invalid SymbolTableIndex" ); |
174 | Sym.WeakTargetSymbolId = Target->UniqueId; |
175 | } |
176 | } |
177 | for (Section &Sec : Obj.getMutableSections()) { |
178 | for (Relocation &R : Sec.Relocs) { |
179 | if (R.Reloc.SymbolTableIndex >= RawSymbolTable.size()) |
180 | return createStringError(EC: object_error::parse_failed, |
181 | S: "SymbolTableIndex out of range" ); |
182 | const Symbol *Sym = RawSymbolTable[R.Reloc.SymbolTableIndex]; |
183 | if (Sym == nullptr) |
184 | return createStringError(EC: object_error::parse_failed, |
185 | S: "invalid SymbolTableIndex" ); |
186 | R.Target = Sym->UniqueId; |
187 | R.TargetName = Sym->Name; |
188 | } |
189 | } |
190 | return Error::success(); |
191 | } |
192 | |
193 | Expected<std::unique_ptr<Object>> COFFReader::create() const { |
194 | auto Obj = std::make_unique<Object>(); |
195 | |
196 | bool IsBigObj = false; |
197 | if (const coff_file_header *CFH = COFFObj.getCOFFHeader()) { |
198 | Obj->CoffFileHeader = *CFH; |
199 | } else { |
200 | const coff_bigobj_file_header *CBFH = COFFObj.getCOFFBigObjHeader(); |
201 | if (!CBFH) |
202 | return createStringError(EC: object_error::parse_failed, |
203 | S: "no COFF file header returned" ); |
204 | // Only copying the few fields from the bigobj header that we need |
205 | // and won't recreate in the end. |
206 | Obj->CoffFileHeader.Machine = CBFH->Machine; |
207 | Obj->CoffFileHeader.TimeDateStamp = CBFH->TimeDateStamp; |
208 | IsBigObj = true; |
209 | } |
210 | |
211 | if (Error E = readExecutableHeaders(Obj&: *Obj)) |
212 | return std::move(E); |
213 | if (Error E = readSections(Obj&: *Obj)) |
214 | return std::move(E); |
215 | if (Error E = readSymbols(Obj&: *Obj, IsBigObj)) |
216 | return std::move(E); |
217 | if (Error E = setSymbolTargets(*Obj)) |
218 | return std::move(E); |
219 | |
220 | return std::move(Obj); |
221 | } |
222 | |
223 | } // end namespace coff |
224 | } // end namespace objcopy |
225 | } // end namespace llvm |
226 | |