]> git.saurik.com Git - apple/ld64.git/commitdiff
ld64-278.4.tar.gz developer-tools-83 developer-tools-831 developer-tools-832 developer-tools-833 v278.4
authorApple <opensource@apple.com>
Tue, 18 Sep 2018 20:50:58 +0000 (20:50 +0000)
committerApple <opensource@apple.com>
Tue, 18 Sep 2018 20:50:58 +0000 (20:50 +0000)
28 files changed:
src/ld/HeaderAndLoadCommands.hpp
src/ld/InputFiles.cpp
src/ld/LinkEdit.hpp
src/ld/LinkEditClassic.hpp
src/ld/Options.cpp
src/ld/Options.h
src/ld/OutputFile.cpp
src/ld/Resolver.cpp
src/ld/SymbolTable.cpp
src/ld/ld.hpp
src/ld/parsers/libunwind/DwarfInstructions.hpp
src/ld/parsers/lto_file.cpp
src/ld/parsers/lto_file.h
src/ld/parsers/macho_relocatable_file.cpp
src/ld/parsers/textstub_dylib_file.cpp
src/ld/passes/bitcode_bundle.cpp
src/ld/passes/code_dedup.cpp
src/ld/passes/objc.cpp
src/ld/passes/order.cpp
src/other/ObjectDump.cpp
src/other/dyldinfo.cpp
src/other/machochecker.cpp
unit-tests/test-cases/lto-live_support_section/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-live_support_section/foo.c [new file with mode: 0644]
unit-tests/test-cases/lto-unexport-sym/Makefile [new file with mode: 0644]
unit-tests/test-cases/lto-unexport-sym/a.c [new file with mode: 0644]
unit-tests/test-cases/lto-unexport-sym/b.c [new file with mode: 0644]
unit-tests/test-cases/lto-unexport-sym/unexp.list [new file with mode: 0644]

index 454eb1f668abeca75965c9bcb86cb8ef5aef3955..a7d66207cf12e8d0c211a3eb5b57a22fd479eb1f 100644 (file)
@@ -176,7 +176,7 @@ HeaderAndLoadCommandsAtom<A>::HeaderAndLoadCommandsAtom(const Options& opts, ld:
                                ld::Atom::definitionRegular, ld::Atom::combineNever, 
                                ld::Atom::scopeTranslationUnit, ld::Atom::typeUnclassified, 
                                ld::Atom::symbolTableNotIn, false, false, false, 
-                               (opts.outputKind() == Options::kPreload) ? ld::Atom::Alignment(0) : ld::Atom::Alignment(12) ), 
+                               (opts.outputKind() == Options::kPreload) ? ld::Atom::Alignment(0) : ld::Atom::Alignment(log2(opts.segmentAlignment())) ),
                _options(opts), _state(state), _writer(writer), _address(0), _uuidCmdInOutputBuffer(NULL), _linkeditCmdOffset(0), _symboltableCmdOffset(0)
 {
        bzero(_uuid, 16);
@@ -724,7 +724,7 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copySingleSegmentLoadCommand(uint8_t* p)
                if ( cmd->fileoff() == 0 )
                        cmd->set_fileoff(fsect->fileOffset);
                cmd->set_vmsize(fsect->address + fsect->size - cmd->vmaddr());
-               if ( (fsect->type() != ld::Section::typeZeroFill) && (fsect->type() != ld::Section::typeTentativeDefs) )
+               if ( !sectionTakesNoDiskSpace(fsect) )
                        cmd->set_filesize(fsect->fileOffset + fsect->size - cmd->fileoff());
                ++msect;
        }
@@ -1348,14 +1348,21 @@ uint8_t* HeaderAndLoadCommandsAtom<A>::copyDylibLoadCommand(uint8_t* p, const ld
 {
        uint32_t sz = alignedSize(sizeof(macho_dylib_command<P>) + strlen(dylib->installPath()) + 1);
        macho_dylib_command<P>* cmd = (macho_dylib_command<P>*)p;
+       bool weakLink = dylib->forcedWeakLinked() || dylib->allSymbolsAreWeakImported();
+       bool upward = dylib->willBeUpwardDylib() && _options.useUpwardDylibs();
+       bool reExport = dylib->willBeReExported() && _options.useSimplifiedDylibReExports();
+       if ( weakLink && upward )
+               warning("cannot weak upward link.  Dropping weak for %s", dylib->installPath());
+       if ( weakLink && reExport )
+               warning("cannot weak re-export a dylib.  Dropping weak for %s", dylib->installPath());
        if ( dylib->willBeLazyLoadedDylib() )
                cmd->set_cmd(LC_LAZY_LOAD_DYLIB);
-       else if ( dylib->forcedWeakLinked() || dylib->allSymbolsAreWeakImported() )
-               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
-       else if ( dylib->willBeReExported() && _options.useSimplifiedDylibReExports() )
+       else if ( reExport )
                cmd->set_cmd(LC_REEXPORT_DYLIB);
-       else if ( dylib->willBeUpwardDylib() && _options.useUpwardDylibs() )
+       else if ( upward )
                cmd->set_cmd(LC_LOAD_UPWARD_DYLIB);
+       else if ( weakLink )
+               cmd->set_cmd(LC_LOAD_WEAK_DYLIB);
        else
                cmd->set_cmd(LC_LOAD_DYLIB);
        cmd->set_cmdsize(sz);
index e8e6bcc81cdf6a658f58429d7359df6ff3324f8f..79401f2bf03013ea5d3dbc3137cae184755ac08e 100644 (file)
@@ -177,6 +177,11 @@ private:
 ld::Section CustomStackAtom::_s_section("__UNIXSTACK", "__stack", ld::Section::typeStack, true);
 
 
+static bool isCompilerSupportLib(const char* path) {
+       const char* libName = strrchr(path, '/');
+       return ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) );
+}
+
 
 const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
 {
@@ -210,14 +215,16 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len)
 ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib)
 {
        // map in whole file
-       uint64_t len = info.fileLen;
+       struct stat stat_buf;
        int fd = ::open(info.path, O_RDONLY, 0);
        if ( fd == -1 )
                throwf("can't open file, errno=%d", errno);
-       if ( info.fileLen < 20 )
-               throwf("file too small (length=%llu)", info.fileLen);
-
-       uint8_t* p = (uint8_t*)::mmap(NULL, info.fileLen, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+       if ( ::fstat(fd, &stat_buf) != 0 )
+               throwf("fstat(%s) failed, errno=%d\n", info.path, errno);
+       if ( stat_buf.st_size < 20 )
+               throwf("file too small (length=%llu)", stat_buf.st_size);
+       int64_t len = stat_buf.st_size;
+       uint8_t* p = (uint8_t*)::mmap(NULL, stat_buf.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
        if ( p == (uint8_t*)(-1) )
                throwf("can't map file, errno=%d", errno);
 
@@ -255,23 +262,23 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
                if ( sliceFound ) {
                        uint32_t fileOffset = OSSwapBigToHostInt32(archs[sliceToUse].offset);
                        len = OSSwapBigToHostInt32(archs[sliceToUse].size);
-                       if ( fileOffset+len > info.fileLen ) {
+                       if ( fileOffset+len > stat_buf.st_size ) {
                                // <rdar://problem/17593430> file size was read awhile ago.  If file is being written, wait a second to see if big enough now
                                sleep(1);
-                               uint64_t newFileLen = info.fileLen;
+                               int64_t newFileLen = stat_buf.st_size;
                                struct stat statBuffer;
                                if ( stat(info.path, &statBuffer) == 0 ) {
                                        newFileLen = statBuffer.st_size;
                                }
                                if ( fileOffset+len > newFileLen ) {
                                        throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", 
-                                               fileOffset, fileOffset+len, info.fileLen);
+                                               fileOffset, fileOffset+len, stat_buf.st_size);
                                }
                        }
                        // if requested architecture is page aligned within fat file, then remap just that portion of file
                        if ( (fileOffset & 0x00000FFF) == 0 ) {
                                // unmap whole file
-                               munmap((caddr_t)p, info.fileLen);
+                               munmap((caddr_t)p, stat_buf.st_size);
                                // re-map just part we need
                                p = (uint8_t*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, fileOffset);
                                if ( p == (uint8_t*)(-1) )
@@ -355,8 +362,7 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib
        archOpts.verboseLoad                    = _options.whyLoad();
        archOpts.logAllFiles                    = _options.logAllFiles();
        // Set ObjSource Kind, libclang_rt is compiler static library
-       const char* libName = strrchr(info.path, '/');
-       if ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) )
+       if ( isCompilerSupportLib(info.path) )
                archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive;
        else
                archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive;
@@ -485,35 +491,12 @@ void InputFiles::logArchive(ld::File* file) const
 
 void InputFiles::logTraceInfo(const char* format, ...) const
 {
-       // one time open() of custom LD_TRACE_FILE
-       static int trace_file = -1;
-       if ( trace_file == -1 ) {
-               const char *trace_file_path = _options.traceOutputFile();
-               if ( trace_file_path != NULL ) {
-                       trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666);
-                       if ( trace_file == -1 )
-                               throwf("Could not open or create trace file (errno=%d): %s", errno, trace_file_path);
-               }
-               else {
-                       trace_file = fileno(stderr);
-               }
-       }
-
        char trace_buffer[MAXPATHLEN * 2];
     va_list ap;
        va_start(ap, format);
        int length = vsnprintf(trace_buffer, sizeof(trace_buffer), format, ap);
        va_end(ap);
-       char* buffer_ptr = trace_buffer;
-
-       while (length > 0) {
-               ssize_t amount_written = write(trace_file, buffer_ptr, length);
-               if(amount_written == -1)
-                       /* Failure to write shouldn't fail the build. */
-                       return;
-               buffer_ptr += amount_written;
-               length -= amount_written;
-       }
+       _options.writeToTraceFile(trace_buffer, length);
 }
 
 
@@ -1232,6 +1215,10 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal
                                // <rdar://problem/9740166> force loaded archives should be in LD_TRACE
                                if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && (_options.traceArchives() || _options.traceEmitJSON()) )
                                        logArchive(archive);
+
+                               if ( isCompilerSupportLib(info.path) && (info.options.fForceLoad || _options.fullyLoadArchives()) )
+                                       state.forceLoadCompilerRT = true;
+
                                _searchLibraries.push_back(LibraryInfo(archive));
                                if ( _options.dumpDependencyInfo() )
                                        _options.dumpDependency(Options::depArchive, archive->path());
