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