MachONormalizedFileFromAtoms.cpp revision 326909
1280461Sdim//===- lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp ------------===// 2280461Sdim// 3280461Sdim// The LLVM Linker 4280461Sdim// 5280461Sdim// This file is distributed under the University of Illinois Open Source 6280461Sdim// License. See LICENSE.TXT for details. 7280461Sdim// 8280461Sdim//===----------------------------------------------------------------------===// 9280461Sdim 10280461Sdim/// 11280461Sdim/// \file Converts from in-memory Atoms to in-memory normalized mach-o. 12280461Sdim/// 13280461Sdim/// +------------+ 14280461Sdim/// | normalized | 15280461Sdim/// +------------+ 16280461Sdim/// ^ 17280461Sdim/// | 18280461Sdim/// | 19280461Sdim/// +-------+ 20280461Sdim/// | Atoms | 21280461Sdim/// +-------+ 22280461Sdim 23280461Sdim#include "ArchHandler.h" 24314564Sdim#include "DebugInfo.h" 25321369Sdim#include "MachONormalizedFile.h" 26280461Sdim#include "MachONormalizedFileBinaryUtils.h" 27280461Sdim#include "lld/Core/Error.h" 28280461Sdim#include "lld/Core/LLVM.h" 29280461Sdim#include "llvm/ADT/StringRef.h" 30280461Sdim#include "llvm/ADT/StringSwitch.h" 31321369Sdim#include "llvm/BinaryFormat/MachO.h" 32280461Sdim#include "llvm/Support/Casting.h" 33280461Sdim#include "llvm/Support/Debug.h" 34280461Sdim#include "llvm/Support/ErrorHandling.h" 35280461Sdim#include "llvm/Support/Format.h" 36280461Sdim#include <map> 37280461Sdim#include <system_error> 38314564Sdim#include <unordered_set> 39280461Sdim 40280461Sdimusing llvm::StringRef; 41280461Sdimusing llvm::isa; 42280461Sdimusing namespace llvm::MachO; 43280461Sdimusing namespace lld::mach_o::normalized; 44280461Sdimusing namespace lld; 45280461Sdim 46280461Sdimnamespace { 47280461Sdim 48280461Sdimstruct AtomInfo { 49280461Sdim const DefinedAtom *atom; 50280461Sdim uint64_t offsetInSection; 51280461Sdim}; 52280461Sdim 53280461Sdimstruct SectionInfo { 54280461Sdim SectionInfo(StringRef seg, StringRef sect, SectionType type, 55293846Sdim const MachOLinkingContext &ctxt, uint32_t attr, 56293846Sdim bool relocsToDefinedCanBeImplicit); 57280461Sdim 58280461Sdim StringRef segmentName; 59280461Sdim StringRef sectionName; 60280461Sdim SectionType type; 61280461Sdim uint32_t attributes; 62280461Sdim uint64_t address; 63280461Sdim uint64_t size; 64292934Sdim uint16_t alignment; 65293846Sdim 66293846Sdim /// If this is set, the any relocs in this section which point to defined 67293846Sdim /// addresses can be implicitly generated. This is the case for the 68293846Sdim /// __eh_frame section where references to the function can be implicit if the 69293846Sdim /// function is defined. 70293846Sdim bool relocsToDefinedCanBeImplicit; 71293846Sdim 72293846Sdim 73280461Sdim std::vector<AtomInfo> atomsAndOffsets; 74280461Sdim uint32_t normalizedSectionIndex; 75280461Sdim uint32_t finalSectionIndex; 76280461Sdim}; 77280461Sdim 78280461SdimSectionInfo::SectionInfo(StringRef sg, StringRef sct, SectionType t, 79293846Sdim const MachOLinkingContext &ctxt, uint32_t attrs, 80293846Sdim bool relocsToDefinedCanBeImplicit) 81280461Sdim : segmentName(sg), sectionName(sct), type(t), attributes(attrs), 82292934Sdim address(0), size(0), alignment(1), 83293846Sdim relocsToDefinedCanBeImplicit(relocsToDefinedCanBeImplicit), 84280461Sdim normalizedSectionIndex(0), finalSectionIndex(0) { 85292934Sdim uint16_t align = 1; 86280461Sdim if (ctxt.sectionAligned(segmentName, sectionName, align)) { 87280461Sdim alignment = align; 88280461Sdim } 89280461Sdim} 90280461Sdim 91280461Sdimstruct SegmentInfo { 92280461Sdim SegmentInfo(StringRef name); 93280461Sdim 94280461Sdim StringRef name; 95280461Sdim uint64_t address; 96280461Sdim uint64_t size; 97303239Sdim uint32_t init_access; 98303239Sdim uint32_t max_access; 99280461Sdim std::vector<SectionInfo*> sections; 100280461Sdim uint32_t normalizedSegmentIndex; 101280461Sdim}; 102280461Sdim 103280461SdimSegmentInfo::SegmentInfo(StringRef n) 104303239Sdim : name(n), address(0), size(0), init_access(0), max_access(0), 105303239Sdim normalizedSegmentIndex(0) { 106280461Sdim} 107280461Sdim 108280461Sdimclass Util { 109280461Sdimpublic: 110280461Sdim Util(const MachOLinkingContext &ctxt) 111292934Sdim : _ctx(ctxt), _archHandler(ctxt.archHandler()), _entryAtom(nullptr), 112303239Sdim _hasTLVDescriptors(false), _subsectionsViaSymbols(true) {} 113280461Sdim ~Util(); 114280461Sdim 115303239Sdim void processDefinedAtoms(const lld::File &atomFile); 116303239Sdim void processAtomAttributes(const DefinedAtom *atom); 117303239Sdim void assignAtomToSection(const DefinedAtom *atom); 118280461Sdim void organizeSections(); 119280461Sdim void assignAddressesToSections(const NormalizedFile &file); 120280461Sdim uint32_t fileFlags(); 121280461Sdim void copySegmentInfo(NormalizedFile &file); 122280461Sdim void copySectionInfo(NormalizedFile &file); 123280461Sdim void updateSectionInfo(NormalizedFile &file); 124280461Sdim void buildAtomToAddressMap(); 125314564Sdim llvm::Error synthesizeDebugNotes(NormalizedFile &file); 126303239Sdim llvm::Error addSymbols(const lld::File &atomFile, NormalizedFile &file); 127280461Sdim void addIndirectSymbols(const lld::File &atomFile, NormalizedFile &file); 128280461Sdim void addRebaseAndBindingInfo(const lld::File &, NormalizedFile &file); 129280461Sdim void addExportInfo(const lld::File &, NormalizedFile &file); 130280461Sdim void addSectionRelocs(const lld::File &, NormalizedFile &file); 131303239Sdim void addFunctionStarts(const lld::File &, NormalizedFile &file); 132280461Sdim void buildDataInCodeArray(const lld::File &, NormalizedFile &file); 133280461Sdim void addDependentDylibs(const lld::File &, NormalizedFile &file); 134280461Sdim void copyEntryPointAddress(NormalizedFile &file); 135280461Sdim void copySectionContent(NormalizedFile &file); 136280461Sdim 137303239Sdim bool allSourceFilesHaveMinVersions() const { 138303239Sdim return _allSourceFilesHaveMinVersions; 139303239Sdim } 140303239Sdim 141303239Sdim uint32_t minVersion() const { 142303239Sdim return _minVersion; 143303239Sdim } 144303239Sdim 145303239Sdim LoadCommandType minVersionCommandType() const { 146303239Sdim return _minVersionCommandType; 147303239Sdim } 148303239Sdim 149280461Sdimprivate: 150280461Sdim typedef std::map<DefinedAtom::ContentType, SectionInfo*> TypeToSection; 151280461Sdim typedef llvm::DenseMap<const Atom*, uint64_t> AtomToAddress; 152280461Sdim 153280461Sdim struct DylibInfo { int ordinal; bool hasWeak; bool hasNonWeak; }; 154280461Sdim typedef llvm::StringMap<DylibInfo> DylibPathToInfo; 155280461Sdim 156280461Sdim SectionInfo *sectionForAtom(const DefinedAtom*); 157280461Sdim SectionInfo *getRelocatableSection(DefinedAtom::ContentType type); 158280461Sdim SectionInfo *getFinalSection(DefinedAtom::ContentType type); 159280461Sdim void appendAtom(SectionInfo *sect, const DefinedAtom *atom); 160280461Sdim SegmentInfo *segmentForName(StringRef segName); 161280461Sdim void layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr); 162280461Sdim void layoutSectionsInTextSegment(size_t, SegmentInfo *, uint64_t &); 163280461Sdim void copySectionContent(SectionInfo *si, ContentBytes &content); 164280461Sdim uint16_t descBits(const DefinedAtom* atom); 165280461Sdim int dylibOrdinal(const SharedLibraryAtom *sa); 166280461Sdim void segIndexForSection(const SectionInfo *sect, 167280461Sdim uint8_t &segmentIndex, uint64_t &segmentStartAddr); 168280461Sdim const Atom *targetOfLazyPointer(const DefinedAtom *lpAtom); 169280461Sdim const Atom *targetOfStub(const DefinedAtom *stubAtom); 170303239Sdim llvm::Error getSymbolTableRegion(const DefinedAtom* atom, 171303239Sdim bool &inGlobalsRegion, 172303239Sdim SymbolScope &symbolScope); 173280461Sdim void appendSection(SectionInfo *si, NormalizedFile &file); 174280461Sdim uint32_t sectionIndexForAtom(const Atom *atom); 175326909Sdim void fixLazyReferenceImm(const DefinedAtom *atom, uint32_t offset, 176326909Sdim NormalizedFile &file); 177280461Sdim 178280461Sdim typedef llvm::DenseMap<const Atom*, uint32_t> AtomToIndex; 179280461Sdim struct AtomAndIndex { const Atom *atom; uint32_t index; SymbolScope scope; }; 180280461Sdim struct AtomSorter { 181280461Sdim bool operator()(const AtomAndIndex &left, const AtomAndIndex &right); 182280461Sdim }; 183280461Sdim struct SegmentSorter { 184280461Sdim bool operator()(const SegmentInfo *left, const SegmentInfo *right); 185280461Sdim static unsigned weight(const SegmentInfo *); 186280461Sdim }; 187280461Sdim struct TextSectionSorter { 188280461Sdim bool operator()(const SectionInfo *left, const SectionInfo *right); 189280461Sdim static unsigned weight(const SectionInfo *); 190280461Sdim }; 191280461Sdim 192292934Sdim const MachOLinkingContext &_ctx; 193280461Sdim mach_o::ArchHandler &_archHandler; 194280461Sdim llvm::BumpPtrAllocator _allocator; 195280461Sdim std::vector<SectionInfo*> _sectionInfos; 196280461Sdim std::vector<SegmentInfo*> _segmentInfos; 197280461Sdim TypeToSection _sectionMap; 198280461Sdim std::vector<SectionInfo*> _customSections; 199280461Sdim AtomToAddress _atomToAddress; 200280461Sdim DylibPathToInfo _dylibInfo; 201280461Sdim const DefinedAtom *_entryAtom; 202280461Sdim AtomToIndex _atomToSymbolIndex; 203280461Sdim std::vector<const Atom *> _machHeaderAliasAtoms; 204292934Sdim bool _hasTLVDescriptors; 205303239Sdim bool _subsectionsViaSymbols; 206303239Sdim bool _allSourceFilesHaveMinVersions = true; 207303239Sdim LoadCommandType _minVersionCommandType = (LoadCommandType)0; 208303239Sdim uint32_t _minVersion = 0; 209314564Sdim std::vector<lld::mach_o::Stab> _stabs; 210280461Sdim}; 211280461Sdim 212280461SdimUtil::~Util() { 213280461Sdim // The SectionInfo structs are BumpPtr allocated, but atomsAndOffsets needs 214280461Sdim // to be deleted. 215280461Sdim for (SectionInfo *si : _sectionInfos) { 216280461Sdim // clear() destroys vector elements, but does not deallocate. 217280461Sdim // Instead use swap() to deallocate vector buffer. 218280461Sdim std::vector<AtomInfo> empty; 219280461Sdim si->atomsAndOffsets.swap(empty); 220280461Sdim } 221280461Sdim // The SegmentInfo structs are BumpPtr allocated, but sections needs 222280461Sdim // to be deleted. 223280461Sdim for (SegmentInfo *sgi : _segmentInfos) { 224280461Sdim std::vector<SectionInfo*> empty2; 225280461Sdim sgi->sections.swap(empty2); 226280461Sdim } 227280461Sdim} 228280461Sdim 229280461SdimSectionInfo *Util::getRelocatableSection(DefinedAtom::ContentType type) { 230280461Sdim StringRef segmentName; 231280461Sdim StringRef sectionName; 232280461Sdim SectionType sectionType; 233280461Sdim SectionAttr sectionAttrs; 234293846Sdim bool relocsToDefinedCanBeImplicit; 235280461Sdim 236280461Sdim // Use same table used by when parsing .o files. 237280461Sdim relocatableSectionInfoForContentType(type, segmentName, sectionName, 238293846Sdim sectionType, sectionAttrs, 239293846Sdim relocsToDefinedCanBeImplicit); 240280461Sdim // If we already have a SectionInfo with this name, re-use it. 241280461Sdim // This can happen if two ContentType map to the same mach-o section. 242280461Sdim for (auto sect : _sectionMap) { 243280461Sdim if (sect.second->sectionName.equals(sectionName) && 244280461Sdim sect.second->segmentName.equals(segmentName)) { 245280461Sdim return sect.second; 246280461Sdim } 247280461Sdim } 248280461Sdim // Otherwise allocate new SectionInfo object. 249292934Sdim auto *sect = new (_allocator) 250293846Sdim SectionInfo(segmentName, sectionName, sectionType, _ctx, sectionAttrs, 251293846Sdim relocsToDefinedCanBeImplicit); 252280461Sdim _sectionInfos.push_back(sect); 253280461Sdim _sectionMap[type] = sect; 254280461Sdim return sect; 255280461Sdim} 256280461Sdim 257280461Sdim#define ENTRY(seg, sect, type, atomType) \ 258280461Sdim {seg, sect, type, DefinedAtom::atomType } 259280461Sdim 260280461Sdimstruct MachOFinalSectionFromAtomType { 261280461Sdim StringRef segmentName; 262280461Sdim StringRef sectionName; 263280461Sdim SectionType sectionType; 264280461Sdim DefinedAtom::ContentType atomType; 265280461Sdim}; 266280461Sdim 267280461Sdimconst MachOFinalSectionFromAtomType sectsToAtomType[] = { 268280461Sdim ENTRY("__TEXT", "__text", S_REGULAR, typeCode), 269303239Sdim ENTRY("__TEXT", "__text", S_REGULAR, typeMachHeader), 270280461Sdim ENTRY("__TEXT", "__cstring", S_CSTRING_LITERALS, typeCString), 271280461Sdim ENTRY("__TEXT", "__ustring", S_REGULAR, typeUTF16String), 272280461Sdim ENTRY("__TEXT", "__const", S_REGULAR, typeConstant), 273280461Sdim ENTRY("__TEXT", "__const", S_4BYTE_LITERALS, typeLiteral4), 274280461Sdim ENTRY("__TEXT", "__const", S_8BYTE_LITERALS, typeLiteral8), 275280461Sdim ENTRY("__TEXT", "__const", S_16BYTE_LITERALS, typeLiteral16), 276280461Sdim ENTRY("__TEXT", "__stubs", S_SYMBOL_STUBS, typeStub), 277280461Sdim ENTRY("__TEXT", "__stub_helper", S_REGULAR, typeStubHelper), 278280461Sdim ENTRY("__TEXT", "__gcc_except_tab", S_REGULAR, typeLSDA), 279280461Sdim ENTRY("__TEXT", "__eh_frame", S_COALESCED, typeCFI), 280280461Sdim ENTRY("__TEXT", "__unwind_info", S_REGULAR, typeProcessedUnwindInfo), 281280461Sdim ENTRY("__DATA", "__data", S_REGULAR, typeData), 282280461Sdim ENTRY("__DATA", "__const", S_REGULAR, typeConstData), 283280461Sdim ENTRY("__DATA", "__cfstring", S_REGULAR, typeCFString), 284280461Sdim ENTRY("__DATA", "__la_symbol_ptr", S_LAZY_SYMBOL_POINTERS, 285280461Sdim typeLazyPointer), 286280461Sdim ENTRY("__DATA", "__mod_init_func", S_MOD_INIT_FUNC_POINTERS, 287280461Sdim typeInitializerPtr), 288280461Sdim ENTRY("__DATA", "__mod_term_func", S_MOD_TERM_FUNC_POINTERS, 289280461Sdim typeTerminatorPtr), 290280461Sdim ENTRY("__DATA", "__got", S_NON_LAZY_SYMBOL_POINTERS, 291280461Sdim typeGOT), 292303239Sdim ENTRY("__DATA", "__nl_symbol_ptr", S_NON_LAZY_SYMBOL_POINTERS, 293303239Sdim typeNonLazyPointer), 294292934Sdim ENTRY("__DATA", "__thread_vars", S_THREAD_LOCAL_VARIABLES, 295292934Sdim typeThunkTLV), 296292934Sdim ENTRY("__DATA", "__thread_data", S_THREAD_LOCAL_REGULAR, 297292934Sdim typeTLVInitialData), 298292934Sdim ENTRY("__DATA", "__thread_ptrs", S_THREAD_LOCAL_VARIABLE_POINTERS, 299292934Sdim typeTLVInitializerPtr), 300292934Sdim ENTRY("__DATA", "__thread_bss", S_THREAD_LOCAL_ZEROFILL, 301292934Sdim typeTLVInitialZeroFill), 302280461Sdim ENTRY("__DATA", "__bss", S_ZEROFILL, typeZeroFill), 303280461Sdim ENTRY("__DATA", "__interposing", S_INTERPOSING, typeInterposingTuples), 304280461Sdim}; 305280461Sdim#undef ENTRY 306280461Sdim 307280461SdimSectionInfo *Util::getFinalSection(DefinedAtom::ContentType atomType) { 308280461Sdim for (auto &p : sectsToAtomType) { 309280461Sdim if (p.atomType != atomType) 310280461Sdim continue; 311280461Sdim SectionAttr sectionAttrs = 0; 312280461Sdim switch (atomType) { 313303239Sdim case DefinedAtom::typeMachHeader: 314280461Sdim case DefinedAtom::typeCode: 315280461Sdim case DefinedAtom::typeStub: 316280461Sdim case DefinedAtom::typeStubHelper: 317303239Sdim sectionAttrs = S_ATTR_PURE_INSTRUCTIONS | S_ATTR_SOME_INSTRUCTIONS; 318280461Sdim break; 319292934Sdim case DefinedAtom::typeThunkTLV: 320292934Sdim _hasTLVDescriptors = true; 321292934Sdim break; 322280461Sdim default: 323280461Sdim break; 324280461Sdim } 325280461Sdim // If we already have a SectionInfo with this name, re-use it. 326280461Sdim // This can happen if two ContentType map to the same mach-o section. 327280461Sdim for (auto sect : _sectionMap) { 328280461Sdim if (sect.second->sectionName.equals(p.sectionName) && 329280461Sdim sect.second->segmentName.equals(p.segmentName)) { 330280461Sdim return sect.second; 331280461Sdim } 332280461Sdim } 333280461Sdim // Otherwise allocate new SectionInfo object. 334292934Sdim auto *sect = new (_allocator) SectionInfo( 335293846Sdim p.segmentName, p.sectionName, p.sectionType, _ctx, sectionAttrs, 336293846Sdim /* relocsToDefinedCanBeImplicit */ false); 337280461Sdim _sectionInfos.push_back(sect); 338280461Sdim _sectionMap[atomType] = sect; 339280461Sdim return sect; 340280461Sdim } 341280461Sdim llvm_unreachable("content type not yet supported"); 342280461Sdim} 343280461Sdim 344280461SdimSectionInfo *Util::sectionForAtom(const DefinedAtom *atom) { 345280461Sdim if (atom->sectionChoice() == DefinedAtom::sectionBasedOnContent) { 346280461Sdim // Section for this atom is derived from content type. 347280461Sdim DefinedAtom::ContentType type = atom->contentType(); 348280461Sdim auto pos = _sectionMap.find(type); 349280461Sdim if ( pos != _sectionMap.end() ) 350280461Sdim return pos->second; 351292934Sdim bool rMode = (_ctx.outputMachOType() == llvm::MachO::MH_OBJECT); 352280461Sdim return rMode ? getRelocatableSection(type) : getFinalSection(type); 353280461Sdim } else { 354280461Sdim // This atom needs to be in a custom section. 355280461Sdim StringRef customName = atom->customSectionName(); 356280461Sdim // Look to see if we have already allocated the needed custom section. 357280461Sdim for(SectionInfo *sect : _customSections) { 358280461Sdim const DefinedAtom *firstAtom = sect->atomsAndOffsets.front().atom; 359280461Sdim if (firstAtom->customSectionName().equals(customName)) { 360280461Sdim return sect; 361280461Sdim } 362280461Sdim } 363280461Sdim // Not found, so need to create a new custom section. 364280461Sdim size_t seperatorIndex = customName.find('/'); 365280461Sdim assert(seperatorIndex != StringRef::npos); 366280461Sdim StringRef segName = customName.slice(0, seperatorIndex); 367280461Sdim StringRef sectName = customName.drop_front(seperatorIndex + 1); 368292934Sdim auto *sect = 369293846Sdim new (_allocator) SectionInfo(segName, sectName, S_REGULAR, _ctx, 370293846Sdim 0, /* relocsToDefinedCanBeImplicit */ false); 371280461Sdim _customSections.push_back(sect); 372280461Sdim _sectionInfos.push_back(sect); 373280461Sdim return sect; 374280461Sdim } 375280461Sdim} 376280461Sdim 377280461Sdimvoid Util::appendAtom(SectionInfo *sect, const DefinedAtom *atom) { 378280461Sdim // Figure out offset for atom in this section given alignment constraints. 379280461Sdim uint64_t offset = sect->size; 380280461Sdim DefinedAtom::Alignment atomAlign = atom->alignment(); 381292934Sdim uint64_t align = atomAlign.value; 382280461Sdim uint64_t requiredModulus = atomAlign.modulus; 383292934Sdim uint64_t currentModulus = (offset % align); 384280461Sdim if ( currentModulus != requiredModulus ) { 385280461Sdim if ( requiredModulus > currentModulus ) 386280461Sdim offset += requiredModulus-currentModulus; 387280461Sdim else 388292934Sdim offset += align+requiredModulus-currentModulus; 389280461Sdim } 390280461Sdim // Record max alignment of any atom in this section. 391292934Sdim if (align > sect->alignment) 392292934Sdim sect->alignment = atomAlign.value; 393280461Sdim // Assign atom to this section with this offset. 394280461Sdim AtomInfo ai = {atom, offset}; 395280461Sdim sect->atomsAndOffsets.push_back(ai); 396280461Sdim // Update section size to include this atom. 397280461Sdim sect->size = offset + atom->size(); 398280461Sdim} 399280461Sdim 400303239Sdimvoid Util::processDefinedAtoms(const lld::File &atomFile) { 401280461Sdim for (const DefinedAtom *atom : atomFile.defined()) { 402303239Sdim processAtomAttributes(atom); 403303239Sdim assignAtomToSection(atom); 404303239Sdim } 405303239Sdim} 406303239Sdim 407303239Sdimvoid Util::processAtomAttributes(const DefinedAtom *atom) { 408303239Sdim if (auto *machoFile = dyn_cast<mach_o::MachOFile>(&atom->file())) { 409303239Sdim // If the file doesn't use subsections via symbols, then make sure we don't 410303239Sdim // add that flag to the final output file if we have a relocatable file. 411303239Sdim if (!machoFile->subsectionsViaSymbols()) 412303239Sdim _subsectionsViaSymbols = false; 413303239Sdim 414303239Sdim // All the source files must have min versions for us to output an object 415303239Sdim // file with a min version. 416303239Sdim if (auto v = machoFile->minVersion()) 417303239Sdim _minVersion = std::max(_minVersion, v); 418280461Sdim else 419303239Sdim _allSourceFilesHaveMinVersions = false; 420303239Sdim 421303239Sdim // If we don't have a platform load command, but one of the source files 422303239Sdim // does, then take the one from the file. 423303239Sdim if (!_minVersionCommandType) 424303239Sdim if (auto v = machoFile->minVersionLoadCommandKind()) 425303239Sdim _minVersionCommandType = v; 426280461Sdim } 427280461Sdim} 428280461Sdim 429303239Sdimvoid Util::assignAtomToSection(const DefinedAtom *atom) { 430303239Sdim if (atom->contentType() == DefinedAtom::typeMachHeader) { 431303239Sdim _machHeaderAliasAtoms.push_back(atom); 432303239Sdim // Assign atom to this section with this offset. 433303239Sdim AtomInfo ai = {atom, 0}; 434303239Sdim sectionForAtom(atom)->atomsAndOffsets.push_back(ai); 435303239Sdim } else if (atom->contentType() == DefinedAtom::typeDSOHandle) 436303239Sdim _machHeaderAliasAtoms.push_back(atom); 437303239Sdim else 438303239Sdim appendAtom(sectionForAtom(atom), atom); 439303239Sdim} 440303239Sdim 441280461SdimSegmentInfo *Util::segmentForName(StringRef segName) { 442280461Sdim for (SegmentInfo *si : _segmentInfos) { 443280461Sdim if ( si->name.equals(segName) ) 444280461Sdim return si; 445280461Sdim } 446292934Sdim auto *info = new (_allocator) SegmentInfo(segName); 447303239Sdim 448303239Sdim // Set the initial segment protection. 449280461Sdim if (segName.equals("__TEXT")) 450303239Sdim info->init_access = VM_PROT_READ | VM_PROT_EXECUTE; 451280461Sdim else if (segName.equals("__PAGEZERO")) 452303239Sdim info->init_access = 0; 453303239Sdim else if (segName.equals("__LINKEDIT")) 454303239Sdim info->init_access = VM_PROT_READ; 455303239Sdim else { 456303239Sdim // All others default to read-write 457303239Sdim info->init_access = VM_PROT_READ | VM_PROT_WRITE; 458303239Sdim } 459303239Sdim 460303239Sdim // Set max segment protection 461303239Sdim // Note, its overkill to use a switch statement here, but makes it so much 462303239Sdim // easier to use switch coverage to catch new cases. 463303239Sdim switch (_ctx.os()) { 464303239Sdim case lld::MachOLinkingContext::OS::unknown: 465303239Sdim case lld::MachOLinkingContext::OS::macOSX: 466303239Sdim case lld::MachOLinkingContext::OS::iOS_simulator: 467303239Sdim if (segName.equals("__PAGEZERO")) { 468303239Sdim info->max_access = 0; 469303239Sdim break; 470303239Sdim } 471303239Sdim // All others default to all 472303239Sdim info->max_access = VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE; 473303239Sdim break; 474303239Sdim case lld::MachOLinkingContext::OS::iOS: 475303239Sdim // iPhoneOS always uses same protection for max and initial 476303239Sdim info->max_access = info->init_access; 477303239Sdim break; 478303239Sdim } 479280461Sdim _segmentInfos.push_back(info); 480280461Sdim return info; 481280461Sdim} 482280461Sdim 483280461Sdimunsigned Util::SegmentSorter::weight(const SegmentInfo *seg) { 484280461Sdim return llvm::StringSwitch<unsigned>(seg->name) 485280461Sdim .Case("__PAGEZERO", 1) 486280461Sdim .Case("__TEXT", 2) 487280461Sdim .Case("__DATA", 3) 488280461Sdim .Default(100); 489280461Sdim} 490280461Sdim 491280461Sdimbool Util::SegmentSorter::operator()(const SegmentInfo *left, 492280461Sdim const SegmentInfo *right) { 493280461Sdim return (weight(left) < weight(right)); 494280461Sdim} 495280461Sdim 496280461Sdimunsigned Util::TextSectionSorter::weight(const SectionInfo *sect) { 497280461Sdim return llvm::StringSwitch<unsigned>(sect->sectionName) 498280461Sdim .Case("__text", 1) 499280461Sdim .Case("__stubs", 2) 500280461Sdim .Case("__stub_helper", 3) 501280461Sdim .Case("__const", 4) 502280461Sdim .Case("__cstring", 5) 503280461Sdim .Case("__unwind_info", 98) 504280461Sdim .Case("__eh_frame", 99) 505280461Sdim .Default(10); 506280461Sdim} 507280461Sdim 508280461Sdimbool Util::TextSectionSorter::operator()(const SectionInfo *left, 509280461Sdim const SectionInfo *right) { 510280461Sdim return (weight(left) < weight(right)); 511280461Sdim} 512280461Sdim 513280461Sdimvoid Util::organizeSections() { 514293258Sdim // NOTE!: Keep this in sync with assignAddressesToSections. 515293258Sdim switch (_ctx.outputMachOType()) { 516280461Sdim case llvm::MachO::MH_EXECUTE: 517280461Sdim // Main executables, need a zero-page segment 518280461Sdim segmentForName("__PAGEZERO"); 519280461Sdim // Fall into next case. 520321369Sdim LLVM_FALLTHROUGH; 521280461Sdim case llvm::MachO::MH_DYLIB: 522280461Sdim case llvm::MachO::MH_BUNDLE: 523280461Sdim // All dynamic code needs TEXT segment to hold the load commands. 524280461Sdim segmentForName("__TEXT"); 525280461Sdim break; 526280461Sdim default: 527280461Sdim break; 528293258Sdim } 529303239Sdim segmentForName("__LINKEDIT"); 530303239Sdim 531293258Sdim // Group sections into segments. 532293258Sdim for (SectionInfo *si : _sectionInfos) { 533293258Sdim SegmentInfo *seg = segmentForName(si->segmentName); 534293258Sdim seg->sections.push_back(si); 535293258Sdim } 536293258Sdim // Sort segments. 537293258Sdim std::sort(_segmentInfos.begin(), _segmentInfos.end(), SegmentSorter()); 538280461Sdim 539293258Sdim // Sort sections within segments. 540293258Sdim for (SegmentInfo *seg : _segmentInfos) { 541293258Sdim if (seg->name.equals("__TEXT")) { 542293258Sdim std::sort(seg->sections.begin(), seg->sections.end(), 543293258Sdim TextSectionSorter()); 544280461Sdim } 545293258Sdim } 546280461Sdim 547293258Sdim // Record final section indexes. 548293258Sdim uint32_t segmentIndex = 0; 549293258Sdim uint32_t sectionIndex = 1; 550293258Sdim for (SegmentInfo *seg : _segmentInfos) { 551293258Sdim seg->normalizedSegmentIndex = segmentIndex++; 552293258Sdim for (SectionInfo *sect : seg->sections) 553293258Sdim sect->finalSectionIndex = sectionIndex++; 554280461Sdim } 555280461Sdim} 556280461Sdim 557280461Sdimvoid Util::layoutSectionsInSegment(SegmentInfo *seg, uint64_t &addr) { 558280461Sdim seg->address = addr; 559280461Sdim for (SectionInfo *sect : seg->sections) { 560303239Sdim sect->address = llvm::alignTo(addr, sect->alignment); 561280461Sdim addr = sect->address + sect->size; 562280461Sdim } 563303239Sdim seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize()); 564280461Sdim} 565280461Sdim 566280461Sdim// __TEXT segment lays out backwards so padding is at front after load commands. 567280461Sdimvoid Util::layoutSectionsInTextSegment(size_t hlcSize, SegmentInfo *seg, 568280461Sdim uint64_t &addr) { 569280461Sdim seg->address = addr; 570280461Sdim // Walks sections starting at end to calculate padding for start. 571280461Sdim int64_t taddr = 0; 572280461Sdim for (auto it = seg->sections.rbegin(); it != seg->sections.rend(); ++it) { 573280461Sdim SectionInfo *sect = *it; 574280461Sdim taddr -= sect->size; 575292934Sdim taddr = taddr & (0 - sect->alignment); 576280461Sdim } 577280461Sdim int64_t padding = taddr - hlcSize; 578280461Sdim while (padding < 0) 579292934Sdim padding += _ctx.pageSize(); 580280461Sdim // Start assigning section address starting at padded offset. 581280461Sdim addr += (padding + hlcSize); 582280461Sdim for (SectionInfo *sect : seg->sections) { 583303239Sdim sect->address = llvm::alignTo(addr, sect->alignment); 584280461Sdim addr = sect->address + sect->size; 585280461Sdim } 586303239Sdim seg->size = llvm::alignTo(addr - seg->address, _ctx.pageSize()); 587280461Sdim} 588280461Sdim 589280461Sdimvoid Util::assignAddressesToSections(const NormalizedFile &file) { 590293258Sdim // NOTE!: Keep this in sync with organizeSections. 591280461Sdim size_t hlcSize = headerAndLoadCommandsSize(file); 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) { 1494326909Sdim for (const auto &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