index c4421ef5c5594e396ec51195b2c49f2bf6c437c4..bde04736665d011582e45372911a190ca35be1ac 100644 (file)
@@ -998,7 +998,7 @@ void ExportInfoAtom<A>::encode() const
                                entry.flags |= EXPORT_SYMBOL_FLAGS_WEAK_DEFINITION;
                        entry.other = this->_writer.compressedOrdinalForAtom(atom);
                        if ( entry.other == BIND_SPECIAL_DYLIB_SELF ) {
-                               warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->file()->path());
+                               warning("not adding explict export for symbol %s because it is already re-exported from dylib %s", entry.name, atom->safeFilePath());
                                continue;
                        }
                        if ( atom->isAlias() ) {
index ce7c8201ec69ea5756ca7c69a21fc7d7e2107899..fd9098f15d76876793a45fb85f31ff9bfe756eba 100644 (file)
@@ -1824,6 +1824,27 @@ void SectionRelocationsAtom<arm64>::encodeSectionReloc(ld::Internal::FinalSectio
                        relocs.push_back(reloc1);
                        break;
 
+               case ld::Fixup::kindStoreARM64TLVPLoadPageOff12:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPageOff12:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(false);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_TLVP_LOAD_PAGEOFF12);
+                       relocs.push_back(reloc1);
+                       break;
+
+               case ld::Fixup::kindStoreARM64TLVPLoadPage21:
+               case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadPage21:
+                       reloc1.set_r_address(address);
+                       reloc1.set_r_symbolnum(symbolNum);
+                       reloc1.set_r_pcrel(true);
+                       reloc1.set_r_length(2);
+                       reloc1.set_r_extern(external);
+                       reloc1.set_r_type(ARM64_RELOC_TLVP_LOAD_PAGE21);
+                       relocs.push_back(reloc1);
+                       break;
 
                case ld::Fixup::kindStoreLittleEndian64:
                case ld::Fixup::kindStoreTargetAddressLittleEndian64:
index faf9c169878445d50fdeabde1f4039a12a41bb75..d36bc02cfc6b6835b331685cba79ff40904a996f 100644 (file)
@@ -120,7 +120,6 @@ bool Options::FileInfo::checkFileExists(const Options& options, const char *p)
          p = path;
        if ( stat(p, &statBuffer) == 0 ) {
                if (p != path) path = strdup(p);
-               fileLen = statBuffer.st_size;
                modTime = statBuffer.st_mtime;
                return true;
        }
@@ -145,7 +144,7 @@ Options::Options(int argc, const char* argv[])
          fClientName(NULL),
          fUmbrellaName(NULL), fInitFunctionName(NULL), fDotOutputFile(NULL), fExecutablePath(NULL),
          fBundleLoader(NULL), fDtraceScriptName(NULL), fSegAddrTablePath(NULL), fMapPath(NULL), 
-         fDyldInstallPath("/usr/lib/dyld"), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
+         fDyldInstallPath("/usr/lib/dyld"), fLtoCachePath(NULL), fTempLtoObjectPath(NULL), fOverridePathlibLTO(NULL), fLtoCpu(NULL),
          fZeroPageSize(ULLONG_MAX), fStackSize(0), fStackAddr(0), fSourceVersion(0), fSDKVersion(0), fExecutableStack(false), 
          fNonExecutableHeap(false), fDisableNonExecutableHeap(false),
          fMinimumHeaderPad(32), fSegmentAlignment(4096), 
@@ -195,7 +194,7 @@ Options::Options(int argc, const char* argv[])
          fPlatform(kPlatformUnknown), fDebugInfoStripping(kDebugInfoMinimal), fTraceOutputFile(NULL),
          fMacVersionMin(ld::macVersionUnset), fIOSVersionMin(ld::iOSVersionUnset), fWatchOSVersionMin(ld::wOSVersionUnset),
          fSaveTempFiles(false), fSnapshotRequested(false), fPipelineFifo(NULL),
-         fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fMaxDefaultCommonAlign(0)
+         fDependencyInfoPath(NULL), fDependencyFileDescriptor(-1), fTraceFileDescriptor(-1), fMaxDefaultCommonAlign(0)
 {
        this->checkForClassic(argc, argv);
        this->parsePreCommandLineEnvironmentSettings();
@@ -213,8 +212,11 @@ Options::Options(int argc, const char* argv[])
 
 Options::~Options()
 {
-  if ( fDependencyFileDescriptor != -1 )
-       ::close(fDependencyFileDescriptor);
+       if ( fDependencyFileDescriptor != -1 )
+               ::close(fDependencyFileDescriptor);
+
+       if ( fTraceFileDescriptor != -1 )
+               ::close(fTraceFileDescriptor);
 }
 
 bool Options::errorBecauseOfWarnings() const
@@ -831,13 +833,6 @@ bool Options::findFile(const std::string &path, const std::vector<std::string> &
                        break;
        }
 
-       // If we found a text-based stub file, check if it should be used.
-       if ( !tbdInfo.missing() ) {
-               if (tapi::LinkerInterfaceFile::shouldPreferTextBasedStubFile(tbdInfo.path)) {
-                       result = tbdInfo;
-                       return true;
-               }
-       }
        FileInfo dylibInfo;
        {
                bool found = dylibInfo.checkFileExists(*this, path.c_str());
@@ -845,32 +840,30 @@ bool Options::findFile(const std::string &path, const std::vector<std::string> &
                        printf("[Logging for XBS]%sfound library: '%s'\n", (found ? " " : " not "), path.c_str());
        }
 
-       // There is only a text-based stub file.
-       if ( !tbdInfo.missing() && dylibInfo.missing() ) {
-               result = tbdInfo;
-               return true;
-       }
-       // There is only a dynamic library file.
-       else if ( tbdInfo.missing() && !dylibInfo.missing() ) {
-               result = dylibInfo;
-               return true;
+       // There is only a text-based stub file or a dynamic library file.
+       if ( tbdInfo.missing() != dylibInfo.missing() ) {
+               result = tbdInfo.missing() ? dylibInfo : tbdInfo;
        }
        // There are both - a text-based stub file and a dynamic library file.
        else if ( !tbdInfo.missing() && !dylibInfo.missing() ) {
-               // If the files are still in synv we can use and should use the text-based stub file.
-               if (tapi::LinkerInterfaceFile::areEquivalent(tbdInfo.path, dylibInfo.path)) {
+               // Check if we should prefer the text-based stub file (installapi).
+               if (tapi::LinkerInterfaceFile::shouldPreferTextBasedStubFile(tbdInfo.path)) {
+                       result = tbdInfo;
+               }
+               // If the files are still in sync we can use and should use the text-based stub file.
+               else if (tapi::LinkerInterfaceFile::areEquivalent(tbdInfo.path, dylibInfo.path)) {
                        result = tbdInfo;
                }
                // Otherwise issue a warning and fall-back to the dynamic library file.
                else {
                        warning("text-based stub file %s and library file %s are out of sync. Falling back to library file for linking.", tbdInfo.path, dylibInfo.path);
                        result = dylibInfo;
-
                }
-               return true;
+       } else {
+               return false;
        }
 
-       return false;
+       return true;
 }
 
 static bool startsWith(const std::string& str, const std::string& prefix)
@@ -5661,10 +5654,6 @@ void Options::checkIllegalOptionCombinations()
        if ( fReverseMapPath != NULL && !fHideSymbols ) {
                throw "-bitcode_symbol_map can only be used with -bitcode_hide_symbols";
        }
-       if ( fBitcodeKind != kBitcodeProcess &&
-                fOutputKind != Options::kObjectFile ) {
-               throw "-bitcode_process_mode can only be used together with -r";
-       }
        // auto fix up the process type for strip -S.
        // when there is only one input and output type is object file, downgrade kBitcodeProcess to kBitcodeAsData.
        if ( fOutputKind == Options::kObjectFile && fInputFiles.size() == 1 && fBitcodeKind == Options::kBitcodeProcess )
@@ -5885,4 +5874,28 @@ void Options::dumpDependency(uint8_t opcode, const char* path) const
 }
 
 
+void Options::writeToTraceFile(const char* buffer, size_t len) const
+{
+       // one time open() of custom LD_TRACE_FILE
+       if ( fTraceFileDescriptor == -1 ) {
+               if ( fTraceOutputFile != NULL ) {
+                       fTraceFileDescriptor = open(fTraceOutputFile, O_WRONLY | O_APPEND | O_CREAT, 0666);
+                       if ( fTraceFileDescriptor == -1 )
+                               throwf("Could not open or create trace file (errno=%d): %s", errno, fTraceOutputFile);
+               }
+               else {
+                       fTraceFileDescriptor = fileno(stderr);
+               }
+       }
+
+       while (len > 0) {
+               ssize_t amountWritten = write(fTraceFileDescriptor, buffer, len);
+               if ( amountWritten == -1 )
+                       /* Failure to write shouldn't fail the build. */
+                       return;
+               buffer += amountWritten;
+               len -= amountWritten;
+       }
+}
+
 
index e257e30fde636ad3d2335fe84326a44b13f63159..d489fd655a99a6f84a955fe3ece32b9c7215c507 100644 (file)
@@ -129,10 +129,30 @@ public:
                }
        }
 
+       static void userReadableSwiftVersion(uint8_t value, char versionString[64])
+       {
+               switch (value) {
+                       case 1:
+                               strcpy(versionString, "1.0");
+                               break;
+                       case 2:
+                               strcpy(versionString, "1.1");
+                               break;
+                       case 3:
+                               strcpy(versionString, "2.0");
+                               break;
+                       case 4:
+                               strcpy(versionString, "3.0");
+                               break;
+                       default:
+                               sprintf(versionString, "unknown ABI version 0x%02X", value);
+               }
+       }
+
+
        class FileInfo {
     public:
                const char*                             path;
-               uint64_t                                fileLen;
                time_t                                  modTime;
                LibraryOptions                  options;
                ld::File::Ordinal               ordinal;
@@ -145,11 +165,10 @@ public:
         // The use pattern for FileInfo is to create one on the stack in a leaf function and return
         // it to the calling frame by copy. Therefore the copy constructor steals the path string from
         // the source, which dies with the stack frame.
-        FileInfo(FileInfo const &other) : path(other.path), fileLen(other.fileLen), modTime(other.modTime), options(other.options), ordinal(other.ordinal), fromFileList(other.fromFileList), inputFileSlot(-1) { ((FileInfo&)other).path = NULL; };
+        FileInfo(FileInfo const &other) : path(other.path), modTime(other.modTime), options(other.options), ordinal(other.ordinal), fromFileList(other.fromFileList), inputFileSlot(-1) { ((FileInfo&)other).path = NULL; };
 
                FileInfo &operator=(FileInfo other) {
                        std::swap(path, other.path);
-                       std::swap(fileLen, other.fileLen);
                        std::swap(modTime, other.modTime);
                        std::swap(options, other.options);
                        std::swap(ordinal, other.ordinal);
@@ -160,10 +179,10 @@ public:
                }
 
         // Create an empty FileInfo. The path can be set implicitly by checkFileExists().
-        FileInfo() : path(NULL), fileLen(0), modTime(-1), options(), fromFileList(false) {};
+        FileInfo() : path(NULL), modTime(-1), options(), fromFileList(false) {};
         
         // Create a FileInfo for a specific path, but does not stat the file.
-        FileInfo(const char *_path) : path(strdup(_path)), fileLen(0), modTime(-1), options(), fromFileList(false) {};
+        FileInfo(const char *_path) : path(strdup(_path)), modTime(-1), options(), fromFileList(false) {};
 
         ~FileInfo() { if (path) ::free((void*)path); }
         
@@ -484,6 +503,7 @@ public:
        uint8_t                                         maxDefaultCommonAlign() const { return fMaxDefaultCommonAlign; }
        bool                                            hasDataSymbolMoves() const { return !fSymbolsMovesData.empty(); }
        bool                                            hasCodeSymbolMoves() const { return !fSymbolsMovesCode.empty(); }
+       void                                            writeToTraceFile(const char* buffer, size_t len) const;
 
        static uint32_t                         parseVersionNumber32(const char*);
 
@@ -795,6 +815,7 @@ private:
     const char*                                                        fPipelineFifo;
        const char*                                                     fDependencyInfoPath;
        mutable int                                                     fDependencyFileDescriptor;
+       mutable int                                                     fTraceFileDescriptor;
        uint8_t                                                         fMaxDefaultCommonAlign;
 };
 
index 732eb547ee4ac72f0ccec2599b53ed6972435390..3b775c911c2ec8876501c96dceb229b324998c29 100644 (file)
@@ -2223,6 +2223,7 @@ void OutputFile::applyFixUps(ld::Internal& state, uint64_t mhAddress, const ld::
                                                // Leave ADRP as-is
                                                set32LE(infoB.instructionContent, makeNOP());   
                                                ldrInfoC.offset += addInfoB.addend;
+                                               ldrInfoC.baseReg = adrpInfoA.destReg;
                                                set32LE(infoC.instructionContent, makeLoadOrStore(ldrInfoC));
                                                if ( _options.verboseOptimizationHints() )
                                                        fprintf(stderr, "adrp-add-ldr at 0x%08llX T2 transformed to ADRP/LDR \n", infoC.instructionAddress);
@@ -2627,7 +2628,7 @@ void OutputFile::writeAtoms(ld::Internal& state, uint8_t* wholeBuffer)
                        }
                        catch (const char* msg) {
                                if ( atom->file() != NULL )
-                                       throwf("%s in '%s' from %s", msg, atom->name(), atom->file()->path());
+                                       throwf("%s in '%s' from %s", msg, atom->name(), atom->safeFilePath());
                                else
                                        throwf("%s in '%s'", msg, atom->name());
                        }
@@ -2778,7 +2779,7 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                        // <rdar://problem/12264302> Don't use mmap on non-hfs volumes
                        struct statfs fsInfo;
                        if ( statfs(_options.outputFilePath(), &fsInfo) != -1 ) {
-                               if ( strcmp(fsInfo.f_fstypename, "hfs") == 0) {
+                               if ( (strcmp(fsInfo.f_fstypename, "hfs") == 0) || (strcmp(fsInfo.f_fstypename, "apfs") == 0) ) {
                                        (void)unlink(_options.outputFilePath());
                                        outputIsMappableFile = true;
                                }
@@ -2802,7 +2803,7 @@ void OutputFile::writeOutputFile(ld::Internal& state)
                        end[1] = '\0';
                        struct statfs fsInfo;
                        if ( statfs(dirPath, &fsInfo) != -1 ) {
-                               if ( strcmp(fsInfo.f_fstypename, "hfs") == 0) {
+                               if ( (strcmp(fsInfo.f_fstypename, "hfs") == 0) || (strcmp(fsInfo.f_fstypename, "apfs") == 0) ) {
                                        outputIsMappableFile = true;
                                }
                        }
@@ -4037,17 +4038,17 @@ void OutputFile::noteTextReloc(const ld::Atom* atom, const ld::Atom* target)
                                warning("PIE disabled. Absolute addressing (perhaps -mdynamic-no-pic) not allowed in code signed PIE, "
                                "but used in %s from %s. " 
                                "To fix this warning, don't compile with -mdynamic-no-pic or link with -Wl,-no_pie", 
-                               atom->name(), atom->file()->path());
+                               atom->name(), atom->safeFilePath());
                        }
                }
                this->pieDisabled = true;
        }
        else if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) ) {
-               throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+               throwf("illegal text-relocoation (direct reference) to (global,weak) %s in %s from %s in %s", target->name(), target->safeFilePath(), atom->name(), atom->safeFilePath());
        }
        else {
                if ( (target->file() != NULL) && (atom->file() != NULL) )
-                       throwf("illegal text-relocation to '%s' in %s from '%s' in %s", target->name(), target->file()->path(), atom->name(), atom->file()->path());
+                       throwf("illegal text-relocation to '%s' in %s from '%s' in %s", target->name(), target->safeFilePath(), atom->name(), atom->safeFilePath());
         else
             throwf("illegal text reloc in '%s' to '%s'", atom->name(), target->name());
        }
