diff --git a/lld/MachO/Config.h b/lld/MachO/Config.h --- a/lld/MachO/Config.h +++ b/lld/MachO/Config.h @@ -43,6 +43,7 @@ uint32_t headerPad; llvm::StringRef installName; llvm::StringRef outputFile; + llvm::StringRef ltoObjPath; bool demangle = false; llvm::MachO::Architecture arch; PlatformInfo platform; diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -642,6 +642,7 @@ config->headerPad = args::getHex(args, OPT_headerpad, /*Default=*/32); config->headerPadMaxInstallNames = args.hasArg(OPT_headerpad_max_install_names); + config->ltoObjPath = args.getLastArgValue(OPT_object_path_lto); config->outputType = getOutputType(args); config->runtimePaths = args::getStrings(args, OPT_rpath); config->allLoad = args.hasArg(OPT_all_load); diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -14,11 +14,14 @@ #include "lld/Common/Strings.h" #include "lld/Common/TargetOptionsCommandFlags.h" #include "llvm/LTO/LTO.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" #include "llvm/Support/raw_ostream.h" using namespace lld; using namespace lld::macho; using namespace llvm; +using namespace llvm::sys; static lto::Config createConfig() { lto::Config c; @@ -55,6 +58,19 @@ checkError(ltoObj->add(std::move(f.obj), resols)); } +static void setModTime(StringRef path, std::time_t t) { + int fd; + std::error_code ec = fs::openFileForRead(path, fd); + if (ec) + fatal("failed to open " + path); + ec = fs::setLastAccessAndModificationTime(fd, toTimePoint(t)); + if (ec) + fatal("failed to set modification time for " + path); + ec = fs::closeFile(fd); + if (ec) + fatal("failed to close " + path); +} + // Merge all the bitcode files we have seen, codegen the result // and return the resulting ObjectFile(s). std::vector BitcodeCompiler::compile() { @@ -73,12 +89,30 @@ saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); } - // TODO: set modTime properly + if (!config->ltoObjPath.empty()) + fs::create_directories(config->ltoObjPath); + std::vector ret; - for (unsigned i = 0; i != maxTasks; ++i) - if (!buf[i].empty()) - ret.push_back( - make(MemoryBufferRef(buf[i], "lto.tmp"), /*modTime=*/0, "")); + for (unsigned i = 0; i != maxTasks; ++i) { + if (buf[i].empty()) { + continue; + } + SmallString<261> filePath("/tmp/lto.tmp"); + if (!config->ltoObjPath.empty()) { + filePath = config->ltoObjPath; + path::append(filePath, Twine(i) + "." + + getArchitectureName(config->arch) + ".lto.o"); + saveBuffer(buf[i], filePath); + + // Instead of retrieving the real modtime, we instead zero it out -- + // this ensures that the output binary is reproducible, instead of + // containing a STABS timestamp entry that keeps changing. + setModTime(filePath, 0); + } + ret.push_back( + make(MemoryBufferRef(buf[i], saver.save(filePath.str())), + /*modTime=*/0, "")); + } return ret; } diff --git a/lld/MachO/Options.td b/lld/MachO/Options.td --- a/lld/MachO/Options.td +++ b/lld/MachO/Options.td @@ -842,7 +842,6 @@ def object_path_lto : Separate<["-"], "object_path_lto">, MetaVarName<"">, HelpText<"Retain any temporary mach-o file in that would otherwise be deleted during LTO">, - Flags<[HelpHidden]>, Group; def lto_library : Separate<["-"], "lto_library">, MetaVarName<"">, diff --git a/lld/test/MachO/lto-object-path.ll b/lld/test/MachO/lto-object-path.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/lto-object-path.ll @@ -0,0 +1,35 @@ +; REQUIRES: x86 + +; RUN: rm -rf %t; mkdir %t +; RUN: llvm-as %s -o %t/test.o + +; RUN: %lld %t/test.o -o %t/test +; RUN: llvm-nm -pa %t/test | FileCheck %s -DOSO=/tmp/lto.tmp + +; RUN: %lld %t/test.o -o %t/test -object_path_lto %t/lto-temps +; RUN: llvm-nm -pa %t/test | FileCheck %s -DOSO=%t/lto-temps/0.x86_64.lto.o + +; CHECK: 0000000000000000 - 00 0000 SO /tmp/test.cpp +; CHECK-NEXT: 0000000000000000 - 03 0001 OSO [[OSO]] +; CHECK-NEXT: {{[0-9a-f]+}} - 01 0000 FUN _main +; CHECK-NEXT: 0000000000000001 - 00 0000 FUN +; CHECK-NEXT: 0000000000000000 - 01 0000 SO +; CHECK-NEXT: {{[0-9a-f]+}} T _main + +target triple = "x86_64-apple-macosx10.15.0" +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +define void @main() #0 !dbg !4 { + ret void +} + +!llvm.module.flags = !{ !0, !1 } +!llvm.dbg.cu = !{!2} + +!0 = !{i32 7, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !3, emissionKind: FullDebug) +!3 = !DIFile(filename: "test.cpp", directory: "/tmp") +!4 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 1, type: !5, scopeLine: 1, unit: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{}