1 //===- yaml2coff - Convert YAML to a COFF object file ---------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// \brief The COFF component of yaml2obj.
13 //===----------------------------------------------------------------------===//
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/ADT/SmallString.h"
18 #include "llvm/ADT/StringExtras.h"
19 #include "llvm/ADT/StringMap.h"
20 #include "llvm/ADT/StringSwitch.h"
21 #include "llvm/Object/COFF.h"
22 #include "llvm/Object/COFFYAML.h"
23 #include "llvm/Support/Endian.h"
24 #include "llvm/Support/MemoryBuffer.h"
25 #include "llvm/Support/SourceMgr.h"
26 #include "llvm/Support/raw_ostream.h"
31 /// This parses a yaml stream that represents a COFF object file.
32 /// See docs/yaml2obj for the yaml scheema.
34 COFFParser(COFFYAML::Object
&Obj
)
35 : Obj(Obj
), SectionTableStart(0), SectionTableSize(0) {
36 // A COFF string table always starts with a 4 byte size field. Offsets into
37 // it include this size, so allocate it now.
38 StringTable
.append(4, char(0));
41 bool useBigObj() const {
42 return static_cast<int32_t>(Obj
.Sections
.size()) >
43 COFF::MaxNumberOfSections16
;
46 bool isPE() const { return Obj
.OptionalHeader
.hasValue(); }
47 bool is64Bit() const {
48 return Obj
.Header
.Machine
== COFF::IMAGE_FILE_MACHINE_AMD64
;
51 uint32_t getFileAlignment() const {
52 return Obj
.OptionalHeader
->Header
.FileAlignment
;
55 unsigned getHeaderSize() const {
56 return useBigObj() ? COFF::Header32Size
: COFF::Header16Size
;
59 unsigned getSymbolSize() const {
60 return useBigObj() ? COFF::Symbol32Size
: COFF::Symbol16Size
;
63 bool parseSections() {
64 for (std::vector
<COFFYAML::Section
>::iterator i
= Obj
.Sections
.begin(),
65 e
= Obj
.Sections
.end(); i
!= e
; ++i
) {
66 COFFYAML::Section
&Sec
= *i
;
68 // If the name is less than 8 bytes, store it in place, otherwise
69 // store it in the string table.
70 StringRef Name
= Sec
.Name
;
72 if (Name
.size() <= COFF::NameSize
) {
73 std::copy(Name
.begin(), Name
.end(), Sec
.Header
.Name
);
75 // Add string to the string table and format the index for output.
76 unsigned Index
= getStringIndex(Name
);
77 std::string str
= utostr(Index
);
79 errs() << "String table got too large";
82 Sec
.Header
.Name
[0] = '/';
83 std::copy(str
.begin(), str
.end(), Sec
.Header
.Name
+ 1);
86 Sec
.Header
.Characteristics
|= (Log2_32(Sec
.Alignment
) + 1) << 20;
92 for (std::vector
<COFFYAML::Symbol
>::iterator i
= Obj
.Symbols
.begin(),
93 e
= Obj
.Symbols
.end(); i
!= e
; ++i
) {
94 COFFYAML::Symbol
&Sym
= *i
;
96 // If the name is less than 8 bytes, store it in place, otherwise
97 // store it in the string table.
98 StringRef Name
= Sym
.Name
;
99 if (Name
.size() <= COFF::NameSize
) {
100 std::copy(Name
.begin(), Name
.end(), Sym
.Header
.Name
);
102 // Add string to the string table and format the index for output.
103 unsigned Index
= getStringIndex(Name
);
104 *reinterpret_cast<support::aligned_ulittle32_t
*>(
105 Sym
.Header
.Name
+ 4) = Index
;
108 Sym
.Header
.Type
= Sym
.SimpleType
;
109 Sym
.Header
.Type
|= Sym
.ComplexType
<< COFF::SCT_COMPLEX_TYPE_SHIFT
;
115 if (!parseSections())
122 unsigned getStringIndex(StringRef Str
) {
123 StringMap
<unsigned>::iterator i
= StringTableMap
.find(Str
);
124 if (i
== StringTableMap
.end()) {
125 unsigned Index
= StringTable
.size();
126 StringTable
.append(Str
.begin(), Str
.end());
127 StringTable
.push_back(0);
128 StringTableMap
[Str
] = Index
;
134 COFFYAML::Object
&Obj
;
136 StringMap
<unsigned> StringTableMap
;
137 std::string StringTable
;
138 uint32_t SectionTableStart
;
139 uint32_t SectionTableSize
;
142 // Take a CP and assign addresses and sizes to everything. Returns false if the
143 // layout is not valid to do.
144 static bool layoutOptionalHeader(COFFParser
&CP
) {
147 unsigned PEHeaderSize
= CP
.is64Bit() ? sizeof(object::pe32plus_header
)
148 : sizeof(object::pe32_header
);
149 CP
.Obj
.Header
.SizeOfOptionalHeader
=
151 sizeof(object::data_directory
) * (COFF::NUM_DATA_DIRECTORIES
+ 1);
156 enum { DOSStubSize
= 128 };
159 // Take a CP and assign addresses and sizes to everything. Returns false if the
160 // layout is not valid to do.
161 static bool layoutCOFF(COFFParser
&CP
) {
162 // The section table starts immediately after the header, including the
164 CP
.SectionTableStart
=
165 CP
.getHeaderSize() + CP
.Obj
.Header
.SizeOfOptionalHeader
;
167 CP
.SectionTableStart
+= DOSStubSize
+ sizeof(COFF::PEMagic
);
168 CP
.SectionTableSize
= COFF::SectionSize
* CP
.Obj
.Sections
.size();
170 uint32_t CurrentSectionDataOffset
=
171 CP
.SectionTableStart
+ CP
.SectionTableSize
;
173 // Assign each section data address consecutively.
174 for (COFFYAML::Section
&S
: CP
.Obj
.Sections
) {
175 if (S
.SectionData
.binary_size() > 0) {
176 CurrentSectionDataOffset
= RoundUpToAlignment(
177 CurrentSectionDataOffset
, CP
.isPE() ? CP
.getFileAlignment() : 4);
178 S
.Header
.SizeOfRawData
= S
.SectionData
.binary_size();
180 S
.Header
.SizeOfRawData
=
181 RoundUpToAlignment(S
.Header
.SizeOfRawData
, CP
.getFileAlignment());
182 S
.Header
.PointerToRawData
= CurrentSectionDataOffset
;
183 CurrentSectionDataOffset
+= S
.Header
.SizeOfRawData
;
184 if (!S
.Relocations
.empty()) {
185 S
.Header
.PointerToRelocations
= CurrentSectionDataOffset
;
186 S
.Header
.NumberOfRelocations
= S
.Relocations
.size();
187 CurrentSectionDataOffset
+=
188 S
.Header
.NumberOfRelocations
* COFF::RelocationSize
;
191 S
.Header
.SizeOfRawData
= 0;
192 S
.Header
.PointerToRawData
= 0;
196 uint32_t SymbolTableStart
= CurrentSectionDataOffset
;
198 // Calculate number of symbols.
199 uint32_t NumberOfSymbols
= 0;
200 for (std::vector
<COFFYAML::Symbol
>::iterator i
= CP
.Obj
.Symbols
.begin(),
201 e
= CP
.Obj
.Symbols
.end();
203 uint32_t NumberOfAuxSymbols
= 0;
204 if (i
->FunctionDefinition
)
205 NumberOfAuxSymbols
+= 1;
206 if (i
->bfAndefSymbol
)
207 NumberOfAuxSymbols
+= 1;
209 NumberOfAuxSymbols
+= 1;
210 if (!i
->File
.empty())
211 NumberOfAuxSymbols
+=
212 (i
->File
.size() + CP
.getSymbolSize() - 1) / CP
.getSymbolSize();
213 if (i
->SectionDefinition
)
214 NumberOfAuxSymbols
+= 1;
216 NumberOfAuxSymbols
+= 1;
217 i
->Header
.NumberOfAuxSymbols
= NumberOfAuxSymbols
;
218 NumberOfSymbols
+= 1 + NumberOfAuxSymbols
;
221 // Store all the allocated start addresses in the header.
222 CP
.Obj
.Header
.NumberOfSections
= CP
.Obj
.Sections
.size();
223 CP
.Obj
.Header
.NumberOfSymbols
= NumberOfSymbols
;
224 if (NumberOfSymbols
> 0 || CP
.StringTable
.size() > 4)
225 CP
.Obj
.Header
.PointerToSymbolTable
= SymbolTableStart
;
227 CP
.Obj
.Header
.PointerToSymbolTable
= 0;
229 *reinterpret_cast<support::ulittle32_t
*>(&CP
.StringTable
[0])
230 = CP
.StringTable
.size();
235 template <typename value_type
>
236 struct binary_le_impl
{
238 binary_le_impl(value_type V
) : Value(V
) {}
241 template <typename value_type
>
242 raw_ostream
&operator <<( raw_ostream
&OS
243 , const binary_le_impl
<value_type
> &BLE
) {
244 char Buffer
[sizeof(BLE
.Value
)];
245 support::endian::write
<value_type
, support::little
, support::unaligned
>(
247 OS
.write(Buffer
, sizeof(BLE
.Value
));
251 template <typename value_type
>
252 binary_le_impl
<value_type
> binary_le(value_type V
) {
253 return binary_le_impl
<value_type
>(V
);
256 template <size_t NumBytes
>
261 template <size_t NumBytes
>
262 raw_ostream
&operator<<(raw_ostream
&OS
, const zeros_impl
<NumBytes
> &) {
263 char Buffer
[NumBytes
];
264 memset(Buffer
, 0, sizeof(Buffer
));
265 OS
.write(Buffer
, sizeof(Buffer
));
269 template <typename T
>
270 zeros_impl
<sizeof(T
)> zeros(const T
&) {
271 return zeros_impl
<sizeof(T
)>();
274 struct num_zeros_impl
{
276 num_zeros_impl(size_t N
) : N(N
) {}
279 raw_ostream
&operator<<(raw_ostream
&OS
, const num_zeros_impl
&NZI
) {
280 for (size_t I
= 0; I
!= NZI
.N
; ++I
)
285 num_zeros_impl
num_zeros(size_t N
) {
286 num_zeros_impl
NZI(N
);
290 template <typename T
>
291 static uint32_t initializeOptionalHeader(COFFParser
&CP
, uint16_t Magic
, T Header
) {
292 memset(Header
, 0, sizeof(*Header
));
293 Header
->Magic
= Magic
;
294 Header
->SectionAlignment
= CP
.Obj
.OptionalHeader
->Header
.SectionAlignment
;
295 Header
->FileAlignment
= CP
.Obj
.OptionalHeader
->Header
.FileAlignment
;
296 uint32_t SizeOfCode
= 0, SizeOfInitializedData
= 0,
297 SizeOfUninitializedData
= 0;
298 uint32_t SizeOfHeaders
= RoundUpToAlignment(
299 CP
.SectionTableStart
+ CP
.SectionTableSize
, Header
->FileAlignment
);
300 uint32_t SizeOfImage
=
301 RoundUpToAlignment(SizeOfHeaders
, Header
->SectionAlignment
);
302 uint32_t BaseOfData
= 0;
303 for (const COFFYAML::Section
&S
: CP
.Obj
.Sections
) {
304 if (S
.Header
.Characteristics
& COFF::IMAGE_SCN_CNT_CODE
)
305 SizeOfCode
+= S
.Header
.SizeOfRawData
;
306 if (S
.Header
.Characteristics
& COFF::IMAGE_SCN_CNT_INITIALIZED_DATA
)
307 SizeOfInitializedData
+= S
.Header
.SizeOfRawData
;
308 if (S
.Header
.Characteristics
& COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA
)
309 SizeOfUninitializedData
+= S
.Header
.SizeOfRawData
;
310 if (S
.Name
.equals(".text"))
311 Header
->BaseOfCode
= S
.Header
.VirtualAddress
; // RVA
312 else if (S
.Name
.equals(".data"))
313 BaseOfData
= S
.Header
.VirtualAddress
; // RVA
314 if (S
.Header
.VirtualAddress
)
316 RoundUpToAlignment(S
.Header
.VirtualSize
, Header
->SectionAlignment
);
318 Header
->SizeOfCode
= SizeOfCode
;
319 Header
->SizeOfInitializedData
= SizeOfInitializedData
;
320 Header
->SizeOfUninitializedData
= SizeOfUninitializedData
;
321 Header
->AddressOfEntryPoint
=
322 CP
.Obj
.OptionalHeader
->Header
.AddressOfEntryPoint
; // RVA
323 Header
->ImageBase
= CP
.Obj
.OptionalHeader
->Header
.ImageBase
;
324 Header
->MajorOperatingSystemVersion
=
325 CP
.Obj
.OptionalHeader
->Header
.MajorOperatingSystemVersion
;
326 Header
->MinorOperatingSystemVersion
=
327 CP
.Obj
.OptionalHeader
->Header
.MinorOperatingSystemVersion
;
328 Header
->MajorImageVersion
=
329 CP
.Obj
.OptionalHeader
->Header
.MajorImageVersion
;
330 Header
->MinorImageVersion
=
331 CP
.Obj
.OptionalHeader
->Header
.MinorImageVersion
;
332 Header
->MajorSubsystemVersion
=
333 CP
.Obj
.OptionalHeader
->Header
.MajorSubsystemVersion
;
334 Header
->MinorSubsystemVersion
=
335 CP
.Obj
.OptionalHeader
->Header
.MinorSubsystemVersion
;
336 Header
->SizeOfImage
= SizeOfImage
;
337 Header
->SizeOfHeaders
= SizeOfHeaders
;
338 Header
->Subsystem
= CP
.Obj
.OptionalHeader
->Header
.Subsystem
;
339 Header
->DLLCharacteristics
= CP
.Obj
.OptionalHeader
->Header
.DLLCharacteristics
;
340 Header
->SizeOfStackReserve
= CP
.Obj
.OptionalHeader
->Header
.SizeOfStackReserve
;
341 Header
->SizeOfStackCommit
= CP
.Obj
.OptionalHeader
->Header
.SizeOfStackCommit
;
342 Header
->SizeOfHeapReserve
= CP
.Obj
.OptionalHeader
->Header
.SizeOfHeapReserve
;
343 Header
->SizeOfHeapCommit
= CP
.Obj
.OptionalHeader
->Header
.SizeOfHeapCommit
;
344 Header
->NumberOfRvaAndSize
= COFF::NUM_DATA_DIRECTORIES
+ 1;
348 static bool writeCOFF(COFFParser
&CP
, raw_ostream
&OS
) {
350 // PE files start with a DOS stub.
351 object::dos_header DH
;
352 memset(&DH
, 0, sizeof(DH
));
354 // DOS EXEs start with "MZ" magic.
357 // Initializing the AddressOfRelocationTable is strictly optional but
358 // mollifies certain tools which expect it to have a value greater than
360 DH
.AddressOfRelocationTable
= sizeof(DH
);
361 // This is the address of the PE signature.
362 DH
.AddressOfNewExeHeader
= DOSStubSize
;
364 // Write out our DOS stub.
365 OS
.write(reinterpret_cast<char *>(&DH
), sizeof(DH
));
366 // Write padding until we reach the position of where our PE signature
368 OS
<< num_zeros(DOSStubSize
- sizeof(DH
));
369 // Write out the PE signature.
370 OS
.write(COFF::PEMagic
, sizeof(COFF::PEMagic
));
372 if (CP
.useBigObj()) {
373 OS
<< binary_le(static_cast<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN
))
374 << binary_le(static_cast<uint16_t>(0xffff))
375 << binary_le(static_cast<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion
))
376 << binary_le(CP
.Obj
.Header
.Machine
)
377 << binary_le(CP
.Obj
.Header
.TimeDateStamp
);
378 OS
.write(COFF::BigObjMagic
, sizeof(COFF::BigObjMagic
));
379 OS
<< zeros(uint32_t(0))
380 << zeros(uint32_t(0))
381 << zeros(uint32_t(0))
382 << zeros(uint32_t(0))
383 << binary_le(CP
.Obj
.Header
.NumberOfSections
)
384 << binary_le(CP
.Obj
.Header
.PointerToSymbolTable
)
385 << binary_le(CP
.Obj
.Header
.NumberOfSymbols
);
387 OS
<< binary_le(CP
.Obj
.Header
.Machine
)
388 << binary_le(static_cast<int16_t>(CP
.Obj
.Header
.NumberOfSections
))
389 << binary_le(CP
.Obj
.Header
.TimeDateStamp
)
390 << binary_le(CP
.Obj
.Header
.PointerToSymbolTable
)
391 << binary_le(CP
.Obj
.Header
.NumberOfSymbols
)
392 << binary_le(CP
.Obj
.Header
.SizeOfOptionalHeader
)
393 << binary_le(CP
.Obj
.Header
.Characteristics
);
397 object::pe32plus_header PEH
;
398 initializeOptionalHeader(CP
, COFF::PE32Header::PE32_PLUS
, &PEH
);
399 OS
.write(reinterpret_cast<char *>(&PEH
), sizeof(PEH
));
401 object::pe32_header PEH
;
402 uint32_t BaseOfData
= initializeOptionalHeader(CP
, COFF::PE32Header::PE32
, &PEH
);
403 PEH
.BaseOfData
= BaseOfData
;
404 OS
.write(reinterpret_cast<char *>(&PEH
), sizeof(PEH
));
406 for (const Optional
<COFF::DataDirectory
> &DD
:
407 CP
.Obj
.OptionalHeader
->DataDirectories
) {
408 if (!DD
.hasValue()) {
409 OS
<< zeros(uint32_t(0));
410 OS
<< zeros(uint32_t(0));
412 OS
<< binary_le(DD
->RelativeVirtualAddress
);
413 OS
<< binary_le(DD
->Size
);
416 OS
<< zeros(uint32_t(0));
417 OS
<< zeros(uint32_t(0));
420 assert(OS
.tell() == CP
.SectionTableStart
);
421 // Output section table.
422 for (std::vector
<COFFYAML::Section
>::iterator i
= CP
.Obj
.Sections
.begin(),
423 e
= CP
.Obj
.Sections
.end();
425 OS
.write(i
->Header
.Name
, COFF::NameSize
);
426 OS
<< binary_le(i
->Header
.VirtualSize
)
427 << binary_le(i
->Header
.VirtualAddress
)
428 << binary_le(i
->Header
.SizeOfRawData
)
429 << binary_le(i
->Header
.PointerToRawData
)
430 << binary_le(i
->Header
.PointerToRelocations
)
431 << binary_le(i
->Header
.PointerToLineNumbers
)
432 << binary_le(i
->Header
.NumberOfRelocations
)
433 << binary_le(i
->Header
.NumberOfLineNumbers
)
434 << binary_le(i
->Header
.Characteristics
);
436 assert(OS
.tell() == CP
.SectionTableStart
+ CP
.SectionTableSize
);
438 unsigned CurSymbol
= 0;
439 StringMap
<unsigned> SymbolTableIndexMap
;
440 for (std::vector
<COFFYAML::Symbol
>::iterator I
= CP
.Obj
.Symbols
.begin(),
441 E
= CP
.Obj
.Symbols
.end();
443 SymbolTableIndexMap
[I
->Name
] = CurSymbol
;
444 CurSymbol
+= 1 + I
->Header
.NumberOfAuxSymbols
;
447 // Output section data.
448 for (const COFFYAML::Section
&S
: CP
.Obj
.Sections
) {
449 if (!S
.Header
.SizeOfRawData
)
451 assert(S
.Header
.PointerToRawData
>= OS
.tell());
452 OS
<< num_zeros(S
.Header
.PointerToRawData
- OS
.tell());
453 S
.SectionData
.writeAsBinary(OS
);
454 assert(S
.Header
.SizeOfRawData
>= S
.SectionData
.binary_size());
455 OS
<< num_zeros(S
.Header
.SizeOfRawData
- S
.SectionData
.binary_size());
456 for (const COFFYAML::Relocation
&R
: S
.Relocations
) {
457 uint32_t SymbolTableIndex
= SymbolTableIndexMap
[R
.SymbolName
];
458 OS
<< binary_le(R
.VirtualAddress
)
459 << binary_le(SymbolTableIndex
)
460 << binary_le(R
.Type
);
464 // Output symbol table.
466 for (std::vector
<COFFYAML::Symbol
>::const_iterator i
= CP
.Obj
.Symbols
.begin(),
467 e
= CP
.Obj
.Symbols
.end();
469 OS
.write(i
->Header
.Name
, COFF::NameSize
);
470 OS
<< binary_le(i
->Header
.Value
);
472 OS
<< binary_le(i
->Header
.SectionNumber
);
474 OS
<< binary_le(static_cast<int16_t>(i
->Header
.SectionNumber
));
475 OS
<< binary_le(i
->Header
.Type
)
476 << binary_le(i
->Header
.StorageClass
)
477 << binary_le(i
->Header
.NumberOfAuxSymbols
);
479 if (i
->FunctionDefinition
)
480 OS
<< binary_le(i
->FunctionDefinition
->TagIndex
)
481 << binary_le(i
->FunctionDefinition
->TotalSize
)
482 << binary_le(i
->FunctionDefinition
->PointerToLinenumber
)
483 << binary_le(i
->FunctionDefinition
->PointerToNextFunction
)
484 << zeros(i
->FunctionDefinition
->unused
)
485 << num_zeros(CP
.getSymbolSize() - COFF::Symbol16Size
);
486 if (i
->bfAndefSymbol
)
487 OS
<< zeros(i
->bfAndefSymbol
->unused1
)
488 << binary_le(i
->bfAndefSymbol
->Linenumber
)
489 << zeros(i
->bfAndefSymbol
->unused2
)
490 << binary_le(i
->bfAndefSymbol
->PointerToNextFunction
)
491 << zeros(i
->bfAndefSymbol
->unused3
)
492 << num_zeros(CP
.getSymbolSize() - COFF::Symbol16Size
);
494 OS
<< binary_le(i
->WeakExternal
->TagIndex
)
495 << binary_le(i
->WeakExternal
->Characteristics
)
496 << zeros(i
->WeakExternal
->unused
)
497 << num_zeros(CP
.getSymbolSize() - COFF::Symbol16Size
);
498 if (!i
->File
.empty()) {
499 unsigned SymbolSize
= CP
.getSymbolSize();
500 uint32_t NumberOfAuxRecords
=
501 (i
->File
.size() + SymbolSize
- 1) / SymbolSize
;
502 uint32_t NumberOfAuxBytes
= NumberOfAuxRecords
* SymbolSize
;
503 uint32_t NumZeros
= NumberOfAuxBytes
- i
->File
.size();
504 OS
.write(i
->File
.data(), i
->File
.size());
505 OS
<< num_zeros(NumZeros
);
507 if (i
->SectionDefinition
)
508 OS
<< binary_le(i
->SectionDefinition
->Length
)
509 << binary_le(i
->SectionDefinition
->NumberOfRelocations
)
510 << binary_le(i
->SectionDefinition
->NumberOfLinenumbers
)
511 << binary_le(i
->SectionDefinition
->CheckSum
)
512 << binary_le(static_cast<int16_t>(i
->SectionDefinition
->Number
))
513 << binary_le(i
->SectionDefinition
->Selection
)
514 << zeros(i
->SectionDefinition
->unused
)
515 << binary_le(static_cast<int16_t>(i
->SectionDefinition
->Number
>> 16))
516 << num_zeros(CP
.getSymbolSize() - COFF::Symbol16Size
);
518 OS
<< binary_le(i
->CLRToken
->AuxType
)
519 << zeros(i
->CLRToken
->unused1
)
520 << binary_le(i
->CLRToken
->SymbolTableIndex
)
521 << zeros(i
->CLRToken
->unused2
)
522 << num_zeros(CP
.getSymbolSize() - COFF::Symbol16Size
);
525 // Output string table.
526 if (CP
.Obj
.Header
.PointerToSymbolTable
)
527 OS
.write(&CP
.StringTable
[0], CP
.StringTable
.size());
531 int yaml2coff(yaml::Input
&YIn
, raw_ostream
&Out
) {
532 COFFYAML::Object Doc
;
535 errs() << "yaml2obj: Failed to parse YAML file!\n";
541 errs() << "yaml2obj: Failed to parse YAML file!\n";
545 if (!layoutOptionalHeader(CP
)) {
546 errs() << "yaml2obj: Failed to layout optional header for COFF file!\n";
549 if (!layoutCOFF(CP
)) {
550 errs() << "yaml2obj: Failed to layout COFF file!\n";
553 if (!writeCOFF(CP
, Out
)) {
554 errs() << "yaml2obj: Failed to write COFF file!\n";