@@ -4082,7 +4083,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
                                warning("direct access in function '%s' from file '%s' to global weak symbol '%s' from file '%s' means the weak symbol cannot be overridden at runtime. "
                                                "This was likely caused by different translation units being compiled with different visibility settings.",
-                                                 demangledName, atom->file()->path(), _options.demangleSymbol(target->name()), target->file()->path());
+                                                 demangledName, atom->safeFilePath(), _options.demangleSymbol(target->name()), target->safeFilePath());
                        }
                        return;
                }
@@ -4111,7 +4112,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
                        warning("direct access in function '%s' from file '%s' to global weak symbol '%s' from file '%s' means the weak symbol cannot be overridden at runtime. "
                                        "This was likely caused by different translation units being compiled with different visibility settings.",
-                                         demangledName, atom->file()->path(), _options.demangleSymbol(target->name()), target->file()->path());
+                                         demangledName, atom->safeFilePath(), _options.demangleSymbol(target->name()), target->safeFilePath());
                }
                return;
        }
@@ -4124,6 +4125,7 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
        if ( target == NULL )
                return; 
 
+       const uint64_t pointerSize = (_options.architecture() & CPU_ARCH_ABI64) ? 8 : 4;
        bool inReadOnlySeg = ((_options.initialSegProtection(sect->segmentName()) & VM_PROT_WRITE) == 0);
        bool needsRebase = false;
        bool needsBinding = false;
@@ -4266,12 +4268,21 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                                                if ( (targetAddress+checkAddend) > sctEnd ) {
                                                        warning("data symbol %s from %s has pointer to %s + 0x%08llX. "  
                                                                        "That large of an addend may disable %s from being put in the dyld shared cache.", 
-                                                                       atom->name(), atom->file()->path(), target->name(), addend, _options.installPath() );
+                                                                       atom->name(), atom->safeFilePath(), target->name(), addend, _options.installPath() );
                                                }
                                        }
                                }
                        }
                }
+               if ( ((address & (pointerSize-1)) != 0) && (rebaseType == REBASE_TYPE_POINTER) ) {
+                       if ( (pointerSize == 8) && ((address & 7) == 4) ) {
+                               // for now, don't warning about 8-byte pointers only 4-byte aligned
+                       }
+                       else {
+                               warning("pointer not aligned at address 0x%llX (%s + %lld from %s)",
+                                               address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+                       }
+               }
                _rebaseInfo.push_back(RebaseInfo(rebaseType, address));
        }
        if ( needsBinding ) {
@@ -4279,6 +4290,15 @@ void OutputFile::addDyldInfo(ld::Internal& state,  ld::Internal::FinalSection* s
                        noteTextReloc(atom, target);
                        sect->hasExternalRelocs = true; // so dyld knows to change permissions on __TEXT segment
                }
+               if ( ((address & (pointerSize-1)) != 0) && (type == BIND_TYPE_POINTER) ) {
+                       if ( (pointerSize == 8) && ((address & 7) == 4) ) {
+                               // for now, don't warning about 8-byte pointers only 4-byte aligned
+                       }
+                       else {
+                               warning("pointer not aligned at address 0x%llX (%s + %lld from %s)",
+                                               address, atom->name(), (address - atom->finalAddress()), atom->safeFilePath());
+                       }
+               }
                _bindingInfo.push_back(BindingInfo(type, this->compressedOrdinalForAtom(target), target->name(), weak_import, address, addend));
        }
        if ( needsLazyBinding ) {
@@ -4330,14 +4350,19 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                assert(minusTarget->definition() != ld::Atom::definitionProxy);
                assert(target != NULL);
                assert(target->definition() != ld::Atom::definitionProxy);
-               // make sure target is not global and weak
-               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName)
-                               && (atom->section().type() != ld::Section::typeCFI)
-                               && (atom->section().type() != ld::Section::typeDtraceDOF)
-                               && (atom->section().type() != ld::Section::typeUnwindInfo) 
-                               && (minusTarget != target) ) {
-                       // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
-                       throwf("bad codegen, pointer diff in %s to global weak symbol %s", atom->name(), target->name());
+               // check if target of pointer-diff is global and weak
+               if ( (target->scope() == ld::Atom::scopeGlobal) && (target->combine() == ld::Atom::combineByName) && (target->definition() == ld::Atom::definitionRegular) ) {
+                       if ( (atom->section().type() == ld::Section::typeCFI)
+                               || (atom->section().type() == ld::Section::typeDtraceDOF)
+                               || (atom->section().type() == ld::Section::typeUnwindInfo) ) {
+                               // ok for __eh_frame and __uwind_info to use pointer diffs to global weak symbols
+                               return;
+                       }
+                       // Have direct reference to weak-global.  This should be an indrect reference
+                       const char* demangledName = strdup(_options.demangleSymbol(atom->name()));
+                       warning("direct access in function '%s' from file '%s' to global weak symbol '%s' from file '%s' means the weak symbol cannot be overridden at runtime. "
+                                       "This was likely caused by different translation units being compiled with different visibility settings.",
+                                         demangledName, atom->safeFilePath(), _options.demangleSymbol(target->name()), target->safeFilePath());
                }
                return;
        }
@@ -4443,14 +4468,14 @@ void OutputFile::addClassicRelocs(ld::Internal& state, ld::Internal::FinalSectio
                case ld::Fixup::kindStoreThumbLow16:
                        // no way to encode rebasing of binding for these instructions
                        if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
-                               throwf("no supported runtime lo16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+                               throwf("no supported runtime lo16 relocation in %s from %s to %s", atom->name(), atom->safeFilePath(), target->name());
                        break;
                                
                case ld::Fixup::kindStoreARMHigh16:
                case ld::Fixup::kindStoreThumbHigh16:
                        // no way to encode rebasing of binding for these instructions
                        if ( _options.outputSlidable() || (target->definition() == ld::Atom::definitionProxy) )
-                               throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->file()->path(), target->name());
+                               throwf("no supported runtime hi16 relocation in %s from %s to %s", atom->name(), atom->safeFilePath(), target->name());
                        break;
 
                default:
@@ -5052,6 +5077,14 @@ void OutputFile::writeMapFile(ld::Internal& state)
        }
 }
 
