xref: /llvm-project-15.0.7/lld/MachO/Driver.cpp (revision bb09ef95)
1 //===- Driver.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 "Driver.h"
10 #include "Config.h"
11 #include "DriverUtils.h"
12 #include "InputFiles.h"
13 #include "ObjC.h"
14 #include "OutputSection.h"
15 #include "OutputSegment.h"
16 #include "SymbolTable.h"
17 #include "Symbols.h"
18 #include "SyntheticSections.h"
19 #include "Target.h"
20 #include "Writer.h"
21 
22 #include "lld/Common/Args.h"
23 #include "lld/Common/Driver.h"
24 #include "lld/Common/ErrorHandler.h"
25 #include "lld/Common/LLVM.h"
26 #include "lld/Common/Memory.h"
27 #include "lld/Common/Version.h"
28 #include "llvm/ADT/DenseSet.h"
29 #include "llvm/ADT/StringExtras.h"
30 #include "llvm/ADT/StringRef.h"
31 #include "llvm/BinaryFormat/MachO.h"
32 #include "llvm/BinaryFormat/Magic.h"
33 #include "llvm/Object/Archive.h"
34 #include "llvm/Option/ArgList.h"
35 #include "llvm/Option/Option.h"
36 #include "llvm/Support/FileSystem.h"
37 #include "llvm/Support/Host.h"
38 #include "llvm/Support/MemoryBuffer.h"
39 #include "llvm/Support/Path.h"
40 
41 #include <algorithm>
42 
43 using namespace llvm;
44 using namespace llvm::MachO;
45 using namespace llvm::object;
46 using namespace llvm::opt;
47 using namespace llvm::sys;
48 using namespace lld;
49 using namespace lld::macho;
50 
51 Configuration *lld::macho::config;
52 
53 // Create prefix string literals used in Options.td
54 #define PREFIX(NAME, VALUE) const char *NAME[] = VALUE;
55 #include "Options.inc"
56 #undef PREFIX
57 
58 // Create table mapping all options defined in Options.td
59 static const opt::OptTable::Info optInfo[] = {
60 #define OPTION(X1, X2, ID, KIND, GROUP, ALIAS, X7, X8, X9, X10, X11, X12)      \
61   {X1, X2, X10,         X11,         OPT_##ID, opt::Option::KIND##Class,       \
62    X9, X8, OPT_##GROUP, OPT_##ALIAS, X7,       X12},
63 #include "Options.inc"
64 #undef OPTION
65 };
66 
67 MachOOptTable::MachOOptTable() : OptTable(optInfo) {}
68 
69 opt::InputArgList MachOOptTable::parse(ArrayRef<const char *> argv) {
70   // Make InputArgList from string vectors.
71   unsigned missingIndex;
72   unsigned missingCount;
73   SmallVector<const char *, 256> vec(argv.data(), argv.data() + argv.size());
74 
75   opt::InputArgList args = ParseArgs(vec, missingIndex, missingCount);
76 
77   if (missingCount)
78     error(Twine(args.getArgString(missingIndex)) + ": missing argument");
79 
80   for (opt::Arg *arg : args.filtered(OPT_UNKNOWN))
81     error("unknown argument: " + arg->getSpelling());
82   return args;
83 }
84 
85 void MachOOptTable::printHelp(const char *argv0, bool showHidden) const {
86   PrintHelp(lld::outs(), (std::string(argv0) + " [options] file...").c_str(),
87             "LLVM Linker", showHidden);
88   lld::outs() << "\n";
89 }
90 
91 static Optional<std::string> findWithExtension(StringRef base,
92                                                ArrayRef<StringRef> extensions) {
93   for (StringRef ext : extensions) {
94     Twine location = base + ext;
95     if (fs::exists(location))
96       return location.str();
97   }
98   return {};
99 }
100 
101 static Optional<std::string> findLibrary(StringRef name) {
102   llvm::SmallString<261> location;
103   for (StringRef dir : config->librarySearchPaths) {
104       location = dir;
105       path::append(location, Twine("lib") + name);
106       if (Optional<std::string> path =
107               findWithExtension(location, {".tbd", ".dylib", ".a"}))
108         return path;
109   }
110   return {};
111 }
112 
113 static Optional<std::string> findFramework(StringRef name) {
114   llvm::SmallString<260> symlink;
115   StringRef suffix;
116   std::tie(name, suffix) = name.split(",");
117   for (StringRef dir : config->frameworkSearchPaths) {
118     symlink = dir;
119     path::append(symlink, name + ".framework", name);
120 
121     if (!suffix.empty()) {
122       // NOTE: we must resolve the symlink before trying the suffixes, because
123       // there are no symlinks for the suffixed paths.
124       llvm::SmallString<260> location;
125       if (!fs::real_path(symlink, location)) {
126         // only append suffix if realpath() succeeds
127         Twine suffixed = location + suffix;
128         if (fs::exists(suffixed))
129           return suffixed.str();
130       }
131       // Suffix lookup failed, fall through to the no-suffix case.
132     }
133 
134     if (Optional<std::string> path = resolveDylibPath(symlink))
135       return path;
136   }
137   return {};
138 }
139 
140 static TargetInfo *createTargetInfo(opt::InputArgList &args) {
141   StringRef arch = args.getLastArgValue(OPT_arch, "x86_64");
142   config->arch = llvm::MachO::getArchitectureFromName(
143       args.getLastArgValue(OPT_arch, arch));
144   switch (config->arch) {
145   case llvm::MachO::AK_x86_64:
146   case llvm::MachO::AK_x86_64h:
147     return createX86_64TargetInfo();
148   default:
149     fatal("missing or unsupported -arch " + arch);
150   }
151 }
152 
153 static bool warnIfNotDirectory(StringRef option, StringRef path) {
154   if (!fs::exists(path)) {
155     warn("directory not found for option -" + option + path);
156     return false;
157   } else if (!fs::is_directory(path)) {
158     warn("option -" + option + path + " references a non-directory path");
159     return false;
160   }
161   return true;
162 }
163 
164 static void getSearchPaths(std::vector<StringRef> &paths, unsigned optionCode,
165                            opt::InputArgList &args,
166                            const std::vector<StringRef> &roots,
167                            const SmallVector<StringRef, 2> &systemPaths) {
168   StringRef optionLetter{optionCode == OPT_F ? "F" : "L"};
169   for (StringRef path : args::getStrings(args, optionCode)) {
170     // NOTE: only absolute paths are re-rooted to syslibroot(s)
171     bool found = false;
172     if (path::is_absolute(path, path::Style::posix)) {
173       for (StringRef root : roots) {
174         SmallString<261> buffer(root);
175         path::append(buffer, path);
176         // Do not warn about paths that are computed via the syslib roots
177         if (fs::is_directory(buffer)) {
178           paths.push_back(saver.save(buffer.str()));
179           found = true;
180         }
181       }
182     }
183     if (!found && warnIfNotDirectory(optionLetter, path))
184       paths.push_back(path);
185   }
186 
187   // `-Z` suppresses the standard "system" search paths.
188   if (args.hasArg(OPT_Z))
189     return;
190 
191   for (auto const &path : systemPaths) {
192     for (auto root : roots) {
193       SmallString<261> buffer(root);
194       path::append(buffer, path);
195       if (warnIfNotDirectory(optionLetter, buffer))
196         paths.push_back(saver.save(buffer.str()));
197     }
198   }
199 }
200 
201 static void getLibrarySearchPaths(opt::InputArgList &args,
202                                   const std::vector<StringRef> &roots,
203                                   std::vector<StringRef> &paths) {
204   getSearchPaths(paths, OPT_L, args, roots, {"/usr/lib", "/usr/local/lib"});
205 }
206 
207 static void getFrameworkSearchPaths(opt::InputArgList &args,
208                                     const std::vector<StringRef> &roots,
209                                     std::vector<StringRef> &paths) {
210   getSearchPaths(paths, OPT_F, args, roots,
211                  {"/Library/Frameworks", "/System/Library/Frameworks"});
212 }
213 
214 // Returns slices of MB by parsing MB as an archive file.
215 // Each slice consists of a member file in the archive.
216 static std::vector<MemoryBufferRef> getArchiveMembers(MemoryBufferRef mb) {
217   std::unique_ptr<Archive> file =
218       CHECK(Archive::create(mb),
219             mb.getBufferIdentifier() + ": failed to parse archive");
220 
221   std::vector<MemoryBufferRef> v;
222   Error err = Error::success();
223   for (const Archive::Child &c : file->children(err)) {
224     MemoryBufferRef mbref =
225         CHECK(c.getMemoryBufferRef(),
226               mb.getBufferIdentifier() +
227                   ": could not get the buffer for a child of the archive");
228     v.push_back(mbref);
229   }
230   if (err)
231     fatal(mb.getBufferIdentifier() +
232           ": Archive::children failed: " + toString(std::move(err)));
233 
234   return v;
235 }
236 
237 static void addFile(StringRef path) {
238   Optional<MemoryBufferRef> buffer = readFile(path);
239   if (!buffer)
240     return;
241   MemoryBufferRef mbref = *buffer;
242 
243   switch (identify_magic(mbref.getBuffer())) {
244   case file_magic::archive: {
245     std::unique_ptr<object::Archive> file = CHECK(
246         object::Archive::create(mbref), path + ": failed to parse archive");
247 
248     if (!file->isEmpty() && !file->hasSymbolTable())
249       error(path + ": archive has no index; run ranlib to add one");
250 
251     if (config->allLoad) {
252       if (Optional<MemoryBufferRef> buffer = readFile(path))
253         for (MemoryBufferRef member : getArchiveMembers(*buffer))
254           inputFiles.push_back(make<ObjFile>(member));
255     } else if (config->forceLoadObjC) {
256       for (const object::Archive::Symbol &sym : file->symbols())
257         if (sym.getName().startswith(objc::klass))
258           symtab->addUndefined(sym.getName());
259 
260       // TODO: no need to look for ObjC sections for a given archive member if
261       // we already found that it contains an ObjC symbol. We should also
262       // consider creating a LazyObjFile class in order to avoid double-loading
263       // these files here and below (as part of the ArchiveFile).
264       if (Optional<MemoryBufferRef> buffer = readFile(path))
265         for (MemoryBufferRef member : getArchiveMembers(*buffer))
266           if (hasObjCSection(member))
267             inputFiles.push_back(make<ObjFile>(member));
268     }
269 
270     inputFiles.push_back(make<ArchiveFile>(std::move(file)));
271     break;
272   }
273   case file_magic::macho_object:
274     inputFiles.push_back(make<ObjFile>(mbref));
275     break;
276   case file_magic::macho_dynamically_linked_shared_lib:
277     inputFiles.push_back(make<DylibFile>(mbref));
278     break;
279   case file_magic::tapi_file: {
280     Optional<DylibFile *> dylibFile = makeDylibFromTAPI(mbref);
281     if (!dylibFile)
282       return;
283     inputFiles.push_back(*dylibFile);
284     break;
285   }
286   default:
287     error(path + ": unhandled file type");
288   }
289 }
290 
291 static void addFileList(StringRef path) {
292   Optional<MemoryBufferRef> buffer = readFile(path);
293   if (!buffer)
294     return;
295   MemoryBufferRef mbref = *buffer;
296   for (StringRef path : args::getLines(mbref))
297     addFile(path);
298 }
299 
300 static void forceLoadArchive(StringRef path) {
301   if (Optional<MemoryBufferRef> buffer = readFile(path))
302     for (MemoryBufferRef member : getArchiveMembers(*buffer))
303       inputFiles.push_back(make<ObjFile>(member));
304 }
305 
306 static std::array<StringRef, 6> archNames{"arm",    "arm64", "i386",
307                                           "x86_64", "ppc",   "ppc64"};
308 static bool isArchString(StringRef s) {
309   static DenseSet<StringRef> archNamesSet(archNames.begin(), archNames.end());
310   return archNamesSet.find(s) != archNamesSet.end();
311 }
312 
313 // An order file has one entry per line, in the following format:
314 //
315 //   <arch>:<object file>:<symbol name>
316 //
317 // <arch> and <object file> are optional. If not specified, then that entry
318 // matches any symbol of that name.
319 //
320 // If a symbol is matched by multiple entries, then it takes the lowest-ordered
321 // entry (the one nearest to the front of the list.)
322 //
323 // The file can also have line comments that start with '#'.
324 static void parseOrderFile(StringRef path) {
325   Optional<MemoryBufferRef> buffer = readFile(path);
326   if (!buffer) {
327     error("Could not read order file at " + path);
328     return;
329   }
330 
331   MemoryBufferRef mbref = *buffer;
332   size_t priority = std::numeric_limits<size_t>::max();
333   for (StringRef rest : args::getLines(mbref)) {
334     StringRef arch, objectFile, symbol;
335 
336     std::array<StringRef, 3> fields;
337     uint8_t fieldCount = 0;
338     while (rest != "" && fieldCount < 3) {
339       std::pair<StringRef, StringRef> p = getToken(rest, ": \t\n\v\f\r");
340       StringRef tok = p.first;
341       rest = p.second;
342 
343       // Check if we have a comment
344       if (tok == "" || tok[0] == '#')
345         break;
346 
347       fields[fieldCount++] = tok;
348     }
349 
350     switch (fieldCount) {
351     case 3:
352       arch = fields[0];
353       objectFile = fields[1];
354       symbol = fields[2];
355       break;
356     case 2:
357       (isArchString(fields[0]) ? arch : objectFile) = fields[0];
358       symbol = fields[1];
359       break;
360     case 1:
361       symbol = fields[0];
362       break;
363     case 0:
364       break;
365     default:
366       llvm_unreachable("too many fields in order file");
367     }
368 
369     if (!arch.empty()) {
370       if (!isArchString(arch)) {
371         error("invalid arch \"" + arch + "\" in order file: expected one of " +
372               llvm::join(archNames, ", "));
373         continue;
374       }
375 
376       // TODO: Update when we extend support for other archs
377       if (arch != "x86_64")
378         continue;
379     }
380 
381     if (!objectFile.empty() && !objectFile.endswith(".o")) {
382       error("invalid object file name \"" + objectFile +
383             "\" in order file: should end with .o");
384       continue;
385     }
386 
387     if (!symbol.empty()) {
388       SymbolPriorityEntry &entry = config->priorities[symbol];
389       if (!objectFile.empty())
390         entry.objectFiles.insert(std::make_pair(objectFile, priority));
391       else
392         entry.anyObjectFile = std::max(entry.anyObjectFile, priority);
393     }
394 
395     --priority;
396   }
397 }
398 
399 // We expect sub-library names of the form "libfoo", which will match a dylib
400 // with a path of .*/libfoo.{dylib, tbd}.
401 // XXX ld64 seems to ignore the extension entirely when matching sub-libraries;
402 // I'm not sure what the use case for that is.
403 static bool markSubLibrary(StringRef searchName) {
404   for (InputFile *file : inputFiles) {
405     if (auto *dylibFile = dyn_cast<DylibFile>(file)) {
406       StringRef filename = path::filename(dylibFile->getName());
407       if (filename.consume_front(searchName) &&
408           (filename == ".dylib" || filename == ".tbd")) {
409         dylibFile->reexport = true;
410         return true;
411       }
412     }
413   }
414   return false;
415 }
416 
417 static inline char toLowerDash(char x) {
418   if (x >= 'A' && x <= 'Z')
419     return x - 'A' + 'a';
420   else if (x == ' ')
421     return '-';
422   return x;
423 }
424 
425 static std::string lowerDash(StringRef s) {
426   return std::string(map_iterator(s.begin(), toLowerDash),
427                      map_iterator(s.end(), toLowerDash));
428 }
429 
430 static void handlePlatformVersion(const opt::Arg *arg) {
431   StringRef platformStr = arg->getValue(0);
432   StringRef minVersionStr = arg->getValue(1);
433   StringRef sdkVersionStr = arg->getValue(2);
434 
435   // TODO(compnerd) see if we can generate this case list via XMACROS
436   config->platform.kind =
437       llvm::StringSwitch<llvm::MachO::PlatformKind>(lowerDash(platformStr))
438           .Cases("macos", "1", llvm::MachO::PlatformKind::macOS)
439           .Cases("ios", "2", llvm::MachO::PlatformKind::iOS)
440           .Cases("tvos", "3", llvm::MachO::PlatformKind::tvOS)
441           .Cases("watchos", "4", llvm::MachO::PlatformKind::watchOS)
442           .Cases("bridgeos", "5", llvm::MachO::PlatformKind::bridgeOS)
443           .Cases("mac-catalyst", "6", llvm::MachO::PlatformKind::macCatalyst)
444           .Cases("ios-simulator", "7", llvm::MachO::PlatformKind::iOSSimulator)
445           .Cases("tvos-simulator", "8",
446                  llvm::MachO::PlatformKind::tvOSSimulator)
447           .Cases("watchos-simulator", "9",
448                  llvm::MachO::PlatformKind::watchOSSimulator)
449           .Default(llvm::MachO::PlatformKind::unknown);
450   if (config->platform.kind == llvm::MachO::PlatformKind::unknown)
451     error(Twine("malformed platform: ") + platformStr);
452   // TODO: check validity of version strings, which varies by platform
453   // NOTE: ld64 accepts version strings with 5 components
454   // llvm::VersionTuple accepts no more than 4 components
455   // Has Apple ever published version strings with 5 components?
456   if (config->platform.minimum.tryParse(minVersionStr))
457     error(Twine("malformed minimum version: ") + minVersionStr);
458   if (config->platform.sdk.tryParse(sdkVersionStr))
459     error(Twine("malformed sdk version: ") + sdkVersionStr);
460 }
461 
462 static void warnIfDeprecatedOption(const opt::Option &opt) {
463   if (!opt.getGroup().isValid())
464     return;
465   if (opt.getGroup().getID() == OPT_grp_deprecated) {
466     warn("Option `" + opt.getPrefixedName() + "' is deprecated in ld64:");
467     warn(opt.getHelpText());
468   }
469 }
470 
471 static void warnIfUnimplementedOption(const opt::Option &opt) {
472   if (!opt.getGroup().isValid())
473     return;
474   switch (opt.getGroup().getID()) {
475   case OPT_grp_deprecated:
476     // warn about deprecated options elsewhere
477     break;
478   case OPT_grp_undocumented:
479     warn("Option `" + opt.getPrefixedName() +
480          "' is undocumented. Should lld implement it?");
481     break;
482   case OPT_grp_obsolete:
483     warn("Option `" + opt.getPrefixedName() +
484          "' is obsolete. Please modernize your usage.");
485     break;
486   case OPT_grp_ignored:
487     warn("Option `" + opt.getPrefixedName() + "' is ignored.");
488     break;
489   default:
490     warn("Option `" + opt.getPrefixedName() +
491          "' is not yet implemented. Stay tuned...");
492     break;
493   }
494 }
495 
496 bool macho::link(llvm::ArrayRef<const char *> argsArr, bool canExitEarly,
497                  raw_ostream &stdoutOS, raw_ostream &stderrOS) {
498   lld::stdoutOS = &stdoutOS;
499   lld::stderrOS = &stderrOS;
500 
501   stderrOS.enable_colors(stderrOS.has_colors());
502   // TODO: Set up error handler properly, e.g. the errorLimitExceededMsg
503 
504   MachOOptTable parser;
505   opt::InputArgList args = parser.parse(argsArr.slice(1));
506 
507   if (args.hasArg(OPT_help_hidden)) {
508     parser.printHelp(argsArr[0], /*showHidden=*/true);
509     return true;
510   } else if (args.hasArg(OPT_help)) {
511     parser.printHelp(argsArr[0], /*showHidden=*/false);
512     return true;
513   }
514 
515   config = make<Configuration>();
516   symtab = make<SymbolTable>();
517   target = createTargetInfo(args);
518 
519   config->entry = symtab->addUndefined(args.getLastArgValue(OPT_e, "_main"));
520   config->outputFile = args.getLastArgValue(OPT_o, "a.out");
521   config->installName =
522       args.getLastArgValue(OPT_install_name, config->outputFile);
523   config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32);
524   config->outputType = args.hasArg(OPT_dylib) ? MH_DYLIB : MH_EXECUTE;
525   config->runtimePaths = args::getStrings(args, OPT_rpath);
526   config->allLoad = args.hasArg(OPT_all_load);
527 
528   std::vector<StringRef> &roots = config->systemLibraryRoots;
529   for (const Arg *arg : args.filtered(OPT_syslibroot))
530     roots.push_back(arg->getValue());
531   // NOTE: the final `-syslibroot` being `/` will ignore all roots
532   if (roots.size() && roots.back() == "/")
533     roots.clear();
534   // NOTE: roots can never be empty - add an empty root to simplify the library
535   // and framework search path computation.
536   if (roots.empty())
537     roots.emplace_back("");
538 
539   getLibrarySearchPaths(args, roots, config->librarySearchPaths);
540   getFrameworkSearchPaths(args, roots, config->frameworkSearchPaths);
541   config->forceLoadObjC = args.hasArg(OPT_ObjC);
542 
543   if (args.hasArg(OPT_v)) {
544     message(getLLDVersion());
545     message(StringRef("Library search paths:") +
546             (config->librarySearchPaths.size()
547                  ? "\n\t" + llvm::join(config->librarySearchPaths, "\n\t")
548                  : ""));
549     message(StringRef("Framework search paths:") +
550             (config->frameworkSearchPaths.size()
551                  ? "\n\t" + llvm::join(config->frameworkSearchPaths, "\n\t")
552                  : ""));
553     freeArena();
554     return !errorCount();
555   }
556 
557   for (const auto &arg : args) {
558     const auto &opt = arg->getOption();
559     warnIfDeprecatedOption(opt);
560     switch (arg->getOption().getID()) {
561     case OPT_INPUT:
562       addFile(arg->getValue());
563       break;
564     case OPT_filelist:
565       addFileList(arg->getValue());
566       break;
567     case OPT_force_load:
568       forceLoadArchive(arg->getValue());
569       break;
570     case OPT_l: {
571       StringRef name = arg->getValue();
572       if (Optional<std::string> path = findLibrary(name)) {
573         addFile(*path);
574         break;
575       }
576       error("library not found for -l" + name);
577       break;
578     }
579     case OPT_framework: {
580       StringRef name = arg->getValue();
581       if (Optional<std::string> path = findFramework(name)) {
582         addFile(*path);
583         break;
584       }
585       error("framework not found for -framework " + name);
586       break;
587     }
588     case OPT_platform_version:
589       handlePlatformVersion(arg);
590       break;
591     case OPT_all_load:
592     case OPT_o:
593     case OPT_dylib:
594     case OPT_e:
595     case OPT_F:
596     case OPT_L:
597     case OPT_ObjC:
598     case OPT_headerpad:
599     case OPT_install_name:
600     case OPT_rpath:
601     case OPT_sub_library:
602     case OPT_Z:
603     case OPT_arch:
604     case OPT_syslibroot:
605     case OPT_sectcreate:
606       // handled elsewhere
607       break;
608     default:
609       warnIfUnimplementedOption(opt);
610       break;
611     }
612   }
613 
614   // Now that all dylibs have been loaded, search for those that should be
615   // re-exported.
616   for (opt::Arg *arg : args.filtered(OPT_sub_library)) {
617     config->hasReexports = true;
618     StringRef searchName = arg->getValue();
619     if (!markSubLibrary(searchName))
620       error("-sub_library " + searchName + " does not match a supplied dylib");
621   }
622 
623   StringRef orderFile = args.getLastArgValue(OPT_order_file);
624   if (!orderFile.empty())
625     parseOrderFile(orderFile);
626 
627   if (config->outputType == MH_EXECUTE && !isa<Defined>(config->entry)) {
628     error("undefined symbol: " + config->entry->getName());
629     return false;
630   }
631 
632   createSyntheticSections();
633   symtab->addDSOHandle(in.header);
634 
635   for (opt::Arg *arg : args.filtered(OPT_sectcreate)) {
636     StringRef segName = arg->getValue(0);
637     StringRef sectName = arg->getValue(1);
638     StringRef fileName = arg->getValue(2);
639     Optional<MemoryBufferRef> buffer = readFile(fileName);
640     if (buffer)
641       inputFiles.push_back(make<OpaqueFile>(*buffer, segName, sectName));
642   }
643 
644   // Initialize InputSections.
645   for (InputFile *file : inputFiles) {
646     for (SubsectionMap &map : file->subsections) {
647       for (auto &p : map) {
648         InputSection *isec = p.second;
649         inputSections.push_back(isec);
650       }
651     }
652   }
653 
654   // Write to an output file.
655   writeResult();
656 
657   if (canExitEarly)
658     exitLld(errorCount() ? 1 : 0);
659 
660   freeArena();
661   return !errorCount();
662 }
663