brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.8 KiB · fba6988 Raw
660 lines · cpp
1//===-- MachOUtils.cpp - Mach-o specific helpers for dsymutil  ------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "MachOUtils.h"10#include "BinaryHolder.h"11#include "DebugMap.h"12#include "LinkUtils.h"13#include "llvm/ADT/SmallString.h"14#include "llvm/CodeGen/NonRelocatableStringpool.h"15#include "llvm/MC/MCAssembler.h"16#include "llvm/MC/MCMachObjectWriter.h"17#include "llvm/MC/MCObjectStreamer.h"18#include "llvm/MC/MCSectionMachO.h"19#include "llvm/MC/MCStreamer.h"20#include "llvm/MC/MCSubtargetInfo.h"21#include "llvm/Object/MachO.h"22#include "llvm/Support/FileUtilities.h"23#include "llvm/Support/Program.h"24#include "llvm/Support/WithColor.h"25#include "llvm/Support/raw_ostream.h"26 27namespace llvm {28namespace dsymutil {29namespace MachOUtils {30 31llvm::Error ArchAndFile::createTempFile() {32  SmallString<256> SS;33  std::error_code EC = sys::fs::createTemporaryFile("dsym", "dwarf", FD, SS);34 35  if (EC)36    return errorCodeToError(EC);37 38  Path = SS.str();39 40  return Error::success();41}42 43llvm::StringRef ArchAndFile::getPath() const {44  assert(!Path.empty() && "path called before createTempFile");45  return Path;46}47 48int ArchAndFile::getFD() const {49  assert((FD != -1) && "path called before createTempFile");50  return FD;51}52 53ArchAndFile::~ArchAndFile() {54  if (!Path.empty())55    sys::fs::remove(Path);56}57 58std::string getArchName(StringRef Arch) {59  if (Arch.starts_with("thumb"))60    return (llvm::Twine("arm") + Arch.drop_front(5)).str();61  return std::string(Arch);62}63 64static bool runLipo(StringRef SDKPath, SmallVectorImpl<StringRef> &Args) {65  auto Path = sys::findProgramByName("lipo", ArrayRef(SDKPath));66  if (!Path)67    Path = sys::findProgramByName("lipo");68 69  if (!Path) {70    WithColor::error() << "lipo: " << Path.getError().message() << "\n";71    return false;72  }73 74  std::string ErrMsg;75  int result =76      sys::ExecuteAndWait(*Path, Args, std::nullopt, {}, 0, 0, &ErrMsg);77  if (result) {78    WithColor::error() << "lipo: " << ErrMsg << "\n";79    return false;80  }81 82  return true;83}84 85bool generateUniversalBinary(SmallVectorImpl<ArchAndFile> &ArchFiles,86                             StringRef OutputFileName,87                             const LinkOptions &Options, StringRef SDKPath,88                             bool Fat64) {89  // No need to merge one file into a universal fat binary.90  if (ArchFiles.size() == 1) {91    llvm::StringRef TmpPath = ArchFiles.front().getPath();92    if (auto EC = sys::fs::rename(TmpPath, OutputFileName)) {93      // If we can't rename, try to copy to work around cross-device link94      // issues.95      EC = sys::fs::copy_file(TmpPath, OutputFileName);96      if (EC) {97        WithColor::error() << "while keeping " << TmpPath << " as "98                           << OutputFileName << ": " << EC.message() << "\n";99        return false;100      }101      sys::fs::remove(TmpPath);102    }103    return true;104  }105 106  SmallVector<StringRef, 8> Args;107  Args.push_back("lipo");108  Args.push_back("-create");109 110  for (auto &Thin : ArchFiles)111    Args.push_back(Thin.getPath());112 113  // Align segments to match dsymutil-classic alignment.114  for (auto &Thin : ArchFiles) {115    Thin.Arch = getArchName(Thin.Arch);116    Args.push_back("-segalign");117    Args.push_back(Thin.Arch);118    Args.push_back("20");119  }120 121  // Use a 64-bit fat header if requested.122  if (Fat64)123    Args.push_back("-fat64");124 125  Args.push_back("-output");126  Args.push_back(OutputFileName.data());127 128  if (Options.Verbose) {129    outs() << "Running lipo\n";130    for (auto Arg : Args)131      outs() << ' ' << Arg;132    outs() << "\n";133  }134 135  return Options.NoOutput ? true : runLipo(SDKPath, Args);136}137 138// Return a MachO::segment_command_64 that holds the same values as the passed139// MachO::segment_command. We do that to avoid having to duplicate the logic140// for 32bits and 64bits segments.141struct MachO::segment_command_64 adaptFrom32bits(MachO::segment_command Seg) {142  MachO::segment_command_64 Seg64;143  Seg64.cmd = Seg.cmd;144  Seg64.cmdsize = Seg.cmdsize;145  memcpy(Seg64.segname, Seg.segname, sizeof(Seg.segname));146  Seg64.vmaddr = Seg.vmaddr;147  Seg64.vmsize = Seg.vmsize;148  Seg64.fileoff = Seg.fileoff;149  Seg64.filesize = Seg.filesize;150  Seg64.maxprot = Seg.maxprot;151  Seg64.initprot = Seg.initprot;152  Seg64.nsects = Seg.nsects;153  Seg64.flags = Seg.flags;154  return Seg64;155}156 157// Iterate on all \a Obj segments, and apply \a Handler to them.158template <typename FunctionTy>159static void iterateOnSegments(const object::MachOObjectFile &Obj,160                              FunctionTy Handler) {161  for (const auto &LCI : Obj.load_commands()) {162    MachO::segment_command_64 Segment;163    if (LCI.C.cmd == MachO::LC_SEGMENT)164      Segment = adaptFrom32bits(Obj.getSegmentLoadCommand(LCI));165    else if (LCI.C.cmd == MachO::LC_SEGMENT_64)166      Segment = Obj.getSegment64LoadCommand(LCI);167    else168      continue;169 170    Handler(Segment);171  }172}173 174// Transfer the symbols described by \a NList to \a NewSymtab which is just the175// raw contents of the symbol table for the dSYM companion file. \returns176// whether the symbol was transferred or not.177template <typename NListTy>178static bool transferSymbol(NListTy NList, bool IsLittleEndian,179                           StringRef Strings, SmallVectorImpl<char> &NewSymtab,180                           NonRelocatableStringpool &NewStrings,181                           bool &InDebugNote) {182  // Do not transfer undefined symbols, we want real addresses.183  if ((NList.n_type & MachO::N_TYPE) == MachO::N_UNDF)184    return false;185 186  // Do not transfer N_AST symbols as their content is copied into a section of187  // the Mach-O companion file.188  if (NList.n_type == MachO::N_AST)189    return false;190 191  StringRef Name = StringRef(Strings.begin() + NList.n_strx);192 193  // An N_SO with a filename opens a debugging scope and another one without a194  // name closes it. Don't transfer anything in the debugging scope.195  if (InDebugNote) {196    InDebugNote =197        (NList.n_type != MachO::N_SO) || (!Name.empty() && Name[0] != '\0');198    return false;199  } else if (NList.n_type == MachO::N_SO) {200    InDebugNote = true;201    return false;202  }203 204  // FIXME: The + 1 is here to mimic dsymutil-classic that has 2 empty205  // strings at the start of the generated string table (There is206  // corresponding code in the string table emission).207  NList.n_strx = NewStrings.getStringOffset(Name) + 1;208  if (IsLittleEndian != sys::IsLittleEndianHost)209    MachO::swapStruct(NList);210 211  NewSymtab.append(reinterpret_cast<char *>(&NList),212                   reinterpret_cast<char *>(&NList + 1));213  return true;214}215 216// Wrapper around transferSymbol to transfer all of \a Obj symbols217// to \a NewSymtab. This function does not write in the output file.218// \returns the number of symbols in \a NewSymtab.219static unsigned transferSymbols(const object::MachOObjectFile &Obj,220                                SmallVectorImpl<char> &NewSymtab,221                                NonRelocatableStringpool &NewStrings) {222  unsigned Syms = 0;223  StringRef Strings = Obj.getStringTableData();224  bool IsLittleEndian = Obj.isLittleEndian();225  bool InDebugNote = false;226 227  if (Obj.is64Bit()) {228    for (const object::SymbolRef &Symbol : Obj.symbols()) {229      object::DataRefImpl DRI = Symbol.getRawDataRefImpl();230      if (transferSymbol(Obj.getSymbol64TableEntry(DRI), IsLittleEndian,231                         Strings, NewSymtab, NewStrings, InDebugNote))232        ++Syms;233    }234  } else {235    for (const object::SymbolRef &Symbol : Obj.symbols()) {236      object::DataRefImpl DRI = Symbol.getRawDataRefImpl();237      if (transferSymbol(Obj.getSymbolTableEntry(DRI), IsLittleEndian, Strings,238                         NewSymtab, NewStrings, InDebugNote))239        ++Syms;240    }241  }242  return Syms;243}244 245static MachO::section246getSection(const object::MachOObjectFile &Obj,247           const MachO::segment_command &Seg,248           const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {249  return Obj.getSection(LCI, Idx);250}251 252static MachO::section_64253getSection(const object::MachOObjectFile &Obj,254           const MachO::segment_command_64 &Seg,255           const object::MachOObjectFile::LoadCommandInfo &LCI, unsigned Idx) {256  return Obj.getSection64(LCI, Idx);257}258 259// Transfer \a Segment from \a Obj to the output file. This calls into \a Writer260// to write these load commands directly in the output file at the current261// position.262//263// The function also tries to find a hole in the address map to fit the __DWARF264// segment of \a DwarfSegmentSize size. \a EndAddress is updated to point at the265// highest segment address.266//267// When the __LINKEDIT segment is transferred, its offset and size are set resp.268// to \a LinkeditOffset and \a LinkeditSize.269//270// When the eh_frame section is transferred, its offset and size are set resp.271// to \a EHFrameOffset and \a EHFrameSize.272template <typename SegmentTy>273static void transferSegmentAndSections(274    const object::MachOObjectFile::LoadCommandInfo &LCI, SegmentTy Segment,275    const object::MachOObjectFile &Obj, MachObjectWriter &Writer,276    uint64_t LinkeditOffset, uint64_t LinkeditSize, uint64_t EHFrameOffset,277    uint64_t EHFrameSize, uint64_t DwarfSegmentSize, uint64_t &GapForDwarf,278    uint64_t &EndAddress) {279  if (StringRef("__DWARF") == Segment.segname)280    return;281 282  if (StringRef("__TEXT") == Segment.segname && EHFrameSize > 0) {283    Segment.fileoff = EHFrameOffset;284    Segment.filesize = EHFrameSize;285  } else if (StringRef("__LINKEDIT") == Segment.segname) {286    Segment.fileoff = LinkeditOffset;287    Segment.filesize = LinkeditSize;288    // Resize vmsize by rounding to the page size.289    Segment.vmsize = alignTo(LinkeditSize, 0x1000);290  } else {291    Segment.fileoff = Segment.filesize = 0;292  }293 294  // Check if the end address of the last segment and our current295  // start address leave a sufficient gap to store the __DWARF296  // segment.297  uint64_t PrevEndAddress = EndAddress;298  EndAddress = alignTo(EndAddress, 0x1000);299  if (GapForDwarf == UINT64_MAX && Segment.vmaddr > EndAddress &&300      Segment.vmaddr - EndAddress >= DwarfSegmentSize)301    GapForDwarf = EndAddress;302 303  // The segments are not necessarily sorted by their vmaddr.304  EndAddress =305      std::max<uint64_t>(PrevEndAddress, Segment.vmaddr + Segment.vmsize);306  unsigned nsects = Segment.nsects;307  if (Obj.isLittleEndian() != sys::IsLittleEndianHost)308    MachO::swapStruct(Segment);309  Writer.W.OS.write(reinterpret_cast<char *>(&Segment), sizeof(Segment));310  for (unsigned i = 0; i < nsects; ++i) {311    auto Sect = getSection(Obj, Segment, LCI, i);312    if (StringRef("__eh_frame") == Sect.sectname) {313      Sect.offset = EHFrameOffset;314      Sect.reloff = Sect.nreloc = 0;315    } else {316      Sect.offset = Sect.reloff = Sect.nreloc = 0;317    }318    if (Obj.isLittleEndian() != sys::IsLittleEndianHost)319      MachO::swapStruct(Sect);320    Writer.W.OS.write(reinterpret_cast<char *>(&Sect), sizeof(Sect));321  }322}323 324// Write the __DWARF segment load command to the output file.325static bool createDwarfSegment(const MCAssembler& Asm,uint64_t VMAddr, uint64_t FileOffset,326                               uint64_t FileSize, unsigned NumSections,327                                MachObjectWriter &Writer) {328  Writer.writeSegmentLoadCommand("__DWARF", NumSections, VMAddr,329                                 alignTo(FileSize, 0x1000), FileOffset,330                                 FileSize, /* MaxProt */ 7,331                                 /* InitProt =*/3);332 333  for (unsigned int i = 0, n = Writer.getSectionOrder().size(); i != n; ++i) {334    auto *Sec = static_cast<MCSectionMachO *>(Writer.getSectionOrder()[i]);335    if (!Asm.getSectionFileSize(*Sec))336      continue;337 338    Align Alignment = Sec->getAlign();339    if (Alignment > 1) {340      VMAddr = alignTo(VMAddr, Alignment);341      FileOffset = alignTo(FileOffset, Alignment);342    }343    if (FileOffset > UINT32_MAX)344      return error("section " + Sec->getName() +345                   "'s file offset exceeds 4GB."346                   " Refusing to produce an invalid Mach-O file.");347    Writer.writeSection(Asm, *Sec, VMAddr, FileOffset, 0, 0, 0);348 349    FileOffset += Asm.getSectionAddressSize(*Sec);350    VMAddr += Asm.getSectionAddressSize(*Sec);351  }352  return true;353}354 355static bool isExecutable(const object::MachOObjectFile &Obj) {356  if (Obj.is64Bit())357    return Obj.getHeader64().filetype != MachO::MH_OBJECT;358  else359    return Obj.getHeader().filetype != MachO::MH_OBJECT;360}361 362static unsigned segmentLoadCommandSize(bool Is64Bit, unsigned NumSections) {363  if (Is64Bit)364    return sizeof(MachO::segment_command_64) +365           NumSections * sizeof(MachO::section_64);366 367  return sizeof(MachO::segment_command) + NumSections * sizeof(MachO::section);368}369 370// Stream a dSYM companion binary file corresponding to the binary referenced371// by \a DM to \a OutFile. The passed \a MS MCStreamer is setup to write to372// \a OutFile and it must be using a MachObjectWriter object to do so.373bool generateDsymCompanion(374    llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> VFS, const DebugMap &DM,375    MCStreamer &MS, raw_fd_ostream &OutFile,376    const std::vector<MachOUtils::DwarfRelocationApplicationInfo>377        &RelocationsToApply) {378  auto &ObjectStreamer = static_cast<MCObjectStreamer &>(MS);379  MCAssembler &MCAsm = ObjectStreamer.getAssembler();380  auto &Writer = static_cast<MachObjectWriter &>(MCAsm.getWriter());381 382  // Layout but don't emit.383  MCAsm.layout();384 385  BinaryHolder InputBinaryHolder(VFS, false);386 387  auto ObjectEntry = InputBinaryHolder.getObjectEntry(DM.getBinaryPath());388  if (!ObjectEntry) {389    auto Err = ObjectEntry.takeError();390    return error(Twine("opening ") + DM.getBinaryPath() + ": " +391                     toString(std::move(Err)),392                 "output file streaming");393  }394 395  auto Object =396      ObjectEntry->getObjectAs<object::MachOObjectFile>(DM.getTriple());397  if (!Object) {398    auto Err = Object.takeError();399    return error(Twine("opening ") + DM.getBinaryPath() + ": " +400                     toString(std::move(Err)),401                 "output file streaming");402  }403 404  auto &InputBinary = *Object;405 406  bool Is64Bit = Writer.is64Bit();407  MachO::symtab_command SymtabCmd = InputBinary.getSymtabLoadCommand();408 409  // Compute the number of load commands we will need.410  unsigned LoadCommandSize = 0;411  unsigned NumLoadCommands = 0;412 413  bool HasSymtab = false;414 415  // Check LC_SYMTAB and get LC_UUID and LC_BUILD_VERSION.416  MachO::uuid_command UUIDCmd;417  SmallVector<MachO::build_version_command, 2> BuildVersionCmd;418  memset(&UUIDCmd, 0, sizeof(UUIDCmd));419  for (auto &LCI : InputBinary.load_commands()) {420    switch (LCI.C.cmd) {421    case MachO::LC_UUID:422      if (UUIDCmd.cmd)423        return error("Binary contains more than one UUID");424      UUIDCmd = InputBinary.getUuidCommand(LCI);425      ++NumLoadCommands;426      LoadCommandSize += sizeof(UUIDCmd);427      break;428    case MachO::LC_BUILD_VERSION: {429      MachO::build_version_command Cmd;430      memset(&Cmd, 0, sizeof(Cmd));431      Cmd = InputBinary.getBuildVersionLoadCommand(LCI);432      ++NumLoadCommands;433      LoadCommandSize += sizeof(Cmd);434      // LLDB doesn't care about the build tools for now.435      Cmd.ntools = 0;436      BuildVersionCmd.push_back(Cmd);437      break;438    }439    case MachO::LC_SYMTAB:440      HasSymtab = true;441      break;442    default:443      break;444    }445  }446 447  // If we have a valid symtab to copy, do it.448  bool ShouldEmitSymtab = HasSymtab && isExecutable(InputBinary);449  if (ShouldEmitSymtab) {450    LoadCommandSize += sizeof(MachO::symtab_command);451    ++NumLoadCommands;452  }453 454  // If we have a valid eh_frame to copy, do it.455  uint64_t EHFrameSize = 0;456  StringRef EHFrameData;457  for (const object::SectionRef &Section : InputBinary.sections()) {458    Expected<StringRef> NameOrErr = Section.getName();459    if (!NameOrErr) {460      consumeError(NameOrErr.takeError());461      continue;462    }463    StringRef SectionName = *NameOrErr;464    SectionName = SectionName.substr(SectionName.find_first_not_of("._"));465    if (SectionName == "eh_frame") {466      if (Expected<StringRef> ContentsOrErr = Section.getContents()) {467        EHFrameData = *ContentsOrErr;468        EHFrameSize = Section.getSize();469      } else {470        consumeError(ContentsOrErr.takeError());471      }472    }473  }474 475  unsigned HeaderSize =476      Is64Bit ? sizeof(MachO::mach_header_64) : sizeof(MachO::mach_header);477  // We will copy every segment that isn't __DWARF.478  iterateOnSegments(InputBinary, [&](const MachO::segment_command_64 &Segment) {479    if (StringRef("__DWARF") == Segment.segname)480      return;481 482    ++NumLoadCommands;483    LoadCommandSize += segmentLoadCommandSize(Is64Bit, Segment.nsects);484  });485 486  // We will add our own brand new __DWARF segment if we have debug487  // info.488  unsigned NumDwarfSections = 0;489  uint64_t DwarfSegmentSize = 0;490 491  for (unsigned int i = 0, n = Writer.getSectionOrder().size(); i != n; ++i) {492    MCSection *Sec = Writer.getSectionOrder()[i];493    if (Sec->begin() == Sec->end())494      continue;495 496    if (uint64_t Size = MCAsm.getSectionFileSize(*Sec)) {497      DwarfSegmentSize = alignTo(DwarfSegmentSize, Sec->getAlign());498      DwarfSegmentSize += Size;499      ++NumDwarfSections;500    }501  }502 503  if (NumDwarfSections) {504    ++NumLoadCommands;505    LoadCommandSize += segmentLoadCommandSize(Is64Bit, NumDwarfSections);506  }507 508  SmallString<0> NewSymtab;509  // Legacy dsymutil puts an empty string at the start of the line table.510  // thus we set NonRelocatableStringpool(,PutEmptyString=true)511  NonRelocatableStringpool NewStrings(true);512  unsigned NListSize = Is64Bit ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);513  unsigned NumSyms = 0;514  uint64_t NewStringsSize = 0;515  if (ShouldEmitSymtab) {516    NewSymtab.reserve(SymtabCmd.nsyms * NListSize / 2);517    NumSyms = transferSymbols(InputBinary, NewSymtab, NewStrings);518    NewStringsSize = NewStrings.getSize() + 1;519  }520 521  uint64_t SymtabStart = LoadCommandSize;522  SymtabStart += HeaderSize;523  SymtabStart = alignTo(SymtabStart, 0x1000);524 525  // We gathered all the information we need, start emitting the output file.526  Writer.writeHeader(MachO::MH_DSYM, NumLoadCommands, LoadCommandSize,527                     /*SubsectionsViaSymbols=*/false);528 529  // Write the load commands.530  assert(OutFile.tell() == HeaderSize);531  if (UUIDCmd.cmd != 0) {532    Writer.W.write<uint32_t>(UUIDCmd.cmd);533    Writer.W.write<uint32_t>(sizeof(UUIDCmd));534    OutFile.write(reinterpret_cast<const char *>(UUIDCmd.uuid), 16);535    assert(OutFile.tell() == HeaderSize + sizeof(UUIDCmd));536  }537  for (auto Cmd : BuildVersionCmd) {538    Writer.W.write<uint32_t>(Cmd.cmd);539    Writer.W.write<uint32_t>(sizeof(Cmd));540    Writer.W.write<uint32_t>(Cmd.platform);541    Writer.W.write<uint32_t>(Cmd.minos);542    Writer.W.write<uint32_t>(Cmd.sdk);543    Writer.W.write<uint32_t>(Cmd.ntools);544  }545 546  assert(SymtabCmd.cmd && "No symbol table.");547  uint64_t StringStart = SymtabStart + NumSyms * NListSize;548  if (ShouldEmitSymtab)549    Writer.writeSymtabLoadCommand(SymtabStart, NumSyms, StringStart,550                                  NewStringsSize);551 552  uint64_t EHFrameStart = StringStart + NewStringsSize;553  EHFrameStart = alignTo(EHFrameStart, 0x1000);554 555  uint64_t DwarfSegmentStart = EHFrameStart + EHFrameSize;556  DwarfSegmentStart = alignTo(DwarfSegmentStart, 0x1000);557 558  // Write the load commands for the segments and sections we 'import' from559  // the original binary.560  uint64_t EndAddress = 0;561  uint64_t GapForDwarf = UINT64_MAX;562  for (auto &LCI : InputBinary.load_commands()) {563    if (LCI.C.cmd == MachO::LC_SEGMENT)564      transferSegmentAndSections(565          LCI, InputBinary.getSegmentLoadCommand(LCI), InputBinary, Writer,566          SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,567          EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);568    else if (LCI.C.cmd == MachO::LC_SEGMENT_64)569      transferSegmentAndSections(570          LCI, InputBinary.getSegment64LoadCommand(LCI), InputBinary, Writer,571          SymtabStart, StringStart + NewStringsSize - SymtabStart, EHFrameStart,572          EHFrameSize, DwarfSegmentSize, GapForDwarf, EndAddress);573  }574 575  uint64_t DwarfVMAddr = alignTo(EndAddress, 0x1000);576  uint64_t DwarfVMMax = Is64Bit ? UINT64_MAX : UINT32_MAX;577  if (DwarfVMAddr + DwarfSegmentSize > DwarfVMMax ||578      DwarfVMAddr + DwarfSegmentSize < DwarfVMAddr /* Overflow */) {579    // There is no room for the __DWARF segment at the end of the580    // address space. Look through segments to find a gap.581    DwarfVMAddr = GapForDwarf;582    if (DwarfVMAddr == UINT64_MAX)583      warn("not enough VM space for the __DWARF segment.",584           "output file streaming");585  }586 587  // Write the load command for the __DWARF segment.588  if (!createDwarfSegment(MCAsm, DwarfVMAddr, DwarfSegmentStart, DwarfSegmentSize,589                          NumDwarfSections, Writer))590    return false;591 592  assert(OutFile.tell() == LoadCommandSize + HeaderSize);593  OutFile.write_zeros(SymtabStart - (LoadCommandSize + HeaderSize));594  assert(OutFile.tell() == SymtabStart);595 596  // Transfer symbols.597  if (ShouldEmitSymtab) {598    OutFile << NewSymtab.str();599    assert(OutFile.tell() == StringStart);600 601    // Transfer string table.602    // FIXME: The NonRelocatableStringpool starts with an empty string, but603    // dsymutil-classic starts the reconstructed string table with 2 of these.604    // Reproduce that behavior for now (there is corresponding code in605    // transferSymbol).606    OutFile << '\0';607    std::vector<DwarfStringPoolEntryRef> Strings =608        NewStrings.getEntriesForEmission();609    for (auto EntryRef : Strings) {610      OutFile.write(EntryRef.getString().data(),611                    EntryRef.getString().size() + 1);612    }613  }614  assert(OutFile.tell() == StringStart + NewStringsSize);615 616  // Pad till the EH frame start.617  OutFile.write_zeros(EHFrameStart - (StringStart + NewStringsSize));618  assert(OutFile.tell() == EHFrameStart);619 620  // Transfer eh_frame.621  if (EHFrameSize > 0)622    OutFile << EHFrameData;623  assert(OutFile.tell() == EHFrameStart + EHFrameSize);624 625  // Pad till the Dwarf segment start.626  OutFile.write_zeros(DwarfSegmentStart - (EHFrameStart + EHFrameSize));627  assert(OutFile.tell() == DwarfSegmentStart);628 629  // Emit the Dwarf sections contents.630  for (const MCSection &Sec : MCAsm) {631    uint64_t Pos = OutFile.tell();632    OutFile.write_zeros(alignTo(Pos, Sec.getAlign()) - Pos);633    MCAsm.writeSectionData(OutFile, &Sec);634  }635 636  // Apply relocations to the contents of the DWARF segment.637  // We do this here because the final value written depend on the DWARF vm638  // addr, which is only calculated in this function.639  if (!RelocationsToApply.empty()) {640    if (!OutFile.supportsSeeking())641      report_fatal_error(642          "Cannot apply relocations to file that doesn't support seeking!");643 644    uint64_t Pos = OutFile.tell();645    for (auto &RelocationToApply : RelocationsToApply) {646      OutFile.seek(DwarfSegmentStart + RelocationToApply.AddressFromDwarfStart);647      int32_t Value = RelocationToApply.Value;648      if (RelocationToApply.ShouldSubtractDwarfVM)649        Value -= DwarfVMAddr;650      OutFile.write((char *)&Value, sizeof(int32_t));651    }652    OutFile.seek(Pos);653  }654 655  return true;656}657} // namespace MachOUtils658} // namespace dsymutil659} // namespace llvm660