+static std::string realPathString(const char* path)
+{
+       char realName[MAXPATHLEN];
+       if ( realpath(path, realName) != NULL )
+               return realName;
+       return path;
+}
+
 void OutputFile::writeJSONEntry(ld::Internal& state)
 {
        if ( _options.traceEmitJSON() && (_options.UUIDMode() != Options::kUUIDNone) && (_options.traceOutputFile() != NULL) ) {
@@ -5099,7 +5132,7 @@ void OutputFile::writeJSONEntry(ld::Internal& state)
                if (dynamicList.size() > 0) {
                        jsonEntry += ",\"dynamic\":[";
                        for (const ld::dylib::File* dylib :  dynamicList) {
-                               jsonEntry += "\"" + std::string(dylib->path()) + "\"";
+                               jsonEntry += "\"" + realPathString(dylib->path()) + "\"";
                                if ((dylib != dynamicList.back())) {
                                        jsonEntry += ",";
                                }
@@ -5110,7 +5143,7 @@ void OutputFile::writeJSONEntry(ld::Internal& state)
                if (upwardList.size() > 0) {
                        jsonEntry += ",\"upward-dynamic\":[";
                        for (const ld::dylib::File* dylib :  upwardList) {
-                               jsonEntry += "\"" + std::string(dylib->path()) + "\"";
+                               jsonEntry += "\"" + realPathString(dylib->path()) + "\"";
                                if ((dylib != upwardList.back())) {
                                        jsonEntry += ",";
                                }
@@ -5121,7 +5154,7 @@ void OutputFile::writeJSONEntry(ld::Internal& state)
                if (reexportList.size() > 0) {
                        jsonEntry += ",\"re-exports\":[";
                        for (const ld::dylib::File* dylib :  reexportList) {
-                               jsonEntry += "\"" + std::string(dylib->path()) + "\"";
+                               jsonEntry += "\"" + realPathString(dylib->path()) + "\"";
                                if ((dylib != reexportList.back())) {
                                        jsonEntry += ",";
                                }
@@ -5132,18 +5165,23 @@ void OutputFile::writeJSONEntry(ld::Internal& state)
                if (state.archivePaths.size() > 0) {
                        jsonEntry += ",\"archives\":[";
                        for (const std::string& archivePath : state.archivePaths) {
-                               jsonEntry += "\"" + std::string(archivePath) + "\"";
+                               jsonEntry += "\"" + realPathString(archivePath.c_str()) + "\"";
                                if ((archivePath != state.archivePaths.back())) {
                                        jsonEntry += ",";
                                }
                        }
                        jsonEntry += "]";
                }
+
+               if (state.bundleLoader != NULL) {
+                       jsonEntry += ",\"bundle-loader\":";
+                       jsonEntry += "\"" + realPathString(state.bundleLoader->path()) + "\"";
+               }
+
                jsonEntry += "}\n";
                
                // Write the JSON entry to the trace file.
-               std::ofstream out(_options.traceOutputFile(), ios::app);
-               out << jsonEntry;
+               _options.writeToTraceFile(jsonEntry.c_str(), jsonEntry.size());
        }
 }
        
index 1c8f16e041bdcc99c210757518feca3b0bbd479a..24af5f8083186ab3e993b7c33832c17a6cbe0299 100644 (file)
@@ -337,25 +337,6 @@ void Resolver::doLinkerOption(const std::vector<const char*>& linkerOption, cons
        }
 }
 
-static void userReadableSwiftVersion(uint8_t value, char versionString[64])
-{
-       switch (value) {
-               case 1:
-                       strcpy(versionString, "1.0");
-                       break;
-               case 2:
-                       strcpy(versionString, "1.1");
-                       break;
-               case 3:
-                       strcpy(versionString, "2.0");
-                       break;
-               case 4:
-                       strcpy(versionString, "3.0");
-                       break;
-               default:
-                       sprintf(versionString, "unknown ABI version 0x%02X", value);
-       }
-}
 
 void Resolver::doFile(const ld::File& file)
 {
@@ -378,9 +359,11 @@ void Resolver::doFile(const ld::File& file)
                // Resolve bitcode section in the object file
                if ( _options.bundleBitcode() ) {
                        if ( objFile->getBitcode() == NULL ) {
-                               // No bitcode section, figure out if the object file comes from LTO/compiler static library
-                               if (objFile->sourceKind() != ld::relocatable::File::kSourceLTO &&
-                                       objFile->sourceKind() != ld::relocatable::File::kSourceCompilerArchive ) {
+                               // Handle the special case for compiler_rt objects. Add the file to the list to be process.
+                               if ( objFile->sourceKind() == ld::relocatable::File::kSourceCompilerArchive ) {
+                                       _internal.filesFromCompilerRT.push_back(objFile);
+                               } else if (objFile->sourceKind() != ld::relocatable::File::kSourceLTO  ) {
+                                       // No bitcode section, figure out if the object file comes from LTO/compiler static library
                                        switch ( _options.platform() ) {
                                        case Options::kPlatformOSX:
                                        case Options::kPlatformUnknown:
@@ -467,8 +450,8 @@ void Resolver::doFile(const ld::File& file)
                        else if ( file.swiftVersion() != _internal.swiftVersion ) {
                                char fileVersion[64];
                                char otherVersion[64];
-                               userReadableSwiftVersion(file.swiftVersion(), fileVersion);
-                               userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
+                               Options::userReadableSwiftVersion(file.swiftVersion(), fileVersion);
+                               Options::userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
                                if ( file.swiftVersion() > _internal.swiftVersion ) {
                                        throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)", 
                                                   file.path(), fileVersion, otherVersion);
@@ -638,8 +621,8 @@ void Resolver::doFile(const ld::File& file)
                        else if ( file.swiftVersion() != _internal.swiftVersion ) {
                                char fileVersion[64];
                                char otherVersion[64];
-                               userReadableSwiftVersion(file.swiftVersion(), fileVersion);
-                               userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
+                               Options::userReadableSwiftVersion(file.swiftVersion(), fileVersion);
+                               Options::userReadableSwiftVersion(_internal.swiftVersion, otherVersion);
                                if ( file.swiftVersion() > _internal.swiftVersion ) {
                                        throwf("%s compiled with newer version of Swift language (%s) than previous files (%s)", 
                                                   file.path(), fileVersion, otherVersion);
@@ -707,14 +690,14 @@ void Resolver::doAtom(const ld::Atom& atom)
                                                        }
                                                        else if ( _options.outputKind() == Options::kDynamicLibrary ) {
                                                                if ( atom.file() != NULL )
-                                                                       warning("target OS does not support re-exporting symbol %s from %s\n", _options.demangleSymbol(name), atom.file()->path());
+                                                                       warning("target OS does not support re-exporting symbol %s from %s\n", _options.demangleSymbol(name), atom.safeFilePath());
                                                                else
                                                                        warning("target OS does not support re-exporting symbol %s\n", _options.demangleSymbol(name));
                                                        }
                                                }
                                                else {
                                                        if ( atom.file() != NULL )
-                                                               warning("cannot export hidden symbol %s from %s", _options.demangleSymbol(name), atom.file()->path());
+                                                               warning("cannot export hidden symbol %s from %s", _options.demangleSymbol(name), atom.safeFilePath());
                                                        else
                                                                warning("cannot export hidden symbol %s", _options.demangleSymbol(name));
                                                }
@@ -726,7 +709,7 @@ void Resolver::doAtom(const ld::Atom& atom)
                                                (const_cast<ld::Atom*>(&atom))->setScope(ld::Atom::scopeGlobal);
                                        }
                                        else {
-                                               throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
+                                               throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.safeFilePath());
                                        }
                                }
                                break;
@@ -737,7 +720,7 @@ void Resolver::doAtom(const ld::Atom& atom)
                                        //fprintf(stderr, "demote %s to hidden\n", name);
                                }
                                if ( _options.canReExportSymbols() && _options.shouldReExport(name) ) {
-                                       throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.file()->path());
+                                       throwf("requested re-export symbol %s is not from a dylib, but from %s\n", _options.demangleSymbol(name), atom.safeFilePath());
                                }
                                break;
                }
@@ -995,12 +978,12 @@ void Resolver::markLive(const ld::Atom& atom, WhyLiveBackChain* previous)
        //fprintf(stderr, "markLive(%p) %s\n", &atom, atom.name());
        // if -why_live cares about this symbol, then dump chain
        if ( (previous->referer != NULL) && _options.printWhyLive(atom.name()) ) {
-               fprintf(stderr, "%s from %s\n", atom.name(), atom.file()->path());
+               fprintf(stderr, "%s from %s\n", atom.name(), atom.safeFilePath());
                int depth = 1;
                for(WhyLiveBackChain* p = previous; p != NULL; p = p->previous, ++depth) {
                        for(int i=depth; i > 0; --i)
                                fprintf(stderr, "  ");
-                       fprintf(stderr, "%s from %s\n", p->referer->name(), p->referer->file()->path());
+                       fprintf(stderr, "%s from %s\n", p->referer->name(), p->referer->safeFilePath());
                }
        }
        
@@ -1395,11 +1378,11 @@ bool Resolver::printReferencedBy(const char* name, SymbolTable::IndirectBindingS
                                                        ++foundReferenceCount;
                                        }
                                        else if ( atom->contentType() == ld::Atom::typeCFI ) {
-                                               fprintf(stderr, "      Dwarf Exception Unwind Info (__eh_frame) in %s\n", pathLeafName(atom->file()->path()));
+                                               fprintf(stderr, "      Dwarf Exception Unwind Info (__eh_frame) in %s\n", pathLeafName(atom->safeFilePath()));
                                                ++foundReferenceCount;
                                        }
                                        else {
-                                               fprintf(stderr, "      %s in %s\n", _options.demangleSymbol(atom->name()), pathLeafName(atom->file()->path()));
+                                               fprintf(stderr, "      %s in %s\n", _options.demangleSymbol(atom->name()), pathLeafName(atom->safeFilePath()));
                                                ++foundReferenceCount;
                                                break; // if undefined used twice in a function, only show first
                                        }
@@ -1744,6 +1727,7 @@ void Resolver::linkTimeOptimize()
        optOpt.pie                                                      = _options.positionIndependentExecutable();
        optOpt.mainExecutable                           = _options.linkingMainExecutable();;
        optOpt.staticExecutable                         = (_options.outputKind() == Options::kStaticExecutable);
+       optOpt.preload                                          = (_options.outputKind() == Options::kPreload);
        optOpt.relocatable                                      = (_options.outputKind() == Options::kObjectFile);
        optOpt.allowTextRelocs                          = _options.allowTextRelocs();
        optOpt.linkerDeadStripping                      = _options.deadCodeStrip();
@@ -1753,7 +1737,7 @@ void Resolver::linkTimeOptimize()
        optOpt.armUsesZeroCostExceptions    = _options.armUsesZeroCostExceptions();
        optOpt.simulator                                        = _options.targetIOSSimulator();
        optOpt.ignoreMismatchPlatform           = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable));
-       optOpt.bitcodeBundle                            = _options.bundleBitcode();
+       optOpt.bitcodeBundle                            = (_options.bundleBitcode() && (_options.bitcodeKind() != Options::kBitcodeMarker));
        optOpt.maxDefaultCommonAlignment        = _options.maxDefaultCommonAlign();
        optOpt.arch                                                     = _options.architecture();
        optOpt.mcpu                                                     = _options.mcpuLTO();
@@ -1801,8 +1785,15 @@ void Resolver::linkTimeOptimize()
 
        // if -dead_strip on command line
        if ( _options.deadCodeStrip() ) {
-               // clear liveness bit
+               // run through all atoms again and make live_section LTO atoms are preserved from dead_stripping if needed
+               _dontDeadStripIfReferencesLive.clear();
                for (std::vector<const ld::Atom*>::const_iterator it=_atoms.begin(); it != _atoms.end(); ++it) {
+                       const ld::Atom* atom = *it;
+                       if ( atom->dontDeadStripIfReferencesLive() ) {
+                               _dontDeadStripIfReferencesLive.push_back(atom);
+                       }
+
+                       // clear liveness bit
                        (const_cast<ld::Atom*>(*it))->setLive((*it)->dontDeadStrip());
                }
                // and re-compute dead code
index 4be0c5e264a1b10903b7cc1ff09aeb896540422e..3c12a777d930e6e38915dca081c034d30a3b3cf1 100644 (file)
@@ -132,7 +132,7 @@ void SymbolTable::addDuplicateSymbol(const char *name, const ld::Atom *atom)
     // check if file is already in the list, add it if not
     bool found = false;
     for (DuplicatedSymbolAtomList::iterator it = atoms->begin(); !found && it != atoms->end(); it++)
-        if (strcmp((*it)->file()->path(), atom->file()->path()) == 0)
+        if (strcmp((*it)->safeFilePath(), atom->safeFilePath()) == 0)
             found = true;
     if (!found)
         atoms->push_back(atom);
@@ -158,7 +158,7 @@ void SymbolTable::checkDuplicateSymbols() const
             foundDuplicate = true;
             fprintf(stderr, "duplicate symbol %s in:\n", symbolIt->first);
             for (DuplicatedSymbolAtomList::iterator atomIt = atoms->begin(); atomIt != atoms->end(); atomIt++) {
-                fprintf(stderr, "    %s\n", (*atomIt)->file()->path());
+                fprintf(stderr, "    %s\n", (*atomIt)->safeFilePath());
             }
         }
     }
@@ -284,18 +284,18 @@ private:
                        case Options::kCommonsIgnoreDylibs:
                                if ( _options.warnCommons() )
                                        warning("using common symbol %s from %s and ignoring defintion from dylib %s",
-                                                       proxy.name(), proxy.file()->path(), dylib.file()->path());
+                                                       proxy.name(), proxy.safeFilePath(), dylib.safeFilePath());
                                pickAtom(dylib);
                                break;
                        case Options::kCommonsOverriddenByDylibs:
                                if ( _options.warnCommons() )
                                        warning("replacing common symbol %s from %s with true definition from dylib %s",
-                                                       proxy.name(), proxy.file()->path(), dylib.file()->path());
+                                                       proxy.name(), proxy.safeFilePath(), dylib.safeFilePath());
                                pickAtom(proxy);
                                break;
                        case Options::kCommonsConflictsDylibsError:
                                throwf("common symbol %s from %s conflicts with defintion from dylib %s",
-                                          proxy.name(), proxy.file()->path(), dylib.file()->path());
+                                          proxy.name(), proxy.safeFilePath(), dylib.safeFilePath());
                }
        }
        
