1280461Sdim//===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===// 2280461Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6280461Sdim// 7280461Sdim//===----------------------------------------------------------------------===// 8280461Sdim 9280461Sdim/// 10280461Sdim/// \file Converts from in-memory Atoms to in-memory normalized mach-o. 11280461Sdim/// 12280461Sdim/// +------------+ 13280461Sdim/// | normalized | 14280461Sdim/// +------------+ 15280461Sdim/// ^ 16280461Sdim/// | 17280461Sdim/// | 18280461Sdim/// +-------+ 19280461Sdim/// | Atoms | 20280461Sdim/// +-------+ 21280461Sdim 22280461Sdim#include "ArchHandler.h" 23314564Sdim#include "DebugInfo.h" 24321369Sdim#include "MachONormalizedFile.h" 25280461Sdim#include "MachONormalizedFileBinaryUtils.h" 26327952Sdim#include "lld/Common/LLVM.h" 27280461Sdim#include "lld/Core/Error.h" 28280461Sdim#include "llvm/ADT/StringRef.h" 29280461Sdim#include "llvm/ADT/StringSwitch.h" 30321369Sdim#include "llvm/BinaryFormat/MachO.h" 31280461Sdim#include "llvm/Support/Casting.h" 32280461Sdim#include "llvm/Support/Debug.h" 33280461Sdim#include "llvm/Support/ErrorHandling.h" 34280461Sdim#include "llvm/Support/Format.h" 35280461Sdim#include <map> 36280461Sdim#include <system_error> 37314564Sdim#include <unordered_set> 38280461Sdim 39280461Sdimusing llvm::StringRef; 40280461Sdimusing llvm::isa; 41280461Sdimusing namespace llvm::MachO; 42280461Sdimusing namespace lld::mach_o::normalized; 43280461Sdimusing namespace lld; 44280461Sdim 45280461Sdimnamespace { 46280461Sdim 47280461Sdimstruct AtomInfo { 48280461Sdim const DefinedAtom *atom; 49280461Sdim uint64_t offsetInSection; 50280461Sdim}; 51280461Sdim 52280461Sdimstruct SectionInfo { 53280461Sdim SectionInfo(StringRef seg, StringRef sect, SectionType type, 54293846Sdim const MachOLinkingContext &ctxt, uint32_t attr, 55293846Sdim bool relocsToDefinedCanBeImplicit); 56280461Sdim 57280461Sdim StringRef segmentName; 58280461Sdim StringRef sectionName; 59280461Sdim SectionType type; 60280461Sdim uint32_t attributes; 61280461Sdim uint64_t address; 62280461Sdim uint64_t size; 63292934Sdim uint16_t alignment; 64293846Sdim 65293846Sdim /// If this is set, the any relocs in this section which point to defined 66293846Sdim /// addresses can be implicitly generated. This is the case for the 67293846Sdim /// __eh_frame section where references to the function can be implicit if the 68293846Sdim /// function is defined. 69293846Sdim bool relocsToDefinedCanBeImplicit; 70293846Sdim 71293846Sdim 72280461Sdim std::vector<AtomInfo> atomsAndOffsets; 73280461Sdim uint32_t normalizedSectionIndex; 74280461Sdim uint32_t finalSectionIndex; 75280461Sdim}; 76280461Sdim 77280461SdimSectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t, 78293846Sdim const MachOLinkingContext &ctxt, uint32_t attrs, 79293846Sdim bool relocsToDefinedCanBeImplicit) 80280461Sdim : segmentName(sg), sectionName(sct), type(t), attributes(attrs), 81292934Sdim address(0), size(0), alignment(1), 82293846Sdim relocsToDefinedCanBeImplicit(relocsToDefinedCanBeImplicit), 83280461Sdim normalizedSectionIndex(0), finalSectionIndex(0) { 84292934Sdim uint16_t align = 1; 85280461Sdim if (ctxt.sectionAligned(segmentName, sectionName, align)) { 86280461Sdim alignment = align; 87280461Sdim } 88280461Sdim} 89280461Sdim 90280461Sdimstruct SegmentInfo { 91280461Sdim SegmentInfo(StringRef name); 92280461Sdim 93280461Sdim StringRef name; 94280461Sdim uint64_t address; 95280461Sdim uint64_t size; 96303239Sdim uint32_t init_access; 97303239Sdim uint32_t max_access; 98280461Sdim std::vector<SectionInfo*> sections; 99280461Sdim uint32_t normalizedSegmentIndex; 100280461Sdim}; 101280461Sdim 102280461SdimSegmentInfo::SegmentInfo(StringRef n) 103303239Sdim : name(n), address(0), size(0), init_access(0), max_access(0), 104303239Sdim normalizedSegmentIndex(0) { 105280461Sdim} 106280461Sdim 107280461Sdimclass Util { 108280461Sdimpublic: 109280461Sdim Util(const MachOLinkingContext &ctxt) 110292934Sdim : _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr), 111303239Sdim _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {} 112280461Sdim ~Util(); 113280461Sdim 114303239Sdim void processDefinedAtoms(const lld::File &atomFile); 115303239Sdim void processAtomAttributes(const DefinedAtom *atom); 116303239Sdim void assignAtomToSection(const DefinedAtom *atom); 117280461Sdim void organizeSections(); 118280461Sdim void assignAddressesToSections(const NormalizedFile &file); 119280461Sdim uint32_t fileFlags(); 120280461Sdim void copySegmentInfo(NormalizedFile &file); 121280461Sdim void copySectionInfo(NormalizedFile &file); 122280461Sdim void updateSectionInfo(NormalizedFile &file); 123280461Sdim void buildAtomToAddressMap(); 124314564Sdim llvm::Error synthesizeDebugNotes(NormalizedFile &file); 125303239Sdim llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file); 126280461Sdim void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file); 127280461Sdim void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file); 128280461Sdim void addExportInfo(const lld::File &, NormalizedFile &file); 129280461Sdim void addSectionRelocs(const lld::File &, NormalizedFile &file); 130303239Sdim void addFunctionStarts(const lld::File &, NormalizedFile &file); 131280461Sdim void buildDataInCodeArray(const lld::File &, NormalizedFile &file); 132280461Sdim void addDependentDylibs(const lld::File &, NormalizedFile &file); 133280461Sdim void copyEntryPointAddress(NormalizedFile &file); 134280461Sdim void copySectionContent(NormalizedFile &file); 135280461Sdim 136303239Sdim bool allSourceFilesHaveMinVersions() const { 137303239Sdim return _allSourceFilesHaveMinVersions; 138303239Sdim } 139303239Sdim 140303239Sdim uint32_t minVersion() const { 141303239Sdim return _minVersion; 142303239Sdim } 143303239Sdim 144303239Sdim LoadCommandType minVersionCommandType() const { 145303239Sdim return _minVersionCommandType; 146303239Sdim } 147303239Sdim 148280461Sdimprivate: 149280461Sdim typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection; 150280461Sdim typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress; 151280461Sdim 152280461Sdim struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; }; 153280461Sdim typedef llvm::StringMap<DylibInfo> DylibPathToInfo; 154280461Sdim 155280461Sdim SectionInfo *sectionForAtom(const DefinedAtom*); 156280461Sdim SectionInfo *getRelocatableSection(DefinedAtom::ContentType type); 157280461Sdim SectionInfo *getFinalSection(DefinedAtom::ContentType type); 158280461Sdim void appendAtom(SectionInfo *sect, const DefinedAtom *atom); 159280461Sdim SegmentInfo *segmentForName(StringRef segName); 160280461Sdim void layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr); 161280461Sdim void layoutSectionsInTextSegment(size_t, SegmentInfo *, uint64_t &); 162280461Sdim void copySectionContent(SectionInfo *si, ContentBytes &content); 163280461Sdim uint16_t descBits(const DefinedAtom* atom); 164280461Sdim int dylibOrdinal(const SharedLibraryAtom *sa); 165280461Sdim void segIndexForSection(const SectionInfo *sect, 166280461Sdim uint8_t &segmentIndex, uint64_t &segmentStartAddr); 167280461Sdim const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom); 168280461Sdim const Atom *targetOfStub(const DefinedAtom *stubAtom); 169303239Sdim llvm::Error getSymbolTableRegion(const DefinedAtom* atom, 170303239Sdim bool &inGlobalsRegion, 171303239Sdim SymbolScope &symbolScope); 172280461Sdim void appendSection(SectionInfo *si, NormalizedFile &file); 173280461Sdim uint32_t sectionIndexForAtom(const Atom *atom); 174326909Sdim void fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset, 175326909Sdim NormalizedFile &file); 176280461Sdim 177280461Sdim typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex; 178280461Sdim struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; }; 179280461Sdim struct AtomSorter { 180280461Sdim bool operator()(const AtomAndIndex &left, const AtomAndIndex &right); 181280461Sdim }; 182280461Sdim struct SegmentSorter { 183280461Sdim bool operator()(const SegmentInfo *left, const SegmentInfo *right); 184280461Sdim static unsigned weight(const SegmentInfo *); 185280461Sdim }; 186280461Sdim struct TextSectionSorter { 187280461Sdim bool operator()(const SectionInfo *left, const SectionInfo *right); 188280461Sdim static unsigned weight(const SectionInfo *); 189280461Sdim }; 190280461Sdim 191292934Sdim const MachOLinkingContext &_ctx; 192280461Sdim mach_o::ArchHandler &_archHandler; 193280461Sdim llvm::BumpPtrAllocator _allocator; 194280461Sdim std::vector<SectionInfo*> _sectionInfos; 195280461Sdim std::vector<SegmentInfo*> _segmentInfos; 196280461Sdim TypeToSection _sectionMap; 197280461Sdim std::vector<SectionInfo*> _customSections; 198280461Sdim AtomToAddress _atomToAddress; 199280461Sdim DylibPathToInfo _dylibInfo; 200280461Sdim const DefinedAtom *_entryAtom; 201280461Sdim AtomToIndex _atomToSymbolIndex; 202280461Sdim std::vector<const Atom *> _machHeaderAliasAtoms; 203292934Sdim bool _hasTLVDescriptors; 204303239Sdim bool _subsectionsViaSymbols; 205303239Sdim bool _allSourceFilesHaveMinVersions = true; 206303239Sdim LoadCommandType _minVersionCommandType = (LoadCommandType)0; 207303239Sdim uint32_t _minVersion = 0; 208314564Sdim std::vector<lld::mach_o::Stab> _stabs; 209280461Sdim}; 210280461Sdim 211280461SdimUtil::~Util() { 212280461Sdim // The SectionInfo structs are BumpPtr allocated, but atomsAndOffsets needs 213280461Sdim // to be deleted. 214280461Sdim for (SectionInfo *si : _sectionInfos) { 215280461Sdim // clear() destroys vector elements, but does not deallocate. 216280461Sdim // Instead use swap() to deallocate vector buffer. 217280461Sdim std::vector<AtomInfo> empty; 218280461Sdim si->atomsAndOffsets.swap(empty); 219280461Sdim } 220280461Sdim // The SegmentInfo structs are BumpPtr allocated, but sections needs 221280461Sdim // to be deleted. 222280461Sdim for (SegmentInfo *sgi : _segmentInfos) { 223280461Sdim std::vector<SectionInfo*> empty2; 224280461Sdim sgi->sections.swap(empty2); 225280461Sdim } 226280461Sdim} 227280461Sdim 228280461SdimSectionInfo *Util::getRelocatableSection(DefinedAtom::ContentType type) { 229280461Sdim StringRef segmentName; 230280461Sdim StringRef sectionName; 231280461Sdim SectionType sectionType; 232280461Sdim SectionAttr sectionAttrs; 233293846Sdim bool relocsToDefinedCanBeImplicit; 234280461Sdim 235280461Sdim // Use same table used by when parsing .o files. 236280461Sdim relocatableSectionInfoForContentType(type, segmentName, sectionName, 237293846Sdim sectionType, sectionAttrs, 238293846Sdim relocsToDefinedCanBeImplicit); 239280461Sdim // If we already have a SectionInfo with this name, re-use it. 240280461Sdim // This can happen if two ContentType map to the same mach-o section. 241280461Sdim for (auto sect : _sectionMap) { 242280461Sdim if (sect.second->sectionName.equals(sectionName) && 243280461Sdim sect.second->segmentName.equals(segmentName)) { 244280461Sdim return sect.second; 245280461Sdim } 246280461Sdim } 247280461Sdim // Otherwise allocate new SectionInfo object. 248292934Sdim auto *sect = new (_allocator) 249293846Sdim SectionInfo(segmentName, sectionName, sectionType, _ctx, sectionAttrs, 250293846Sdim relocsToDefinedCanBeImplicit); 251280461Sdim _sectionInfos.push_back(sect); 252280461Sdim _sectionMap[type] = sect; 253280461Sdim return sect; 254280461Sdim} 255280461Sdim 256280461Sdim#define ENTRY(seg, sect, type, atomType) \ 257280461Sdim {seg, sect, type, DefinedAtom::atomType } 258280461Sdim 259280461Sdimstruct MachOFinalSectionFromAtomType { 260280461Sdim StringRef segmentName; 261280461Sdim StringRef sectionName; 262280461Sdim SectionType sectionType; 263280461Sdim DefinedAtom::ContentType atomType; 264280461Sdim}; 265280461Sdim 266280461Sdimconst MachOFinalSectionFromAtomType sectsToAtomType[] = { 267280461Sdim ENTRY("__TEXT", "__text", S_REGULAR, typeCode), 268303239Sdim ENTRY("__TEXT", "__text", S_REGULAR, typeMachHeader), 269280461Sdim ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString), 270280461Sdim ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String), 271280461Sdim ENTRY("__TEXT", "__const", S_REGULAR, typeConstant), 272280461Sdim ENTRY("__TEXT", "__const", S_4BYTE_LITERALS, typeLiteral4), 273280461Sdim ENTRY("__TEXT", "__const", S_8BYTE_LITERALS, typeLiteral8), 274280461Sdim ENTRY("__TEXT", "__const", S_16BYTE_LITERALS, typeLiteral16), 275280461Sdim ENTRY("__TEXT", "__stubs", S_SYMBOL_STUBS, typeStub), 276280461Sdim ENTRY("__TEXT", "__stub_helper", S_REGULAR, typeStubHelper), 277280461Sdim ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA), 278280461Sdim ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI), 279280461Sdim ENTRY("__TEXT", "__unwind_info", S_REGULAR, typeProcessedUnwindInfo), 280280461Sdim ENTRY("__DATA", "__data", S_REGULAR, typeData), 281280461Sdim ENTRY("__DATA", "__const", S_REGULAR, typeConstData), 282280461Sdim ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString), 283280461Sdim ENTRY("__DATA", "__la_symbol_ptr", S_LAZY_SYMBOL_POINTERS, 284280461Sdim typeLazyPointer), 285280461Sdim ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS, 286280461Sdim typeInitializerPtr), 287280461Sdim ENTRY("__DATA", "__mod_term_func", S_MOD_TERM_FUNC_POINTERS, 288280461Sdim typeTerminatorPtr), 289280461Sdim ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS, 290280461Sdim typeGOT), 291303239Sdim ENTRY("__DATA", "__nl_symbol_ptr", S_NON_LAZY_SYMBOL_POINTERS, 292303239Sdim typeNonLazyPointer), 293292934Sdim ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES, 294292934Sdim typeThunkTLV), 295292934Sdim ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, 296292934Sdim typeTLVInitialData), 297292934Sdim ENTRY("__DATA", "__thread_ptrs", S_THREAD_LOCAL_VARIABLE_POINTERS, 298292934Sdim typeTLVInitializerPtr), 299292934Sdim ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL, 300292934Sdim typeTLVInitialZeroFill), 301280461Sdim ENTRY("__DATA", "__bss", S_ZEROFILL, typeZeroFill), 302280461Sdim ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples), 303280461Sdim}; 304280461Sdim#undef ENTRY 305280461Sdim 306280461SdimSectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) { 307280461Sdim for (auto &p : sectsToAtomType) { 308280461Sdim if (p.atomType != atomType) 309280461Sdim continue; 310280461Sdim SectionAttr sectionAttrs = 0; 311280461Sdim switch (atomType) { 312303239Sdim case DefinedAtom::typeMachHeader: 313280461Sdim case DefinedAtom::typeCode: 314280461Sdim case DefinedAtom::typeStub: 315280461Sdim case DefinedAtom::typeStubHelper: 316303239Sdim sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS; 317280461Sdim break; 318292934Sdim case DefinedAtom::typeThunkTLV: 319292934Sdim _hasTLVDescriptors = true; 320292934Sdim break; 321280461Sdim default: 322280461Sdim break; 323280461Sdim } 324280461Sdim // If we already have a SectionInfo with this name, re-use it. 325280461Sdim // This can happen if two ContentType map to the same mach-o section. 326280461Sdim for (auto sect : _sectionMap) { 327280461Sdim if (sect.second->sectionName.equals(p.sectionName) && 328280461Sdim sect.second->segmentName.equals(p.segmentName)) { 329280461Sdim return sect.second; 330280461Sdim } 331280461Sdim } 332280461Sdim // Otherwise allocate new SectionInfo object. 333292934Sdim auto *sect = new (_allocator) SectionInfo( 334293846Sdim p.segmentName, p.sectionName, p.sectionType, _ctx, sectionAttrs, 335293846Sdim /* relocsToDefinedCanBeImplicit */ false); 336280461Sdim _sectionInfos.push_back(sect); 337280461Sdim _sectionMap[atomType] = sect; 338280461Sdim return sect; 339280461Sdim } 340280461Sdim llvm_unreachable("content type not yet supported"); 341280461Sdim} 342280461Sdim 343280461SdimSectionInfo *Util::sectionForAtom(const DefinedAtom *atom) { 344280461Sdim if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) { 345280461Sdim // Section for this atom is derived from content type. 346280461Sdim DefinedAtom::ContentType type = atom->contentType(); 347280461Sdim auto pos = _sectionMap.find(type); 348280461Sdim if ( pos != _sectionMap.end() ) 349280461Sdim return pos->second; 350292934Sdim bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); 351280461Sdim return rMode ? getRelocatableSection(type) : getFinalSection(type); 352280461Sdim } else { 353280461Sdim // This atom needs to be in a custom section. 354280461Sdim StringRef customName = atom->customSectionName(); 355280461Sdim // Look to see if we have already allocated the needed custom section. 356280461Sdim for(SectionInfo *sect : _customSections) { 357280461Sdim const DefinedAtom *firstAtom = sect->atomsAndOffsets.front().atom; 358280461Sdim if (firstAtom->customSectionName().equals(customName)) { 359280461Sdim return sect; 360280461Sdim } 361280461Sdim } 362280461Sdim // Not found, so need to create a new custom section. 363280461Sdim size_t seperatorIndex = customName.find('/'); 364280461Sdim assert(seperatorIndex != StringRef::npos); 365280461Sdim StringRef segName = customName.slice(0, seperatorIndex); 366280461Sdim StringRef sectName = customName.drop_front(seperatorIndex + 1); 367292934Sdim auto *sect = 368293846Sdim new (_allocator) SectionInfo(segName, sectName, S_REGULAR, _ctx, 369293846Sdim 0, /* relocsToDefinedCanBeImplicit */ false); 370280461Sdim _customSections.push_back(sect); 371280461Sdim _sectionInfos.push_back(sect); 372280461Sdim return sect; 373280461Sdim } 374280461Sdim} 375280461Sdim 376280461Sdimvoid Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) { 377280461Sdim // Figure out offset for atom in this section given alignment constraints. 378280461Sdim uint64_t offset = sect->size; 379280461Sdim DefinedAtom::Alignment atomAlign = atom->alignment(); 380292934Sdim uint64_t align = atomAlign.value; 381280461Sdim uint64_t requiredModulus = atomAlign.modulus; 382292934Sdim uint64_t currentModulus = (offset % align); 383280461Sdim if ( currentModulus != requiredModulus ) { 384280461Sdim if ( requiredModulus > currentModulus ) 385280461Sdim offset += requiredModulus-currentModulus; 386280461Sdim else 387292934Sdim offset += align+requiredModulus-currentModulus; 388280461Sdim } 389280461Sdim // Record max alignment of any atom in this section. 390292934Sdim if (align > sect->alignment) 391292934Sdim sect->alignment = atomAlign.value; 392280461Sdim // Assign atom to this section with this offset. 393280461Sdim AtomInfo ai = {atom, offset}; 394280461Sdim sect->atomsAndOffsets.push_back(ai); 395280461Sdim // Update section size to include this atom. 396280461Sdim sect->size = offset + atom->size(); 397280461Sdim} 398280461Sdim 399303239Sdimvoid Util::processDefinedAtoms(const lld::File &atomFile) { 400280461Sdim for (const DefinedAtom *atom : atomFile.defined()) { 401303239Sdim processAtomAttributes(atom); 402303239Sdim assignAtomToSection(atom); 403303239Sdim } 404303239Sdim} 405303239Sdim 406303239Sdimvoid Util::processAtomAttributes(const DefinedAtom *atom) { 407303239Sdim if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) { 408303239Sdim // If the file doesn't use subsections via symbols, then make sure we don't 409303239Sdim // add that flag to the final output file if we have a relocatable file. 410303239Sdim if (!machoFile->subsectionsViaSymbols()) 411303239Sdim _subsectionsViaSymbols = false; 412303239Sdim 413303239Sdim // All the source files must have min versions for us to output an object 414303239Sdim // file with a min version. 415303239Sdim if (auto v = machoFile->minVersion()) 416303239Sdim _minVersion = std::max(_minVersion, v); 417280461Sdim else 418303239Sdim _allSourceFilesHaveMinVersions = false; 419303239Sdim 420303239Sdim // If we don't have a platform load command, but one of the source files 421303239Sdim // does, then take the one from the file. 422303239Sdim if (!_minVersionCommandType) 423303239Sdim if (auto v = machoFile->minVersionLoadCommandKind()) 424303239Sdim _minVersionCommandType = v; 425280461Sdim } 426280461Sdim} 427280461Sdim 428303239Sdimvoid Util::assignAtomToSection(const DefinedAtom *atom) { 429303239Sdim if (atom->contentType() == DefinedAtom::typeMachHeader) { 430303239Sdim _machHeaderAliasAtoms.push_back(atom); 431303239Sdim // Assign atom to this section with this offset. 432303239Sdim AtomInfo ai = {atom, 0}; 433303239Sdim sectionForAtom(atom)->atomsAndOffsets.push_back(ai); 434303239Sdim } else if (atom->contentType() == DefinedAtom::typeDSOHandle) 435303239Sdim _machHeaderAliasAtoms.push_back(atom); 436303239Sdim else 437303239Sdim appendAtom(sectionForAtom(atom), atom); 438303239Sdim} 439303239Sdim 440280461SdimSegmentInfo *Util::segmentForName(StringRef segName) { 441280461Sdim for (SegmentInfo *si : _segmentInfos) { 442280461Sdim if ( si->name.equals(segName) ) 443280461Sdim return si; 444280461Sdim } 445292934Sdim auto *info = new (_allocator) SegmentInfo(segName); 446303239Sdim 447303239Sdim // Set the initial segment protection. 448280461Sdim if (segName.equals("__TEXT")) 449303239Sdim info->init_access = VM_PROT_READ | VM_PROT_EXECUTE; 450280461Sdim else if (segName.equals("__PAGEZERO")) 451303239Sdim info->init_access = 0; 452303239Sdim else if (segName.equals("__LINKEDIT")) 453303239Sdim info->init_access = VM_PROT_READ; 454303239Sdim else { 455303239Sdim // All others default to read-write 456303239Sdim info->init_access = VM_PROT_READ | VM_PROT_WRITE; 457303239Sdim } 458303239Sdim 459303239Sdim // Set max segment protection 460303239Sdim // Note, its overkill to use a switch statement here, but makes it so much 461303239Sdim // easier to use switch coverage to catch new cases. 462303239Sdim switch (_ctx.os()) { 463303239Sdim case lld::MachOLinkingContext::OS::unknown: 464303239Sdim case lld::MachOLinkingContext::OS::macOSX: 465303239Sdim case lld::MachOLinkingContext::OS::iOS_simulator: 466303239Sdim if (segName.equals("__PAGEZERO")) { 467303239Sdim info->max_access = 0; 468303239Sdim break; 469303239Sdim } 470303239Sdim // All others default to all 471303239Sdim info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; 472303239Sdim break; 473303239Sdim case lld::MachOLinkingContext::OS::iOS: 474303239Sdim // iPhoneOS always uses same protection for max and initial 475303239Sdim info->max_access = info->init_access; 476303239Sdim break; 477303239Sdim } 478280461Sdim _segmentInfos.push_back(info); 479280461Sdim return info; 480280461Sdim} 481280461Sdim 482280461Sdimunsigned Util::SegmentSorter::weight(const SegmentInfo *seg) { 483280461Sdim return llvm::StringSwitch<unsigned>(seg->name) 484280461Sdim .Case("__PAGEZERO", 1) 485280461Sdim .Case("__TEXT", 2) 486280461Sdim .Case("__DATA", 3) 487280461Sdim .Default(100); 488280461Sdim} 489280461Sdim 490280461Sdimbool Util::SegmentSorter::operator()(const SegmentInfo *left, 491280461Sdim const SegmentInfo *right) { 492280461Sdim return (weight(left) < weight(right)); 493280461Sdim} 494280461Sdim 495280461Sdimunsigned Util::TextSectionSorter::weight(const SectionInfo *sect) { 496280461Sdim return llvm::StringSwitch<unsigned>(sect->sectionName) 497280461Sdim .Case("__text", 1) 498280461Sdim .Case("__stubs", 2) 499280461Sdim .Case("__stub_helper", 3) 500280461Sdim .Case("__const", 4) 501280461Sdim .Case("__cstring", 5) 502280461Sdim .Case("__unwind_info", 98) 503280461Sdim .Case("__eh_frame", 99) 504280461Sdim .Default(10); 505280461Sdim} 506280461Sdim 507280461Sdimbool Util::TextSectionSorter::operator()(const SectionInfo *left, 508280461Sdim const SectionInfo *right) { 509280461Sdim return (weight(left) < weight(right)); 510280461Sdim} 511280461Sdim 512280461Sdimvoid Util::organizeSections() { 513293258Sdim // NOTE!: Keep this in sync with assignAddressesToSections. 514293258Sdim switch (_ctx.outputMachOType()) { 515280461Sdim case llvm::MachO::MH_EXECUTE: 516280461Sdim // Main executables, need a zero-page segment 517280461Sdim segmentForName("__PAGEZERO"); 518280461Sdim // Fall into next case. 519321369Sdim LLVM_FALLTHROUGH; 520280461Sdim case llvm::MachO::MH_DYLIB: 521280461Sdim case llvm::MachO::MH_BUNDLE: 522280461Sdim // All dynamic code needs TEXT segment to hold the load commands. 523280461Sdim segmentForName("__TEXT"); 524280461Sdim break; 525280461Sdim default: 526280461Sdim break; 527293258Sdim } 528303239Sdim segmentForName("__LINKEDIT"); 529303239Sdim 530293258Sdim // Group sections into segments. 531293258Sdim for (SectionInfo *si : _sectionInfos) { 532293258Sdim SegmentInfo *seg = segmentForName(si->segmentName); 533293258Sdim seg->sections.push_back(si); 534293258Sdim } 535293258Sdim // Sort segments. 536293258Sdim std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter()); 537280461Sdim 538293258Sdim // Sort sections within segments. 539293258Sdim for (SegmentInfo *seg : _segmentInfos) { 540293258Sdim if (seg->name.equals("__TEXT")) { 541293258Sdim std::sort(seg->sections.begin(), seg->sections.end(), 542293258Sdim TextSectionSorter()); 543280461Sdim } 544293258Sdim } 545280461Sdim 546293258Sdim // Record final section indexes. 547293258Sdim uint32_t segmentIndex = 0; 548293258Sdim uint32_t sectionIndex = 1; 549293258Sdim for (SegmentInfo *seg : _segmentInfos) { 550293258Sdim seg->normalizedSegmentIndex = segmentIndex++; 551293258Sdim for (SectionInfo *sect : seg->sections) 552293258Sdim sect->finalSectionIndex = sectionIndex++; 553280461Sdim } 554280461Sdim} 555280461Sdim 556280461Sdimvoid Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) { 557280461Sdim seg->address = addr; 558280461Sdim for (SectionInfo *sect : seg->sections) { 559303239Sdim sect->address = llvm::alignTo(addr, sect->alignment); 560280461Sdim addr = sect->address + sect->size; 561280461Sdim } 562303239Sdim seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize()); 563280461Sdim} 564280461Sdim 565280461Sdim// __TEXT segment lays out backwards so padding is at front after load commands. 566280461Sdimvoid Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg, 567280461Sdim uint64_t &addr) { 568280461Sdim seg->address = addr; 569280461Sdim // Walks sections starting at end to calculate padding for start. 570280461Sdim int64_t taddr = 0; 571280461Sdim for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) { 572280461Sdim SectionInfo *sect = *it; 573280461Sdim taddr -= sect->size; 574292934Sdim taddr = taddr & (0 - sect->alignment); 575280461Sdim } 576280461Sdim int64_t padding = taddr - hlcSize; 577280461Sdim while (padding < 0) 578292934Sdim padding += _ctx.pageSize(); 579280461Sdim // Start assigning section address starting at padded offset. 580280461Sdim addr += (padding + hlcSize); 581280461Sdim for (SectionInfo *sect : seg->sections) { 582303239Sdim sect->address = llvm::alignTo(addr, sect->alignment); 583280461Sdim addr = sect->address + sect->size; 584280461Sdim } 585303239Sdim seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize()); 586280461Sdim} 587280461Sdim 588280461Sdimvoid Util::assignAddressesToSections(const NormalizedFile &file) { 589293258Sdim // NOTE!: Keep this in sync with organizeSections. 590353358Sdim size_t hlcSize = headerAndLoadCommandsSize(file, 591353358Sdim _ctx.generateFunctionStartsLoadCommand()); 592280461Sdim uint64_t address = 0; 593293258Sdim for (SegmentInfo *seg : _segmentInfos) { 594293258Sdim if (seg->name.equals("__PAGEZERO")) { 595293258Sdim seg->size = _ctx.pageZeroSize(); 596293258Sdim address += seg->size; 597293258Sdim } 598293258Sdim else if (seg->name.equals("__TEXT")) { 599293258Sdim // _ctx.baseAddress() == 0 implies it was either unspecified or 600293258Sdim // pageZeroSize is also 0. In either case resetting address is safe. 601293258Sdim address = _ctx.baseAddress() ? _ctx.baseAddress() : address; 602293258Sdim layoutSectionsInTextSegment(hlcSize, seg, address); 603293258Sdim } else 604293258Sdim layoutSectionsInSegment(seg, address); 605280461Sdim 606303239Sdim address = llvm::alignTo(address, _ctx.pageSize()); 607293258Sdim } 608293258Sdim DEBUG_WITH_TYPE("WriterMachO-norm", 609293258Sdim llvm::dbgs() << "assignAddressesToSections()\n"; 610293258Sdim for (SegmentInfo *sgi : _segmentInfos) { 611293258Sdim llvm::dbgs() << " address=" << llvm::format("0x%08llX", sgi->address) 612293258Sdim << ", size=" << llvm::format("0x%08llX", sgi->size) 613293258Sdim << ", segment-name='" << sgi->name 614293258Sdim << "'\n"; 615293258Sdim for (SectionInfo *si : sgi->sections) { 616293258Sdim llvm::dbgs()<< " addr=" << llvm::format("0x%08llX", si->address) 617293258Sdim << ", size=" << llvm::format("0x%08llX", si->size) 618293258Sdim << ", section-name='" << si->sectionName 619293258Sdim << "\n"; 620280461Sdim } 621280461Sdim } 622293258Sdim ); 623280461Sdim} 624280461Sdim 625280461Sdimvoid Util::copySegmentInfo(NormalizedFile &file) { 626280461Sdim for (SegmentInfo *sgi : _segmentInfos) { 627280461Sdim Segment seg; 628280461Sdim seg.name = sgi->name; 629280461Sdim seg.address = sgi->address; 630280461Sdim seg.size = sgi->size; 631303239Sdim seg.init_access = sgi->init_access; 632303239Sdim seg.max_access = sgi->max_access; 633280461Sdim file.segments.push_back(seg); 634280461Sdim } 635280461Sdim} 636280461Sdim 637280461Sdimvoid Util::appendSection(SectionInfo *si, NormalizedFile &file) { 638280461Sdim // Add new empty section to end of file.sections. 639280461Sdim Section temp; 640280461Sdim file.sections.push_back(std::move(temp)); 641280461Sdim Section* normSect = &file.sections.back(); 642280461Sdim // Copy fields to normalized section. 643280461Sdim normSect->segmentName = si->segmentName; 644280461Sdim normSect->sectionName = si->sectionName; 645280461Sdim normSect->type = si->type; 646280461Sdim normSect->attributes = si->attributes; 647280461Sdim normSect->address = si->address; 648280461Sdim normSect->alignment = si->alignment; 649280461Sdim // Record where normalized section is. 650280461Sdim si->normalizedSectionIndex = file.sections.size()-1; 651280461Sdim} 652280461Sdim 653280461Sdimvoid Util::copySectionContent(NormalizedFile &file) { 654292934Sdim const bool r = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); 655280461Sdim 656280461Sdim // Utility function for ArchHandler to find address of atom in output file. 657280461Sdim auto addrForAtom = [&] (const Atom &atom) -> uint64_t { 658280461Sdim auto pos = _atomToAddress.find(&atom); 659280461Sdim assert(pos != _atomToAddress.end()); 660280461Sdim return pos->second; 661280461Sdim }; 662280461Sdim 663280461Sdim auto sectionAddrForAtom = [&] (const Atom &atom) -> uint64_t { 664280461Sdim for (const SectionInfo *sectInfo : _sectionInfos) 665280461Sdim for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets) 666280461Sdim if (atomInfo.atom == &atom) 667280461Sdim return sectInfo->address; 668280461Sdim llvm_unreachable("atom not assigned to section"); 669280461Sdim }; 670280461Sdim 671280461Sdim for (SectionInfo *si : _sectionInfos) { 672280461Sdim Section *normSect = &file.sections[si->normalizedSectionIndex]; 673292934Sdim if (isZeroFillSection(si->type)) { 674280461Sdim const uint8_t *empty = nullptr; 675280461Sdim normSect->content = llvm::makeArrayRef(empty, si->size); 676280461Sdim continue; 677280461Sdim } 678280461Sdim // Copy content from atoms to content buffer for section. 679303239Sdim llvm::MutableArrayRef<uint8_t> sectionContent; 680303239Sdim if (si->size) { 681303239Sdim uint8_t *sectContent = file.ownedAllocations.Allocate<uint8_t>(si->size); 682303239Sdim sectionContent = llvm::MutableArrayRef<uint8_t>(sectContent, si->size); 683303239Sdim normSect->content = sectionContent; 684303239Sdim } 685280461Sdim for (AtomInfo &ai : si->atomsAndOffsets) { 686303239Sdim if (!ai.atom->size()) { 687303239Sdim assert(ai.atom->begin() == ai.atom->end() && 688303239Sdim "Cannot have references without content"); 689303239Sdim continue; 690303239Sdim } 691303239Sdim auto atomContent = sectionContent.slice(ai.offsetInSection, 692303239Sdim ai.atom->size()); 693280461Sdim _archHandler.generateAtomContent(*ai.atom, r, addrForAtom, 694292934Sdim sectionAddrForAtom, _ctx.baseAddress(), 695292934Sdim atomContent); 696280461Sdim } 697280461Sdim } 698280461Sdim} 699280461Sdim 700280461Sdimvoid Util::copySectionInfo(NormalizedFile &file) { 701280461Sdim file.sections.reserve(_sectionInfos.size()); 702293258Sdim // Write sections grouped by segment. 703293258Sdim for (SegmentInfo *sgi : _segmentInfos) { 704293258Sdim for (SectionInfo *si : sgi->sections) { 705280461Sdim appendSection(si, file); 706280461Sdim } 707280461Sdim } 708280461Sdim} 709280461Sdim 710280461Sdimvoid Util::updateSectionInfo(NormalizedFile &file) { 711280461Sdim file.sections.reserve(_sectionInfos.size()); 712293258Sdim // sections grouped by segment. 713293258Sdim for (SegmentInfo *sgi : _segmentInfos) { 714293258Sdim Segment *normSeg = &file.segments[sgi->normalizedSegmentIndex]; 715293258Sdim normSeg->address = sgi->address; 716293258Sdim normSeg->size = sgi->size; 717293258Sdim for (SectionInfo *si : sgi->sections) { 718280461Sdim Section *normSect = &file.sections[si->normalizedSectionIndex]; 719280461Sdim normSect->address = si->address; 720280461Sdim } 721280461Sdim } 722280461Sdim} 723280461Sdim 724280461Sdimvoid Util::copyEntryPointAddress(NormalizedFile &nFile) { 725303239Sdim if (!_entryAtom) { 726303239Sdim nFile.entryAddress = 0; 727303239Sdim return; 728303239Sdim } 729303239Sdim 730292934Sdim if (_ctx.outputTypeHasEntry()) { 731280461Sdim if (_archHandler.isThumbFunction(*_entryAtom)) 732280461Sdim nFile.entryAddress = (_atomToAddress[_entryAtom] | 1); 733280461Sdim else 734280461Sdim nFile.entryAddress = _atomToAddress[_entryAtom]; 735280461Sdim } 736280461Sdim} 737280461Sdim 738280461Sdimvoid Util::buildAtomToAddressMap() { 739280461Sdim DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs() 740280461Sdim << "assign atom addresses:\n"); 741292934Sdim const bool lookForEntry = _ctx.outputTypeHasEntry(); 742280461Sdim for (SectionInfo *sect : _sectionInfos) { 743280461Sdim for (const AtomInfo &info : sect->atomsAndOffsets) { 744280461Sdim _atomToAddress[info.atom] = sect->address + info.offsetInSection; 745280461Sdim if (lookForEntry && (info.atom->contentType() == DefinedAtom::typeCode) && 746280461Sdim (info.atom->size() != 0) && 747292934Sdim info.atom->name() == _ctx.entrySymbolName()) { 748280461Sdim _entryAtom = info.atom; 749280461Sdim } 750280461Sdim DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs() 751293258Sdim << " address=" 752293258Sdim << llvm::format("0x%016X", _atomToAddress[info.atom]) 753293258Sdim << llvm::format(" 0x%09lX", info.atom) 754293258Sdim << ", file=#" 755293258Sdim << info.atom->file().ordinal() 756293258Sdim << ", atom=#" 757293258Sdim << info.atom->ordinal() 758293258Sdim << ", name=" 759293258Sdim << info.atom->name() 760293258Sdim << ", type=" 761293258Sdim << info.atom->contentType() 762293258Sdim << "\n"); 763280461Sdim } 764280461Sdim } 765293258Sdim DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs() 766293258Sdim << "assign header alias atom addresses:\n"); 767280461Sdim for (const Atom *atom : _machHeaderAliasAtoms) { 768292934Sdim _atomToAddress[atom] = _ctx.baseAddress(); 769293258Sdim#ifndef NDEBUG 770293258Sdim if (auto *definedAtom = dyn_cast<DefinedAtom>(atom)) { 771293258Sdim DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs() 772293258Sdim << " address=" 773293258Sdim << llvm::format("0x%016X", _atomToAddress[atom]) 774293258Sdim << llvm::format(" 0x%09lX", atom) 775293258Sdim << ", file=#" 776293258Sdim << definedAtom->file().ordinal() 777293258Sdim << ", atom=#" 778293258Sdim << definedAtom->ordinal() 779293258Sdim << ", name=" 780293258Sdim << definedAtom->name() 781293258Sdim << ", type=" 782293258Sdim << definedAtom->contentType() 783293258Sdim << "\n"); 784293258Sdim } else { 785293258Sdim DEBUG_WITH_TYPE("WriterMachO-address", llvm::dbgs() 786293258Sdim << " address=" 787293258Sdim << llvm::format("0x%016X", _atomToAddress[atom]) 788293258Sdim << " atom=" << atom 789293258Sdim << " name=" << atom->name() << "\n"); 790293258Sdim } 791293258Sdim#endif 792280461Sdim } 793280461Sdim} 794280461Sdim 795314564Sdimllvm::Error Util::synthesizeDebugNotes(NormalizedFile &file) { 796314564Sdim 797314564Sdim // Bail out early if we don't need to generate a debug map. 798314564Sdim if (_ctx.debugInfoMode() == MachOLinkingContext::DebugInfoMode::noDebugMap) 799314564Sdim return llvm::Error::success(); 800314564Sdim 801314564Sdim std::vector<const DefinedAtom*> atomsNeedingDebugNotes; 802314564Sdim std::set<const mach_o::MachOFile*> filesWithStabs; 803314564Sdim bool objFileHasDwarf = false; 804314564Sdim const File *objFile = nullptr; 805314564Sdim 806314564Sdim for (SectionInfo *sect : _sectionInfos) { 807314564Sdim for (const AtomInfo &info : sect->atomsAndOffsets) { 808314564Sdim if (const DefinedAtom *atom = dyn_cast<DefinedAtom>(info.atom)) { 809314564Sdim 810314564Sdim // FIXME: No stabs/debug-notes for symbols that wouldn't be in the 811314564Sdim // symbol table. 812314564Sdim // FIXME: No stabs/debug-notes for kernel dtrace probes. 813314564Sdim 814314564Sdim if (atom->contentType() == DefinedAtom::typeCFI || 815314564Sdim atom->contentType() == DefinedAtom::typeCString) 816314564Sdim continue; 817314564Sdim 818314564Sdim // Whenever we encounter a new file, update the 'objfileHasDwarf' flag. 819314564Sdim if (&info.atom->file() != objFile) { 820314564Sdim objFileHasDwarf = false; 821314564Sdim if (const mach_o::MachOFile *atomFile = 822314564Sdim dyn_cast<mach_o::MachOFile>(&info.atom->file())) { 823314564Sdim if (atomFile->debugInfo()) { 824314564Sdim if (isa<mach_o::DwarfDebugInfo>(atomFile->debugInfo())) 825314564Sdim objFileHasDwarf = true; 826314564Sdim else if (isa<mach_o::StabsDebugInfo>(atomFile->debugInfo())) 827314564Sdim filesWithStabs.insert(atomFile); 828314564Sdim } 829314564Sdim } 830314564Sdim } 831314564Sdim 832314564Sdim // If this atom is from a file that needs dwarf, add it to the list. 833314564Sdim if (objFileHasDwarf) 834314564Sdim atomsNeedingDebugNotes.push_back(info.atom); 835314564Sdim } 836314564Sdim } 837314564Sdim } 838314564Sdim 839314564Sdim // Sort atoms needing debug notes by file ordinal, then atom ordinal. 840314564Sdim std::sort(atomsNeedingDebugNotes.begin(), atomsNeedingDebugNotes.end(), 841314564Sdim [](const DefinedAtom *lhs, const DefinedAtom *rhs) { 842314564Sdim if (lhs->file().ordinal() != rhs->file().ordinal()) 843314564Sdim return (lhs->file().ordinal() < rhs->file().ordinal()); 844314564Sdim return (lhs->ordinal() < rhs->ordinal()); 845314564Sdim }); 846314564Sdim 847314564Sdim // FIXME: Handle <rdar://problem/17689030>: Add -add_ast_path option to \ 848314564Sdim // linker which add N_AST stab entry to output 849314564Sdim // See OutputFile::synthesizeDebugNotes in ObjectFile.cpp in ld64. 850314564Sdim 851314564Sdim StringRef oldFileName = ""; 852314564Sdim StringRef oldDirPath = ""; 853314564Sdim bool wroteStartSO = false; 854314564Sdim std::unordered_set<std::string> seenFiles; 855314564Sdim for (const DefinedAtom *atom : atomsNeedingDebugNotes) { 856314564Sdim const auto &atomFile = cast<mach_o::MachOFile>(atom->file()); 857314564Sdim assert(dyn_cast_or_null<lld::mach_o::DwarfDebugInfo>(atomFile.debugInfo()) 858314564Sdim && "file for atom needing debug notes does not contain dwarf"); 859314564Sdim auto &dwarf = cast<lld::mach_o::DwarfDebugInfo>(*atomFile.debugInfo()); 860314564Sdim 861314564Sdim auto &tu = dwarf.translationUnitSource(); 862314564Sdim StringRef newFileName = tu.name; 863314564Sdim StringRef newDirPath = tu.path; 864314564Sdim 865314564Sdim // Add an SO whenever the TU source file changes. 866314564Sdim if (newFileName != oldFileName || newDirPath != oldDirPath) { 867314564Sdim // Translation unit change, emit ending SO 868314564Sdim if (oldFileName != "") 869314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, "")); 870314564Sdim 871314564Sdim oldFileName = newFileName; 872314564Sdim oldDirPath = newDirPath; 873314564Sdim 874314564Sdim // If newDirPath doesn't end with a '/' we need to add one: 875314564Sdim if (newDirPath.back() != '/') { 876314564Sdim char *p = 877314564Sdim file.ownedAllocations.Allocate<char>(newDirPath.size() + 2); 878314564Sdim memcpy(p, newDirPath.data(), newDirPath.size()); 879314564Sdim p[newDirPath.size()] = '/'; 880314564Sdim p[newDirPath.size() + 1] = '\0'; 881314564Sdim newDirPath = p; 882314564Sdim } 883314564Sdim 884314564Sdim // New translation unit, emit start SOs: 885314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newDirPath)); 886314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_SO, 0, 0, 0, newFileName)); 887314564Sdim 888314564Sdim // Synthesize OSO for start of file. 889314564Sdim char *fullPath = nullptr; 890314564Sdim { 891314564Sdim SmallString<1024> pathBuf(atomFile.path()); 892314564Sdim if (auto EC = llvm::sys::fs::make_absolute(pathBuf)) 893314564Sdim return llvm::errorCodeToError(EC); 894314564Sdim fullPath = file.ownedAllocations.Allocate<char>(pathBuf.size() + 1); 895314564Sdim memcpy(fullPath, pathBuf.c_str(), pathBuf.size() + 1); 896314564Sdim } 897314564Sdim 898314564Sdim // Get mod time. 899314564Sdim uint32_t modTime = 0; 900314564Sdim llvm::sys::fs::file_status stat; 901314564Sdim if (!llvm::sys::fs::status(fullPath, stat)) 902314564Sdim if (llvm::sys::fs::exists(stat)) 903314564Sdim modTime = llvm::sys::toTimeT(stat.getLastModificationTime()); 904314564Sdim 905314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_OSO, _ctx.getCPUSubType(), 1, 906314564Sdim modTime, fullPath)); 907314564Sdim // <rdar://problem/6337329> linker should put cpusubtype in n_sect field 908314564Sdim // of nlist entry for N_OSO debug note entries. 909314564Sdim wroteStartSO = true; 910314564Sdim } 911314564Sdim 912314564Sdim if (atom->contentType() == DefinedAtom::typeCode) { 913314564Sdim // Synthesize BNSYM and start FUN stabs. 914314564Sdim _stabs.push_back(mach_o::Stab(atom, N_BNSYM, 1, 0, 0, "")); 915314564Sdim _stabs.push_back(mach_o::Stab(atom, N_FUN, 1, 0, 0, atom->name())); 916314564Sdim // Synthesize any SOL stabs needed 917314564Sdim // FIXME: add SOL stabs. 918314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_FUN, 0, 0, 919314564Sdim atom->rawContent().size(), "")); 920314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_ENSYM, 1, 0, 921314564Sdim atom->rawContent().size(), "")); 922314564Sdim } else { 923314564Sdim if (atom->scope() == Atom::scopeTranslationUnit) 924314564Sdim _stabs.push_back(mach_o::Stab(atom, N_STSYM, 1, 0, 0, atom->name())); 925314564Sdim else 926314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_GSYM, 1, 0, 0, atom->name())); 927314564Sdim } 928314564Sdim } 929314564Sdim 930314564Sdim // Emit ending SO if necessary. 931314564Sdim if (wroteStartSO) 932314564Sdim _stabs.push_back(mach_o::Stab(nullptr, N_SO, 1, 0, 0, "")); 933314564Sdim 934314564Sdim // Copy any stabs from .o file. 935314564Sdim for (const auto *objFile : filesWithStabs) { 936314564Sdim const auto &stabsList = 937314564Sdim cast<mach_o::StabsDebugInfo>(objFile->debugInfo())->stabs(); 938314564Sdim for (auto &stab : stabsList) { 939314564Sdim // FIXME: Drop stabs whose atoms have been dead-stripped. 940314564Sdim _stabs.push_back(stab); 941314564Sdim } 942314564Sdim } 943314564Sdim 944314564Sdim return llvm::Error::success(); 945314564Sdim} 946314564Sdim 947280461Sdimuint16_t Util::descBits(const DefinedAtom* atom) { 948280461Sdim uint16_t desc = 0; 949280461Sdim switch (atom->merge()) { 950280461Sdim case lld::DefinedAtom::mergeNo: 951280461Sdim case lld::DefinedAtom::mergeAsTentative: 952280461Sdim break; 953280461Sdim case lld::DefinedAtom::mergeAsWeak: 954280461Sdim case lld::DefinedAtom::mergeAsWeakAndAddressUsed: 955280461Sdim desc |= N_WEAK_DEF; 956280461Sdim break; 957280461Sdim case lld::DefinedAtom::mergeSameNameAndSize: 958280461Sdim case lld::DefinedAtom::mergeByLargestSection: 959280461Sdim case lld::DefinedAtom::mergeByContent: 960280461Sdim llvm_unreachable("Unsupported DefinedAtom::merge()"); 961280461Sdim break; 962280461Sdim } 963280461Sdim if (atom->contentType() == lld::DefinedAtom::typeResolver) 964280461Sdim desc |= N_SYMBOL_RESOLVER; 965303239Sdim if (atom->contentType() == lld::DefinedAtom::typeMachHeader) 966303239Sdim desc |= REFERENCED_DYNAMICALLY; 967280461Sdim if (_archHandler.isThumbFunction(*atom)) 968280461Sdim desc |= N_ARM_THUMB_DEF; 969314564Sdim if (atom->deadStrip() == DefinedAtom::deadStripNever && 970314564Sdim _ctx.outputMachOType() == llvm::MachO::MH_OBJECT) { 971280461Sdim if ((atom->contentType() != DefinedAtom::typeInitializerPtr) 972280461Sdim && (atom->contentType() != DefinedAtom::typeTerminatorPtr)) 973280461Sdim desc |= N_NO_DEAD_STRIP; 974280461Sdim } 975280461Sdim return desc; 976280461Sdim} 977280461Sdim 978280461Sdimbool Util::AtomSorter::operator()(const AtomAndIndex &left, 979280461Sdim const AtomAndIndex &right) { 980280461Sdim return (left.atom->name().compare(right.atom->name()) < 0); 981280461Sdim} 982280461Sdim 983303239Sdimllvm::Error Util::getSymbolTableRegion(const DefinedAtom* atom, 984303239Sdim bool &inGlobalsRegion, 985303239Sdim SymbolScope &scope) { 986292934Sdim bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); 987280461Sdim switch (atom->scope()) { 988280461Sdim case Atom::scopeTranslationUnit: 989280461Sdim scope = 0; 990280461Sdim inGlobalsRegion = false; 991314564Sdim return llvm::Error::success(); 992280461Sdim case Atom::scopeLinkageUnit: 993292934Sdim if ((_ctx.exportMode() == MachOLinkingContext::ExportMode::whiteList) && 994292934Sdim _ctx.exportSymbolNamed(atom->name())) { 995303239Sdim return llvm::make_error<GenericError>( 996303239Sdim Twine("cannot export hidden symbol ") + atom->name()); 997280461Sdim } 998280461Sdim if (rMode) { 999292934Sdim if (_ctx.keepPrivateExterns()) { 1000280461Sdim // -keep_private_externs means keep in globals region as N_PEXT. 1001280461Sdim scope = N_PEXT | N_EXT; 1002280461Sdim inGlobalsRegion = true; 1003314564Sdim return llvm::Error::success(); 1004280461Sdim } 1005280461Sdim } 1006280461Sdim // scopeLinkageUnit symbols are no longer global once linked. 1007280461Sdim scope = N_PEXT; 1008280461Sdim inGlobalsRegion = false; 1009314564Sdim return llvm::Error::success(); 1010280461Sdim case Atom::scopeGlobal: 1011292934Sdim if (_ctx.exportRestrictMode()) { 1012292934Sdim if (_ctx.exportSymbolNamed(atom->name())) { 1013280461Sdim scope = N_EXT; 1014280461Sdim inGlobalsRegion = true; 1015314564Sdim return llvm::Error::success(); 1016280461Sdim } else { 1017280461Sdim scope = N_PEXT; 1018280461Sdim inGlobalsRegion = false; 1019314564Sdim return llvm::Error::success(); 1020280461Sdim } 1021280461Sdim } else { 1022280461Sdim scope = N_EXT; 1023280461Sdim inGlobalsRegion = true; 1024314564Sdim return llvm::Error::success(); 1025280461Sdim } 1026280461Sdim break; 1027280461Sdim } 1028280461Sdim llvm_unreachable("atom->scope() unknown enum value"); 1029280461Sdim} 1030280461Sdim 1031314564Sdim 1032314564Sdim 1033303239Sdimllvm::Error Util::addSymbols(const lld::File &atomFile, 1034303239Sdim NormalizedFile &file) { 1035292934Sdim bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); 1036314564Sdim // Mach-O symbol table has four regions: stabs, locals, globals, undefs. 1037280461Sdim 1038314564Sdim // Add all stabs. 1039314564Sdim for (auto &stab : _stabs) { 1040314564Sdim Symbol sym; 1041314564Sdim sym.type = static_cast<NListType>(stab.type); 1042314564Sdim sym.scope = 0; 1043314564Sdim sym.sect = stab.other; 1044314564Sdim sym.desc = stab.desc; 1045314564Sdim if (stab.atom) 1046314564Sdim sym.value = _atomToAddress[stab.atom]; 1047314564Sdim else 1048314564Sdim sym.value = stab.value; 1049314564Sdim sym.name = stab.str; 1050314564Sdim file.stabsSymbols.push_back(sym); 1051314564Sdim } 1052314564Sdim 1053280461Sdim // Add all local (non-global) symbols in address order 1054280461Sdim std::vector<AtomAndIndex> globals; 1055280461Sdim globals.reserve(512); 1056280461Sdim for (SectionInfo *sect : _sectionInfos) { 1057280461Sdim for (const AtomInfo &info : sect->atomsAndOffsets) { 1058280461Sdim const DefinedAtom *atom = info.atom; 1059280461Sdim if (!atom->name().empty()) { 1060280461Sdim SymbolScope symbolScope; 1061280461Sdim bool inGlobalsRegion; 1062280461Sdim if (auto ec = getSymbolTableRegion(atom, inGlobalsRegion, symbolScope)){ 1063280461Sdim return ec; 1064280461Sdim } 1065280461Sdim if (inGlobalsRegion) { 1066280461Sdim AtomAndIndex ai = { atom, sect->finalSectionIndex, symbolScope }; 1067280461Sdim globals.push_back(ai); 1068280461Sdim } else { 1069280461Sdim Symbol sym; 1070280461Sdim sym.name = atom->name(); 1071280461Sdim sym.type = N_SECT; 1072280461Sdim sym.scope = symbolScope; 1073280461Sdim sym.sect = sect->finalSectionIndex; 1074280461Sdim sym.desc = descBits(atom); 1075280461Sdim sym.value = _atomToAddress[atom]; 1076280461Sdim _atomToSymbolIndex[atom] = file.localSymbols.size(); 1077280461Sdim file.localSymbols.push_back(sym); 1078280461Sdim } 1079280461Sdim } else if (rMode && _archHandler.needsLocalSymbolInRelocatableFile(atom)){ 1080280461Sdim // Create 'Lxxx' labels for anonymous atoms if archHandler says so. 1081280461Sdim static unsigned tempNum = 1; 1082280461Sdim char tmpName[16]; 1083280461Sdim sprintf(tmpName, "L%04u", tempNum++); 1084280461Sdim StringRef tempRef(tmpName); 1085280461Sdim Symbol sym; 1086280461Sdim sym.name = tempRef.copy(file.ownedAllocations); 1087280461Sdim sym.type = N_SECT; 1088280461Sdim sym.scope = 0; 1089280461Sdim sym.sect = sect->finalSectionIndex; 1090280461Sdim sym.desc = 0; 1091280461Sdim sym.value = _atomToAddress[atom]; 1092280461Sdim _atomToSymbolIndex[atom] = file.localSymbols.size(); 1093280461Sdim file.localSymbols.push_back(sym); 1094280461Sdim } 1095280461Sdim } 1096280461Sdim } 1097280461Sdim 1098280461Sdim // Sort global symbol alphabetically, then add to symbol table. 1099280461Sdim std::sort(globals.begin(), globals.end(), AtomSorter()); 1100280461Sdim const uint32_t globalStartIndex = file.localSymbols.size(); 1101280461Sdim for (AtomAndIndex &ai : globals) { 1102280461Sdim Symbol sym; 1103280461Sdim sym.name = ai.atom->name(); 1104280461Sdim sym.type = N_SECT; 1105280461Sdim sym.scope = ai.scope; 1106280461Sdim sym.sect = ai.index; 1107280461Sdim sym.desc = descBits(static_cast<const DefinedAtom*>(ai.atom)); 1108280461Sdim sym.value = _atomToAddress[ai.atom]; 1109280461Sdim _atomToSymbolIndex[ai.atom] = globalStartIndex + file.globalSymbols.size(); 1110280461Sdim file.globalSymbols.push_back(sym); 1111280461Sdim } 1112280461Sdim 1113280461Sdim // Sort undefined symbol alphabetically, then add to symbol table. 1114280461Sdim std::vector<AtomAndIndex> undefs; 1115280461Sdim undefs.reserve(128); 1116280461Sdim for (const UndefinedAtom *atom : atomFile.undefined()) { 1117280461Sdim AtomAndIndex ai = { atom, 0, N_EXT }; 1118280461Sdim undefs.push_back(ai); 1119280461Sdim } 1120280461Sdim for (const SharedLibraryAtom *atom : atomFile.sharedLibrary()) { 1121280461Sdim AtomAndIndex ai = { atom, 0, N_EXT }; 1122280461Sdim undefs.push_back(ai); 1123280461Sdim } 1124280461Sdim std::sort(undefs.begin(), undefs.end(), AtomSorter()); 1125280461Sdim const uint32_t start = file.globalSymbols.size() + file.localSymbols.size(); 1126280461Sdim for (AtomAndIndex &ai : undefs) { 1127280461Sdim Symbol sym; 1128280461Sdim uint16_t desc = 0; 1129280461Sdim if (!rMode) { 1130292934Sdim uint8_t ordinal = 0; 1131292934Sdim if (!_ctx.useFlatNamespace()) 1132292934Sdim ordinal = dylibOrdinal(dyn_cast<SharedLibraryAtom>(ai.atom)); 1133280461Sdim llvm::MachO::SET_LIBRARY_ORDINAL(desc, ordinal); 1134280461Sdim } 1135280461Sdim sym.name = ai.atom->name(); 1136280461Sdim sym.type = N_UNDF; 1137280461Sdim sym.scope = ai.scope; 1138280461Sdim sym.sect = 0; 1139280461Sdim sym.desc = desc; 1140280461Sdim sym.value = 0; 1141280461Sdim _atomToSymbolIndex[ai.atom] = file.undefinedSymbols.size() + start; 1142280461Sdim file.undefinedSymbols.push_back(sym); 1143280461Sdim } 1144280461Sdim 1145314564Sdim return llvm::Error::success(); 1146280461Sdim} 1147280461Sdim 1148280461Sdimconst Atom *Util::targetOfLazyPointer(const DefinedAtom *lpAtom) { 1149280461Sdim for (const Reference *ref : *lpAtom) { 1150280461Sdim if (_archHandler.isLazyPointer(*ref)) { 1151280461Sdim return ref->target(); 1152280461Sdim } 1153280461Sdim } 1154280461Sdim return nullptr; 1155280461Sdim} 1156280461Sdim 1157280461Sdimconst Atom *Util::targetOfStub(const DefinedAtom *stubAtom) { 1158280461Sdim for (const Reference *ref : *stubAtom) { 1159280461Sdim if (const Atom *ta = ref->target()) { 1160280461Sdim if (const DefinedAtom *lpAtom = dyn_cast<DefinedAtom>(ta)) { 1161280461Sdim const Atom *target = targetOfLazyPointer(lpAtom); 1162280461Sdim if (target) 1163280461Sdim return target; 1164280461Sdim } 1165280461Sdim } 1166280461Sdim } 1167280461Sdim return nullptr; 1168280461Sdim} 1169280461Sdim 1170280461Sdimvoid Util::addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file) { 1171280461Sdim for (SectionInfo *si : _sectionInfos) { 1172280461Sdim Section &normSect = file.sections[si->normalizedSectionIndex]; 1173280461Sdim switch (si->type) { 1174280461Sdim case llvm::MachO::S_NON_LAZY_SYMBOL_POINTERS: 1175280461Sdim for (const AtomInfo &info : si->atomsAndOffsets) { 1176280461Sdim bool foundTarget = false; 1177280461Sdim for (const Reference *ref : *info.atom) { 1178280461Sdim const Atom *target = ref->target(); 1179280461Sdim if (target) { 1180280461Sdim if (isa<const SharedLibraryAtom>(target)) { 1181280461Sdim uint32_t index = _atomToSymbolIndex[target]; 1182280461Sdim normSect.indirectSymbols.push_back(index); 1183280461Sdim foundTarget = true; 1184280461Sdim } else { 1185280461Sdim normSect.indirectSymbols.push_back( 1186280461Sdim llvm::MachO::INDIRECT_SYMBOL_LOCAL); 1187280461Sdim } 1188280461Sdim } 1189280461Sdim } 1190280461Sdim if (!foundTarget) { 1191280461Sdim normSect.indirectSymbols.push_back( 1192280461Sdim llvm::MachO::INDIRECT_SYMBOL_ABS); 1193280461Sdim } 1194280461Sdim } 1195280461Sdim break; 1196280461Sdim case llvm::MachO::S_LAZY_SYMBOL_POINTERS: 1197280461Sdim for (const AtomInfo &info : si->atomsAndOffsets) { 1198280461Sdim const Atom *target = targetOfLazyPointer(info.atom); 1199280461Sdim if (target) { 1200280461Sdim uint32_t index = _atomToSymbolIndex[target]; 1201280461Sdim normSect.indirectSymbols.push_back(index); 1202280461Sdim } 1203280461Sdim } 1204280461Sdim break; 1205280461Sdim case llvm::MachO::S_SYMBOL_STUBS: 1206280461Sdim for (const AtomInfo &info : si->atomsAndOffsets) { 1207280461Sdim const Atom *target = targetOfStub(info.atom); 1208280461Sdim if (target) { 1209280461Sdim uint32_t index = _atomToSymbolIndex[target]; 1210280461Sdim normSect.indirectSymbols.push_back(index); 1211280461Sdim } 1212280461Sdim } 1213280461Sdim break; 1214280461Sdim default: 1215280461Sdim break; 1216280461Sdim } 1217280461Sdim } 1218280461Sdim} 1219280461Sdim 1220314564Sdimvoid Util::addDependentDylibs(const lld::File &atomFile, 1221314564Sdim NormalizedFile &nFile) { 1222280461Sdim // Scan all imported symbols and build up list of dylibs they are from. 1223280461Sdim int ordinal = 1; 1224314564Sdim for (const auto *dylib : _ctx.allDylibs()) { 1225314564Sdim DylibPathToInfo::iterator pos = _dylibInfo.find(dylib->installName()); 1226280461Sdim if (pos == _dylibInfo.end()) { 1227280461Sdim DylibInfo info; 1228314564Sdim bool flatNamespaceAtom = dylib == _ctx.flatNamespaceFile(); 1229292934Sdim 1230292934Sdim // If we're in -flat_namespace mode (or this atom came from the flat 1231292934Sdim // namespace file under -undefined dynamic_lookup) then use the flat 1232292934Sdim // lookup ordinal. 1233292934Sdim if (flatNamespaceAtom || _ctx.useFlatNamespace()) 1234292934Sdim info.ordinal = BIND_SPECIAL_DYLIB_FLAT_LOOKUP; 1235292934Sdim else 1236292934Sdim info.ordinal = ordinal++; 1237314564Sdim info.hasWeak = false; 1238280461Sdim info.hasNonWeak = !info.hasWeak; 1239314564Sdim _dylibInfo[dylib->installName()] = info; 1240292934Sdim 1241292934Sdim // Unless this was a flat_namespace atom, record the source dylib. 1242292934Sdim if (!flatNamespaceAtom) { 1243292934Sdim DependentDylib depInfo; 1244314564Sdim depInfo.path = dylib->installName(); 1245292934Sdim depInfo.kind = llvm::MachO::LC_LOAD_DYLIB; 1246314564Sdim depInfo.currentVersion = _ctx.dylibCurrentVersion(dylib->path()); 1247314564Sdim depInfo.compatVersion = _ctx.dylibCompatVersion(dylib->path()); 1248292934Sdim nFile.dependentDylibs.push_back(depInfo); 1249292934Sdim } 1250280461Sdim } else { 1251314564Sdim pos->second.hasWeak = false; 1252314564Sdim pos->second.hasNonWeak = !pos->second.hasWeak; 1253280461Sdim } 1254280461Sdim } 1255280461Sdim // Automatically weak link dylib in which all symbols are weak (canBeNull). 1256280461Sdim for (DependentDylib &dep : nFile.dependentDylibs) { 1257280461Sdim DylibInfo &info = _dylibInfo[dep.path]; 1258280461Sdim if (info.hasWeak && !info.hasNonWeak) 1259280461Sdim dep.kind = llvm::MachO::LC_LOAD_WEAK_DYLIB; 1260292934Sdim else if (_ctx.isUpwardDylib(dep.path)) 1261280461Sdim dep.kind = llvm::MachO::LC_LOAD_UPWARD_DYLIB; 1262280461Sdim } 1263280461Sdim} 1264280461Sdim 1265280461Sdimint Util::dylibOrdinal(const SharedLibraryAtom *sa) { 1266280461Sdim return _dylibInfo[sa->loadName()].ordinal; 1267280461Sdim} 1268280461Sdim 1269280461Sdimvoid Util::segIndexForSection(const SectionInfo *sect, uint8_t &segmentIndex, 1270280461Sdim uint64_t &segmentStartAddr) { 1271280461Sdim segmentIndex = 0; 1272280461Sdim for (const SegmentInfo *seg : _segmentInfos) { 1273280461Sdim if ((seg->address <= sect->address) 1274280461Sdim && (seg->address+seg->size >= sect->address+sect->size)) { 1275280461Sdim segmentStartAddr = seg->address; 1276280461Sdim return; 1277280461Sdim } 1278280461Sdim ++segmentIndex; 1279280461Sdim } 1280280461Sdim llvm_unreachable("section not in any segment"); 1281280461Sdim} 1282280461Sdim 1283280461Sdimuint32_t Util::sectionIndexForAtom(const Atom *atom) { 1284280461Sdim uint64_t address = _atomToAddress[atom]; 1285280461Sdim for (const SectionInfo *si : _sectionInfos) { 1286280461Sdim if ((si->address <= address) && (address < si->address+si->size)) 1287293258Sdim return si->finalSectionIndex; 1288280461Sdim } 1289280461Sdim llvm_unreachable("atom not in any section"); 1290280461Sdim} 1291280461Sdim 1292280461Sdimvoid Util::addSectionRelocs(const lld::File &, NormalizedFile &file) { 1293292934Sdim if (_ctx.outputMachOType() != llvm::MachO::MH_OBJECT) 1294280461Sdim return; 1295280461Sdim 1296280461Sdim // Utility function for ArchHandler to find symbol index for an atom. 1297280461Sdim auto symIndexForAtom = [&] (const Atom &atom) -> uint32_t { 1298280461Sdim auto pos = _atomToSymbolIndex.find(&atom); 1299280461Sdim assert(pos != _atomToSymbolIndex.end()); 1300280461Sdim return pos->second; 1301280461Sdim }; 1302280461Sdim 1303280461Sdim // Utility function for ArchHandler to find section index for an atom. 1304280461Sdim auto sectIndexForAtom = [&] (const Atom &atom) -> uint32_t { 1305280461Sdim return sectionIndexForAtom(&atom); 1306280461Sdim }; 1307280461Sdim 1308280461Sdim // Utility function for ArchHandler to find address of atom in output file. 1309280461Sdim auto addressForAtom = [&] (const Atom &atom) -> uint64_t { 1310280461Sdim auto pos = _atomToAddress.find(&atom); 1311280461Sdim assert(pos != _atomToAddress.end()); 1312280461Sdim return pos->second; 1313280461Sdim }; 1314280461Sdim 1315280461Sdim for (SectionInfo *si : _sectionInfos) { 1316280461Sdim Section &normSect = file.sections[si->normalizedSectionIndex]; 1317280461Sdim for (const AtomInfo &info : si->atomsAndOffsets) { 1318280461Sdim const DefinedAtom *atom = info.atom; 1319280461Sdim for (const Reference *ref : *atom) { 1320293846Sdim // Skip emitting relocs for sections which are always able to be 1321293846Sdim // implicitly regenerated and where the relocation targets an address 1322293846Sdim // which is defined. 1323293846Sdim if (si->relocsToDefinedCanBeImplicit && isa<DefinedAtom>(ref->target())) 1324293846Sdim continue; 1325280461Sdim _archHandler.appendSectionRelocations(*atom, info.offsetInSection, *ref, 1326280461Sdim symIndexForAtom, 1327280461Sdim sectIndexForAtom, 1328280461Sdim addressForAtom, 1329280461Sdim normSect.relocations); 1330280461Sdim } 1331280461Sdim } 1332280461Sdim } 1333280461Sdim} 1334280461Sdim 1335303239Sdimvoid Util::addFunctionStarts(const lld::File &, NormalizedFile &file) { 1336303239Sdim if (!_ctx.generateFunctionStartsLoadCommand()) 1337303239Sdim return; 1338303239Sdim file.functionStarts.reserve(8192); 1339303239Sdim // Delta compress function starts, starting with the mach header symbol. 1340303239Sdim const uint64_t badAddress = ~0ULL; 1341303239Sdim uint64_t addr = badAddress; 1342303239Sdim for (SectionInfo *si : _sectionInfos) { 1343303239Sdim for (const AtomInfo &info : si->atomsAndOffsets) { 1344303239Sdim auto type = info.atom->contentType(); 1345303239Sdim if (type == DefinedAtom::typeMachHeader) { 1346303239Sdim addr = _atomToAddress[info.atom]; 1347303239Sdim continue; 1348303239Sdim } 1349303239Sdim if (type != DefinedAtom::typeCode) 1350303239Sdim continue; 1351303239Sdim assert(addr != badAddress && "Missing mach header symbol"); 1352303239Sdim // Skip atoms which have 0 size. This is so that LC_FUNCTION_STARTS 1353303239Sdim // can't spill in to the next section. 1354303239Sdim if (!info.atom->size()) 1355303239Sdim continue; 1356303239Sdim uint64_t nextAddr = _atomToAddress[info.atom]; 1357303239Sdim if (_archHandler.isThumbFunction(*info.atom)) 1358303239Sdim nextAddr |= 1; 1359303239Sdim uint64_t delta = nextAddr - addr; 1360303239Sdim if (delta) { 1361303239Sdim ByteBuffer buffer; 1362303239Sdim buffer.append_uleb128(delta); 1363303239Sdim file.functionStarts.insert(file.functionStarts.end(), buffer.bytes(), 1364303239Sdim buffer.bytes() + buffer.size()); 1365303239Sdim } 1366303239Sdim addr = nextAddr; 1367303239Sdim } 1368303239Sdim } 1369303239Sdim 1370303239Sdim // Null terminate, and pad to pointer size for this arch. 1371303239Sdim file.functionStarts.push_back(0); 1372303239Sdim 1373303239Sdim auto size = file.functionStarts.size(); 1374303239Sdim for (unsigned i = size, e = llvm::alignTo(size, _ctx.is64Bit() ? 8 : 4); 1375303239Sdim i != e; ++i) 1376303239Sdim file.functionStarts.push_back(0); 1377303239Sdim} 1378303239Sdim 1379280461Sdimvoid Util::buildDataInCodeArray(const lld::File &, NormalizedFile &file) { 1380303239Sdim if (!_ctx.generateDataInCodeLoadCommand()) 1381303239Sdim return; 1382280461Sdim for (SectionInfo *si : _sectionInfos) { 1383280461Sdim for (const AtomInfo &info : si->atomsAndOffsets) { 1384280461Sdim // Atoms that contain data-in-code have "transition" references 1385280461Sdim // which mark a point where the embedded data starts of ends. 1386280461Sdim // This needs to be converted to the mach-o format which is an array 1387280461Sdim // of data-in-code ranges. 1388280461Sdim uint32_t startOffset = 0; 1389280461Sdim DataRegionType mode = DataRegionType(0); 1390280461Sdim for (const Reference *ref : *info.atom) { 1391280461Sdim if (ref->kindNamespace() != Reference::KindNamespace::mach_o) 1392280461Sdim continue; 1393280461Sdim if (_archHandler.isDataInCodeTransition(ref->kindValue())) { 1394280461Sdim DataRegionType nextMode = (DataRegionType)ref->addend(); 1395280461Sdim if (mode != nextMode) { 1396280461Sdim if (mode != 0) { 1397280461Sdim // Found end data range, so make range entry. 1398280461Sdim DataInCode entry; 1399280461Sdim entry.offset = si->address + info.offsetInSection + startOffset; 1400280461Sdim entry.length = ref->offsetInAtom() - startOffset; 1401280461Sdim entry.kind = mode; 1402280461Sdim file.dataInCode.push_back(entry); 1403280461Sdim } 1404280461Sdim } 1405280461Sdim mode = nextMode; 1406280461Sdim startOffset = ref->offsetInAtom(); 1407280461Sdim } 1408280461Sdim } 1409280461Sdim if (mode != 0) { 1410280461Sdim // Function ends with data (no end transition). 1411280461Sdim DataInCode entry; 1412280461Sdim entry.offset = si->address + info.offsetInSection + startOffset; 1413280461Sdim entry.length = info.atom->size() - startOffset; 1414280461Sdim entry.kind = mode; 1415280461Sdim file.dataInCode.push_back(entry); 1416280461Sdim } 1417280461Sdim } 1418280461Sdim } 1419280461Sdim} 1420280461Sdim 1421280461Sdimvoid Util::addRebaseAndBindingInfo(const lld::File &atomFile, 1422280461Sdim NormalizedFile &nFile) { 1423292934Sdim if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT) 1424280461Sdim return; 1425280461Sdim 1426280461Sdim uint8_t segmentIndex; 1427280461Sdim uint64_t segmentStartAddr; 1428326909Sdim uint32_t offsetInBindInfo = 0; 1429326909Sdim 1430280461Sdim for (SectionInfo *sect : _sectionInfos) { 1431280461Sdim segIndexForSection(sect, segmentIndex, segmentStartAddr); 1432280461Sdim for (const AtomInfo &info : sect->atomsAndOffsets) { 1433280461Sdim const DefinedAtom *atom = info.atom; 1434280461Sdim for (const Reference *ref : *atom) { 1435280461Sdim uint64_t segmentOffset = _atomToAddress[atom] + ref->offsetInAtom() 1436280461Sdim - segmentStartAddr; 1437280461Sdim const Atom* targ = ref->target(); 1438280461Sdim if (_archHandler.isPointer(*ref)) { 1439280461Sdim // A pointer to a DefinedAtom requires rebasing. 1440280461Sdim if (isa<DefinedAtom>(targ)) { 1441280461Sdim RebaseLocation rebase; 1442280461Sdim rebase.segIndex = segmentIndex; 1443280461Sdim rebase.segOffset = segmentOffset; 1444280461Sdim rebase.kind = llvm::MachO::REBASE_TYPE_POINTER; 1445280461Sdim nFile.rebasingInfo.push_back(rebase); 1446280461Sdim } 1447280461Sdim // A pointer to an SharedLibraryAtom requires binding. 1448280461Sdim if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) { 1449280461Sdim BindLocation bind; 1450280461Sdim bind.segIndex = segmentIndex; 1451280461Sdim bind.segOffset = segmentOffset; 1452280461Sdim bind.kind = llvm::MachO::BIND_TYPE_POINTER; 1453280461Sdim bind.canBeNull = sa->canBeNullAtRuntime(); 1454280461Sdim bind.ordinal = dylibOrdinal(sa); 1455280461Sdim bind.symbolName = targ->name(); 1456280461Sdim bind.addend = ref->addend(); 1457280461Sdim nFile.bindingInfo.push_back(bind); 1458280461Sdim } 1459280461Sdim } 1460280461Sdim else if (_archHandler.isLazyPointer(*ref)) { 1461280461Sdim BindLocation bind; 1462280461Sdim if (const SharedLibraryAtom *sa = dyn_cast<SharedLibraryAtom>(targ)) { 1463280461Sdim bind.ordinal = dylibOrdinal(sa); 1464280461Sdim } else { 1465280461Sdim bind.ordinal = llvm::MachO::BIND_SPECIAL_DYLIB_SELF; 1466280461Sdim } 1467280461Sdim bind.segIndex = segmentIndex; 1468280461Sdim bind.segOffset = segmentOffset; 1469280461Sdim bind.kind = llvm::MachO::BIND_TYPE_POINTER; 1470280461Sdim bind.canBeNull = false; //sa->canBeNullAtRuntime(); 1471280461Sdim bind.symbolName = targ->name(); 1472280461Sdim bind.addend = ref->addend(); 1473280461Sdim nFile.lazyBindingInfo.push_back(bind); 1474326909Sdim 1475326909Sdim // Now that we know the segmentOffset and the ordinal attribute, 1476326909Sdim // we can fix the helper's code 1477326909Sdim 1478326909Sdim fixLazyReferenceImm(atom, offsetInBindInfo, nFile); 1479326909Sdim 1480326909Sdim // 5 bytes for opcodes + variable sizes (target name + \0 and offset 1481326909Sdim // encode's size) 1482326909Sdim offsetInBindInfo += 1483326909Sdim 6 + targ->name().size() + llvm::getULEB128Size(bind.segOffset); 1484326909Sdim if (bind.ordinal > BIND_IMMEDIATE_MASK) 1485326909Sdim offsetInBindInfo += llvm::getULEB128Size(bind.ordinal); 1486280461Sdim } 1487280461Sdim } 1488280461Sdim } 1489280461Sdim } 1490280461Sdim} 1491280461Sdim 1492326909Sdimvoid Util::fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset, 1493326909Sdim NormalizedFile &file) { 1494360784Sdim for (const Reference *ref : *atom) { 1495326909Sdim const DefinedAtom *da = dyn_cast<DefinedAtom>(ref->target()); 1496326909Sdim if (da == nullptr) 1497326909Sdim return; 1498326909Sdim 1499326909Sdim const Reference *helperRef = nullptr; 1500326909Sdim for (const Reference *hr : *da) { 1501326909Sdim if (hr->kindValue() == _archHandler.lazyImmediateLocationKind()) { 1502326909Sdim helperRef = hr; 1503326909Sdim break; 1504326909Sdim } 1505326909Sdim } 1506326909Sdim if (helperRef == nullptr) 1507326909Sdim continue; 1508326909Sdim 1509326909Sdim // TODO: maybe get the fixed atom content from _archHandler ? 1510326909Sdim for (SectionInfo *sectInfo : _sectionInfos) { 1511326909Sdim for (const AtomInfo &atomInfo : sectInfo->atomsAndOffsets) { 1512326909Sdim if (atomInfo.atom == helperRef->target()) { 1513326909Sdim auto sectionContent = 1514326909Sdim file.sections[sectInfo->normalizedSectionIndex].content; 1515326909Sdim uint8_t *rawb = 1516326909Sdim file.ownedAllocations.Allocate<uint8_t>(sectionContent.size()); 1517326909Sdim llvm::MutableArrayRef<uint8_t> newContent{rawb, 1518326909Sdim sectionContent.size()}; 1519326909Sdim std::copy(sectionContent.begin(), sectionContent.end(), 1520326909Sdim newContent.begin()); 1521326909Sdim llvm::support::ulittle32_t *loc = 1522326909Sdim reinterpret_cast<llvm::support::ulittle32_t *>( 1523326909Sdim &newContent[atomInfo.offsetInSection + 1524326909Sdim helperRef->offsetInAtom()]); 1525326909Sdim *loc = offset; 1526326909Sdim file.sections[sectInfo->normalizedSectionIndex].content = newContent; 1527326909Sdim } 1528326909Sdim } 1529326909Sdim } 1530326909Sdim } 1531326909Sdim} 1532326909Sdim 1533280461Sdimvoid Util::addExportInfo(const lld::File &atomFile, NormalizedFile &nFile) { 1534292934Sdim if (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT) 1535280461Sdim return; 1536280461Sdim 1537280461Sdim for (SectionInfo *sect : _sectionInfos) { 1538280461Sdim for (const AtomInfo &info : sect->atomsAndOffsets) { 1539280461Sdim const DefinedAtom *atom = info.atom; 1540280461Sdim if (atom->scope() != Atom::scopeGlobal) 1541280461Sdim continue; 1542292934Sdim if (_ctx.exportRestrictMode()) { 1543292934Sdim if (!_ctx.exportSymbolNamed(atom->name())) 1544280461Sdim continue; 1545280461Sdim } 1546280461Sdim Export exprt; 1547280461Sdim exprt.name = atom->name(); 1548292934Sdim exprt.offset = _atomToAddress[atom] - _ctx.baseAddress(); 1549280461Sdim exprt.kind = EXPORT_SYMBOL_FLAGS_KIND_REGULAR; 1550280461Sdim if (atom->merge() == DefinedAtom::mergeAsWeak) 1551280461Sdim exprt.flags = EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION; 1552280461Sdim else 1553280461Sdim exprt.flags = 0; 1554280461Sdim exprt.otherOffset = 0; 1555280461Sdim exprt.otherName = StringRef(); 1556280461Sdim nFile.exportInfo.push_back(exprt); 1557280461Sdim } 1558280461Sdim } 1559280461Sdim} 1560280461Sdim 1561280461Sdimuint32_t Util::fileFlags() { 1562280461Sdim // FIXME: these need to determined at runtime. 1563292934Sdim if (_ctx.outputMachOType() == MH_OBJECT) { 1564303239Sdim return _subsectionsViaSymbols ? MH_SUBSECTIONS_VIA_SYMBOLS : 0; 1565280461Sdim } else { 1566292934Sdim uint32_t flags = MH_DYLDLINK; 1567292934Sdim if (!_ctx.useFlatNamespace()) 1568292934Sdim flags |= MH_TWOLEVEL | MH_NOUNDEFS; 1569292934Sdim if ((_ctx.outputMachOType() == MH_EXECUTE) && _ctx.PIE()) 1570292934Sdim flags |= MH_PIE; 1571292934Sdim if (_hasTLVDescriptors) 1572292934Sdim flags |= (MH_PIE | MH_HAS_TLV_DESCRIPTORS); 1573292934Sdim return flags; 1574280461Sdim } 1575280461Sdim} 1576280461Sdim 1577280461Sdim} // end anonymous namespace 1578280461Sdim 1579280461Sdimnamespace lld { 1580280461Sdimnamespace mach_o { 1581280461Sdimnamespace normalized { 1582280461Sdim 1583280461Sdim/// Convert a set of Atoms into a normalized mach-o file. 1584303239Sdimllvm::Expected<std::unique_ptr<NormalizedFile>> 1585280461SdimnormalizedFromAtoms(const lld::File &atomFile, 1586280461Sdim const MachOLinkingContext &context) { 1587280461Sdim // The util object buffers info until the normalized file can be made. 1588280461Sdim Util util(context); 1589303239Sdim util.processDefinedAtoms(atomFile); 1590280461Sdim util.organizeSections(); 1591280461Sdim 1592280461Sdim std::unique_ptr<NormalizedFile> f(new NormalizedFile()); 1593280461Sdim NormalizedFile &normFile = *f.get(); 1594280461Sdim normFile.arch = context.arch(); 1595280461Sdim normFile.fileType = context.outputMachOType(); 1596280461Sdim normFile.flags = util.fileFlags(); 1597292934Sdim normFile.stackSize = context.stackSize(); 1598280461Sdim normFile.installName = context.installName(); 1599280461Sdim normFile.currentVersion = context.currentVersion(); 1600280461Sdim normFile.compatVersion = context.compatibilityVersion(); 1601303239Sdim normFile.os = context.os(); 1602303239Sdim 1603303239Sdim // If we are emitting an object file, then the min version is the maximum 1604303239Sdim // of the min's of all the source files and the cmdline. 1605303239Sdim if (normFile.fileType == llvm::MachO::MH_OBJECT) 1606303239Sdim normFile.minOSverson = std::max(context.osMinVersion(), util.minVersion()); 1607303239Sdim else 1608303239Sdim normFile.minOSverson = context.osMinVersion(); 1609303239Sdim 1610303239Sdim normFile.minOSVersionKind = util.minVersionCommandType(); 1611303239Sdim 1612303239Sdim normFile.sdkVersion = context.sdkVersion(); 1613303239Sdim normFile.sourceVersion = context.sourceVersion(); 1614303239Sdim 1615303239Sdim if (context.generateVersionLoadCommand() && 1616303239Sdim context.os() != MachOLinkingContext::OS::unknown) 1617303239Sdim normFile.hasMinVersionLoadCommand = true; 1618303239Sdim else if (normFile.fileType == llvm::MachO::MH_OBJECT && 1619303239Sdim util.allSourceFilesHaveMinVersions() && 1620303239Sdim ((normFile.os != MachOLinkingContext::OS::unknown) || 1621303239Sdim util.minVersionCommandType())) { 1622303239Sdim // If we emit an object file, then it should contain a min version load 1623303239Sdim // command if all of the source files also contained min version commands. 1624303239Sdim // Also, we either need to have a platform, or found a platform from the 1625303239Sdim // source object files. 1626303239Sdim normFile.hasMinVersionLoadCommand = true; 1627303239Sdim } 1628303239Sdim normFile.generateDataInCodeLoadCommand = 1629303239Sdim context.generateDataInCodeLoadCommand(); 1630280461Sdim normFile.pageSize = context.pageSize(); 1631280461Sdim normFile.rpaths = context.rpaths(); 1632280461Sdim util.addDependentDylibs(atomFile, normFile); 1633280461Sdim util.copySegmentInfo(normFile); 1634280461Sdim util.copySectionInfo(normFile); 1635280461Sdim util.assignAddressesToSections(normFile); 1636280461Sdim util.buildAtomToAddressMap(); 1637314564Sdim if (auto err = util.synthesizeDebugNotes(normFile)) 1638314564Sdim return std::move(err); 1639280461Sdim util.updateSectionInfo(normFile); 1640280461Sdim util.copySectionContent(normFile); 1641280461Sdim if (auto ec = util.addSymbols(atomFile, normFile)) { 1642303239Sdim return std::move(ec); 1643280461Sdim } 1644280461Sdim util.addIndirectSymbols(atomFile, normFile); 1645280461Sdim util.addRebaseAndBindingInfo(atomFile, normFile); 1646280461Sdim util.addExportInfo(atomFile, normFile); 1647280461Sdim util.addSectionRelocs(atomFile, normFile); 1648303239Sdim util.addFunctionStarts(atomFile, normFile); 1649280461Sdim util.buildDataInCodeArray(atomFile, normFile); 1650280461Sdim util.copyEntryPointAddress(normFile); 1651280461Sdim 1652280461Sdim return std::move(f); 1653280461Sdim} 1654280461Sdim 1655280461Sdim} // namespace normalized 1656280461Sdim} // namespace mach_o 1657280461Sdim} // namespace lld 1658