+ StubHelperAtom<x86_64>* helper = new StubHelperAtom<x86_64>(writer, target, *this);
+ fReferences.push_back(new WriterReference<x86_64>(0, x86_64::kPointer, helper));
+}
+
+
+template <typename A>
+LazyPointerAtom<A>::LazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
+ : WriterAtom<A>(writer, Segment::fgDataSegment), fName(lazyPointerName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedLazyPointers.push_back(this);
+
+ fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
+}
+
+
+
+template <typename A>
+const char* LazyPointerAtom<A>::lazyPointerName(const char* name)
+{
+ char* buf;
+ asprintf(&buf, "%s$lazy_pointer", name);
+ return buf;
+}
+
+template <typename A>
+void LazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ bzero(buffer, getSize());
+}
+
+
+template <typename A>
+NonLazyPointerAtom<A>::NonLazyPointerAtom(Writer<A>& writer, ObjectFile::Atom& target)
+ : WriterAtom<A>(writer, Segment::fgDataSegment), fName(nonlazyPointerName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedNonLazyPointers.push_back(this);
+
+ fReferences.push_back(new WriterReference<A>(0, A::kPointer, &target));
+}
+
+template <typename A>
+const char* NonLazyPointerAtom<A>::nonlazyPointerName(const char* name)
+{
+ char* buf;
+ asprintf(&buf, "%s$non_lazy_pointer", name);
+ return buf;
+}
+
+template <typename A>
+void NonLazyPointerAtom<A>::copyRawContent(uint8_t buffer[]) const
+{
+ bzero(buffer, getSize());
+}
+
+
+
+template <>
+bool StubAtom<ppc64>::pic() const
+{
+ // no-pic stubs for ppc64 don't work if lazy pointer is above low 2GB.
+ // Usually that only happens if page zero is very large
+ return ( fWriter.fSlideable || ((fWriter.fPageZeroAtom != NULL) && (fWriter.fPageZeroAtom->getSize() > 4096)) );
+}
+
+template <>
+bool StubAtom<ppc>::pic() const
+{
+ return fWriter.fSlideable;
+}
+
+template <>
+ObjectFile::Alignment StubAtom<ppc>::getAlignment() const
+{
+ return 2;
+}
+
+template <>
+ObjectFile::Alignment StubAtom<ppc64>::getAlignment() const
+{
+ return 2;
+}
+
+template <>
+StubAtom<ppc>::StubAtom(Writer<ppc>& writer, ObjectFile::Atom& target)
+ : WriterAtom<ppc>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedStubs.push_back(this);
+
+ LazyPointerAtom<ppc>* lp = new LazyPointerAtom<ppc>(writer, target);
+ if ( pic() ) {
+ // picbase is 8 bytes into atom
+ fReferences.push_back(new WriterReference<ppc>(12, ppc::kPICBaseHigh16, lp, 0, this, 8));
+ fReferences.push_back(new WriterReference<ppc>(20, ppc::kPICBaseLow16, lp, 0, this, 8));
+ }
+ else {
+ fReferences.push_back(new WriterReference<ppc>(0, ppc::kAbsHigh16AddLow, lp));
+ fReferences.push_back(new WriterReference<ppc>(4, ppc::kAbsLow16, lp));
+ }
+}
+
+template <>
+StubAtom<ppc64>::StubAtom(Writer<ppc64>& writer, ObjectFile::Atom& target)
+ : WriterAtom<ppc64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedStubs.push_back(this);
+
+ LazyPointerAtom<ppc64>* lp = new LazyPointerAtom<ppc64>(writer, target);
+ if ( pic() ) {
+ // picbase is 8 bytes into atom
+ fReferences.push_back(new WriterReference<ppc64>(12, ppc64::kPICBaseHigh16, lp, 0, this, 8));
+ fReferences.push_back(new WriterReference<ppc64>(20, ppc64::kPICBaseLow14, lp, 0, this, 8));
+ }
+ else {
+ fReferences.push_back(new WriterReference<ppc64>(0, ppc64::kAbsHigh16AddLow, lp));
+ fReferences.push_back(new WriterReference<ppc64>(4, ppc64::kAbsLow14, lp));
+ }
+}
+
+// specialize to put x86 fast stub in __IMPORT segment with no lazy pointer
+template <>
+StubAtom<x86>::StubAtom(Writer<x86>& writer, ObjectFile::Atom& target)
+ : WriterAtom<x86>(writer, writer.fOptions.readOnlyx86Stubs() ? Segment::fgROImportSegment : Segment::fgImportSegment),
+ fTarget(target)
+{
+ if ( &target == NULL )
+ fName = "cache-line-crossing-stub";
+ else {
+ fName = stubName(target.getName());
+ writer.fAllSynthesizedStubs.push_back(this);
+ }
+}
+
+template <>
+StubAtom<x86_64>::StubAtom(Writer<x86_64>& writer, ObjectFile::Atom& target)
+ : WriterAtom<x86_64>(writer, Segment::fgTextSegment), fName(stubName(target.getName())), fTarget(target)
+{
+ writer.fAllSynthesizedStubs.push_back(this);
+
+ LazyPointerAtom<x86_64>* lp = new LazyPointerAtom<x86_64>(writer, target);
+ fReferences.push_back(new WriterReference<x86_64>(2, x86_64::kPCRel32, lp));
+}
+
+template <typename A>
+const char* StubAtom<A>::stubName(const char* name)
+{
+ 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<x86>::getSize() const
+{
+ return 5;
+}
+
+template <>
+uint64_t StubAtom<x86_64>::getSize() const
+{
+ return 6;
+}
+
+template <>
+ObjectFile::Alignment StubAtom<x86>::getAlignment() const
+{
+ // special case x86 fast stubs to be byte aligned
+ return 0;
+}
+
+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.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;
+}
+
+// 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<x86>::getSectionName() const
+{
+ 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), fLoadCommandsSection(NULL),
+ fLoadCommandsSegment(NULL), fPadSegmentInfo(NULL), fSplitCodeToDataContentAtom(NULL), fModuleInfoAtom(NULL),
+ fPageZeroAtom(NULL), fSymbolTableCount(0), fLargestAtomSize(1),
+ fEmitVirtualSections(false), fHasWeakExports(false), fReferencesWeakImports(false),
+ fCanScatter(false), fWritableSegmentPastFirst4GB(false), fNoReExportedDylibs(false), fSlideable(false),
+ fFirstWritableSegment(NULL), fAnonNameIndex(1000)
+{
+ // for UNIX conformance, error if file exists and is not writable
+ if ( (access(path, F_OK) == 0) && (access(path, W_OK) == -1) )
+ throwf("can't write output file: %s", path);
+
+ int permissions = 0777;
+ if ( fOptions.outputKind() == Options::kObjectFile )
+ permissions = 0666;
+ // Calling unlink first assures the file is gone so that open creates it with correct permissions
+ // It also handles the case where fFilePath file is not writable but its directory is
+ // And it means we don't have to truncate the file when done writing (in case new is smaller than old)
+ (void)unlink(fFilePath);
+ fFileDescriptor = open(fFilePath, O_CREAT | O_WRONLY | O_TRUNC, permissions);
+ if ( fFileDescriptor == -1 ) {
+ throwf("can't open output file for writing: %s", path);
+ }
+
+ 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;
+ uint8_t ordinal = 1;
+ switch ( fOptions.outputKind() ) {
+ case Options::kDynamicExecutable:
+ 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");