@@ -307,7 +307,7 @@ private:
                } else if ( _atomB.combine() == ld::Atom::combineByName ) {
                        pickAtomA();
                } else {
-                               throwf("symbol %s exported from both %s and %s\n", _atomA.name(), _atomA.file()->path(), _atomB.file()->path());
+                               throwf("symbol %s exported from both %s and %s\n", _atomA.name(), _atomA.safeFilePath(), _atomB.safeFilePath());
                }
        }
        
@@ -322,10 +322,8 @@ private:
                                                break;
                                        case ld::Atom::definitionTentative:
                                                if ( _atomB.size() > _atomA.size() ) {
-                                                       const char* atomApath = (_atomA.file() != NULL) ? _atomA.file()->path() : "<internal>";
-                                                       const char* atomBpath = (_atomB.file() != NULL) ? _atomB.file()->path() : "<internal>";
                                                        warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
-                                                                       _atomA.name(), _atomB.size(), atomBpath, _atomA.size(), atomApath);
+                                                                       _atomA.name(), _atomB.size(), _atomB.safeFilePath(), _atomA.size(), _atomA.safeFilePath());
                                                }
                                                pickAtomA();
                                                break;
@@ -342,10 +340,8 @@ private:
                                switch (_atomB.definition()) {
                                        case ld::Atom::definitionRegular:
                                                if ( _atomA.size() > _atomB.size() ) {
-                                                       const char* atomApath = (_atomA.file() != NULL) ? _atomA.file()->path() : "<internal>";
-                                                       const char* atomBpath = (_atomB.file() != NULL) ? _atomB.file()->path() : "<internal>";
                                                        warning("tentative definition of '%s' with size %llu from '%s' is being replaced by real definition of smaller size %llu from '%s'",
-                                                                       _atomA.name(), _atomA.size(),atomApath, _atomB.size(), atomBpath);
+                                                                       _atomA.name(), _atomA.size(),_atomA.safeFilePath(), _atomB.size(), _atomB.safeFilePath());
                                                }
                                                pickAtomB();
                                                break;
@@ -505,7 +501,7 @@ bool SymbolTable::add(const ld::Atom& atom, bool ignoreDuplicates)
 void SymbolTable::markCoalescedAway(const ld::Atom* atom)
 {
        // remove this from list of all atoms used
-       //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
+       //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->safeFilePath());
        (const_cast<ld::Atom*>(atom))->setCoalescedAway();
        
        //
@@ -893,7 +889,7 @@ void SymbolTable::printStatistics()
        //ReferencesHash obj;
        //for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
        //      if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
-       //              fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());
+       //              fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->safeFilePath());
        //      
        //      }
        //}
index 0db1b7e58d57e3f11549dd3a96b66590a8c65627..8351e3fa170666021957464b72df484c0a79c11f 100644 (file)
@@ -225,6 +225,7 @@ namespace relocatable {
                virtual bool                                            hasLongBranchStubs()            { return false; }
                virtual LinkerOptionsList*                      linkerOptions() const = 0;
                virtual SourceKind                                      sourceKind() const { return kSourceUnknown; }
+               virtual const uint8_t*                          fileContent() const { return nullptr; }
        };
 } // namespace relocatable
 
@@ -786,6 +787,7 @@ public:
                                                                                                        _definition = a._definition;
                                                                                                        _combine = a._combine;
                                                                                                        _dontDeadStrip = a._dontDeadStrip;
+                                                                                                       _dontDeadStripIfRefLive = a._dontDeadStripIfRefLive;
                                                                                                        _thumb = a._thumb;
                                                                                                        _autoHide = a._autoHide;
                                                                                                        _contentType = a._contentType;
@@ -797,6 +799,14 @@ public:
                                                                                                        _weakImportState = a._weakImportState;
                                                                                                }
 
+       const char*                                                             safeFilePath() const {
+                                                                                               const File* f = this->file();
+                                                                                               if ( f != NULL )
+                                                                                                       return f->path();
+                                                                                               else
+                                                                                                       return "<internal>";
+                                                                                       }
+
 protected:
        enum AddressMode { modeSectionOffset, modeFinalAddress };
 
@@ -831,7 +841,7 @@ public:
 };
 
 
-       
+
 // utility classes for using std::unordered_map with c-strings
 struct CStringHash {
        size_t operator()(const char* __s) const {
@@ -892,7 +902,8 @@ public:
                                                                                        hasThreadLocalVariableDefinitions(false),
                                                                                        hasWeakExternalSymbols(false),
                                                                                        someObjectHasOptimizationHints(false),
-                                                                                       dropAllBitcode(false), embedMarkerOnly(false)   { }
+                                                                                       dropAllBitcode(false), embedMarkerOnly(false),
+                                                                                       forceLoadCompilerRT(false)      { }
 
        std::vector<FinalSection*>                                      sections;
        std::vector<ld::dylib::File*>                           dylibs;
@@ -905,6 +916,7 @@ public:
        CStringSet                                                                      linkerOptionFrameworks;
        std::vector<const ld::Atom*>                            indirectBindingTable;
        std::vector<const ld::relocatable::File*>       filesWithBitcode;
+       std::vector<const ld::relocatable::File*>       filesFromCompilerRT;
        std::vector<const ld::Atom*>                            deadAtoms;
        std::unordered_set<const char*>                         allUndefProxies;
        const ld::dylib::File*                                          bundleLoader;
@@ -927,6 +939,7 @@ public:
        bool                                                                            someObjectHasOptimizationHints;
        bool                                                                            dropAllBitcode;
        bool                                                                            embedMarkerOnly;
+       bool                                                                            forceLoadCompilerRT;
        std::vector<std::string>                                        ltoBitcodePath;
 };
 
index c14c38f871b596a00d12bb76491bd3ae1b6aba29..711def837dafb040c749d458fca9a23957406f5b 100644 (file)
@@ -275,6 +275,10 @@ const char* DwarfInstructions<A,R>::parseCFIs(A& addressSpace, pint_t ehSectionS
                                  break;
                                }
                        }
+            if ( pcRange == 0 ) {
+                warn(ref, pcStart, "FDE found for zero size function");
+                break;
+            }
                        //fprintf(stderr, "FDE for func at 0x%08X, alreadyHaveCU=%d\n", (uint32_t)entry->u.fdeInfo.function.targetAddress, alreadyHaveCU);
                        if ( alreadyHaveCU && !forceDwarfConversion ) {
                                if ( keepDwarfWhichHasCU )
index 650fd4eff78727d272802604cdacda15427f4ed1..6915ae6ed19316d3b02b584ebe7afb030829803a 100644 (file)
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <sys/param.h>
 #include <sys/fcntl.h>
+#include <sys/mman.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <pthread.h>
@@ -125,7 +126,7 @@ public:
     static bool                                         sHasTriedLocalContext;
     bool                                                mergeIntoGenerator(lto_code_gen_t generator, bool useSetModule);
 #if LTO_API_VERSION >= 18
-       void                                                addToThinGenerator(thinlto_code_gen_t generator);
+       void                                                addToThinGenerator(thinlto_code_gen_t generator, int id);
 #endif
 private:
        friend class Atom;
@@ -291,12 +292,14 @@ private:
                                                                std::vector<const ld::Atom*>&           newAtoms,
                                                                std::vector<const char*>&                       additionalUndefines);
 
+#if LTO_API_VERSION >= 18
        static thinlto_code_gen_t init_thinlto_codegen(const std::vector<File*>&           files,
                                                                                                   const std::vector<const ld::Atom*>& allAtoms,
                                                                                                   ld::Internal&                                       state,
                                                                                                   const OptimizeOptions&                          options,
                                                                                                   CStringToAtom&                      deadllvmAtoms,
                                                                                                   CStringToAtom&                      llvmAtoms);
+#endif
 
        static std::vector<File*>               _s_files;
        static bool                                             _s_llvmOptionsProcessed;
@@ -543,9 +546,11 @@ bool File::mergeIntoGenerator(lto_code_gen_t generator, bool useSetModule) {
 }
 
 #if LTO_API_VERSION >= 18
