LLVM 24.0.0git
COFFEmitter.cpp
Go to the documentation of this file.
1//===- yaml2coff - Convert YAML to a COFF object file ---------------------===//
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/// \file
10/// The COFF component of yaml2obj.
11///
12//===----------------------------------------------------------------------===//
13
15#include "llvm/ADT/StringMap.h"
21#include "llvm/Support/Endian.h"
25#include <optional>
26#include <vector>
27
28using namespace llvm;
30
31namespace {
32
33constexpr auto LittleEndian = llvm::endianness::little;
34
35/// This parses a yaml stream that represents a COFF object file.
36/// See docs/yaml2obj for the yaml scheema.
37struct COFFParser {
38 COFFParser(COFFYAML::Object &Obj, yaml::ErrorHandler EH)
39 : Obj(Obj), ErrHandler(EH) {
40 // A COFF string table always starts with a 4 byte size field. Offsets into
41 // it include this size, so allocate it now.
42 StringTable.append(4, char(0));
43 }
44
45 bool useBigObj() const {
46 return static_cast<int32_t>(Obj.Sections.size()) >
48 }
49
50 bool isPE() const { return Obj.OptionalHeader.has_value(); }
51 bool is64Bit() const { return COFF::is64Bit(Obj.Header.Machine); }
52
53 uint32_t getFileAlignment() const {
54 return Obj.OptionalHeader->Header.FileAlignment;
55 }
56
57 unsigned getSymbolSize() const {
58 return useBigObj() ? COFF::Symbol32Size : COFF::Symbol16Size;
59 }
60
61 bool parseSections() {
62 for (COFFYAML::Section &Sec : Obj.Sections) {
63 // If the name is less than 8 bytes, store it in place, otherwise
64 // store it in the string table.
65 StringRef Name = Sec.Name;
66
67 if (Name.size() <= COFF::NameSize) {
68 llvm::copy(Name, Sec.Header.Name);
69 } else {
70 // Add string to the string table and format the index for output.
71 unsigned Index = getStringIndex(Name);
72 std::string str = utostr(Index);
73 if (str.size() > 7) {
74 ErrHandler("string table got too large");
75 return false;
76 }
77 Sec.Header.Name[0] = '/';
78 llvm::copy(str, Sec.Header.Name + 1);
79 }
80
81 if (Sec.Alignment) {
82 if (Sec.Alignment > 8192) {
83 ErrHandler("section alignment is too large");
84 return false;
85 }
86 if (!isPowerOf2_32(Sec.Alignment)) {
87 ErrHandler("section alignment is not a power of 2");
88 return false;
89 }
90 Sec.Header.Characteristics |= (Log2_32(Sec.Alignment) + 1) << 20;
91 }
92 }
93 return true;
94 }
95
96 bool parseSymbols() {
97 for (COFFYAML::Symbol &Sym : Obj.Symbols) {
98 // If the name is less than 8 bytes, store it in place, otherwise
99 // store it in the string table.
100 StringRef Name = Sym.Name;
101 if (Name.size() <= COFF::NameSize) {
102 llvm::copy(Name, Sym.Header.Name);
103 } else {
104 // Add string to the string table and format the index for output.
105 unsigned Index = getStringIndex(Name);
106 *reinterpret_cast<support::aligned_ulittle32_t *>(Sym.Header.Name + 4) =
107 Index;
108 }
109
110 Sym.Header.Type = Sym.SimpleType;
112 }
113 return true;
114 }
115
116 bool parse() {
117 if (!parseSections())
118 return false;
119 if (!parseSymbols())
120 return false;
121 return true;
122 }
123
124 unsigned getStringIndex(StringRef Str) {
125 auto [It, Inserted] = StringTableMap.try_emplace(Str, StringTable.size());
126 if (Inserted) {
127 StringTable.append(Str.begin(), Str.end());
128 StringTable.push_back(0);
129 }
130 return It->second;
131 }
132
133 COFFYAML::Object &Obj;
134
135 codeview::StringsAndChecksums StringsAndChecksums;
136 BumpPtrAllocator Allocator;
137 StringMap<unsigned> StringTableMap;
138 std::string StringTable;
139 uint32_t SectionTableStart;
140 uint32_t SectionTableSize;
141
142 yaml::ErrorHandler ErrHandler;
143};
144
145enum { DOSStubSize = 128 };
146
147} // end anonymous namespace
148
149static yaml::BinaryRef
152 using namespace codeview;
153 ExitOnError Err("Error occurred writing .debug$S section");
154 auto CVSS =
156
157 std::vector<DebugSubsectionRecordBuilder> Builders;
158 uint32_t Size = sizeof(uint32_t);
159 for (auto &SS : CVSS) {
160 DebugSubsectionRecordBuilder B(SS);
161 Size += B.calculateSerializedLength();
162 Builders.push_back(std::move(B));
163 }
164 uint8_t *Buffer = Allocator.Allocate<uint8_t>(Size);
165 MutableArrayRef<uint8_t> Output(Buffer, Size);
167
169 for (const auto &B : Builders) {
170 Err(B.commit(Writer, CodeViewContainer::ObjectFile));
171 }
172 return {Output};
173}
174
175// Write the content of a section and fill in the header fields locating it.
176// Returns whether the section has any content.
177static bool writeSectionContent(COFFParser &CP, COFFYAML::Section &S,
179 if (!S.SectionData || S.SectionData->binary_size() == 0) {
180 if (S.Name == ".debug$S") {
181 assert(CP.StringsAndChecksums.hasStrings() &&
182 "Object file does not have debug string table!");
183 S.SectionData = toDebugS(S.DebugS, CP.StringsAndChecksums, CP.Allocator);
184 } else if (S.Name == ".debug$T") {
185 S.SectionData = CodeViewYAML::toDebugT(S.DebugT, CP.Allocator, S.Name);
186 } else if (S.Name == ".debug$P") {
187 S.SectionData = CodeViewYAML::toDebugT(S.DebugP, CP.Allocator, S.Name);
188 } else if (S.Name == ".debug$H" && S.DebugH) {
189 S.SectionData = CodeViewYAML::toDebugH(*S.DebugH, CP.Allocator);
190 }
191 }
192
193 bool HasContent = S.SectionData && S.SectionData->binary_size() != 0;
194 for (const auto &E : S.StructuredData)
195 HasContent |= E.size() != 0;
196 // Every BB address map entry encodes at least a version and a feature field.
197 if (S.BBAddrMapEntries && !S.BBAddrMapEntries->empty())
198 HasContent = true;
199
200 // Warn as ELF BBAddrMap does.
201 const std::vector<BBAddrMapYAML::PGOAnalysisMapEntry> *PGOAnalyses = nullptr;
202 if (S.PGOAnalyses) {
203 if (!S.BBAddrMapEntries)
204 WithColor::warning() << "PGOAnalyses should not exist in "
205 ".llvm_bb_addr_map when Entries does not exist";
206 else if (S.BBAddrMapEntries->size() != S.PGOAnalyses->size())
207 WithColor::warning() << "PGOAnalyses must be the same length as Entries "
208 "in .llvm_bb_addr_map";
209 else
210 PGOAnalyses = &S.PGOAnalyses.value();
211 }
212
213 if (!HasContent) {
214 // Leave SizeOfRawData unaltered. For .bss sections in object files, it
215 // carries the section size.
217 return false;
218 }
219
220 CBA.padToAlignment(CP.isPE() ? CP.getFileAlignment() : 4);
222 for (const auto &E : S.StructuredData)
223 E.writeAsBinary(CBA);
224 if (S.SectionData)
226 if (S.BBAddrMapEntries)
228 LittleEndian, CP.is64Bit() ? 8 : 4);
229 if (CP.isPE())
230 CBA.padToAlignment(CP.getFileAlignment());
232 return true;
233}
234
235template <typename T>
236static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic,
237 T Header) {
238 memset(Header, 0, sizeof(*Header));
239 Header->Magic = Magic;
240 Header->SectionAlignment = CP.Obj.OptionalHeader->Header.SectionAlignment;
241 Header->FileAlignment = CP.Obj.OptionalHeader->Header.FileAlignment;
242 uint32_t SizeOfCode = 0, SizeOfInitializedData = 0,
243 SizeOfUninitializedData = 0;
244 uint32_t SizeOfHeaders = alignTo(CP.SectionTableStart + CP.SectionTableSize,
245 Header->FileAlignment);
246 uint32_t SizeOfImage = alignTo(SizeOfHeaders, Header->SectionAlignment);
247 uint32_t BaseOfData = 0;
248 for (const COFFYAML::Section &S : CP.Obj.Sections) {
250 SizeOfCode += S.Header.SizeOfRawData;
252 SizeOfInitializedData += S.Header.SizeOfRawData;
254 SizeOfUninitializedData += S.Header.SizeOfRawData;
255 if (S.Name == ".text")
256 Header->BaseOfCode = S.Header.VirtualAddress; // RVA
257 else if (S.Name == ".data")
258 BaseOfData = S.Header.VirtualAddress; // RVA
260 SizeOfImage += alignTo(S.Header.VirtualSize, Header->SectionAlignment);
261 }
262 Header->SizeOfCode = SizeOfCode;
263 Header->SizeOfInitializedData = SizeOfInitializedData;
264 Header->SizeOfUninitializedData = SizeOfUninitializedData;
265 Header->AddressOfEntryPoint =
266 CP.Obj.OptionalHeader->Header.AddressOfEntryPoint; // RVA
267 Header->ImageBase = CP.Obj.OptionalHeader->Header.ImageBase;
268 Header->MajorOperatingSystemVersion =
269 CP.Obj.OptionalHeader->Header.MajorOperatingSystemVersion;
270 Header->MinorOperatingSystemVersion =
271 CP.Obj.OptionalHeader->Header.MinorOperatingSystemVersion;
272 Header->MajorImageVersion = CP.Obj.OptionalHeader->Header.MajorImageVersion;
273 Header->MinorImageVersion = CP.Obj.OptionalHeader->Header.MinorImageVersion;
274 Header->MajorSubsystemVersion =
275 CP.Obj.OptionalHeader->Header.MajorSubsystemVersion;
276 Header->MinorSubsystemVersion =
277 CP.Obj.OptionalHeader->Header.MinorSubsystemVersion;
278 Header->SizeOfImage = SizeOfImage;
279 Header->SizeOfHeaders = SizeOfHeaders;
280 Header->Subsystem = CP.Obj.OptionalHeader->Header.Subsystem;
281 Header->DLLCharacteristics = CP.Obj.OptionalHeader->Header.DLLCharacteristics;
282 Header->SizeOfStackReserve = CP.Obj.OptionalHeader->Header.SizeOfStackReserve;
283 Header->SizeOfStackCommit = CP.Obj.OptionalHeader->Header.SizeOfStackCommit;
284 Header->SizeOfHeapReserve = CP.Obj.OptionalHeader->Header.SizeOfHeapReserve;
285 Header->SizeOfHeapCommit = CP.Obj.OptionalHeader->Header.SizeOfHeapCommit;
286 Header->NumberOfRvaAndSize = CP.Obj.OptionalHeader->Header.NumberOfRvaAndSize;
287 return BaseOfData;
288}
289
290static bool writeCOFF(COFFParser &CP, ContiguousBlobAccumulator &CBA) {
291 // Calculate number of symbols.
292 CP.Obj.Header.NumberOfSymbols = 0;
293 for (COFFYAML::Symbol &Sym : CP.Obj.Symbols) {
294 uint32_t NumberOfAuxSymbols = 0;
295 if (Sym.FunctionDefinition)
296 NumberOfAuxSymbols += 1;
297 if (Sym.bfAndefSymbol)
298 NumberOfAuxSymbols += 1;
299 if (Sym.WeakExternal)
300 NumberOfAuxSymbols += 1;
301 if (!Sym.File.empty())
302 NumberOfAuxSymbols +=
303 (Sym.File.size() + CP.getSymbolSize() - 1) / CP.getSymbolSize();
304 if (Sym.SectionDefinition)
305 NumberOfAuxSymbols += 1;
306 if (Sym.CLRToken)
307 NumberOfAuxSymbols += 1;
308 Sym.Header.NumberOfAuxSymbols = NumberOfAuxSymbols;
309 CP.Obj.Header.NumberOfSymbols += 1 + NumberOfAuxSymbols;
310 }
311
312 CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size();
313
314 unsigned PEHeaderSize = CP.is64Bit() ? sizeof(object::pe32plus_header)
315 : sizeof(object::pe32_header);
316 if (CP.isPE())
318 PEHeaderSize + sizeof(object::data_directory) *
319 CP.Obj.OptionalHeader->Header.NumberOfRvaAndSize;
320
321 // Save field offsets for writing back their final values.
322 uint64_t PointerToSymbolTableOffset;
323
324 if (CP.isPE()) {
325 // PE files start with a DOS stub.
327 memset(&DH, 0, sizeof(DH));
328
329 // DOS EXEs start with "MZ" magic.
330 DH.Magic[0] = 'M';
331 DH.Magic[1] = 'Z';
332 // Initializing the AddressOfRelocationTable is strictly optional but
333 // mollifies certain tools which expect it to have a value greater than
334 // 0x40.
335 DH.AddressOfRelocationTable = sizeof(DH);
336 // This is the address of the PE signature.
337 DH.AddressOfNewExeHeader = DOSStubSize;
338
339 // Write out our DOS stub.
340 CBA.write(reinterpret_cast<const char *>(&DH), sizeof(DH));
341 // Write padding until we reach the position of where our PE signature
342 // should live.
343 CBA.writeZeros(DOSStubSize - sizeof(DH));
344 // Write out the PE signature.
345 CBA.write(COFF::PEMagic, sizeof(COFF::PEMagic));
346 }
347 if (CP.useBigObj()) {
349 LittleEndian);
350 CBA.write(static_cast<uint16_t>(0xffff), LittleEndian);
352 LittleEndian);
353 CBA.write(CP.Obj.Header.Machine, LittleEndian);
354 CBA.write(CP.Obj.Header.TimeDateStamp, LittleEndian);
356 CBA.writeZeros(4 * sizeof(uint32_t));
357 CBA.write(CP.Obj.Header.NumberOfSections, LittleEndian);
358 PointerToSymbolTableOffset = CBA.getOffset();
359 // The final symbol table offset is written after the section data.
360 CBA.writeZeros(sizeof(CP.Obj.Header.PointerToSymbolTable));
361 CBA.write(CP.Obj.Header.NumberOfSymbols, LittleEndian);
362 } else {
363 CBA.write(CP.Obj.Header.Machine, LittleEndian);
364 CBA.write(static_cast<int16_t>(CP.Obj.Header.NumberOfSections),
365 LittleEndian);
366 CBA.write(CP.Obj.Header.TimeDateStamp, LittleEndian);
367 PointerToSymbolTableOffset = CBA.getOffset();
368 // The final symbol table offset is written after the section data.
369 CBA.writeZeros(sizeof(CP.Obj.Header.PointerToSymbolTable));
370 CBA.write(CP.Obj.Header.NumberOfSymbols, LittleEndian);
371 CBA.write(CP.Obj.Header.SizeOfOptionalHeader, LittleEndian);
372 CBA.write(CP.Obj.Header.Characteristics, LittleEndian);
373 }
374
375 // The optional header, if present, immediately follows the COFF file header.
376 uint64_t OptionalHeaderOffset = CBA.getOffset();
377 if (CP.isPE()) {
378 // Reserve space for the PE header, whose fields depend on the final section
379 // layout. The data directories that follow it are already final.
380 CBA.writeZeros(PEHeaderSize);
381 for (uint32_t I = 0; I < CP.Obj.OptionalHeader->Header.NumberOfRvaAndSize;
382 ++I) {
383 const std::optional<COFF::DataDirectory> *DataDirectories =
384 CP.Obj.OptionalHeader->DataDirectories;
385 uint32_t NumDataDir = std::size(CP.Obj.OptionalHeader->DataDirectories);
386 if (I >= NumDataDir || !DataDirectories[I]) {
387 CBA.writeZeros(2 * sizeof(uint32_t));
388 } else {
389 CBA.write(DataDirectories[I]->RelativeVirtualAddress, LittleEndian);
390 CBA.write(DataDirectories[I]->Size, LittleEndian);
391 }
392 }
393 }
394
395 CP.SectionTableStart = CBA.getOffset();
396 CP.SectionTableSize = COFF::SectionSize * CP.Obj.Sections.size();
397 // Reserve space for the section table. Section offsets and sizes are filled
398 // in later.
399 CBA.writeZeros(CP.SectionTableSize);
400
401 unsigned CurSymbol = 0;
402 StringMap<unsigned> SymbolTableIndexMap;
403 for (const COFFYAML::Symbol &Sym : CP.Obj.Symbols) {
404 SymbolTableIndexMap[Sym.Name] = CurSymbol;
405 CurSymbol += 1 + Sym.Header.NumberOfAuxSymbols;
406 }
407
408 // Collect the CodeView strings and checksums shared by all .debug$S sections.
409 for (COFFYAML::Section &S : CP.Obj.Sections) {
410 // We support specifying exactly one of SectionData or Subsections. So if
411 // there is already some SectionData, then we don't need to do any of this.
412 if (S.Name == ".debug$S" &&
413 (!S.SectionData || S.SectionData->binary_size() == 0)) {
415 CP.StringsAndChecksums);
416 if (CP.StringsAndChecksums.hasChecksums() &&
417 CP.StringsAndChecksums.hasStrings())
418 break;
419 }
420 }
421
422 // Output section data.
423 for (COFFYAML::Section &S : CP.Obj.Sections) {
424 bool HasContent = writeSectionContent(CP, S, CBA);
425 if (!HasContent || S.Relocations.empty())
426 continue;
427
430 S.Header.NumberOfRelocations = 0xffff;
431 CBA.write<uint32_t>(/*VirtualAddress=*/S.Relocations.size() + 1,
432 LittleEndian);
433 CBA.write<uint32_t>(/*SymbolTableIndex=*/0, LittleEndian);
434 CBA.write<uint16_t>(/*Type=*/0, LittleEndian);
435 } else {
437 }
438
439 for (const COFFYAML::Relocation &R : S.Relocations) {
440 uint32_t SymbolTableIndex;
441 if (R.SymbolTableIndex) {
442 if (!R.SymbolName.empty())
444 << "Both SymbolName and SymbolTableIndex specified\n";
445 SymbolTableIndex = *R.SymbolTableIndex;
446 } else {
447 SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
448 }
449 CBA.write(R.VirtualAddress, LittleEndian);
450 CBA.write(SymbolTableIndex, LittleEndian);
451 CBA.write(R.Type, LittleEndian);
452 }
453 }
454
455 // Fill in the optional header now that the section layout is final.
456 if (CP.isPE()) {
457 if (CP.is64Bit()) {
460 CBA.updateDataAt(OptionalHeaderOffset, &PEH, sizeof(PEH));
461 } else {
463 uint32_t BaseOfData =
465 PEH.BaseOfData = BaseOfData;
466 CBA.updateDataAt(OptionalHeaderOffset, &PEH, sizeof(PEH));
467 }
468 }
469
470 // Fill in the section table.
471 static_assert(sizeof(object::coff_section) == COFF::SectionSize,
472 "unexpected COFF section header size");
473 uint64_t SectionHeaderOffset = CP.SectionTableStart;
474 for (const COFFYAML::Section &S : CP.Obj.Sections) {
475 object::coff_section Header{};
476 memcpy(Header.Name, S.Header.Name, COFF::NameSize);
477 Header.VirtualSize = S.Header.VirtualSize;
478 Header.VirtualAddress = S.Header.VirtualAddress;
479 Header.SizeOfRawData = S.Header.SizeOfRawData;
480 Header.PointerToRawData = S.Header.PointerToRawData;
481 Header.PointerToRelocations = S.Header.PointerToRelocations;
482 Header.PointerToLinenumbers = S.Header.PointerToLineNumbers;
483 Header.NumberOfRelocations = S.Header.NumberOfRelocations;
484 Header.NumberOfLinenumbers = S.Header.NumberOfLineNumbers;
485 Header.Characteristics = S.Header.Characteristics;
486 CBA.updateDataAt(SectionHeaderOffset, &Header, sizeof(Header));
487 SectionHeaderOffset += sizeof(Header);
488 }
489
490 // Output symbol table.
491 if (CP.Obj.Header.NumberOfSymbols || CP.StringTable.size() > 4)
493 else
494 CP.Obj.Header.PointerToSymbolTable = 0;
495
496 CBA.updateDataAt(PointerToSymbolTableOffset,
497 CP.Obj.Header.PointerToSymbolTable, LittleEndian);
498
499 for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(),
500 e = CP.Obj.Symbols.end();
501 i != e; ++i) {
502 CBA.write(i->Header.Name, COFF::NameSize);
503 CBA.write(i->Header.Value, LittleEndian);
504 if (CP.useBigObj())
505 CBA.write(i->Header.SectionNumber, LittleEndian);
506 else
507 CBA.write(static_cast<int16_t>(i->Header.SectionNumber), LittleEndian);
508 CBA.write(i->Header.Type, LittleEndian);
509 CBA.write(i->Header.StorageClass, LittleEndian);
510 CBA.write(i->Header.NumberOfAuxSymbols, LittleEndian);
511
512 if (i->FunctionDefinition) {
513 CBA.write(i->FunctionDefinition->TagIndex, LittleEndian);
514 CBA.write(i->FunctionDefinition->TotalSize, LittleEndian);
515 CBA.write(i->FunctionDefinition->PointerToLinenumber, LittleEndian);
516 CBA.write(i->FunctionDefinition->PointerToNextFunction, LittleEndian);
517 CBA.writeZeros(sizeof(i->FunctionDefinition->unused));
518 CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
519 }
520 if (i->bfAndefSymbol) {
521 CBA.writeZeros(sizeof(i->bfAndefSymbol->unused1));
522 CBA.write(i->bfAndefSymbol->Linenumber, LittleEndian);
523 CBA.writeZeros(sizeof(i->bfAndefSymbol->unused2));
524 CBA.write(i->bfAndefSymbol->PointerToNextFunction, LittleEndian);
525 CBA.writeZeros(sizeof(i->bfAndefSymbol->unused3));
526 CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
527 }
528 if (i->WeakExternal) {
529 CBA.write(i->WeakExternal->TagIndex, LittleEndian);
530 CBA.write(i->WeakExternal->Characteristics, LittleEndian);
531 CBA.writeZeros(sizeof(i->WeakExternal->unused));
532 CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
533 }
534 if (!i->File.empty()) {
535 unsigned SymbolSize = CP.getSymbolSize();
536 uint32_t NumberOfAuxRecords =
537 (i->File.size() + SymbolSize - 1) / SymbolSize;
538 uint32_t NumberOfAuxBytes = NumberOfAuxRecords * SymbolSize;
539 uint32_t NumZeros = NumberOfAuxBytes - i->File.size();
540 CBA.write(i->File.data(), i->File.size());
541 CBA.writeZeros(NumZeros);
542 }
543 if (i->SectionDefinition) {
544 CBA.write(i->SectionDefinition->Length, LittleEndian);
545 CBA.write(i->SectionDefinition->NumberOfRelocations, LittleEndian);
546 CBA.write(i->SectionDefinition->NumberOfLinenumbers, LittleEndian);
547 CBA.write(i->SectionDefinition->CheckSum, LittleEndian);
548 CBA.write(static_cast<int16_t>(i->SectionDefinition->Number),
549 LittleEndian);
550 CBA.write(i->SectionDefinition->Selection, LittleEndian);
551 CBA.writeZeros(sizeof(i->SectionDefinition->unused));
552 CBA.write(static_cast<int16_t>(i->SectionDefinition->Number >> 16),
553 LittleEndian);
554 CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
555 }
556 if (i->CLRToken) {
557 CBA.write(i->CLRToken->AuxType, LittleEndian);
558 CBA.writeZeros(sizeof(i->CLRToken->unused1));
559 CBA.write(i->CLRToken->SymbolTableIndex, LittleEndian);
560 CBA.writeZeros(sizeof(i->CLRToken->unused2));
561 CBA.writeZeros(CP.getSymbolSize() - COFF::Symbol16Size);
562 }
563 }
564
565 // Output string table.
566 if (CP.Obj.Header.PointerToSymbolTable) {
567 *reinterpret_cast<support::ulittle32_t *>(CP.StringTable.data()) =
568 CP.StringTable.size();
569 CBA.write(CP.StringTable.data(), CP.StringTable.size());
570 }
571 return true;
572}
573
575 size_t Size = Binary.binary_size();
576 if (UInt32)
577 Size += sizeof(*UInt32);
578 if (LoadConfig32)
579 Size += LoadConfig32->Size;
580 if (LoadConfig64)
581 Size += LoadConfig64->Size;
582 return Size;
583}
584
585template <typename T>
587 CBA.write(reinterpret_cast<const char *>(&S),
588 std::min(sizeof(S), static_cast<size_t>(S.Size)));
589 if (sizeof(S) < S.Size)
590 CBA.writeZeros(S.Size - sizeof(S));
591}
592
594 ContiguousBlobAccumulator &CBA) const {
595 if (UInt32)
596 CBA.write(*UInt32, LittleEndian);
598 if (LoadConfig32)
600 if (LoadConfig64)
602}
603
604namespace llvm {
605namespace yaml {
606
608 ErrorHandler ErrHandler, uint64_t MaxSize) {
609 COFFParser CP(Doc, ErrHandler);
610 if (!CP.parse()) {
611 ErrHandler("failed to parse YAML file");
612 return false;
613 }
614
615 // Limit the output size to guard against a runaway YAML description.
616 ContiguousBlobAccumulator CBA(/*BaseOffset=*/0, MaxSize);
617 if (!writeCOFF(CP, CBA)) {
618 ErrHandler("failed to write COFF file");
619 return false;
620 }
621 if (Error E = CBA.takeLimitError()) {
622 // Match ELF by reporting a custom error message instead below.
623 consumeError(std::move(E));
624 ErrHandler("the desired output size is greater than permitted. Use the "
625 "--max-size option to change the limit");
626 return false;
627 }
628
629 CBA.writeBlobToStream(Out);
630 return true;
631}
632
633} // namespace yaml
634} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file defines the StringMap class.
uint64_t uint64_t
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static bool writeCOFF(COFFParser &CP, ContiguousBlobAccumulator &CBA)
static yaml::BinaryRef toDebugS(ArrayRef< CodeViewYAML::YAMLDebugSubsection > Subsections, const codeview::StringsAndChecksums &SC, BumpPtrAllocator &Allocator)
static void writeLoadConfig(T &S, ContiguousBlobAccumulator &CBA)
static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic, T Header)
static bool writeSectionContent(COFFParser &CP, COFFYAML::Section &S, ContiguousBlobAccumulator &CBA)
This file defines ContiguousBlobAccumulator, the size-limited output buffer shared by the yaml2obj em...
static size_t getStringIndex(StringRef Name)
Definition LVElement.cpp:77
static llvm::Error parse(GsymDataExtractor &Data, uint64_t BaseAddr, LineEntryCallback const &Callback)
Definition LineTable.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
#define T
Basic Register Allocator
This file contains some functions that are useful when dealing with strings.
static bool is64Bit(const char *name)
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Provides write only access to a subclass of WritableBinaryStream.
Error writeInteger(T Value)
Write the integer Value to the underlying stream in the specified endianness.
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Helper for check-and-exit error handling.
Definition Error.h:1460
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
StringMap - This is an unconventional map that is specialized for handling keys that are "strings",...
Definition StringMap.h:129
constexpr bool empty() const
Check if the string is empty.
Definition StringRef.h:141
constexpr size_t size() const
Get the string size.
Definition StringRef.h:144
static LLVM_ABI raw_ostream & warning()
Convenience method for printing "warning: " to stderr.
Definition WithColor.cpp:86
static LLVM_ABI raw_ostream & error()
Convenience method for printing "error: " to stderr.
Definition WithColor.cpp:84
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
Specialized YAMLIO scalar type for representing a binary blob.
Definition YAML.h:64
LLVM_ABI uint64_t padToAlignment(unsigned Align)
LLVM_ABI void writeAsBinary(const BinaryRef &Bin, uint64_t N=UINT64_MAX)
void write(const char *Ptr, size_t Size)
void updateDataAt(uint64_t Pos, T Val, llvm::endianness E)
LLVM_ABI void encodePayload(ArrayRef< BBAddrMapEntry > Entries, const std::vector< PGOAnalysisMapEntry > *PGOAnalyses, yaml::ContiguousBlobAccumulator &CBA, llvm::endianness Endian, unsigned AddressSize)
Encodes the BBAddrMap payload into CBA.
@ NameSize
Definition COFF.h:58
@ Symbol16Size
Definition COFF.h:59
@ SectionSize
Definition COFF.h:61
@ Symbol32Size
Definition COFF.h:60
@ IMAGE_FILE_MACHINE_UNKNOWN
Definition COFF.h:96
@ IMAGE_SCN_CNT_CODE
Definition COFF.h:303
@ IMAGE_SCN_CNT_UNINITIALIZED_DATA
Definition COFF.h:305
@ IMAGE_SCN_CNT_INITIALIZED_DATA
Definition COFF.h:304
@ IMAGE_SCN_LNK_NRELOC_OVFL
Definition COFF.h:330
@ DEBUG_SECTION_MAGIC
Definition COFF.h:839
bool is64Bit(T Machine)
Definition COFF.h:134
const int32_t MaxNumberOfSections16
Definition COFF.h:33
static const char BigObjMagic[]
Definition COFF.h:38
static const char PEMagic[]
Definition COFF.h:36
@ SCT_COMPLEX_TYPE_SHIFT
Type is formed as (base + (derived << SCT_COMPLEX_TYPE_SHIFT))
Definition COFF.h:280
LLVM_ABI void initializeStringsAndChecksums(ArrayRef< YAMLDebugSubsection > Sections, codeview::StringsAndChecksums &SC)
LLVM_ABI Expected< std::vector< std::shared_ptr< codeview::DebugSubsection > > > toCodeViewSubsectionList(BumpPtrAllocator &Allocator, ArrayRef< YAMLDebugSubsection > Subsections, const codeview::StringsAndChecksums &SC)
LLVM_ABI ArrayRef< uint8_t > toDebugH(const DebugHSection &DebugH, BumpPtrAllocator &Alloc)
LLVM_ABI ArrayRef< uint8_t > toDebugT(ArrayRef< LeafRecord >, BumpPtrAllocator &Alloc, StringRef SectionName)
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, unaligned > ulittle32_t
Definition Endian.h:270
detail::packed_endian_specific_integral< uint32_t, llvm::endianness::little, aligned > aligned_ulittle32_t
Definition Endian.h:290
llvm::function_ref< void(const Twine &Msg)> ErrorHandler
Definition yaml2obj.h:68
LLVM_ABI bool yaml2coff(COFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH, uint64_t MaxSize)
This is an optimization pass for GlobalISel generic memory operations.
std::string utostr(uint64_t X, bool isNeg=false)
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:326
constexpr bool isPowerOf2_32(uint32_t Value)
Return true if the argument is a power of two > 0.
Definition MathExtras.h:280
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:149
OutputIt copy(R &&Range, OutputIt Out)
Definition STLExtras.h:1901
BumpPtrAllocatorImpl<> BumpPtrAllocator
The standard BumpPtrAllocator which just uses the default template parameters.
Definition Allocator.h:391
void consumeError(Error Err)
Consume a Error without doing anything.
Definition Error.h:1106
std::optional< PEHeader > OptionalHeader
Definition COFFYAML.h:124
std::vector< Section > Sections
Definition COFFYAML.h:126
std::vector< Symbol > Symbols
Definition COFFYAML.h:127
COFF::header Header
Definition COFFYAML.h:125
std::optional< object::coff_load_configuration64 > LoadConfig64
Definition COFFYAML.h:79
std::optional< object::coff_load_configuration32 > LoadConfig32
Definition COFFYAML.h:78
LLVM_ABI void writeAsBinary(yaml::ContiguousBlobAccumulator &CBA) const
std::optional< uint32_t > UInt32
Definition COFFYAML.h:76
LLVM_ABI size_t size() const
std::vector< CodeViewYAML::YAMLDebugSubsection > DebugS
Definition COFFYAML.h:89
std::vector< SectionDataEntry > StructuredData
Definition COFFYAML.h:93
std::optional< std::vector< BBAddrMapYAML::BBAddrMapEntry > > BBAddrMapEntries
Definition COFFYAML.h:94
std::vector< CodeViewYAML::LeafRecord > DebugT
Definition COFFYAML.h:90
std::optional< yaml::BinaryRef > SectionData
Definition COFFYAML.h:88
std::optional< CodeViewYAML::DebugHSection > DebugH
Definition COFFYAML.h:92
std::vector< CodeViewYAML::LeafRecord > DebugP
Definition COFFYAML.h:91
COFF::section Header
Definition COFFYAML.h:86
std::optional< std::vector< BBAddrMapYAML::PGOAnalysisMapEntry > > PGOAnalyses
Definition COFFYAML.h:95
std::vector< Relocation > Relocations
Definition COFFYAML.h:96
std::optional< COFF::AuxiliaryWeakExternal > WeakExternal
Definition COFFYAML.h:108
std::optional< COFF::AuxiliarybfAndefSymbol > bfAndefSymbol
Definition COFFYAML.h:107
COFF::SymbolComplexType ComplexType
Definition COFFYAML.h:105
std::optional< COFF::AuxiliarySectionDefinition > SectionDefinition
Definition COFFYAML.h:110
std::optional< COFF::AuxiliaryFunctionDefinition > FunctionDefinition
Definition COFFYAML.h:106
COFF::symbol Header
Definition COFFYAML.h:103
COFF::SymbolBaseType SimpleType
Definition COFFYAML.h:104
std::optional< COFF::AuxiliaryCLRToken > CLRToken
Definition COFFYAML.h:111
uint16_t Machine
Definition COFF.h:66
uint32_t TimeDateStamp
Definition COFF.h:68
uint16_t SizeOfOptionalHeader
Definition COFF.h:71
uint32_t NumberOfSymbols
Definition COFF.h:70
int32_t NumberOfSections
Definition COFF.h:67
uint16_t Characteristics
Definition COFF.h:72
uint32_t PointerToSymbolTable
Definition COFF.h:69
uint32_t VirtualSize
Definition COFF.h:287
uint32_t PointerToRelocations
Definition COFF.h:291
uint16_t NumberOfLineNumbers
Definition COFF.h:294
uint32_t PointerToRawData
Definition COFF.h:290
uint32_t SizeOfRawData
Definition COFF.h:289
uint32_t Characteristics
Definition COFF.h:295
uint16_t NumberOfRelocations
Definition COFF.h:293
char Name[NameSize]
Definition COFF.h:286
uint32_t VirtualAddress
Definition COFF.h:288
uint32_t PointerToLineNumbers
Definition COFF.h:292
uint8_t NumberOfAuxSymbols
Definition COFF.h:208
uint16_t Type
Definition COFF.h:206
char Name[NameSize]
Definition COFF.h:203
The DOS compatible header at the front of all PE/COFF executables.
Definition COFF.h:58
support::ulittle16_t AddressOfRelocationTable
Definition COFF.h:71
support::ulittle32_t AddressOfNewExeHeader
Definition COFF.h:77
The 32-bit PE header that follows the COFF header.
Definition COFF.h:109
support::ulittle32_t BaseOfData
Definition COFF.h:118
The 64-bit PE header that follows the COFF header.
Definition COFF.h:145
Common declarations for yaml2obj.