Index: clang/test/Driver/clang-offload-bundler.c =================================================================== --- clang/test/Driver/clang-offload-bundler.c +++ 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 Index: clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp =================================================================== --- clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp +++ 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 @@ 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 @@ // 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,20 +503,38 @@ OFFLOAD_BUNDLER_MAGIC_STR + TargetNames[I] + "=" + InputFileNames[I])); ObjcopyArgs.push_back(InputFileNames[HostInputIndex]); + ObjcopyArgs.push_back(IntermediateObj); + + auto ExecuteObjcopy = [&Objcopy](ArrayRef ObjcopyArgs) -> Error { + // 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() << " \"" << Arg << "\""; + errs() << "\n"; + } else { + if (sys::ExecuteAndWait(*Objcopy, ObjcopyArgs)) + return createStringError(inconvertibleErrorCode(), + "'llvm-objcopy' tool failed"); + } + return Error::success(); + }; + + if (Error Err = ExecuteObjcopy(ObjcopyArgs)) + return Err; + + // And run llvm-objcopy fro 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 (PrintExternalCommands) { - errs() << "\"" << *Objcopy << "\""; - for (StringRef Arg : drop_begin(ObjcopyArgs, 1)) - errs() << " \"" << Arg << "\""; - errs() << "\n"; - } else { - if (sys::ExecuteAndWait(*Objcopy, ObjcopyArgs)) - return createStringError(inconvertibleErrorCode(), - "'llvm-objcopy' tool failed"); - } + if (Error Err = ExecuteObjcopy(ObjcopyArgs)) + return Err; return Error::success(); }