+ char* buf;
+ asprintf(&buf, "%s$stub", name);
+ return buf;
+}
+
+template <>
+uint64_t StubAtom<ppc>::getSize() const
+{
+ return ( pic() ? 32 : 16 );
+}
+
+template <>
+uint64_t StubAtom<ppc64>::getSize() const
+{
+ return ( pic() ? 32 : 16 );
+}
+
+
+template <>
+uint64_t StubAtom<arm>::getSize() const
+{
+ return ( pic() ? 16 : 12 );
+}
+
+template <>
+uint64_t StubAtom<x86>::getSize() const
+{
+ if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
+ if ( pic() )
+ return 20;
+ else
+ return 16;
+ }
+ return 5;
+}
+
+template <>
+uint64_t StubAtom<x86_64>::getSize() const
+{
+ return 6;
+}
+
+template <>
+ObjectFile::Alignment StubAtom<x86>::getAlignment() const
+{
+ if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib )
+ return 2;
+ else
+ return 0; // special case x86 fast stubs to be byte aligned
+}
+
+template <>
+void StubAtom<ppc64>::copyRawContent(uint8_t buffer[]) const
+{
+ if ( pic() ) {
+ OSWriteBigInt32(&buffer [0], 0, 0x7c0802a6); // mflr r0
+ OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
+ OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
+ OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
+ OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
+ OSWriteBigInt32(&buffer[20], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
+ OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
+ OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
+ }
+ else {
+ OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
+ OSWriteBigInt32(&buffer[ 4], 0, 0xe98b0001); // ldu r12,lo16(L_fwrite$lazy_ptr)(r11)
+ OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
+ OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
+ }
+}
+
+template <>
+void StubAtom<ppc>::copyRawContent(uint8_t buffer[]) const
+{
+ if ( pic() ) {
+ OSWriteBigInt32(&buffer[ 0], 0, 0x7c0802a6); // mflr r0
+ OSWriteBigInt32(&buffer[ 4], 0, 0x429f0005); // bcl 20,31,Lpicbase
+ OSWriteBigInt32(&buffer[ 8], 0, 0x7d6802a6); // Lpicbase: mflr r11
+ OSWriteBigInt32(&buffer[12], 0, 0x3d6b0000); // addis r11,r11,ha16(L_fwrite$lazy_ptr-Lpicbase)
+ OSWriteBigInt32(&buffer[16], 0, 0x7c0803a6); // mtlr r0
+ OSWriteBigInt32(&buffer[20], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr-Lpicbase)(r11)
+ OSWriteBigInt32(&buffer[24], 0, 0x7d8903a6); // mtctr r12
+ OSWriteBigInt32(&buffer[28], 0, 0x4e800420); // bctr
+ }
+ else {
+ OSWriteBigInt32(&buffer[ 0], 0, 0x3d600000); // lis r11,ha16(L_fwrite$lazy_ptr)
+ OSWriteBigInt32(&buffer[ 4], 0, 0x858b0000); // lwzu r12,lo16(L_fwrite$lazy_ptr)(r11)
+ OSWriteBigInt32(&buffer[ 8], 0, 0x7d8903a6); // mtctr r12
+ OSWriteBigInt32(&buffer[12], 0, 0x4e800420); // bctr
+ }
+}
+
+template <>
+void StubAtom<x86>::copyRawContent(uint8_t buffer[]) const
+{
+ if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
+ if ( pic() ) {
+ buffer[0] = 0xE8; // call picbase
+ buffer[1] = 0x00;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x58; // pop eax
+ buffer[6] = 0x8D; // lea foo$lazy_pointer-picbase(eax),eax
+ buffer[7] = 0x80;
+ buffer[8] = 0x00;
+ buffer[9] = 0x00;
+ buffer[10] = 0x00;
+ buffer[11] = 0x00;
+ buffer[12] = 0xFF; // jmp *(eax)
+ buffer[13] = 0x20;
+ buffer[14] = 0x50; // push eax
+ buffer[15] = 0xE9; // jump dyld_stub_binding_helper
+ buffer[16] = 0x00;
+ buffer[17] = 0x00;
+ buffer[18] = 0x00;
+ buffer[19] = 0x00;
+ }
+ else {
+ buffer[0] = 0xFF; // jmp *foo$lazy_pointer
+ buffer[1] = 0x25;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+ buffer[6] = 0x68; // pushl $foo$lazy_pointer
+ buffer[7] = 0x00;
+ buffer[8] = 0x00;
+ buffer[9] = 0x00;
+ buffer[10] = 0x00;
+ buffer[11] = 0xE9; // jump dyld_stub_binding_helper
+ buffer[12] = 0x00;
+ buffer[13] = 0x00;
+ buffer[14] = 0x00;
+ buffer[15] = 0x00;
+ }
+ }
+ else {
+ if ( fWriter.fOptions.prebind() ) {
+ uint32_t address = this->getAddress();
+ int32_t rel32 = 0 - (address+5);
+ buffer[0] = 0xE9;
+ buffer[1] = rel32 & 0xFF;
+ buffer[2] = (rel32 >> 8) & 0xFF;
+ buffer[3] = (rel32 >> 16) & 0xFF;
+ buffer[4] = (rel32 >> 24) & 0xFF;
+ }
+ else {
+ buffer[0] = 0xF4;
+ buffer[1] = 0xF4;
+ buffer[2] = 0xF4;
+ buffer[3] = 0xF4;
+ buffer[4] = 0xF4;
+ }
+ }
+}
+
+template <>
+void StubAtom<x86_64>::copyRawContent(uint8_t buffer[]) const
+{
+ buffer[0] = 0xFF; // jmp *foo$lazy_pointer(%rip)
+ buffer[1] = 0x25;
+ buffer[2] = 0x00;
+ buffer[3] = 0x00;
+ buffer[4] = 0x00;
+ buffer[5] = 0x00;
+}
+
+template <>
+void StubAtom<arm>::copyRawContent(uint8_t buffer[]) const
+{
+ if ( pic() ) {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc004); // ldr ip, pc + 12
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe08fc00c); // add ip, pc, ip
+ OSWriteLittleInt32(&buffer[ 8], 0, 0xe59cf000); // ldr pc, [ip]
+ OSWriteLittleInt32(&buffer[12], 0, 0x00000000); // .long L_foo$lazy_ptr - (L1$scv + 8)
+ }
+ else {
+ OSWriteLittleInt32(&buffer[ 0], 0, 0xe59fc000); // ldr ip, [pc, #0]
+ OSWriteLittleInt32(&buffer[ 4], 0, 0xe59cf000); // ldr pc, [ip]
+ OSWriteLittleInt32(&buffer[ 8], 0, 0x00000000); // .long L_foo$lazy_ptr
+ }
+}
+
+// x86_64 stubs are 7 bytes and need no alignment
+template <>
+ObjectFile::Alignment StubAtom<x86_64>::getAlignment() const
+{
+ return 0;
+}
+
+template <>
+const char* StubAtom<ppc>::getSectionName() const
+{
+ return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
+}
+
+template <>
+const char* StubAtom<ppc64>::getSectionName() const
+{
+ return ( pic() ? "__picsymbolstub1" : "__symbol_stub1");
+}
+
+template <>
+const char* StubAtom<arm>::getSectionName() const
+{
+ return ( pic() ? "__picsymbolstub4" : "__symbol_stub4");
+}
+
+template <>
+const char* StubAtom<x86>::getSectionName() const
+{
+ if ( fWriter.fOptions.slowx86Stubs() || fForLazyDylib ) {
+ if ( pic() )
+ return "__picsymbol_stub";
+ else
+ return "__symbol_stub";
+ }
+ return "__jump_table";
+}
+
+
+
+
+struct AtomByNameSorter
+{
+ bool operator()(ObjectFile::Atom* left, ObjectFile::Atom* right)
+ {
+ return (strcmp(left->getName(), right->getName()) < 0);
+ }
+};
+
+template <typename P>
+struct ExternalRelocSorter
+{
+ bool operator()(const macho_relocation_info<P>& left, const macho_relocation_info<P>& right)
+ {
+ // sort first by symbol number
+ if ( left.r_symbolnum() != right.r_symbolnum() )
+ return (left.r_symbolnum() < right.r_symbolnum());
+ // then sort all uses of the same symbol by address
+ return (left.r_address() < right.r_address());
+ }
+};
+
+
+template <typename A>
+Writer<A>::Writer(const char* path, Options& options, std::vector<ExecutableFile::DyLibUsed>& dynamicLibraries)
+ : ExecutableFile::Writer(dynamicLibraries), fFilePath(strdup(path)), fOptions(options),
+ fAllAtoms(NULL), fStabs(NULL), fLoadCommandsSection(NULL),
+ fLoadCommandsSegment(NULL), fEncryptionLoadCommand(NULL), fSegmentCommands(NULL),
+ fSymbolTableCommands(NULL), fHeaderPadding(NULL),
+ fUUIDAtom(NULL), fPadSegmentInfo(NULL), fEntryPoint( NULL), fDyldHelper(NULL), fDyldLazyDylibHelper(NULL),
+ fSectionRelocationsAtom(NULL), fLocalRelocationsAtom(NULL), fExternalRelocationsAtom(NULL),
+ fSymbolTableAtom(NULL), fSplitCodeToDataContentAtom(NULL), fIndirectTableAtom(NULL), fModuleInfoAtom(NULL),
+ fStringsAtom(NULL), fPageZeroAtom(NULL), fSymbolTable(NULL), fSymbolTableCount(0), fSymbolTableStabsCount(0),
+ fSymbolTableLocalCount(0), fSymbolTableExportCount(0), fSymbolTableImportCount(0),
+ fLargestAtomSize(1),
+ fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
+ fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false),
+ fBiggerThanTwoGigs(false), fSlideable(false),
+ fFirstWritableSegment(NULL), fAnonNameIndex(1000)
+{
+ switch ( fOptions.outputKind() ) {
+ case Options::kDynamicExecutable:
+ case Options::kStaticExecutable:
+ if ( fOptions.zeroPageSize() != 0 )
+ fWriterSynthesizedAtoms.push_back(fPageZeroAtom = new PageZeroAtom<A>(*this));
+ if ( fOptions.outputKind() == Options::kDynamicExecutable )
+ fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
+ if ( fOptions.outputKind() == Options::kDynamicExecutable )
+ fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
+ if ( fOptions.hasCustomStack() )
+ fWriterSynthesizedAtoms.push_back(new CustomStackAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
+ break;
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+ // fall through
+ case Options::kObjectFile:
+ fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
+ if ( fOptions.outputKind() == Options::kDynamicLibrary ) {
+ fWriterSynthesizedAtoms.push_back(new DylibIDLoadCommandsAtom<A>(*this));
+ if ( fOptions.initFunctionName() != NULL )
+ fWriterSynthesizedAtoms.push_back(new RoutinesLoadCommandsAtom<A>(*this));
+ }
+ fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
+ if ( fOptions.sharedRegionEligible() )
+ fWriterSynthesizedAtoms.push_back(new SegmentSplitInfoLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSectionRelocationsAtom = new SectionRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
+ if ( fOptions.sharedRegionEligible() ) {
+ fWriterSynthesizedAtoms.push_back(fSplitCodeToDataContentAtom = new SegmentSplitInfoContentAtom<A>(*this));
+ }
+ fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
+ if ( this->needsModuleTable() )
+ fWriterSynthesizedAtoms.push_back(fModuleInfoAtom = new ModuleInfoLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
+ break;
+ case Options::kDyld:
+ fWriterSynthesizedAtoms.push_back(new DsoHandleAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new MachHeaderAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SegmentLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new SymbolTableLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new DyldLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fUUIDAtom = new UUIDLoadCommandAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(new ThreadsLoadCommandsAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fHeaderPadding = new LoadCommandsPaddingAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fLocalRelocationsAtom = new LocalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fSymbolTableAtom = new SymbolTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fExternalRelocationsAtom = new ExternalRelocationsLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fIndirectTableAtom = new IndirectTableLinkEditAtom<A>(*this));
+ fWriterSynthesizedAtoms.push_back(fStringsAtom = new StringsLinkEditAtom<A>(*this));
+ break;
+ }
+
+ // add extra commmands
+ bool hasReExports = false;
+ uint32_t ordinal = 1;
+ switch ( fOptions.outputKind() ) {
+ case Options::kDynamicExecutable:
+ if ( fOptions.makeEncryptable() ) {
+ fEncryptionLoadCommand = new EncryptionLoadCommandsAtom<A>(*this);
+ fWriterSynthesizedAtoms.push_back(fEncryptionLoadCommand);
+ }
+ // fall through
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ {
+ // add dylib load command atoms for all dynamic libraries
+ const unsigned int libCount = dynamicLibraries.size();
+ for (unsigned int i=0; i < libCount; ++i) {
+ ExecutableFile::DyLibUsed& dylibInfo = dynamicLibraries[i];
+ //fprintf(stderr, "dynamicLibraries[%d]: reader=%p, %s, install=%s\n", i, dylibInfo.reader, dylibInfo.reader->getPath(), dylibInfo.reader->getInstallPath() );
+
+ if ( dylibInfo.options.fReExport ) {
+ hasReExports = true;
+ }
+ else {
+ const char* parentUmbrella = dylibInfo.reader->parentUmbrella();
+ if ( (parentUmbrella != NULL) && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
+ const char* thisIDLastSlash = strrchr(fOptions.installPath(), '/');
+ if ( (thisIDLastSlash != NULL) && (strcmp(&thisIDLastSlash[1], parentUmbrella) == 0) )
+ hasReExports = true;
+ }
+ }
+
+ if ( dylibInfo.options.fBundleLoader ) {
+ fLibraryToOrdinal[dylibInfo.reader] = EXECUTABLE_ORDINAL;
+ }
+ else {
+ // see if a DylibLoadCommandsAtom has already been created for this install path
+ bool newDylib = true;
+ const char* dylibInstallPath = dylibInfo.reader->getInstallPath();
+ for (unsigned int seenLib=0; seenLib < i; ++seenLib) {
+ ExecutableFile::DyLibUsed& seenDylibInfo = dynamicLibraries[seenLib];
+ if ( !seenDylibInfo.options.fBundleLoader ) {
+ const char* seenDylibInstallPath = seenDylibInfo.reader->getInstallPath();
+ if ( strcmp(seenDylibInstallPath, dylibInstallPath) == 0 ) {
+ fLibraryToOrdinal[dylibInfo.reader] = fLibraryToOrdinal[seenDylibInfo.reader];
+ fLibraryToLoadCommand[dylibInfo.reader] = fLibraryToLoadCommand[seenDylibInfo.reader];
+ fLibraryAliases[dylibInfo.reader] = seenDylibInfo.reader;
+ newDylib = false;
+ break;
+ }
+ }
+ }
+
+ if ( newDylib ) {
+ // assign new ordinal and check for other paired load commands
+ fLibraryToOrdinal[dylibInfo.reader] = ordinal++;
+ DylibLoadCommandsAtom<A>* dyliblc = new DylibLoadCommandsAtom<A>(*this, dylibInfo);
+ fLibraryToLoadCommand[dylibInfo.reader] = dyliblc;
+ fWriterSynthesizedAtoms.push_back(dyliblc);
+ if ( dylibInfo.options.fReExport
+ && (fOptions.macosxVersionMin() < ObjectFile::ReaderOptions::k10_5)
+ && (fOptions.outputKind() == Options::kDynamicLibrary) ) {
+ // see if child has sub-framework that is this
+ bool isSubFramework = false;
+ const char* childInUmbrella = dylibInfo.reader->parentUmbrella();
+ if ( childInUmbrella != NULL ) {
+ const char* myLeaf = strrchr(fOptions.installPath(), '/');
+ if ( myLeaf != NULL ) {
+ if ( strcmp(childInUmbrella, &myLeaf[1]) == 0 )
+ isSubFramework = true;
+ }
+ }
+ // LC_SUB_FRAMEWORK is in child, so do nothing in parent
+ if ( ! isSubFramework ) {
+ // this dylib also needs a sub_x load command
+ bool isFrameworkReExport = false;
+ const char* lastSlash = strrchr(dylibInstallPath, '/');
+ if ( lastSlash != NULL ) {
+ char frameworkName[strlen(lastSlash)+20];
+ sprintf(frameworkName, "/%s.framework/", &lastSlash[1]);
+ isFrameworkReExport = (strstr(dylibInstallPath, frameworkName) != NULL);
+ }
+ if ( isFrameworkReExport ) {
+ // needs a LC_SUB_UMBRELLA command
+ fWriterSynthesizedAtoms.push_back(new SubUmbrellaLoadCommandsAtom<A>(*this, &lastSlash[1]));
+ }
+ else {
+ // needs a LC_SUB_LIBRARY command
+ const char* nameStart = &lastSlash[1];
+ if ( lastSlash == NULL )
+ nameStart = dylibInstallPath;
+ int len = strlen(nameStart);
+ const char* dot = strchr(nameStart, '.');
+ if ( dot != NULL )
+ len = dot - nameStart;
+ fWriterSynthesizedAtoms.push_back(new SubLibraryLoadCommandsAtom<A>(*this, nameStart, len));
+ }
+ }
+ }
+ }
+ }
+ }
+ // add umbrella command if needed
+ if ( fOptions.umbrellaName() != NULL ) {
+ fWriterSynthesizedAtoms.push_back(new UmbrellaLoadCommandsAtom<A>(*this, fOptions.umbrellaName()));
+ }
+ // add allowable client commands if used
+ std::vector<const char*>& allowableClients = fOptions.allowableClients();
+ for (std::vector<const char*>::iterator it=allowableClients.begin(); it != allowableClients.end(); ++it)
+ fWriterSynthesizedAtoms.push_back(new AllowableClientLoadCommandsAtom<A>(*this, *it));
+ }
+ break;
+ case Options::kStaticExecutable:
+ case Options::kObjectFile:
+ case Options::kDyld:
+ break;
+ }
+ fNoReExportedDylibs = !hasReExports;
+
+ // add any rpath load commands
+ for(std::vector<const char*>::const_iterator it=fOptions.rpaths().begin(); it != fOptions.rpaths().end(); ++it) {
+ fWriterSynthesizedAtoms.push_back(new RPathLoadCommandsAtom<A>(*this, *it));
+ }
+
+ // set up fSlideable
+ switch ( fOptions.outputKind() ) {
+ case Options::kObjectFile:
+ case Options::kStaticExecutable:
+ fSlideable = false;
+ break;
+ case Options::kDynamicExecutable:
+ fSlideable = fOptions.positionIndependentExecutable();
+ break;
+ case Options::kDyld:
+ case Options::kDynamicLibrary:
+ case Options::kDynamicBundle:
+ fSlideable = true;
+ break;
+ }
+
+ //fprintf(stderr, "ordinals table:\n");
+ //for (std::map<class ObjectFile::Reader*, uint32_t>::iterator it = fLibraryToOrdinal.begin(); it != fLibraryToOrdinal.end(); ++it) {
+ // fprintf(stderr, "%d <== %s\n", it->second, it->first->getPath());
+ //}
+}
+
+template <typename A>
+Writer<A>::~Writer()
+{
+ if ( fFilePath != NULL )
+ free((void*)fFilePath);
+ if ( fSymbolTable != NULL )
+ delete [] fSymbolTable;
+}
+
+
+// for ppc64, -mdynamic-no-pic only works in low 2GB, so we might need to split the zeropage into two segments
+template <>bool Writer<ppc64>::mightNeedPadSegment() { return (fOptions.zeroPageSize() >= 0x80000000ULL); }
+template <typename A> bool Writer<A>::mightNeedPadSegment() { return false; }
+
+
+template <typename A>
+ObjectFile::Atom* Writer<A>::getUndefinedProxyAtom(const char* name)
+{
+ if ( fOptions.outputKind() == Options::kObjectFile ) {
+ // when doing -r -exported_symbols_list, don't creat proxy for a symbol
+ // that is supposed to be exported. We want an error instead
+ // <rdar://problem/5062685> ld does not report error when -r is used and exported symbols are not defined.
+ if ( fOptions.hasExportRestrictList() && fOptions.shouldExport(name) )
+ return NULL;
+ else
+ return new UndefinedSymbolProxyAtom<A>(*this, name);
+ }
+ else if ( (fOptions.undefinedTreatment() != Options::kUndefinedError) || fOptions.allowedUndefined(name) )
+ return new UndefinedSymbolProxyAtom<A>(*this, name);
+ else
+ return NULL;
+}
+
+template <typename A>
+uint8_t Writer<A>::ordinalForLibrary(ObjectFile::Reader* lib)
+{
+ // flat namespace images use zero for all ordinals
+ if ( fOptions.nameSpace() != Options::kTwoLevelNameSpace )
+ return 0;
+
+ // is an UndefinedSymbolProxyAtom
+ if ( lib == this )
+ if ( fOptions.nameSpace() == Options::kTwoLevelNameSpace )
+ return DYNAMIC_LOOKUP_ORDINAL;
+
+ std::map<class ObjectFile::Reader*, uint32_t>::iterator pos = fLibraryToOrdinal.find(lib);
+ if ( pos != fLibraryToOrdinal.end() )
+ return pos->second;
+
+ throw "can't find ordinal for imported symbol";
+}
+
+template <typename A>
+ObjectFile::Atom& Writer<A>::makeObjcInfoAtom(ObjectFile::Reader::ObjcConstraint objcContraint, bool objcReplacementClasses)
+{
+ return *(new ObjCInfoAtom<A>(*this, objcContraint, objcReplacementClasses));
+}
+
+
+template <typename A>
+uint64_t Writer<A>::write(std::vector<class ObjectFile::Atom*>& atoms,
+ std::vector<class ObjectFile::Reader::Stab>& stabs,
+ class ObjectFile::Atom* entryPointAtom, class ObjectFile::Atom* dyldHelperAtom,
+ class ObjectFile::Atom* dyldLazyDylibHelperAtom,
+ bool createUUID, bool canScatter, ObjectFile::Reader::CpuConstraint cpuConstraint,
+ bool biggerThanTwoGigs, bool overridesDylibWeakDefines)
+{
+ fAllAtoms = &atoms;
+ fStabs = &stabs;
+ fEntryPoint = entryPointAtom;
+ fDyldHelper = dyldHelperAtom;
+ fDyldLazyDylibHelper = dyldLazyDylibHelperAtom;
+ fCanScatter = canScatter;
+ fCpuConstraint = cpuConstraint;
+ fBiggerThanTwoGigs = biggerThanTwoGigs;
+ fHasWeakExports = overridesDylibWeakDefines; // dyld needs to search this image as if it had weak exports
+
+ try {
+ // Set for create UUID
+ if (createUUID)
+ fUUIDAtom->generate();
+
+ // remove uneeded dylib load commands
+ optimizeDylibReferences();
+
+ // check for mdynamic-no-pic codegen
+ scanForAbsoluteReferences();
+
+ // create inter-library stubs
+ synthesizeStubs();
+
+ // create SegmentInfo and SectionInfo objects and assign all atoms to a section
+ partitionIntoSections();
+
+ // segment load command can now be sized and padding can be set
+ adjustLoadCommandsAndPadding();
+
+ // assign each section a file offset
+ assignFileOffsets();
+
+ // if need to add branch islands, reassign file offsets
+ if ( addBranchIslands() )
+ assignFileOffsets();
+
+ // build symbol table and relocations
+ buildLinkEdit();
+
+ // write map file if requested
+ writeMap();
+
+ // write everything
+ return writeAtoms();
+ } catch (...) {
+ // clean up if any errors
+ (void)unlink(fFilePath);
+ throw;
+ }
+}
+
+template <typename A>
+void Writer<A>::buildLinkEdit()
+{
+ this->collectExportedAndImportedAndLocalAtoms();
+ this->buildSymbolTable();
+ this->buildFixups();
+ this->adjustLinkEditSections();
+}
+
+
+
+template <typename A>
+uint64_t Writer<A>::getAtomLoadAddress(const ObjectFile::Atom* atom)
+{
+ return atom->getAddress();
+// SectionInfo* info = (SectionInfo*)atom->getSection();
+// return info->getBaseAddress() + atom->getSectionOffset();
+}
+
+
+template <>
+const char* Writer<x86_64>::symbolTableName(const ObjectFile::Atom* atom)
+{
+ static unsigned int counter = 0;
+ const char* name = atom->getName();
+ if ( strncmp(name, "cstring=", 8) == 0 )
+ asprintf((char**)&name, "LC%u", counter++);
+ return name;
+}
+
+template <typename A>
+const char* Writer<A>::symbolTableName(const ObjectFile::Atom* atom)
+{
+ return atom->getName();
+}
+
+template <typename A>
+void Writer<A>::setExportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+ // set n_strx
+ entry->set_n_strx(this->fStringsAtom->add(this->symbolTableName(atom)));
+
+ // set n_type
+ if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAsAbsolute ) {
+ entry->set_n_type(N_EXT | N_ABS);
+ }
+ else {
+ entry->set_n_type(N_EXT | N_SECT);
+ if ( (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit) && (fOptions.outputKind() == Options::kObjectFile) ) {
+ if ( fOptions.keepPrivateExterns() )
+ entry->set_n_type(N_EXT | N_SECT | N_PEXT);
+ }
+ }
+
+ // set n_sect (section number of implementation )
+ uint8_t sectionIndex = atom->getSection()->getIndex();
+ entry->set_n_sect(sectionIndex);
+
+ // the __mh_execute_header is magic and must be an absolute symbol
+ if ( (sectionIndex==0)
+ && (fOptions.outputKind() == Options::kDynamicExecutable)
+ && (atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip ))
+ entry->set_n_type(N_EXT | N_ABS);
+
+ // set n_desc
+ uint16_t desc = 0;
+ if ( atom->isThumb() )
+ desc |= N_ARM_THUMB_DEF;
+ if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
+ desc |= REFERENCED_DYNAMICALLY;
+ if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition ) {
+ desc |= N_WEAK_DEF;
+ fHasWeakExports = true;
+ }
+ entry->set_n_desc(desc);
+
+ // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+ if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
+ entry->set_n_value(atom->getSectionOffset());
+ else
+ entry->set_n_value(this->getAtomLoadAddress(atom));
+}
+
+template <typename A>
+void Writer<A>::setImportNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+ // set n_strx
+ entry->set_n_strx(this->fStringsAtom->add(atom->getName()));
+
+ // set n_type
+ if ( (fOptions.outputKind() == Options::kObjectFile)
+ && (atom->getScope() == ObjectFile::Atom::scopeLinkageUnit)
+ && (atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition) )
+ entry->set_n_type(N_UNDF | N_EXT | N_PEXT);
+ else if ( fOptions.prebind() )
+ entry->set_n_type(N_PBUD | N_EXT);
+ else
+ entry->set_n_type(N_UNDF | N_EXT);
+
+ // set n_sect
+ entry->set_n_sect(0);
+
+ uint16_t desc = 0;
+ if ( fOptions.outputKind() != Options::kObjectFile ) {
+ // set n_desc ( high byte is library ordinal, low byte is reference type )
+ std::map<const ObjectFile::Atom*,ObjectFile::Atom*>::iterator pos = fStubsMap.find(atom);
+ if ( pos != fStubsMap.end() || ( strncmp(atom->getName(), ".objc_class_name_", 17) == 0) )
+ desc = REFERENCE_FLAG_UNDEFINED_LAZY;
+ else
+ desc = REFERENCE_FLAG_UNDEFINED_NON_LAZY;
+ try {
+ uint8_t ordinal = this->ordinalForLibrary(atom->getFile());
+ //fprintf(stderr, "ordinal=%u from reader=%p for symbol=%s\n", ordinal, atom->getFile(), atom->getName());
+ SET_LIBRARY_ORDINAL(desc, ordinal);
+ }
+ catch (const char* msg) {
+ throwf("%s %s from %s", msg, atom->getDisplayName(), atom->getFile()->getPath());
+ }
+ }
+ else if ( atom->getDefinitionKind() == ObjectFile::Atom::kTentativeDefinition ) {
+ uint8_t align = atom->getAlignment().powerOf2;
+ // always record custom alignment of common symbols to match what compiler does
+ SET_COMM_ALIGN(desc, align);
+ }
+ if ( atom->isThumb() )
+ desc |= N_ARM_THUMB_DEF;
+ if ( atom->getSymbolTableInclusion() == ObjectFile::Atom::kSymbolTableInAndNeverStrip )
+ desc |= REFERENCED_DYNAMICALLY;
+ if ( ( fOptions.outputKind() != Options::kObjectFile) && (atom->getDefinitionKind() == ObjectFile::Atom::kExternalWeakDefinition) ) {
+ desc |= N_REF_TO_WEAK;
+ fReferencesWeakImports = true;
+ }
+ // set weak_import attribute
+ if ( fWeakImportMap[atom] )
+ desc |= N_WEAK_REF;
+ entry->set_n_desc(desc);
+
+ // set n_value, zero for import proxy and size for tentative definition
+ entry->set_n_value(atom->getSize());
+}
+
+
+template <typename A>
+void Writer<A>::setLocalNlist(const ObjectFile::Atom* atom, macho_nlist<P>* entry)
+{
+ // set n_strx
+ const char* symbolName = this->symbolTableName(atom);
+ char anonName[32];
+ if ( (fOptions.outputKind() == Options::kObjectFile) && !fOptions.keepLocalSymbol(symbolName) ) {
+ sprintf(anonName, "l%u", fAnonNameIndex++);
+ symbolName = anonName;
+ }
+ entry->set_n_strx(this->fStringsAtom->add(symbolName));
+
+ // set n_type
+ uint8_t type = N_SECT;
+ if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
+ type = N_ABS;
+ if ( atom->getScope() == ObjectFile::Atom::scopeLinkageUnit )
+ type |= N_PEXT;
+ entry->set_n_type(type);
+
+ // set n_sect (section number of implementation )
+ uint8_t sectIndex = atom->getSection()->getIndex();
+ if ( sectIndex == 0 ) {
+ // see <mach-o/ldsyms.h> synthesized lable for mach_header needs special section number...
+ if ( strcmp(atom->getSectionName(), "._mach_header") == 0 )
+ sectIndex = 1;
+ }
+ entry->set_n_sect(sectIndex);
+
+ // set n_desc
+ uint16_t desc = 0;
+ if ( atom->getDefinitionKind() == ObjectFile::Atom::kWeakDefinition )
+ desc |= N_WEAK_DEF;
+ if ( atom->isThumb() )
+ desc |= N_ARM_THUMB_DEF;
+ entry->set_n_desc(desc);
+
+ // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+ if ( atom->getDefinitionKind() == ObjectFile::Atom::kAbsoluteSymbol )
+ entry->set_n_value(atom->getSectionOffset());
+ else
+ entry->set_n_value(this->getAtomLoadAddress(atom));
+}
+
+
+template <typename A>
+void Writer<A>::addLocalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
+{
+ macho_nlist<P> entry;
+
+ // set n_strx
+ entry.set_n_strx(fStringsAtom->add(name));
+
+ // set n_type
+ entry.set_n_type(N_SECT);
+
+ // set n_sect (section number of implementation )
+ entry.set_n_sect(atom.getSection()->getIndex());
+
+ // set n_desc
+ entry.set_n_desc(0);
+
+ // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+ entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
+
+ // add
+ fLocalExtraLabels.push_back(entry);
+}
+
+
+
+template <typename A>
+void Writer<A>::addGlobalLabel(ObjectFile::Atom& atom, uint32_t offsetInAtom, const char* name)
+{
+ macho_nlist<P> entry;
+
+ // set n_strx
+ entry.set_n_strx(fStringsAtom->add(name));
+
+ // set n_type
+ entry.set_n_type(N_SECT|N_EXT);
+
+ // set n_sect (section number of implementation )
+ entry.set_n_sect(atom.getSection()->getIndex());
+
+ // set n_desc
+ entry.set_n_desc(0);
+
+ // set n_value ( address this symbol will be at if this executable is loaded at it preferred address )
+ entry.set_n_value(this->getAtomLoadAddress(&atom) + offsetInAtom);
+
+ // add
+ fGlobalExtraLabels.push_back(entry);
+}
+
+template <typename A>
+void Writer<A>::setNlistRange(std::vector<class ObjectFile::Atom*>& atoms, uint32_t startIndex, uint32_t count)
+{
+ macho_nlist<P>* entry = &fSymbolTable[startIndex];
+ for (uint32_t i=0; i < count; ++i, ++entry) {
+ ObjectFile::Atom* atom = atoms[i];
+ if ( &atoms == &fExportedAtoms ) {
+ this->setExportNlist(atom, entry);
+ }
+ else if ( &atoms == &fImportedAtoms ) {
+ this->setImportNlist(atom, entry);
+ }
+ else {
+ this->setLocalNlist(atom, entry);
+ }
+ }
+}
+
+template <typename A>
+void Writer<A>::copyNlistRange(const std::vector<macho_nlist<P> >& entries, uint32_t startIndex)
+{
+ for ( typename std::vector<macho_nlist<P> >::const_iterator it = entries.begin(); it != entries.end(); ++it)
+ fSymbolTable[startIndex++] = *it;
+}
+
+
+template <typename A>
+struct NListNameSorter
+{
+ NListNameSorter(StringsLinkEditAtom<A>* pool) : fStringPool(pool) {}
+
+ bool operator()(const macho_nlist<typename A::P>& left, const macho_nlist<typename A::P>& right)
+ {
+ return (strcmp(fStringPool->stringForIndex(left.n_strx()), fStringPool->stringForIndex(right.n_strx())) < 0);
+ }
+private:
+ StringsLinkEditAtom<A>* fStringPool;
+};
+
+
+template <typename A>
+void Writer<A>::buildSymbolTable()
+{
+ fSymbolTableStabsStartIndex = 0;
+ fSymbolTableStabsCount = fStabs->size();
+ fSymbolTableLocalStartIndex = fSymbolTableStabsStartIndex + fSymbolTableStabsCount;
+ fSymbolTableLocalCount = fLocalSymbolAtoms.size() + fLocalExtraLabels.size();
+ fSymbolTableExportStartIndex = fSymbolTableLocalStartIndex + fSymbolTableLocalCount;
+ fSymbolTableExportCount = fExportedAtoms.size() + fGlobalExtraLabels.size();
+ fSymbolTableImportStartIndex = fSymbolTableExportStartIndex + fSymbolTableExportCount;
+ fSymbolTableImportCount = fImportedAtoms.size();