1 | //===- COFFWriter.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 "COFFWriter.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/Errc.h" |
16 | #include "llvm/Support/ErrorHandling.h" |
17 | #include <cstddef> |
18 | #include <cstdint> |
19 | |
20 | namespace llvm { |
21 | namespace objcopy { |
22 | namespace coff { |
23 | |
24 | using namespace object; |
25 | using namespace COFF; |
26 | |
27 | Error COFFWriter::finalizeRelocTargets() { |
28 | for (Section &Sec : Obj.getMutableSections()) { |
29 | for (Relocation &R : Sec.Relocs) { |
30 | const Symbol *Sym = Obj.findSymbol(UniqueId: R.Target); |
31 | if (Sym == nullptr) |
32 | return createStringError(EC: object_error::invalid_symbol_index, |
33 | Fmt: "relocation target '%s' (%zu) not found" , |
34 | Vals: R.TargetName.str().c_str(), Vals: R.Target); |
35 | R.Reloc.SymbolTableIndex = Sym->RawIndex; |
36 | } |
37 | } |
38 | return Error::success(); |
39 | } |
40 | |
41 | Error COFFWriter::finalizeSymbolContents() { |
42 | for (Symbol &Sym : Obj.getMutableSymbols()) { |
43 | if (Sym.TargetSectionId <= 0) { |
44 | // Undefined, or a special kind of symbol. These negative values |
45 | // are stored in the SectionNumber field which is unsigned. |
46 | Sym.Sym.SectionNumber = static_cast<uint32_t>(Sym.TargetSectionId); |
47 | } else { |
48 | const Section *Sec = Obj.findSection(UniqueId: Sym.TargetSectionId); |
49 | if (Sec == nullptr) |
50 | return createStringError(EC: object_error::invalid_symbol_index, |
51 | Fmt: "symbol '%s' points to a removed section" , |
52 | Vals: Sym.Name.str().c_str()); |
53 | Sym.Sym.SectionNumber = Sec->Index; |
54 | |
55 | if (Sym.Sym.NumberOfAuxSymbols == 1 && |
56 | Sym.Sym.StorageClass == IMAGE_SYM_CLASS_STATIC) { |
57 | coff_aux_section_definition *SD = |
58 | reinterpret_cast<coff_aux_section_definition *>( |
59 | Sym.AuxData[0].Opaque); |
60 | uint32_t SDSectionNumber; |
61 | if (Sym.AssociativeComdatTargetSectionId == 0) { |
62 | // Not a comdat associative section; just set the Number field to |
63 | // the number of the section itself. |
64 | SDSectionNumber = Sec->Index; |
65 | } else { |
66 | Sec = Obj.findSection(UniqueId: Sym.AssociativeComdatTargetSectionId); |
67 | if (Sec == nullptr) |
68 | return createStringError( |
69 | EC: object_error::invalid_symbol_index, |
70 | Fmt: "symbol '%s' is associative to a removed section" , |
71 | Vals: Sym.Name.str().c_str()); |
72 | SDSectionNumber = Sec->Index; |
73 | } |
74 | // Update the section definition with the new section number. |
75 | SD->NumberLowPart = static_cast<uint16_t>(SDSectionNumber); |
76 | SD->NumberHighPart = static_cast<uint16_t>(SDSectionNumber >> 16); |
77 | } |
78 | } |
79 | // Check that we actually have got AuxData to match the weak symbol target |
80 | // we want to set. Only >= 1 would be required, but only == 1 makes sense. |
81 | if (Sym.WeakTargetSymbolId && Sym.Sym.NumberOfAuxSymbols == 1) { |
82 | coff_aux_weak_external *WE = |
83 | reinterpret_cast<coff_aux_weak_external *>(Sym.AuxData[0].Opaque); |
84 | const Symbol *Target = Obj.findSymbol(UniqueId: *Sym.WeakTargetSymbolId); |
85 | if (Target == nullptr) |
86 | return createStringError(EC: object_error::invalid_symbol_index, |
87 | Fmt: "symbol '%s' is missing its weak target" , |
88 | Vals: Sym.Name.str().c_str()); |
89 | WE->TagIndex = Target->RawIndex; |
90 | } |
91 | } |
92 | return Error::success(); |
93 | } |
94 | |
95 | void COFFWriter::layoutSections() { |
96 | for (auto &S : Obj.getMutableSections()) { |
97 | if (S.Header.SizeOfRawData > 0) |
98 | S.Header.PointerToRawData = FileSize; |
99 | else |
100 | S.Header.PointerToRawData = 0; |
101 | FileSize += S.Header.SizeOfRawData; // For executables, this is already |
102 | // aligned to FileAlignment. |
103 | if (S.Relocs.size() >= 0xffff) { |
104 | S.Header.Characteristics |= COFF::IMAGE_SCN_LNK_NRELOC_OVFL; |
105 | S.Header.NumberOfRelocations = 0xffff; |
106 | S.Header.PointerToRelocations = FileSize; |
107 | FileSize += sizeof(coff_relocation); |
108 | } else { |
109 | S.Header.NumberOfRelocations = S.Relocs.size(); |
110 | S.Header.PointerToRelocations = S.Relocs.size() ? FileSize : 0; |
111 | } |
112 | |
113 | FileSize += S.Relocs.size() * sizeof(coff_relocation); |
114 | FileSize = alignTo(Value: FileSize, Align: FileAlignment); |
115 | |
116 | if (S.Header.Characteristics & IMAGE_SCN_CNT_INITIALIZED_DATA) |
117 | SizeOfInitializedData += S.Header.SizeOfRawData; |
118 | } |
119 | } |
120 | |
121 | Expected<size_t> COFFWriter::finalizeStringTable() { |
122 | for (const auto &S : Obj.getSections()) |
123 | if (S.Name.size() > COFF::NameSize) |
124 | StrTabBuilder.add(S: S.Name); |
125 | |
126 | for (const auto &S : Obj.getSymbols()) |
127 | if (S.Name.size() > COFF::NameSize) |
128 | StrTabBuilder.add(S: S.Name); |
129 | |
130 | StrTabBuilder.finalize(); |
131 | |
132 | for (auto &S : Obj.getMutableSections()) { |
133 | memset(s: S.Header.Name, c: 0, n: sizeof(S.Header.Name)); |
134 | if (S.Name.size() <= COFF::NameSize) { |
135 | // Short names can go in the field directly. |
136 | memcpy(dest: S.Header.Name, src: S.Name.data(), n: S.Name.size()); |
137 | } else { |
138 | // Offset of the section name in the string table. |
139 | size_t Offset = StrTabBuilder.getOffset(S: S.Name); |
140 | if (!COFF::encodeSectionName(Out: S.Header.Name, Offset)) |
141 | return createStringError(EC: object_error::invalid_section_index, |
142 | S: "COFF string table is greater than 64GB, " |
143 | "unable to encode section name offset" ); |
144 | } |
145 | } |
146 | for (auto &S : Obj.getMutableSymbols()) { |
147 | if (S.Name.size() > COFF::NameSize) { |
148 | S.Sym.Name.Offset.Zeroes = 0; |
149 | S.Sym.Name.Offset.Offset = StrTabBuilder.getOffset(S: S.Name); |
150 | } else { |
151 | strncpy(dest: S.Sym.Name.ShortName, src: S.Name.data(), n: COFF::NameSize); |
152 | } |
153 | } |
154 | return StrTabBuilder.getSize(); |
155 | } |
156 | |
157 | template <class SymbolTy> |
158 | std::pair<size_t, size_t> COFFWriter::finalizeSymbolTable() { |
159 | size_t RawSymIndex = 0; |
160 | for (auto &S : Obj.getMutableSymbols()) { |
161 | // Symbols normally have NumberOfAuxSymbols set correctly all the time. |
162 | // For file symbols, we need to know the output file's symbol size to be |
163 | // able to calculate the number of slots it occupies. |
164 | if (!S.AuxFile.empty()) |
165 | S.Sym.NumberOfAuxSymbols = |
166 | alignTo(Value: S.AuxFile.size(), Align: sizeof(SymbolTy)) / sizeof(SymbolTy); |
167 | S.RawIndex = RawSymIndex; |
168 | RawSymIndex += 1 + S.Sym.NumberOfAuxSymbols; |
169 | } |
170 | return std::make_pair(x: RawSymIndex * sizeof(SymbolTy), y: sizeof(SymbolTy)); |
171 | } |
172 | |
173 | Error COFFWriter::finalize(bool IsBigObj) { |
174 | size_t SymTabSize, SymbolSize; |
175 | std::tie(args&: SymTabSize, args&: SymbolSize) = IsBigObj |
176 | ? finalizeSymbolTable<coff_symbol32>() |
177 | : finalizeSymbolTable<coff_symbol16>(); |
178 | |
179 | if (Error E = finalizeRelocTargets()) |
180 | return E; |
181 | if (Error E = finalizeSymbolContents()) |
182 | return E; |
183 | |
184 | size_t = 0; |
185 | FileAlignment = 1; |
186 | size_t = 0; |
187 | if (Obj.IsPE) { |
188 | Obj.DosHeader.AddressOfNewExeHeader = |
189 | sizeof(Obj.DosHeader) + Obj.DosStub.size(); |
190 | SizeOfHeaders += Obj.DosHeader.AddressOfNewExeHeader + sizeof(PEMagic); |
191 | |
192 | FileAlignment = Obj.PeHeader.FileAlignment; |
193 | Obj.PeHeader.NumberOfRvaAndSize = Obj.DataDirectories.size(); |
194 | |
195 | PeHeaderSize = Obj.Is64 ? sizeof(pe32plus_header) : sizeof(pe32_header); |
196 | SizeOfHeaders += |
197 | PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); |
198 | } |
199 | Obj.CoffFileHeader.NumberOfSections = Obj.getSections().size(); |
200 | SizeOfHeaders += |
201 | IsBigObj ? sizeof(coff_bigobj_file_header) : sizeof(coff_file_header); |
202 | SizeOfHeaders += sizeof(coff_section) * Obj.getSections().size(); |
203 | SizeOfHeaders = alignTo(Value: SizeOfHeaders, Align: FileAlignment); |
204 | |
205 | Obj.CoffFileHeader.SizeOfOptionalHeader = |
206 | PeHeaderSize + sizeof(data_directory) * Obj.DataDirectories.size(); |
207 | |
208 | FileSize = SizeOfHeaders; |
209 | SizeOfInitializedData = 0; |
210 | |
211 | layoutSections(); |
212 | |
213 | if (Obj.IsPE) { |
214 | Obj.PeHeader.SizeOfHeaders = SizeOfHeaders; |
215 | Obj.PeHeader.SizeOfInitializedData = SizeOfInitializedData; |
216 | |
217 | if (!Obj.getSections().empty()) { |
218 | const Section &S = Obj.getSections().back(); |
219 | Obj.PeHeader.SizeOfImage = |
220 | alignTo(Value: S.Header.VirtualAddress + S.Header.VirtualSize, |
221 | Align: Obj.PeHeader.SectionAlignment); |
222 | } |
223 | |
224 | // If the PE header had a checksum, clear it, since it isn't valid |
225 | // any longer. (We don't calculate a new one.) |
226 | Obj.PeHeader.CheckSum = 0; |
227 | } |
228 | |
229 | Expected<size_t> StrTabSizeOrErr = finalizeStringTable(); |
230 | if (!StrTabSizeOrErr) |
231 | return StrTabSizeOrErr.takeError(); |
232 | |
233 | size_t StrTabSize = *StrTabSizeOrErr; |
234 | |
235 | size_t PointerToSymbolTable = FileSize; |
236 | // StrTabSize <= 4 is the size of an empty string table, only consisting |
237 | // of the length field. |
238 | if (SymTabSize == 0 && StrTabSize <= 4 && Obj.IsPE) { |
239 | // For executables, don't point to the symbol table and skip writing |
240 | // the length field, if both the symbol and string tables are empty. |
241 | PointerToSymbolTable = 0; |
242 | StrTabSize = 0; |
243 | } |
244 | |
245 | size_t NumRawSymbols = SymTabSize / SymbolSize; |
246 | Obj.CoffFileHeader.PointerToSymbolTable = PointerToSymbolTable; |
247 | Obj.CoffFileHeader.NumberOfSymbols = NumRawSymbols; |
248 | FileSize += SymTabSize + StrTabSize; |
249 | FileSize = alignTo(Value: FileSize, Align: FileAlignment); |
250 | |
251 | return Error::success(); |
252 | } |
253 | |
254 | void COFFWriter::(bool IsBigObj) { |
255 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()); |
256 | if (Obj.IsPE) { |
257 | memcpy(dest: Ptr, src: &Obj.DosHeader, n: sizeof(Obj.DosHeader)); |
258 | Ptr += sizeof(Obj.DosHeader); |
259 | memcpy(dest: Ptr, src: Obj.DosStub.data(), n: Obj.DosStub.size()); |
260 | Ptr += Obj.DosStub.size(); |
261 | memcpy(dest: Ptr, src: PEMagic, n: sizeof(PEMagic)); |
262 | Ptr += sizeof(PEMagic); |
263 | } |
264 | if (!IsBigObj) { |
265 | memcpy(dest: Ptr, src: &Obj.CoffFileHeader, n: sizeof(Obj.CoffFileHeader)); |
266 | Ptr += sizeof(Obj.CoffFileHeader); |
267 | } else { |
268 | // Generate a coff_bigobj_file_header, filling it in with the values |
269 | // from Obj.CoffFileHeader. All extra fields that don't exist in |
270 | // coff_file_header can be set to hardcoded values. |
271 | coff_bigobj_file_header ; |
272 | BigObjHeader.Sig1 = IMAGE_FILE_MACHINE_UNKNOWN; |
273 | BigObjHeader.Sig2 = 0xffff; |
274 | BigObjHeader.Version = BigObjHeader::MinBigObjectVersion; |
275 | BigObjHeader.Machine = Obj.CoffFileHeader.Machine; |
276 | BigObjHeader.TimeDateStamp = Obj.CoffFileHeader.TimeDateStamp; |
277 | memcpy(dest: BigObjHeader.UUID, src: BigObjMagic, n: sizeof(BigObjMagic)); |
278 | BigObjHeader.unused1 = 0; |
279 | BigObjHeader.unused2 = 0; |
280 | BigObjHeader.unused3 = 0; |
281 | BigObjHeader.unused4 = 0; |
282 | // The value in Obj.CoffFileHeader.NumberOfSections is truncated, thus |
283 | // get the original one instead. |
284 | BigObjHeader.NumberOfSections = Obj.getSections().size(); |
285 | BigObjHeader.PointerToSymbolTable = Obj.CoffFileHeader.PointerToSymbolTable; |
286 | BigObjHeader.NumberOfSymbols = Obj.CoffFileHeader.NumberOfSymbols; |
287 | |
288 | memcpy(dest: Ptr, src: &BigObjHeader, n: sizeof(BigObjHeader)); |
289 | Ptr += sizeof(BigObjHeader); |
290 | } |
291 | if (Obj.IsPE) { |
292 | if (Obj.Is64) { |
293 | memcpy(dest: Ptr, src: &Obj.PeHeader, n: sizeof(Obj.PeHeader)); |
294 | Ptr += sizeof(Obj.PeHeader); |
295 | } else { |
296 | pe32_header ; |
297 | copyPeHeader(Dest&: PeHeader, Src: Obj.PeHeader); |
298 | // The pe32plus_header (stored in Object) lacks the BaseOfData field. |
299 | PeHeader.BaseOfData = Obj.BaseOfData; |
300 | |
301 | memcpy(dest: Ptr, src: &PeHeader, n: sizeof(PeHeader)); |
302 | Ptr += sizeof(PeHeader); |
303 | } |
304 | for (const auto &DD : Obj.DataDirectories) { |
305 | memcpy(dest: Ptr, src: &DD, n: sizeof(DD)); |
306 | Ptr += sizeof(DD); |
307 | } |
308 | } |
309 | for (const auto &S : Obj.getSections()) { |
310 | memcpy(dest: Ptr, src: &S.Header, n: sizeof(S.Header)); |
311 | Ptr += sizeof(S.Header); |
312 | } |
313 | } |
314 | |
315 | void COFFWriter::writeSections() { |
316 | for (const auto &S : Obj.getSections()) { |
317 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + |
318 | S.Header.PointerToRawData; |
319 | ArrayRef<uint8_t> Contents = S.getContents(); |
320 | std::copy(Contents.begin(), Contents.end(), Ptr); |
321 | |
322 | // For executable sections, pad the remainder of the raw data size with |
323 | // 0xcc, which is int3 on x86. |
324 | if ((S.Header.Characteristics & IMAGE_SCN_CNT_CODE) && |
325 | S.Header.SizeOfRawData > Contents.size()) |
326 | memset(s: Ptr + Contents.size(), c: 0xcc, |
327 | n: S.Header.SizeOfRawData - Contents.size()); |
328 | |
329 | Ptr += S.Header.SizeOfRawData; |
330 | |
331 | if (S.Relocs.size() >= 0xffff) { |
332 | object::coff_relocation R; |
333 | R.VirtualAddress = S.Relocs.size() + 1; |
334 | R.SymbolTableIndex = 0; |
335 | R.Type = 0; |
336 | memcpy(dest: Ptr, src: &R, n: sizeof(R)); |
337 | Ptr += sizeof(R); |
338 | } |
339 | for (const auto &R : S.Relocs) { |
340 | memcpy(dest: Ptr, src: &R.Reloc, n: sizeof(R.Reloc)); |
341 | Ptr += sizeof(R.Reloc); |
342 | } |
343 | } |
344 | } |
345 | |
346 | template <class SymbolTy> void COFFWriter::writeSymbolStringTables() { |
347 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + |
348 | Obj.CoffFileHeader.PointerToSymbolTable; |
349 | for (const auto &S : Obj.getSymbols()) { |
350 | // Convert symbols back to the right size, from coff_symbol32. |
351 | copySymbol<SymbolTy, coff_symbol32>(*reinterpret_cast<SymbolTy *>(Ptr), |
352 | S.Sym); |
353 | Ptr += sizeof(SymbolTy); |
354 | if (!S.AuxFile.empty()) { |
355 | // For file symbols, just write the string into the aux symbol slots, |
356 | // assuming that the unwritten parts are initialized to zero in the memory |
357 | // mapped file. |
358 | std::copy(S.AuxFile.begin(), S.AuxFile.end(), Ptr); |
359 | Ptr += S.Sym.NumberOfAuxSymbols * sizeof(SymbolTy); |
360 | } else { |
361 | // For other auxillary symbols, write their opaque payload into one symbol |
362 | // table slot each. For big object files, the symbols are larger than the |
363 | // opaque auxillary symbol struct and we leave padding at the end of each |
364 | // entry. |
365 | for (const AuxSymbol &AuxSym : S.AuxData) { |
366 | ArrayRef<uint8_t> Ref = AuxSym.getRef(); |
367 | std::copy(Ref.begin(), Ref.end(), Ptr); |
368 | Ptr += sizeof(SymbolTy); |
369 | } |
370 | } |
371 | } |
372 | if (StrTabBuilder.getSize() > 4 || !Obj.IsPE) { |
373 | // Always write a string table in object files, even an empty one. |
374 | StrTabBuilder.write(Buf: Ptr); |
375 | Ptr += StrTabBuilder.getSize(); |
376 | } |
377 | } |
378 | |
379 | Error COFFWriter::write(bool IsBigObj) { |
380 | if (Error E = finalize(IsBigObj)) |
381 | return E; |
382 | |
383 | Buf = WritableMemoryBuffer::getNewMemBuffer(Size: FileSize); |
384 | if (!Buf) |
385 | return createStringError(EC: llvm::errc::not_enough_memory, |
386 | S: "failed to allocate memory buffer of " + |
387 | Twine::utohexstr(Val: FileSize) + " bytes." ); |
388 | |
389 | writeHeaders(IsBigObj); |
390 | writeSections(); |
391 | if (IsBigObj) |
392 | writeSymbolStringTables<coff_symbol32>(); |
393 | else |
394 | writeSymbolStringTables<coff_symbol16>(); |
395 | |
396 | if (Obj.IsPE) |
397 | if (Error E = patchDebugDirectory()) |
398 | return E; |
399 | |
400 | // TODO: Implement direct writing to the output stream (without intermediate |
401 | // memory buffer Buf). |
402 | Out.write(Ptr: Buf->getBufferStart(), Size: Buf->getBufferSize()); |
403 | return Error::success(); |
404 | } |
405 | |
406 | Expected<uint32_t> COFFWriter::virtualAddressToFileAddress(uint32_t RVA) { |
407 | for (const auto &S : Obj.getSections()) { |
408 | if (RVA >= S.Header.VirtualAddress && |
409 | RVA < S.Header.VirtualAddress + S.Header.SizeOfRawData) |
410 | return S.Header.PointerToRawData + RVA - S.Header.VirtualAddress; |
411 | } |
412 | return createStringError(EC: object_error::parse_failed, |
413 | S: "debug directory payload not found" ); |
414 | } |
415 | |
416 | // Locate which sections contain the debug directories, iterate over all |
417 | // the debug_directory structs in there, and set the PointerToRawData field |
418 | // in all of them, according to their new physical location in the file. |
419 | Error COFFWriter::patchDebugDirectory() { |
420 | if (Obj.DataDirectories.size() <= DEBUG_DIRECTORY) |
421 | return Error::success(); |
422 | const data_directory *Dir = &Obj.DataDirectories[DEBUG_DIRECTORY]; |
423 | if (Dir->Size <= 0) |
424 | return Error::success(); |
425 | for (const auto &S : Obj.getSections()) { |
426 | if (Dir->RelativeVirtualAddress >= S.Header.VirtualAddress && |
427 | Dir->RelativeVirtualAddress < |
428 | S.Header.VirtualAddress + S.Header.SizeOfRawData) { |
429 | if (Dir->RelativeVirtualAddress + Dir->Size > |
430 | S.Header.VirtualAddress + S.Header.SizeOfRawData) |
431 | return createStringError(EC: object_error::parse_failed, |
432 | S: "debug directory extends past end of section" ); |
433 | |
434 | size_t Offset = Dir->RelativeVirtualAddress - S.Header.VirtualAddress; |
435 | uint8_t *Ptr = reinterpret_cast<uint8_t *>(Buf->getBufferStart()) + |
436 | S.Header.PointerToRawData + Offset; |
437 | uint8_t *End = Ptr + Dir->Size; |
438 | while (Ptr < End) { |
439 | debug_directory *Debug = reinterpret_cast<debug_directory *>(Ptr); |
440 | if (Debug->PointerToRawData) { |
441 | if (Expected<uint32_t> FilePosOrErr = |
442 | virtualAddressToFileAddress(RVA: Debug->AddressOfRawData)) |
443 | Debug->PointerToRawData = *FilePosOrErr; |
444 | else |
445 | return FilePosOrErr.takeError(); |
446 | } |
447 | Ptr += sizeof(debug_directory); |
448 | Offset += sizeof(debug_directory); |
449 | } |
450 | // Debug directory found and patched, all done. |
451 | return Error::success(); |
452 | } |
453 | } |
454 | return createStringError(EC: object_error::parse_failed, |
455 | S: "debug directory not found" ); |
456 | } |
457 | |
458 | Error COFFWriter::write() { |
459 | bool IsBigObj = Obj.getSections().size() > MaxNumberOfSections16; |
460 | if (IsBigObj && Obj.IsPE) |
461 | return createStringError(EC: object_error::parse_failed, |
462 | S: "too many sections for executable" ); |
463 | return write(IsBigObj); |
464 | } |
465 | |
466 | } // end namespace coff |
467 | } // end namespace objcopy |
468 | } // end namespace llvm |
469 | |