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