diff --git a/clang/test/Driver/clang-offload-bundler.c b/clang/test/Driver/clang-offload-bundler.c index 35c327c56b3bc6..99d638cb889b8c 100644 --- a/clang/test/Driver/clang-offload-bundler.c +++ b/clang/test/Driver/clang-offload-bundler.c @@ -253,7 +253,8 @@ // RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.o,%t.tgt1,%t.tgt2 -outputs=%t.bundle3.o -### 2>&1 \ // RUN: | FileCheck %s -DHOST=%itanium_abi_triple -DINOBJ1=%t.o -DINOBJ2=%t.tgt1 -DINOBJ3=%t.tgt2 -DOUTOBJ=%t.bundle3.o --check-prefix CK-OBJ-CMD -// CK-OBJ-CMD: llvm-objcopy{{(.exe)?}}" "--add-section=__CLANG_OFFLOAD_BUNDLE__host-[[HOST]]=[[INOBJ1]]" "--add-section=__CLANG_OFFLOAD_BUNDLE__openmp-powerpc64le-ibm-linux-gnu=[[INOBJ2]]" "--add-section=__CLANG_OFFLOAD_BUNDLE__openmp-x86_64-pc-linux-gnu=[[INOBJ3]]" "[[INOBJ1]]" "[[OUTOBJ]]" +// CK-OBJ-CMD: llvm-objcopy{{(.exe)?}}" "--add-section=__CLANG_OFFLOAD_BUNDLE__host-[[HOST]]=[[INOBJ1]]" "--add-section=__CLANG_OFFLOAD_BUNDLE__openmp-powerpc64le-ibm-linux-gnu=[[INOBJ2]]" "--add-section=__CLANG_OFFLOAD_BUNDLE__openmp-x86_64-pc-linux-gnu=[[INOBJ3]]" "[[INOBJ1]]" "[[TEMPOBJ:.*]]" +// CK-OBJ-CMD: llvm-objcopy{{(.exe)?}}" "--set-section-flags=__CLANG_OFFLOAD_BUNDLE__host-[[HOST]]=readonly,exclude" "--set-section-flags=__CLANG_OFFLOAD_BUNDLE__openmp-powerpc64le-ibm-linux-gnu=readonly,exclude" "--set-section-flags=__CLANG_OFFLOAD_BUNDLE__openmp-x86_64-pc-linux-gnu=readonly,exclude" "[[TEMPOBJ]]" "[[OUTOBJ]]" // RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -inputs=%t.o,%t.tgt1,%t.tgt2 -outputs=%t.bundle3.o // RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-powerpc64le-ibm-linux-gnu,openmp-x86_64-pc-linux-gnu -outputs=%t.res.o,%t.res.tgt1,%t.res.tgt2 -inputs=%t.bundle3.o -unbundle diff --git a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp index a75d2a630cf482..c215cff303e74d 100644 --- a/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp +++ b/clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp @@ -30,6 +30,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/ErrorOr.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/FileUtilities.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" #include "llvm/Support/Program.h" @@ -463,6 +464,15 @@ class ObjectFileHandler final : public FileHandler { if (NumberOfProcessedInputs != NumberOfInputs) return Error::success(); + // We will use llvm-objcopy to add target objects sections to the output + // fat object. These sections should have 'exclude' flag set which tells + // link editor to remove them from linker inputs when linking executable or + // shared library. llvm-objcopy currently does not support adding new + // section and changing flags for the added section in one invocation, and + // because of that we have to run it two times. First run adds sections and + // the second changes flags. + // TODO: change it to one run once llvm-objcopy starts supporting that. + // Find llvm-objcopy in order to create the bundle binary. ErrorOr Objcopy = sys::findProgramByName( "llvm-objcopy", sys::path::parent_path(BundlerExecutable)); @@ -476,7 +486,15 @@ class ObjectFileHandler final : public FileHandler { // to pass down to llvm-objcopy. OS.close(); - // Compose command line for the objcopy tool. + // Create an intermediate temporary file to save object after the first + // llvm-objcopy run. + SmallString<128u> IntermediateObj; + if (std::error_code EC = sys::fs::createTemporaryFile( + "clang-offload-bundler", "tmp", IntermediateObj)) + return createFileError(IntermediateObj, EC); + FileRemover IntermediateObjRemover(IntermediateObj); + + // Compose llvm-objcopy command line for add target objects' sections. BumpPtrAllocator Alloc; StringSaver SS{Alloc}; SmallVector ObjcopyArgs{"llvm-objcopy"}; @@ -485,25 +503,44 @@ class ObjectFileHandler final : public FileHandler { OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] + "=" + InputFileNames[I])); ObjcopyArgs.push_back(InputFileNames[HostInputIndex]); + ObjcopyArgs.push_back(IntermediateObj); + + if (Error Err = executeObjcopy(*Objcopy, ObjcopyArgs)) + return Err; + + // And run llvm-objcopy for the second time to update section flags. + ObjcopyArgs.resize(1); + for (unsigned I = 0; I < NumberOfInputs; ++I) + ObjcopyArgs.push_back(SS.save(Twine("--set-section-flags=") + + OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] + + "=readonly,exclude")); + ObjcopyArgs.push_back(IntermediateObj); ObjcopyArgs.push_back(OutputFileNames.front()); - // If the user asked for the commands to be printed out, we do that instead - // of executing it. + if (Error Err = executeObjcopy(*Objcopy, ObjcopyArgs)) + return Err; + + return Error::success(); + } + + Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { + return Error::success(); + } + +private: + static Error executeObjcopy(StringRef Objcopy, ArrayRef Args) { + // If the user asked for the commands to be printed out, we do that + // instead of executing it. if (PrintExternalCommands) { - errs() << "\"" << *Objcopy << "\""; - for (StringRef Arg : drop_begin(ObjcopyArgs, 1)) + errs() << "\"" << Objcopy << "\""; + for (StringRef Arg : drop_begin(Args, 1)) errs() << " \"" << Arg << "\""; errs() << "\n"; } else { - if (sys::ExecuteAndWait(*Objcopy, ObjcopyArgs)) + if (sys::ExecuteAndWait(Objcopy, Args)) return createStringError(inconvertibleErrorCode(), "'llvm-objcopy' tool failed"); } - - return Error::success(); - } - - Error WriteBundle(raw_fd_ostream &OS, MemoryBuffer &Input) final { return Error::success(); } };