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