-void File::addToThinGenerator(thinlto_code_gen_t generator) {
+void File::addToThinGenerator(thinlto_code_gen_t generator, int id) {
        assert(!_module && "Expected module to be disposed");
-       ::thinlto_codegen_add_module(generator, _path, (const char *)_content, _contentLength);
+       std::string pathWithID = _path;
+       pathWithID += std::to_string(id);
+       ::thinlto_codegen_add_module(generator, pathWithID.c_str(), (const char *)_content, _contentLength);
 }
 #endif
 
@@ -761,6 +766,12 @@ static lto_codegen_model getCodeModel(const OptimizeOptions& options) {
                        else
                                return LTO_CODEGEN_PIC_MODEL_STATIC;
                }
+               else if ( options.preload ) {
+                       if ( options.pie )
+                               return LTO_CODEGEN_PIC_MODEL_DYNAMIC;
+                       else
+                               return LTO_CODEGEN_PIC_MODEL_STATIC;
+               }
                else {
                        if ( options.pie )
                                return LTO_CODEGEN_PIC_MODEL_DYNAMIC;
@@ -1028,6 +1039,7 @@ bool Parser::optimizeLTO(const std::vector<File*>                         files,
        return true;
 }
 
+#if LTO_API_VERSION >= 18
 // Create the ThinLTO codegenerator
 thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector<File*>&           files,
                                                                                    const std::vector<const ld::Atom*>& allAtoms,
@@ -1178,6 +1190,7 @@ thinlto_code_gen_t Parser::init_thinlto_codegen(const std::vector<File*>&
 
        return thingenerator;
 }
+#endif
 
 // Full LTO processing
 bool Parser::optimizeThinLTO(const std::vector<File*>&              files,
@@ -1210,9 +1223,10 @@ bool Parser::optimizeThinLTO(const std::vector<File*>&              files,
 
 
        ld::File::Ordinal lastOrdinal;
+       int FileId = 0;
        for (auto *f : files) {
                if ( logBitcodeFiles) fprintf(stderr, "thinlto_codegen_add_module(%s)\n", f->path());
-               f->addToThinGenerator(thingenerator);
+               f->addToThinGenerator(thingenerator, FileId++);
                lastOrdinal = f->ordinal();
        }
 
@@ -1259,10 +1273,26 @@ bool Parser::optimizeThinLTO(const std::vector<File*>&              files,
                thinlto_codegen_set_codegen_only(thingenerator, true);
 #endif
 
+       // If object_path_lto is used, we switch to a file-based API: libLTO will
+       // generate the files on disk and we'll map them on-demand.
+
+#if LTO_API_VERSION >= 21
+       bool useFileBasedAPI = (options.tmpObjectFilePath && ::lto_api_version() >= 21);
+       if ( useFileBasedAPI )
+               thinlto_set_generated_objects_dir(thingenerator, options.tmpObjectFilePath);
+#endif
+
        // run code generator
        thinlto_codegen_process(thingenerator);
-       auto numObjects = thinlto_module_get_num_objects(thingenerator);
-       if (!numObjects)
+
+       unsigned numObjects;
+#if LTO_API_VERSION >= 21
+       if ( useFileBasedAPI )
+               numObjects = thinlto_module_get_num_object_files(thingenerator);
+       else
+#endif
+               numObjects = thinlto_module_get_num_objects(thingenerator);
+       if ( numObjects == 0 )
                throwf("could not do ThinLTO codegen (thinlto_codegen_process didn't produce any object): '%s', using libLTO version '%s'", ::lto_get_error_message(), ::lto_get_version());
 
        // if requested, save off objects files
@@ -1277,38 +1307,69 @@ bool Parser::optimizeThinLTO(const std::vector<File*>&              files,
                        if ( fd != -1 ) {
                                ::write(fd, machOFile.Buffer, machOFile.Size);
                                ::close(fd);
-                       } else {
+                       }
+                       else {
                                warning("unable to write temporary ThinLTO output: %s", tempMachoPath.c_str());
                        }
                }
        }
 
-
        // mach-o parsing is done in-memory, but need path for debug notes
        std::string macho_dirpath = "/tmp/thinlto.o";
        if ( options.tmpObjectFilePath != NULL ) {
                macho_dirpath = options.tmpObjectFilePath;
                struct stat statBuffer;
                if( stat(macho_dirpath.c_str(), &statBuffer) != 0 || !S_ISDIR(statBuffer.st_mode) ) {
+                       unlink(macho_dirpath.c_str());
                        if ( mkdir(macho_dirpath.c_str(), 0700) !=0 ) {
                                warning("unable to create ThinLTO output directory for temporary object files: %s", macho_dirpath.c_str());
                        }
                }
        }
 
+       auto get_thinlto_buffer_or_load_file = [&] (unsigned ID) {
+#if LTO_API_VERSION >= 21
+               if ( useFileBasedAPI ) {
+                       const char* path = thinlto_module_get_object_file(thingenerator, ID);
+                       // map in whole file
+                       struct stat stat_buf;
+                       int fd = ::open(path, O_RDONLY, 0);
+                       if ( fd == -1 )
+                               throwf("can't open thinlto file '%s', errno=%d", path, errno);
+                       if ( ::fstat(fd, &stat_buf) != 0 )
+                               throwf("fstat thinlto file '%s' failed, errno=%d\n", path, errno);
+                       size_t len = stat_buf.st_size;
+                       if ( len < 20 )
+                               throwf("ThinLTO file '%s' too small (length=%zu)", path, len);
+                       const char* p = (const char*)::mmap(NULL, len, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+                       if ( p == (const char*)(-1) )
+                               throwf("can't map file, errno=%d", errno);
+                       ::close(fd);
+                       return LTOObjectBuffer{ p, len };
+               }
+#endif
+               return thinlto_module_get_object(thingenerator, ID);
+       };
+
        auto ordinal = ld::File::Ordinal::LTOOrdinal().nextFileListOrdinal();
        for (unsigned bufID = 0; bufID < numObjects; ++bufID) {
-               auto machOFile = thinlto_module_get_object(thingenerator, bufID);
+               auto machOFile = get_thinlto_buffer_or_load_file(bufID);
                if (!machOFile.Size) {
                        warning("Ignoring empty buffer generated by ThinLTO");
                        continue;
                }
 
                // mach-o parsing is done in-memory, but need path for debug notes
-               std::string tmp_path = macho_dirpath + "/" + std::to_string(bufID) + ".o";
-
-               // if needed, save temp mach-o file to specific location
-               if ( options.tmpObjectFilePath != NULL ) {
+               std::string tmp_path;
+#if LTO_API_VERSION >= 21
+               if ( useFileBasedAPI ) {
+                       tmp_path = thinlto_module_get_object_file(thingenerator, bufID);
+               }
+               else
+#endif
+               if ( options.tmpObjectFilePath != NULL) {
+                       tmp_path = macho_dirpath + "/" + std::to_string(bufID) + ".o";
+                       // if needed, save temp mach-o file to specific location
                        int fd = ::open(tmp_path.c_str(), O_CREAT | O_WRONLY | O_TRUNC, 0666);
                        if ( fd != -1) {
                                ::write(fd, (const uint8_t *)machOFile.Buffer, machOFile.Size);
@@ -1401,6 +1462,10 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
        CStringToAtom::const_iterator pos = _llvmAtoms.find(name);
        if ( pos != _llvmAtoms.end() ) {
                // turn Atom into a proxy for this mach-o atom
+               if (pos->second->scope() == ld::Atom::scopeLinkageUnit) {
+                       if (log) fprintf(stderr, "demote %s to hidden after LTO\n", name);
+                       (const_cast<ld::Atom*>(&machoAtom))->setScope(ld::Atom::scopeLinkageUnit);
+               }
                pos->second->setCompiledAtom(machoAtom);
                _lastProxiedAtom = &machoAtom;
                _lastProxiedFile = pos->second->file();
@@ -1420,6 +1485,25 @@ void Parser::AtomSyncer::doAtom(const ld::Atom& machoAtom)
                        else {
                                // Don't pass it back as a new atom
                                if (log) fprintf(stderr, "AtomSyncer, mach-o atom %p matches dead lto atom %p (name=%s)\n", &machoAtom, llvmAtom->second, machoAtom.name());
+                               if ( llvmAtom->second->coalescedAway() ) {
+                                       if (log) fprintf(stderr, "AtomSyncer: dead coalesced atom %s\n", machoAtom.name());
+                                       // <rdar://problem/28269547>
+                                       // We told libLTO to keep a weak atom that will replaced by an native mach-o atom.
+                                       // We also need to remove any atoms directly dependent on this (FDE, LSDA).
+                                       for (ld::Fixup::iterator fit=machoAtom.fixupsBegin(), fend=machoAtom.fixupsEnd(); fit != fend; ++fit) {
+                                               switch ( fit->kind ) {
+                                                       case ld::Fixup::kindNoneGroupSubordinate:
+                                                       case ld::Fixup::kindNoneGroupSubordinateFDE:
+                                                       case ld::Fixup::kindNoneGroupSubordinateLSDA:
+                                                               assert(fit->binding == ld::Fixup::bindingDirectlyBound);
+                                                               (const_cast<ld::Atom*>(fit->u.target))->setCoalescedAway();
+                                                               if (log) fprintf(stderr, "AtomSyncer: mark coalesced-away subordinate atom %s\n", fit->u.target->name());
+                                                               break;
+                                                       default:
+                                                               break;
+                                               }
+                                       }
+                               }
                        } 
                }
                else
index b7601775de700824921f01f3a04eed42c45d1c26..b582a8bb4733cfafdbaa71a3117779a83620f24c 100644 (file)
@@ -58,6 +58,7 @@ struct OptimizeOptions {
        bool                                                            pie; 
        bool                                                            mainExecutable; 
        bool                                                            staticExecutable; 
+       bool                                                            preload;
        bool                                                            relocatable;
        bool                                                            allowTextRelocs; 
        bool                                                            linkerDeadStripping; 
index 776e695a3846fa229a9efd02ea30efb2691e7ff6..c4ecd368dabcbc6a8f0b1b89667a4657ebd7f925 100644 (file)
@@ -111,7 +111,7 @@ public:
        virtual ld::Bitcode*                                                            getBitcode() const                              { return _bitcode.get(); }
        virtual SourceKind                                                                      sourceKind() const                              { return _srcKind; }
        
-       const uint8_t*                                                                          fileContent()                                   { return _fileContent; }
+       virtual const uint8_t*                                                          fileContent() const                             { return _fileContent; }
 private:
        friend class Atom<A>;
        friend class Section<A>;
@@ -1715,11 +1715,14 @@ typename A::P::uint_t Parser<A>::realAddr(typename A::P::uint_t addr)
 #define STACK_ALLOC_IF_SMALL(_type, _name, _actual_count, _maxCount) \
        _type*  _name = NULL;   \
        uint32_t _name##_count = 1; \
-       if ( _actual_count > _maxCount ) \
+       uint32_t _name##_stack_count = _actual_count; \
+       if ( _actual_count > _maxCount ) { \
                _name = (_type*)malloc(sizeof(_type) * _actual_count); \
+               _name##_stack_count = 1; \
+       } \
        else \
                _name##_count = _actual_count; \
-       _type  _name##_buffer[_name##_count]; \
+       _type _name##_buffer[_name##_stack_count]; \
        if ( _name == NULL ) \
                _name = _name##_buffer;
 
@@ -1770,7 +1773,7 @@ ld::relocatable::File* Parser<A>::parse(const ParserOptions& opts)
 
        // create lists of address that already have compact unwind and thus don't need the dwarf parsed
        unsigned cuLsdaCount = 0;
-       pint_t cuStarts[countOfCUs];
+       STACK_ALLOC_IF_SMALL(pint_t, cuStarts, countOfCUs, 1024);
        for (uint32_t i=0; i < countOfCUs; ++i) {
                if ( CUSection<A>::encodingMeansUseDwarf(cuInfoArray[i].compactUnwindInfo) )
                        cuStarts[i] = -1;
@@ -6241,6 +6244,10 @@ template <>
 bool Section<x86_64>::addRelocFixup(class Parser<x86_64>& parser, const macho_relocation_info<P>* reloc)
 {
        const macho_section<P>* sect = this->machoSection();
+       if ( sect == NULL ) {
+               warning("malformed mach-o, relocations not supported on section %s", this->sectionName());
+               return false;
+       }
        uint64_t srcAddr = sect->addr() + reloc->r_address();
        Parser<x86_64>::SourceLocation  src;
        Parser<x86_64>::TargetDesc              target;
index 585446254e6bc3b33b4646e1f3d11a976c730900..0b83d410959e4e7a0b56c5a3e045f717438c8ec0 100644 (file)
@@ -108,14 +108,39 @@ template <typename A>
        : Base(strdup(path), mTime, ord, platform, linkMinOSVersion, allowWeakImports, linkingFlatNamespace,
                   hoistImplicitPublicDylibs, allowSimToMacOSX, addVers)
 {
+       std::unique_ptr<tapi::LinkerInterfaceFile> file;
+       std::string errorMessage;
+
+// <rdar://problem/29038544> Support $ld$weak symbols in .tbd files
+#if ((TAPI_API_VERSION_MAJOR == 1 &&  TAPI_API_VERSION_MINOR >= 1) || (TAPI_API_VERSION_MAJOR > 1))
+       // Check if the library supports the new create API.
+       if (tapi::APIVersion::isAtLeast(1, 1)) {
+               tapi::ParsingFlags flags = tapi::ParsingFlags::None;
+               if (enforceDylibSubtypesMatch)
+                       flags |= tapi::ParsingFlags::ExactCpuSubType;
+
+               if (!allowWeakImports)
+                       flags |= tapi::ParsingFlags::DisallowWeakImports;
+
+               file.reset(tapi::LinkerInterfaceFile::create(
+                       path, fileContent, fileLength, cpuType, cpuSubType, flags,
+                       tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+       } else {
+               auto matchingType = enforceDylibSubtypesMatch ?
+                               tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
+
+               file.reset(tapi::LinkerInterfaceFile::create(
+                       path, fileContent, fileLength, cpuType, cpuSubType, matchingType,
+                       tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+       }
+#else
        auto matchingType = enforceDylibSubtypesMatch ?
-                       tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
+               tapi::CpuSubTypeMatching::Exact : tapi::CpuSubTypeMatching::ABI_Compatible;
 
-       std::string errorMessage;
-       auto file = std::unique_ptr<tapi::LinkerInterfaceFile>(
-               tapi::LinkerInterfaceFile::create(path, fileContent, fileLength, cpuType,
-                                                                                 cpuSubType, matchingType,
-                                                                                 tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+       file.reset(tapi::LinkerInterfaceFile::create(
+               path, fileContent, fileLength, cpuType, cpuSubType, matchingType,
+               tapi::PackedVersion32(linkMinOSVersion), errorMessage));
+#endif
 
        if (file == nullptr)
                throw strdup(errorMessage.c_str());
index 527869a839632191f537f1f2df96c7fe907cb445..7165051294fbc651d8a1d2130075bfe0b9dea368 100644 (file)
@@ -218,6 +218,25 @@ private:
     ld::Internal&                           _state;
 };
 
+#if LTO_API_VERSION >= 7
+static void ltoDiagnosticHandler(lto_codegen_diagnostic_severity_t severity, const char* message, void*)
+{
+    switch ( severity ) {
+#if LTO_API_VERSION >= 10
+        case LTO_DS_REMARK:
+#endif
+        case LTO_DS_NOTE:
+            break; // ignore remarks and notes
+        case LTO_DS_WARNING:
+            warning("%s", message);
+            break;
+        case LTO_DS_ERROR:
+            throwf("%s", message);
+    }
+}
+#endif
+
+
 BitcodeAtom::BitcodeAtom()
 : ld::Atom(bitcodeBundleSection,
            ld::Atom::definitionRegular, ld::Atom::combineNever,
@@ -285,6 +304,11 @@ BitcodeObfuscator::BitcodeObfuscator()
         _lto_get_asm_symbol_num == NULL || _lto_get_asm_symbol_name == NULL || ::lto_api_version() < 14 )
         throwf("loaded libLTO doesn't support -bitcode_hide_symbols: %s", ::lto_get_version());
     _obfuscator = ::lto_codegen_create_in_local_context();
+
+#if LTO_API_VERSION >= 7
+    lto_codegen_set_diagnostic_handler(_obfuscator, ltoDiagnosticHandler, NULL);
+#endif
+
   #if LTO_API_VERSION >= 14
     lto_codegen_set_should_internalize(_obfuscator, false);
   #endif
@@ -455,6 +479,7 @@ void BundleHandler::copyXARProp(xar_file_t src, xar_file_t dst)
              strcmp(key, "hide-symbols") == 0 ||
              strcmp(key, "platform") == 0 ||
              strcmp(key, "sdkversion") == 0 ||
+             strcmp(key, "swift-version") == 0 ||
              strcmp(key, "dylibs/lib") == 0 ||
              strcmp(key, "link-options/option") == 0 ) {
             xar_prop_create(dst, key, val);
@@ -667,6 +692,14 @@ void BitcodeBundle::doPass()
             BitcodeHandler bitcodeHandler((char*)ltoTemp.getContent(), ltoTemp.getSize());
             bitcodeHandler.populateMustPreserveSymbols(obfuscator);
         }
+        // add must preserve symbols from compiler_rt input.
+        for ( auto &f : _state.filesFromCompilerRT ) {
+            std::vector<const char*> symbols;
+            if ( f->fileContent() && mach_o::relocatable::getNonLocalSymbols(f->fileContent(), symbols) ) {
+                for ( auto &sym : symbols)
+                    obfuscator->addMustPreserveSymbols(sym);
+            }
+        }
 
         // special symbols supplied by linker
         obfuscator->addMustPreserveSymbols("___dso_handle");
@@ -958,6 +991,14 @@ void BitcodeBundle::doPass()
     if ( xar_prop_create((xar_file_t)linkXML, "sdkversion", _options.getSDKVersionStr().c_str()) != 0 )
         throwf("could not add SDK version to bitcode bundle");
 
+    // Write swift version into header
+    if (_state.swiftVersion != 0) {
+        char swiftVersion[64];
+        Options::userReadableSwiftVersion(_state.swiftVersion, swiftVersion);
+        if ( xar_prop_create((xar_file_t)linkXML, "swift-version", swiftVersion) )
+            throwf("could not add swift version to bitcode bundle");
+    }
+
     // Write dylibs
     char sdkRoot[PATH_MAX];
     if ( _options.sdkPaths().empty() || (realpath(_options.sdkPaths().front(), sdkRoot) == NULL) )
@@ -993,6 +1034,12 @@ void BitcodeBundle::doPass()
         }
     }
 
+    // Write if compiler_rt is force loaded
+    if (_state.forceLoadCompilerRT) {
+        if ( xar_prop_create((xar_file_t)linkXML, "rt-forceload", "1") != 0 )
+            throwf("could not add compiler_rt force_load info to bitcode bundle");
+    }
+
     // Write link-line into archive
     for ( auto &it : linkCmd ) {
         if (xar_prop_create((xar_file_t)linkXML, "link-options/option", it.c_str()) != 0)
index e067acf98a7e4a53e5b794277d01428f988fe89c..c6bc8fb9701fbee26527336c491abe870a4d6a72 100644 (file)
@@ -49,7 +49,7 @@ public:
                                                                                DeDupAliasAtom(const ld::Atom* dupOf, const ld::Atom* replacement) :
                                                                                        ld::Atom(dupOf->section(), ld::Atom::definitionRegular, ld::Atom::combineNever,
                                                                                                        dupOf->scope(), dupOf->contentType(), ld::Atom::symbolTableIn,
-                                                                                                       false, false, true, 0),
+                                                                                                       false, false, true, dupOf->alignment()),
                                                                                        _dedupOf(dupOf),
                                                                                        _fixup(0, ld::Fixup::k1of1, ld::Fixup::kindNoneFollowOn, ld::Fixup::bindingDirectlyBound, replacement) {
                                                 if ( dupOf->autoHide() )
@@ -142,12 +142,21 @@ struct atom_hashing {
 // A helper for std::unordered_map<> that compares functions
 struct atom_equal {
 
-    struct VisitedSet {
-        std::unordered_set<const ld::Atom*> atoms1;
-        std::unordered_set<const ld::Atom*> atoms2;
+    struct BackChain {
+        BackChain*      prev;
+        const Atom*     inCallChain1;
+        const Atom*     inCallChain2;
+
+        bool inCallChain(const Atom* target) {
+            for (BackChain* p = this; p->prev != NULL; p = p->prev) {
+                if ( (p->inCallChain1 == target) || (p->inCallChain2 == target) )
+                     return true;
+            }
+            return false;
+        }
     };
 
-    static bool sameFixups(const ld::Atom* atom1, const ld::Atom* atom2, VisitedSet& visited) {
+    static bool sameFixups(const ld::Atom* atom1, const ld::Atom* atom2, BackChain& backChain) {
         ++sFixupCompareCount;
         //fprintf(stderr, "sameFixups(%s,%s)\n", atom1->name(), atom2->name());
         Fixup::iterator        f1   = atom1->fixupsBegin();
@@ -198,10 +207,16 @@ struct atom_equal {
                     return false;
                 if ( target1->section().type() != ld::Section::typeCode )
                     return false;
-                // to support co-recursive functions, don't call equals() on targets we've already visited
-                if ( ((visited.atoms1.count(target1) == 0) || (visited.atoms2.count(target2) == 0)) && !equal(target1, target2, visited) )
-                    return false;
-              }
+                // to support co-recursive functions, don't recurse into equals() for targets already in the back chain
+                if ( !backChain.inCallChain(target1) || !backChain.inCallChain(target2) ) {
+                    BackChain nextBackChain;
+                    nextBackChain.prev = &backChain;
+                    nextBackChain.inCallChain1 = target1;
+                    nextBackChain.inCallChain2 = target2;
+                    if ( !equal(target1, target2, nextBackChain) )
+                        return false;
+                }
+            }
 
             ++f1;
             ++f2;
@@ -210,17 +225,21 @@ struct atom_equal {
         return true;
     }
 
-    static bool equal(const ld::Atom* atom1, const ld::Atom* atom2, VisitedSet& visited) {
+    static bool equal(const ld::Atom* atom1, const ld::Atom* atom2, BackChain& backChain) {
+        if ( atom1->size() != atom2->size() )
+            return false;
         if ( atom_hashing::hash(atom1) != atom_hashing::hash(atom2) )
             return false;
-        visited.atoms1.insert(atom1);
-        visited.atoms2.insert(atom2);
-        return sameFixups(atom1, atom2, visited);
+        if ( memcmp(atom1->rawContentPointer(), atom2->rawContentPointer(), atom1->size()) != 0 )
+            return false;
+        bool result = sameFixups(atom1, atom2, backChain);
+        //fprintf(stderr, "sameFixups(%s,%s) = %d\n", atom1->name(), atom2->name(), result);
+        return result;
     }
 
     bool operator()(const ld::Atom* atom1, const ld::Atom* atom2) const {
-        VisitedSet visited;
-        return equal(atom1, atom2, visited);
+        BackChain backChain = { NULL, atom1, atom2 };
+        return equal(atom1, atom2, backChain);
     }
 };
 
@@ -348,7 +367,7 @@ void doPass(const Options& opts, ld::Internal& state)
     if ( log ) {
         fprintf(stderr, "atoms before pruning:\n");
         for (const ld::Atom* atom : textSection->atoms)
-            fprintf(stderr, "  %p (size=%llu) %sp\n", atom, atom->size(), atom->name());
+            fprintf(stderr, "  %p (size=%llu) %s\n", atom, atom->size(), atom->name());
     }
     // remove replaced atoms from section
        textSection->atoms.erase(std::remove_if(textSection->atoms.begin(), textSection->atoms.end(),
@@ -363,7 +382,7 @@ void doPass(const Options& opts, ld::Internal& state)
     if ( log ) {
         fprintf(stderr, "atoms after pruning:\n");
         for (const ld::Atom* atom : textSection->atoms)
-            fprintf(stderr, "  %p (size=%llu) %sp\n", atom, atom->size(), atom->name());
+            fprintf(stderr, "  %p (size=%llu) %s\n", atom, atom->size(), atom->name());
     }
 
    //fprintf(stderr, "hash-count=%lu, fixup-compares=%lu, atom-count=%u\n", sHashCount, sFixupCompareCount, atomsBeingComparedCount);
index e2afca1e2187d11a42ecc3981fc1c1408dc2a710..a9a8c6a0b94620cd1183010f959db3cecc165150 100644 (file)
@@ -1110,12 +1110,12 @@ MethodListAtom<A>::MethodListAtom(ld::Internal& state, const ld::Atom* baseMetho
                                        if ( baseMethodListMethodNameAtoms.count(target) != 0 ) {
                                                warning("%s method '%s' in category from %s overrides method from class in %s", 
                                                        (meta ? "meta" : "instance"), target->rawContentPointer(),
-                                                       categoryMethodListAtom->file()->path(), baseMethodList->file()->path() );
+                                                       categoryMethodListAtom->safeFilePath(), baseMethodList->safeFilePath() );
                                        }
                                        if ( categoryMethodNameAtoms.count(target) != 0 ) {
                                                warning("%s method '%s' in category from %s conflicts with same method from another category", 
                                                        (meta ? "meta" : "instance"), target->rawContentPointer(),
-                                                       categoryMethodListAtom->file()->path());
+                                                       categoryMethodListAtom->safeFilePath());
                                        }
                                        categoryMethodNameAtoms.insert(target);
                                }
@@ -1270,12 +1270,12 @@ void scanCategories(ld::Internal& state,
                                
                                if (Category<A>::getClassProperties(state, categoryAtom)) {
                                        haveCategoriesWithNonNullClassProperties = true;
-                                       // fprintf(stderr, "category in file %s has non-null class properties\n", categoryAtom->file()->path());
+                                       // fprintf(stderr, "category in file %s has non-null class properties\n", categoryAtom->safeFilePath());
                                }
                                
                                if (!categoryAtom->file()->objcHasCategoryClassPropertiesField()) {
                                        haveCategoriesWithoutClassPropertyStorage = true;
-                                       // fprintf(stderr, "category in file %s has no storage for class properties\n", categoryAtom->file()->path());
+                                       // fprintf(stderr, "category in file %s has no storage for class properties\n", categoryAtom->safeFilePath());
                                }
                        }
                }
index a7d31f31618a77f910a4b67f416b3d6a18e0f0dd..05288765b61606b83f8138bf4920c08e79d4f07d 100644 (file)
@@ -530,7 +530,7 @@ void Layout::buildOrdinalOverrideMap()
                                        AtomToOrdinal::iterator pos = _ordinalOverrideMap.find(nextAtom);
                                        if ( pos == _ordinalOverrideMap.end() ) {
                                                _ordinalOverrideMap[nextAtom] = index++;
-                                               if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->name(), nextAtom->file()->path());
+                                               if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s in cluster from %s\n", index, nextAtom->name(), nextAtom->safeFilePath());
                                        }
                                        else {
                                                if (_s_log ) fprintf(stderr, "could not order %s as %u because it was already laid out earlier by %s as %u\n",
@@ -540,7 +540,7 @@ void Layout::buildOrdinalOverrideMap()
                        }
                        else {
                                _ordinalOverrideMap[atom] = index;
-                               if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->name(), atom->file()->path());
+                               if (_s_log ) fprintf(stderr, "override ordinal %u assigned to %s from %s\n", index, atom->name(), atom->safeFilePath());
                        }
                        ++matchCount;
                }
@@ -617,10 +617,20 @@ void Layout::doPass()
        // sort atoms in each section
        for (std::vector<ld::Internal::FinalSection*>::iterator sit=_state.sections.begin(); sit != _state.sections.end(); ++sit) {
                ld::Internal::FinalSection* sect = *sit;
-               if ( sect->type() ==  ld::Section::typeTempAlias )
-                       continue;
-               if ( log ) fprintf(stderr, "sorting section %s\n", sect->sectionName());
-               std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
+               switch ( sect->type() ) {
+                       case ld::Section::typeTempAlias:
+                       case ld::Section::typeStub:
+                       case ld::Section::typeLazyPointer:
+                       case ld::Section::typeLazyPointerClose:
+                       case ld::Section::typeStubClose:
+                       case ld::Section::typeNonLazyPointer:
+                               // these sections are already sorted by pass that created them
+                               break;
+                       default:
+                               if ( log ) fprintf(stderr, "sorting section %s\n", sect->sectionName());
+                               std::sort(sect->atoms.begin(), sect->atoms.end(), _comparer);
+                               break;
+               }
        }
 
        if ( log ) {
index 77399863b14a82c69e18c0e405a125d4b9c0e933..6763e1a358938083c21e4cf2229e7677e736b015 100644 (file)
@@ -396,11 +396,13 @@ struct AtomSorter
                                        rightString = (char*)cstringAtom->rawContentPointer();
                                }
                        }
-                       assert(leftString != NULL);
-                       assert(rightString != NULL);
-                       diff = strcmp(leftString, rightString);
-                       if ( diff != 0 )
-                               return (diff < 0);
+                       if ( leftString != rightString ) {
+                               assert(leftString != NULL);
+                               assert(rightString != NULL);
+                               diff = strcmp(leftString, rightString);
+                               if ( diff != 0 )
+                                       return (diff < 0);
+                       }
                }
                else if ( left->section().type() == ld::Section::typeLiteral4 ) {
                        // if literal sort by content
@@ -804,6 +806,7 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreThumbHigh16:
                        printf(", then store high-16 in Thumb movt");
                        break;
+#if SUPPORT_ARCH_arm64
                case ld::Fixup::kindStoreARM64Branch26:
                        printf(", then store as ARM64 26-bit pcrel branch");
                        break;
@@ -843,9 +846,7 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreARM64PCRelToGOT:
                        printf(", then store as 32-bit delta to GOT entry");
                        break;
-               case ld::Fixup::kindStoreARM64PointerToGOT32:
-                       printf(", then store as 32-bit pointer to GOT entry");
-                       break;
+#endif
                case ld::Fixup::kindDtraceExtra:
                        printf("dtrace static probe extra info");
                        break;
@@ -867,12 +868,14 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreThumbDtraceIsEnableSiteClear:
                        printf("Thumb dtrace static is-enabled site");
                        break;
+#if SUPPORT_ARCH_arm64
                case ld::Fixup::kindStoreARM64DtraceCallSiteNop:
                        printf("ARM64 dtrace static probe site");
                        break;
                case ld::Fixup::kindStoreARM64DtraceIsEnableSiteClear:
                        printf("ARM64 dtrace static is-enabled site");
                        break;
+#endif
                case ld::Fixup::kindLazyTarget:
                        printf("lazy reference to external symbol %s", referenceTargetAtomName(ref));
                        break;
@@ -990,6 +993,7 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindSetTargetTLVTemplateOffsetLittleEndian64:
                        printf("tlv template offset of %s", referenceTargetAtomName(ref));
                        break;
+#if SUPPORT_ARCH_arm64
                case ld::Fixup::kindStoreTargetAddressARM64Branch26:
                        printf("ARM64 store 26-bit pcrel branch to %s", referenceTargetAtomName(ref));
                        break;
@@ -1023,6 +1027,7 @@ void dumper::dumpFixup(const ld::Fixup* ref)
                case ld::Fixup::kindStoreTargetAddressARM64TLVPLoadNowLeaPageOff12:
                        printf("ARM64 store 12-bit page offset of lea for TLV of %s", referenceTargetAtomName(ref));
                        break;
+#endif
                //default:
                //      printf("unknown fixup");
                //      break;
index 83d601e6596db73778ce8cd1d9f7e9e716b80cca..e2719783b1efa0c7750c6feb791f00db5700b077 100644 (file)
@@ -276,10 +276,13 @@ bool DyldInfoPrinter<arm64>::validFile(const uint8_t* fileContent)
        switch (header->filetype()) {
                case MH_EXECUTE:
                case MH_DYLIB:
+               case MH_DYLIB_STUB:
                case MH_BUNDLE:
                case MH_DYLINKER:
                case MH_KEXT_BUNDLE:
                        return true;
+               default:
+                       return false;
        }
        return false;
 }
index 97138e85d6e5c9258bcc7c5739210d6a628f5872..0b08844d25ba4448e741ce7af1ced5ee575910f6 100644 (file)
@@ -455,6 +455,8 @@ void MachOChecker<A>::checkLoadCommands()
                        case LC_LOAD_UPWARD_DYLIB:
                        case LC_VERSION_MIN_MACOSX:
                        case LC_VERSION_MIN_IPHONEOS:
+                       case LC_VERSION_MIN_TVOS:
+                       case LC_VERSION_MIN_WATCHOS:
                        case LC_FUNCTION_STARTS:
                        case LC_DYLD_ENVIRONMENT:
                        case LC_DATA_IN_CODE:
diff --git a/unit-tests/test-cases/lto-live_support_section/Makefile b/unit-tests/test-cases/lto-live_support_section/Makefile
new file mode 100644 (file)
index 0000000..01b417f
--- /dev/null
@@ -0,0 +1,45 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/25585305> __asan_globals section is stripped out when building -flto
+#
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS} -flto -o foo foo.c -Wl,-dead_strip,-exported_symbol,_my_global -v
+    # Check symbols that are expected to be preserved
+       nm -m foo | grep _global_metadata | ${FAIL_IF_EMPTY}
+       nm -m foo | grep _liveness_binder | ${FAIL_IF_EMPTY}
+       nm -m foo | grep _main | ${FAIL_IF_EMPTY}
+       nm -m foo | grep _my_global | ${FAIL_IF_EMPTY}
+
+    # Check symbols that are expected to be stripped
+       nm -m foo | grep unused | ${FAIL_IF_STDIN}
+       
+clean:
+       rm  foo
diff --git a/unit-tests/test-cases/lto-live_support_section/foo.c b/unit-tests/test-cases/lto-live_support_section/foo.c
new file mode 100644 (file)
index 0000000..f49c23a
--- /dev/null
@@ -0,0 +1,22 @@
+
+int my_global = 0;
+
+__attribute__ ((section ("__DATA,__asan_globals,regular")))
+struct { void *ptr; } global_metadata = { .ptr = &my_global };
+
+__attribute__ ((used, section ("__DATA,__asan_liveness,regular,live_support")))
+struct { void *a, *b; } liveness_binder = { .a = &global_metadata, .b = &my_global };
+
+int unused_global = 0;
+
+__attribute__ ((section ("__DATA,__asan_globals,regular")))
+struct { void *ptr; } unused_global_metadata = { .ptr = &unused_global };
+
+__attribute__ ((used, section ("__DATA,__asan_liveness,regular,live_support")))
+struct { void *a, *b; } unused_liveness_binder = { .a = &unused_global_metadata, .b = &unused_global };
+
+
+int main(int argc, char *argv[])
+{
+  return my_global;
+}
diff --git a/unit-tests/test-cases/lto-unexport-sym/Makefile b/unit-tests/test-cases/lto-unexport-sym/Makefile
new file mode 100644 (file)
index 0000000..de0808a
--- /dev/null
@@ -0,0 +1,42 @@
+##
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+#
+# @APPLE_LICENSE_HEADER_START@
+# 
+# This file contains Original Code and/or Modifications of Original Code
+# as defined in and that are subject to the Apple Public Source License
+# Version 2.0 (the 'License'). You may not use this file except in
+# compliance with the License. Please obtain a copy of the License at
+# http://www.opensource.apple.com/apsl/ and read it before using this
+# file.
+# 
+# The Original Code and all software distributed under the License are
+# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+# Please see the License for the specific language governing rights and
+# limitations under the License.
+# 
+# @APPLE_LICENSE_HEADER_END@
+##
+TESTROOT = ../..
+include ${TESTROOT}/include/common.makefile
+
+#
+# <rdar://problem/25585305> __asan_globals section is stripped out when building -flto
+#
+
+
+run: all
+
+all:
+       ${CC} ${CCFLAGS}  -c a.c 
+       ${CC} ${CCFLAGS} -c b.c -flto
+       ${CC} ${CCFLAGS}  a.o b.o -unexported_symbols_list unexp.list
+    # Check that unexported symbols are hidden
+       nm a.out | grep "t _bar" | ${FAIL_IF_EMPTY}
+       nm a.out | grep "t _foo" | ${FAIL_IF_EMPTY}
+       
+clean:
+       rm a.out b.o a.o
diff --git a/unit-tests/test-cases/lto-unexport-sym/a.c b/unit-tests/test-cases/lto-unexport-sym/a.c
new file mode 100644 (file)
index 0000000..89cea52
--- /dev/null
@@ -0,0 +1,7 @@
+void foo();
+void bar() {
+       foo();
+}
+
+int main() {
+}
diff --git a/unit-tests/test-cases/lto-unexport-sym/b.c b/unit-tests/test-cases/lto-unexport-sym/b.c
new file mode 100644 (file)
index 0000000..d0d3aa5
--- /dev/null
@@ -0,0 +1,3 @@
+void foo() {
+       
+}
\ No newline at end of file
diff --git a/unit-tests/test-cases/lto-unexport-sym/unexp.list b/unit-tests/test-cases/lto-unexport-sym/unexp.list
new file mode 100644 (file)
index 0000000..b9e50b8
--- /dev/null
@@ -0,0 +1,2 @@
+_foo
+_bar