1//===- yaml2coff - Convert YAML to a COFF object file ---------------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief The COFF component of yaml2obj.
12///
13//===----------------------------------------------------------------------===//
14
15#include "yaml2obj.h"
16#include "llvm/ADT/STLExtras.h"
17#include "llvm/ADT/StringExtras.h"
18#include "llvm/ADT/StringMap.h"
19#include "llvm/ADT/StringSwitch.h"
20#include "llvm/Object/COFF.h"
21#include "llvm/ObjectYAML/ObjectYAML.h"
22#include "llvm/Support/Endian.h"
23#include "llvm/Support/MemoryBuffer.h"
24#include "llvm/Support/SourceMgr.h"
25#include "llvm/Support/raw_ostream.h"
26#include <vector>
27
28using namespace llvm;
29
30/// This parses a yaml stream that represents a COFF object file.
31/// See docs/yaml2obj for the yaml scheema.
32struct COFFParser {
33  COFFParser(COFFYAML::Object &Obj)
34      : Obj(Obj), SectionTableStart(0), SectionTableSize(0) {
35    // A COFF string table always starts with a 4 byte size field. Offsets into
36    // it include this size, so allocate it now.
37    StringTable.append(4, char(0));
38  }
39
40  bool useBigObj() const {
41    return static_cast<int32_t>(Obj.Sections.size()) >
42           COFF::MaxNumberOfSections16;
43  }
44
45  bool isPE() const { return Obj.OptionalHeader.hasValue(); }
46  bool is64Bit() const {
47    return Obj.Header.Machine == COFF::IMAGE_FILE_MACHINE_AMD64;
48  }
49
50  uint32_t getFileAlignment() const {
51    return Obj.OptionalHeader->Header.FileAlignment;
52  }
53
54  unsigned getHeaderSize() const {
55    return useBigObj() ? COFF::Header32Size : COFF::Header16Size;
56  }
57
58  unsigned getSymbolSize() const {
59    return useBigObj() ? COFF::Symbol32Size : COFF::Symbol16Size;
60  }
61
62  bool parseSections() {
63    for (std::vector<COFFYAML::Section>::iterator i = Obj.Sections.begin(),
64           e = Obj.Sections.end(); i != e; ++i) {
65      COFFYAML::Section &Sec = *i;
66
67      // If the name is less than 8 bytes, store it in place, otherwise
68      // store it in the string table.
69      StringRef Name = Sec.Name;
70
71      if (Name.size() <= COFF::NameSize) {
72        std::copy(Name.begin(), Name.end(), Sec.Header.Name);
73      } else {
74        // Add string to the string table and format the index for output.
75        unsigned Index = getStringIndex(Name);
76        std::string str = utostr(Index);
77        if (str.size() > 7) {
78          errs() << "String table got too large\n";
79          return false;
80        }
81        Sec.Header.Name[0] = '/';
82        std::copy(str.begin(), str.end(), Sec.Header.Name + 1);
83      }
84
85      if (Sec.Alignment) {
86        if (Sec.Alignment > 8192) {
87          errs() << "Section alignment is too large\n";
88          return false;
89        }
90        if (!isPowerOf2_32(Sec.Alignment)) {
91          errs() << "Section alignment is not a power of 2\n";
92          return false;
93        }
94        Sec.Header.Characteristics |= (Log2_32(Sec.Alignment) + 1) << 20;
95      }
96    }
97    return true;
98  }
99
100  bool parseSymbols() {
101    for (std::vector<COFFYAML::Symbol>::iterator i = Obj.Symbols.begin(),
102           e = Obj.Symbols.end(); i != e; ++i) {
103      COFFYAML::Symbol &Sym = *i;
104
105      // If the name is less than 8 bytes, store it in place, otherwise
106      // store it in the string table.
107      StringRef Name = Sym.Name;
108      if (Name.size() <= COFF::NameSize) {
109        std::copy(Name.begin(), Name.end(), Sym.Header.Name);
110      } else {
111        // Add string to the string table and format the index for output.
112        unsigned Index = getStringIndex(Name);
113        *reinterpret_cast<support::aligned_ulittle32_t*>(
114            Sym.Header.Name + 4) = Index;
115      }
116
117      Sym.Header.Type = Sym.SimpleType;
118      Sym.Header.Type |= Sym.ComplexType << COFF::SCT_COMPLEX_TYPE_SHIFT;
119    }
120    return true;
121  }
122
123  bool parse() {
124    if (!parseSections())
125      return false;
126    if (!parseSymbols())
127      return false;
128    return true;
129  }
130
131  unsigned getStringIndex(StringRef Str) {
132    StringMap<unsigned>::iterator i = StringTableMap.find(Str);
133    if (i == StringTableMap.end()) {
134      unsigned Index = StringTable.size();
135      StringTable.append(Str.begin(), Str.end());
136      StringTable.push_back(0);
137      StringTableMap[Str] = Index;
138      return Index;
139    }
140    return i->second;
141  }
142
143  COFFYAML::Object &Obj;
144
145  StringMap<unsigned> StringTableMap;
146  std::string StringTable;
147  uint32_t SectionTableStart;
148  uint32_t SectionTableSize;
149};
150
151// Take a CP and assign addresses and sizes to everything. Returns false if the
152// layout is not valid to do.
153static bool layoutOptionalHeader(COFFParser &CP) {
154  if (!CP.isPE())
155    return true;
156  unsigned PEHeaderSize = CP.is64Bit() ? sizeof(object::pe32plus_header)
157                                       : sizeof(object::pe32_header);
158  CP.Obj.Header.SizeOfOptionalHeader =
159      PEHeaderSize +
160      sizeof(object::data_directory) * (COFF::NUM_DATA_DIRECTORIES + 1);
161  return true;
162}
163
164namespace {
165enum { DOSStubSize = 128 };
166}
167
168// Take a CP and assign addresses and sizes to everything. Returns false if the
169// layout is not valid to do.
170static bool layoutCOFF(COFFParser &CP) {
171  // The section table starts immediately after the header, including the
172  // optional header.
173  CP.SectionTableStart =
174      CP.getHeaderSize() + CP.Obj.Header.SizeOfOptionalHeader;
175  if (CP.isPE())
176    CP.SectionTableStart += DOSStubSize + sizeof(COFF::PEMagic);
177  CP.SectionTableSize = COFF::SectionSize * CP.Obj.Sections.size();
178
179  uint32_t CurrentSectionDataOffset =
180      CP.SectionTableStart + CP.SectionTableSize;
181
182  // Assign each section data address consecutively.
183  for (COFFYAML::Section &S : CP.Obj.Sections) {
184    if (S.SectionData.binary_size() > 0) {
185      CurrentSectionDataOffset = alignTo(CurrentSectionDataOffset,
186                                         CP.isPE() ? CP.getFileAlignment() : 4);
187      S.Header.SizeOfRawData = S.SectionData.binary_size();
188      if (CP.isPE())
189        S.Header.SizeOfRawData =
190            alignTo(S.Header.SizeOfRawData, CP.getFileAlignment());
191      S.Header.PointerToRawData = CurrentSectionDataOffset;
192      CurrentSectionDataOffset += S.Header.SizeOfRawData;
193      if (!S.Relocations.empty()) {
194        S.Header.PointerToRelocations = CurrentSectionDataOffset;
195        S.Header.NumberOfRelocations = S.Relocations.size();
196        CurrentSectionDataOffset +=
197            S.Header.NumberOfRelocations * COFF::RelocationSize;
198      }
199    } else {
200      S.Header.SizeOfRawData = 0;
201      S.Header.PointerToRawData = 0;
202    }
203  }
204
205  uint32_t SymbolTableStart = CurrentSectionDataOffset;
206
207  // Calculate number of symbols.
208  uint32_t NumberOfSymbols = 0;
209  for (std::vector<COFFYAML::Symbol>::iterator i = CP.Obj.Symbols.begin(),
210                                               e = CP.Obj.Symbols.end();
211                                               i != e; ++i) {
212    uint32_t NumberOfAuxSymbols = 0;
213    if (i->FunctionDefinition)
214      NumberOfAuxSymbols += 1;
215    if (i->bfAndefSymbol)
216      NumberOfAuxSymbols += 1;
217    if (i->WeakExternal)
218      NumberOfAuxSymbols += 1;
219    if (!i->File.empty())
220      NumberOfAuxSymbols +=
221          (i->File.size() + CP.getSymbolSize() - 1) / CP.getSymbolSize();
222    if (i->SectionDefinition)
223      NumberOfAuxSymbols += 1;
224    if (i->CLRToken)
225      NumberOfAuxSymbols += 1;
226    i->Header.NumberOfAuxSymbols = NumberOfAuxSymbols;
227    NumberOfSymbols += 1 + NumberOfAuxSymbols;
228  }
229
230  // Store all the allocated start addresses in the header.
231  CP.Obj.Header.NumberOfSections = CP.Obj.Sections.size();
232  CP.Obj.Header.NumberOfSymbols = NumberOfSymbols;
233  if (NumberOfSymbols > 0 || CP.StringTable.size() > 4)
234    CP.Obj.Header.PointerToSymbolTable = SymbolTableStart;
235  else
236    CP.Obj.Header.PointerToSymbolTable = 0;
237
238  *reinterpret_cast<support::ulittle32_t *>(&CP.StringTable[0])
239    = CP.StringTable.size();
240
241  return true;
242}
243
244template <typename value_type>
245struct binary_le_impl {
246  value_type Value;
247  binary_le_impl(value_type V) : Value(V) {}
248};
249
250template <typename value_type>
251raw_ostream &operator <<( raw_ostream &OS
252                        , const binary_le_impl<value_type> &BLE) {
253  char Buffer[sizeof(BLE.Value)];
254  support::endian::write<value_type, support::little, support::unaligned>(
255    Buffer, BLE.Value);
256  OS.write(Buffer, sizeof(BLE.Value));
257  return OS;
258}
259
260template <typename value_type>
261binary_le_impl<value_type> binary_le(value_type V) {
262  return binary_le_impl<value_type>(V);
263}
264
265template <size_t NumBytes> struct zeros_impl {};
266
267template <size_t NumBytes>
268raw_ostream &operator<<(raw_ostream &OS, const zeros_impl<NumBytes> &) {
269  char Buffer[NumBytes];
270  memset(Buffer, 0, sizeof(Buffer));
271  OS.write(Buffer, sizeof(Buffer));
272  return OS;
273}
274
275template <typename T>
276zeros_impl<sizeof(T)> zeros(const T &) {
277  return zeros_impl<sizeof(T)>();
278}
279
280struct num_zeros_impl {
281  size_t N;
282  num_zeros_impl(size_t N) : N(N) {}
283};
284
285raw_ostream &operator<<(raw_ostream &OS, const num_zeros_impl &NZI) {
286  for (size_t I = 0; I != NZI.N; ++I)
287    OS.write(0);
288  return OS;
289}
290
291static num_zeros_impl num_zeros(size_t N) {
292  num_zeros_impl NZI(N);
293  return NZI;
294}
295
296template <typename T>
297static uint32_t initializeOptionalHeader(COFFParser &CP, uint16_t Magic, T Header) {
298  memset(Header, 0, sizeof(*Header));
299  Header->Magic = Magic;
300  Header->SectionAlignment = CP.Obj.OptionalHeader->Header.SectionAlignment;
301  Header->FileAlignment = CP.Obj.OptionalHeader->Header.FileAlignment;
302  uint32_t SizeOfCode = 0, SizeOfInitializedData = 0,
303           SizeOfUninitializedData = 0;
304  uint32_t SizeOfHeaders = alignTo(CP.SectionTableStart + CP.SectionTableSize,
305                                   Header->FileAlignment);
306  uint32_t SizeOfImage = alignTo(SizeOfHeaders, Header->SectionAlignment);
307  uint32_t BaseOfData = 0;
308  for (const COFFYAML::Section &S : CP.Obj.Sections) {
309    if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_CODE)
310      SizeOfCode += S.Header.SizeOfRawData;
311    if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_INITIALIZED_DATA)
312      SizeOfInitializedData += S.Header.SizeOfRawData;
313    if (S.Header.Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
314      SizeOfUninitializedData += S.Header.SizeOfRawData;
315    if (S.Name.equals(".text"))
316      Header->BaseOfCode = S.Header.VirtualAddress; // RVA
317    else if (S.Name.equals(".data"))
318      BaseOfData = S.Header.VirtualAddress; // RVA
319    if (S.Header.VirtualAddress)
320      SizeOfImage += alignTo(S.Header.VirtualSize, Header->SectionAlignment);
321  }
322  Header->SizeOfCode = SizeOfCode;
323  Header->SizeOfInitializedData = SizeOfInitializedData;
324  Header->SizeOfUninitializedData = SizeOfUninitializedData;
325  Header->AddressOfEntryPoint =
326      CP.Obj.OptionalHeader->Header.AddressOfEntryPoint; // RVA
327  Header->ImageBase = CP.Obj.OptionalHeader->Header.ImageBase;
328  Header->MajorOperatingSystemVersion =
329      CP.Obj.OptionalHeader->Header.MajorOperatingSystemVersion;
330  Header->MinorOperatingSystemVersion =
331      CP.Obj.OptionalHeader->Header.MinorOperatingSystemVersion;
332  Header->MajorImageVersion =
333      CP.Obj.OptionalHeader->Header.MajorImageVersion;
334  Header->MinorImageVersion =
335      CP.Obj.OptionalHeader->Header.MinorImageVersion;
336  Header->MajorSubsystemVersion =
337      CP.Obj.OptionalHeader->Header.MajorSubsystemVersion;
338  Header->MinorSubsystemVersion =
339      CP.Obj.OptionalHeader->Header.MinorSubsystemVersion;
340  Header->SizeOfImage = SizeOfImage;
341  Header->SizeOfHeaders = SizeOfHeaders;
342  Header->Subsystem = CP.Obj.OptionalHeader->Header.Subsystem;
343  Header->DLLCharacteristics = CP.Obj.OptionalHeader->Header.DLLCharacteristics;
344  Header->SizeOfStackReserve = CP.Obj.OptionalHeader->Header.SizeOfStackReserve;
345  Header->SizeOfStackCommit = CP.Obj.OptionalHeader->Header.SizeOfStackCommit;
346  Header->SizeOfHeapReserve = CP.Obj.OptionalHeader->Header.SizeOfHeapReserve;
347  Header->SizeOfHeapCommit = CP.Obj.OptionalHeader->Header.SizeOfHeapCommit;
348  Header->NumberOfRvaAndSize = COFF::NUM_DATA_DIRECTORIES + 1;
349  return BaseOfData;
350}
351
352static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
353  if (CP.isPE()) {
354    // PE files start with a DOS stub.
355    object::dos_header DH;
356    memset(&DH, 0, sizeof(DH));
357
358    // DOS EXEs start with "MZ" magic.
359    DH.Magic[0] = 'M';
360    DH.Magic[1] = 'Z';
361    // Initializing the AddressOfRelocationTable is strictly optional but
362    // mollifies certain tools which expect it to have a value greater than
363    // 0x40.
364    DH.AddressOfRelocationTable = sizeof(DH);
365    // This is the address of the PE signature.
366    DH.AddressOfNewExeHeader = DOSStubSize;
367
368    // Write out our DOS stub.
369    OS.write(reinterpret_cast<char *>(&DH), sizeof(DH));
370    // Write padding until we reach the position of where our PE signature
371    // should live.
372    OS << num_zeros(DOSStubSize - sizeof(DH));
373    // Write out the PE signature.
374    OS.write(COFF::PEMagic, sizeof(COFF::PEMagic));
375  }
376  if (CP.useBigObj()) {
377    OS << binary_le(static_cast<uint16_t>(COFF::IMAGE_FILE_MACHINE_UNKNOWN))
378       << binary_le(static_cast<uint16_t>(0xffff))
379       << binary_le(static_cast<uint16_t>(COFF::BigObjHeader::MinBigObjectVersion))
380       << binary_le(CP.Obj.Header.Machine)
381       << binary_le(CP.Obj.Header.TimeDateStamp);
382    OS.write(COFF::BigObjMagic, sizeof(COFF::BigObjMagic));
383    OS << zeros(uint32_t(0))
384       << zeros(uint32_t(0))
385       << zeros(uint32_t(0))
386       << zeros(uint32_t(0))
387       << binary_le(CP.Obj.Header.NumberOfSections)
388       << binary_le(CP.Obj.Header.PointerToSymbolTable)
389       << binary_le(CP.Obj.Header.NumberOfSymbols);
390  } else {
391    OS << binary_le(CP.Obj.Header.Machine)
392       << binary_le(static_cast<int16_t>(CP.Obj.Header.NumberOfSections))
393       << binary_le(CP.Obj.Header.TimeDateStamp)
394       << binary_le(CP.Obj.Header.PointerToSymbolTable)
395       << binary_le(CP.Obj.Header.NumberOfSymbols)
396       << binary_le(CP.Obj.Header.SizeOfOptionalHeader)
397       << binary_le(CP.Obj.Header.Characteristics);
398  }
399  if (CP.isPE()) {
400    if (CP.is64Bit()) {
401      object::pe32plus_header PEH;
402      initializeOptionalHeader(CP, COFF::PE32Header::PE32_PLUS, &PEH);
403      OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
404    } else {
405      object::pe32_header PEH;
406      uint32_t BaseOfData = initializeOptionalHeader(CP, COFF::PE32Header::PE32, &PEH);
407      PEH.BaseOfData = BaseOfData;
408      OS.write(reinterpret_cast<char *>(&PEH), sizeof(PEH));
409    }
410    for (const Optional<COFF::DataDirectory> &DD :
411         CP.Obj.OptionalHeader->DataDirectories) {
412      if (!DD.hasValue()) {
413        OS << zeros(uint32_t(0));
414        OS << zeros(uint32_t(0));
415      } else {
416        OS << binary_le(DD->RelativeVirtualAddress);
417        OS << binary_le(DD->Size);
418      }
419    }
420    OS << zeros(uint32_t(0));
421    OS << zeros(uint32_t(0));
422  }
423
424  assert(OS.tell() == CP.SectionTableStart);
425  // Output section table.
426  for (std::vector<COFFYAML::Section>::iterator i = CP.Obj.Sections.begin(),
427                                                e = CP.Obj.Sections.end();
428                                                i != e; ++i) {
429    OS.write(i->Header.Name, COFF::NameSize);
430    OS << binary_le(i->Header.VirtualSize)
431       << binary_le(i->Header.VirtualAddress)
432       << binary_le(i->Header.SizeOfRawData)
433       << binary_le(i->Header.PointerToRawData)
434       << binary_le(i->Header.PointerToRelocations)
435       << binary_le(i->Header.PointerToLineNumbers)
436       << binary_le(i->Header.NumberOfRelocations)
437       << binary_le(i->Header.NumberOfLineNumbers)
438       << binary_le(i->Header.Characteristics);
439  }
440  assert(OS.tell() == CP.SectionTableStart + CP.SectionTableSize);
441
442  unsigned CurSymbol = 0;
443  StringMap<unsigned> SymbolTableIndexMap;
444  for (std::vector<COFFYAML::Symbol>::iterator I = CP.Obj.Symbols.begin(),
445                                               E = CP.Obj.Symbols.end();
446       I != E; ++I) {
447    SymbolTableIndexMap[I->Name] = CurSymbol;
448    CurSymbol += 1 + I->Header.NumberOfAuxSymbols;
449  }
450
451  // Output section data.
452  for (const COFFYAML::Section &S : CP.Obj.Sections) {
453    if (!S.Header.SizeOfRawData)
454      continue;
455    assert(S.Header.PointerToRawData >= OS.tell());
456    OS << num_zeros(S.Header.PointerToRawData - OS.tell());
457    S.SectionData.writeAsBinary(OS);
458    assert(S.Header.SizeOfRawData >= S.SectionData.binary_size());
459    OS << num_zeros(S.Header.SizeOfRawData - S.SectionData.binary_size());
460    for (const COFFYAML::Relocation &R : S.Relocations) {
461      uint32_t SymbolTableIndex = SymbolTableIndexMap[R.SymbolName];
462      OS << binary_le(R.VirtualAddress)
463         << binary_le(SymbolTableIndex)
464         << binary_le(R.Type);
465    }
466  }
467
468  // Output symbol table.
469
470  for (std::vector<COFFYAML::Symbol>::const_iterator i = CP.Obj.Symbols.begin(),
471                                                     e = CP.Obj.Symbols.end();
472                                                     i != e; ++i) {
473    OS.write(i->Header.Name, COFF::NameSize);
474    OS << binary_le(i->Header.Value);
475    if (CP.useBigObj())
476       OS << binary_le(i->Header.SectionNumber);
477    else
478       OS << binary_le(static_cast<int16_t>(i->Header.SectionNumber));
479    OS << binary_le(i->Header.Type)
480       << binary_le(i->Header.StorageClass)
481       << binary_le(i->Header.NumberOfAuxSymbols);
482
483    if (i->FunctionDefinition)
484      OS << binary_le(i->FunctionDefinition->TagIndex)
485         << binary_le(i->FunctionDefinition->TotalSize)
486         << binary_le(i->FunctionDefinition->PointerToLinenumber)
487         << binary_le(i->FunctionDefinition->PointerToNextFunction)
488         << zeros(i->FunctionDefinition->unused)
489         << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
490    if (i->bfAndefSymbol)
491      OS << zeros(i->bfAndefSymbol->unused1)
492         << binary_le(i->bfAndefSymbol->Linenumber)
493         << zeros(i->bfAndefSymbol->unused2)
494         << binary_le(i->bfAndefSymbol->PointerToNextFunction)
495         << zeros(i->bfAndefSymbol->unused3)
496         << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
497    if (i->WeakExternal)
498      OS << binary_le(i->WeakExternal->TagIndex)
499         << binary_le(i->WeakExternal->Characteristics)
500         << zeros(i->WeakExternal->unused)
501         << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
502    if (!i->File.empty()) {
503      unsigned SymbolSize = CP.getSymbolSize();
504      uint32_t NumberOfAuxRecords =
505          (i->File.size() + SymbolSize - 1) / SymbolSize;
506      uint32_t NumberOfAuxBytes = NumberOfAuxRecords * SymbolSize;
507      uint32_t NumZeros = NumberOfAuxBytes - i->File.size();
508      OS.write(i->File.data(), i->File.size());
509      OS << num_zeros(NumZeros);
510    }
511    if (i->SectionDefinition)
512      OS << binary_le(i->SectionDefinition->Length)
513         << binary_le(i->SectionDefinition->NumberOfRelocations)
514         << binary_le(i->SectionDefinition->NumberOfLinenumbers)
515         << binary_le(i->SectionDefinition->CheckSum)
516         << binary_le(static_cast<int16_t>(i->SectionDefinition->Number))
517         << binary_le(i->SectionDefinition->Selection)
518         << zeros(i->SectionDefinition->unused)
519         << binary_le(static_cast<int16_t>(i->SectionDefinition->Number >> 16))
520         << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
521    if (i->CLRToken)
522      OS << binary_le(i->CLRToken->AuxType)
523         << zeros(i->CLRToken->unused1)
524         << binary_le(i->CLRToken->SymbolTableIndex)
525         << zeros(i->CLRToken->unused2)
526         << num_zeros(CP.getSymbolSize() - COFF::Symbol16Size);
527  }
528
529  // Output string table.
530  if (CP.Obj.Header.PointerToSymbolTable)
531    OS.write(&CP.StringTable[0], CP.StringTable.size());
532  return true;
533}
534
535int yaml2coff(llvm::COFFYAML::Object &Doc, raw_ostream &Out) {
536  COFFParser CP(Doc);
537  if (!CP.parse()) {
538    errs() << "yaml2obj: Failed to parse YAML file!\n";
539    return 1;
540  }
541
542  if (!layoutOptionalHeader(CP)) {
543    errs() << "yaml2obj: Failed to layout optional header for COFF file!\n";
544    return 1;
545  }
546  if (!layoutCOFF(CP)) {
547    errs() << "yaml2obj: Failed to layout COFF file!\n";
548    return 1;
549  }
550  if (!writeCOFF(CP, Out)) {
551    errs() << "yaml2obj: Failed to write COFF file!\n";
552    return 1;
553  }
554  return 0;
555}
556