Skip to content

Commit 566c136

Browse files
authored
[clang-offload-bundler] add .tgtsym section with target symbol names to fat object (#2862)
This patch changes clang-offload-bundler tool to add a new section .tgtsym to fat object file. This section contains names of symbols defined in the embedded target objects prefixed by the offload target id "<kind>-<triple>". Prefixed symbol names are separated by '\0' character in the section data. Signed-off-by: Sergey Dmitriev <[email protected]>
1 parent 78e2599 commit 566c136

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// REQUIRES: x86-registered-target
2+
3+
// This test check that clang-offload-bundler adds .tgtsym section to the output
4+
// file when creating a fat object. This section contains names of the external
5+
// symbols defined in the embdedded target objects with target prefixes.
6+
7+
// RUN: %clang -target %itanium_abi_triple -c %s -o %t.o
8+
// RUN: %clang -target x86_64-pc-linux-gnu -c %s -o %t.tgt1
9+
// RUN: %clang -target spir64 -emit-llvm -c %s -o %t.tgt2
10+
11+
// RUN: clang-offload-bundler -type=o -targets=host-%itanium_abi_triple,openmp-x86_64-pc-linux-gnu,sycl-spir64 -inputs=%t.o,%t.tgt1,%t.tgt2 -outputs=%t.fat.o
12+
// RUN: llvm-readobj --string-dump=.tgtsym %t.fat.o | FileCheck %s
13+
14+
// CHECK: String dump of section '.tgtsym':
15+
// CHECK-DAG: openmp-x86_64-pc-linux-gnu.foo
16+
// CHECK-DAG: openmp-x86_64-pc-linux-gnu.bar
17+
// CHECK-DAG: sycl-spir64.foo
18+
// CHECK-DAG: sycl-spir64.bar
19+
// CHECK-NOT: undefined_func
20+
// CHECK-NOT: static_func
21+
22+
extern void undefined_func(void);
23+
24+
void foo(void) {
25+
undefined_func();
26+
}
27+
28+
static void static_func(void) __attribute__((noinline));
29+
static void static_func(void) {}
30+
31+
void bar(void) {
32+
static_func();
33+
}

clang/tools/clang-offload-bundler/ClangOffloadBundler.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/ADT/StringSet.h"
2424
#include "llvm/ADT/StringSwitch.h"
2525
#include "llvm/ADT/Triple.h"
26+
#include "llvm/IR/LLVMContext.h"
2627
#include "llvm/Object/Archive.h"
2728
#include "llvm/Object/ArchiveWriter.h"
2829
#include "llvm/Object/Binary.h"
@@ -121,6 +122,9 @@ static cl::opt<unsigned>
121122
/// Prefix of an added section name with bundle size.
122123
#define SIZE_SECTION_PREFIX "__CLANG_OFFLOAD_BUNDLE_SIZE__"
123124

125+
/// Section name which holds target symbol names.
126+
#define SYMBOLS_SECTION_NAME ".tgtsym"
127+
124128
/// The index of the host input in the list of inputs.
125129
static unsigned HostInputIndex = ~0u;
126130

@@ -546,6 +550,62 @@ class ObjectFileHandler final : public FileHandler {
546550
/// Input sizes.
547551
SmallVector<uint64_t, 16u> InputSizes;
548552

553+
// Return a buffer with symbol names that are defined in target objects.
554+
// Each symbol name is prefixed by a target name <kind>-<triple> to uniquely
555+
// identify the target it belongs to, and symbol names are separated from each
556+
// other by '\0' characters.
557+
Expected<SmallVector<char, 0>> makeTargetSymbolTable() {
558+
SmallVector<char, 0> SymbolsBuf;
559+
raw_svector_ostream SymbolsOS(SymbolsBuf);
560+
561+
for (unsigned I = 0; I < NumberOfInputs; ++I) {
562+
if (I == HostInputIndex)
563+
continue;
564+
565+
// Get the list of symbols defined in the target object. Open file and
566+
// check if it is a symbolic file.
567+
ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
568+
MemoryBuffer::getFileOrSTDIN(InputFileNames[I]);
569+
if (!BufOrErr)
570+
return createFileError(InputFileNames[I], BufOrErr.getError());
571+
572+
LLVMContext Context;
573+
Expected<std::unique_ptr<Binary>> BinOrErr =
574+
createBinary(BufOrErr.get()->getMemBufferRef(), &Context);
575+
576+
// If it is not a symbolic file just ignore it since we cannot do anything
577+
// with it.
578+
if (!BinOrErr) {
579+
if (auto Err = isNotObjectErrorInvalidFileType(BinOrErr.takeError()))
580+
return std::move(Err);
581+
continue;
582+
}
583+
auto *SF = dyn_cast<SymbolicFile>(&**BinOrErr);
584+
if (!SF)
585+
continue;
586+
587+
for (BasicSymbolRef Symbol : SF->symbols()) {
588+
Expected<uint32_t> FlagsOrErr = Symbol.getFlags();
589+
if (!FlagsOrErr)
590+
return FlagsOrErr.takeError();
591+
592+
// We are interested in externally visible and defined symbols only, so
593+
// ignore it if this is not such a symbol.
594+
bool Undefined = *FlagsOrErr & SymbolRef::SF_Undefined;
595+
bool Global = *FlagsOrErr & SymbolRef::SF_Global;
596+
if (Undefined || !Global)
597+
continue;
598+
599+
// Add symbol name with the target prefix to the buffer.
600+
SymbolsOS << TargetNames[I] << ".";
601+
if (Error Err = Symbol.printName(SymbolsOS))
602+
return std::move(Err);
603+
SymbolsOS << '\0';
604+
}
605+
}
606+
return SymbolsBuf;
607+
}
608+
549609
public:
550610
ObjectFileHandler(std::unique_ptr<ObjectFile> ObjIn)
551611
: FileHandler(), Obj(std::move(ObjIn)),
@@ -793,6 +853,25 @@ class ObjectFileHandler final : public FileHandler {
793853
SIZE_SECTION_PREFIX + TargetNames[I] + "=" +
794854
*SizeFileOrErr));
795855
}
856+
857+
// Add a section with symbol names that are defined in target objects to the
858+
// output fat object.
859+
Expected<SmallVector<char, 0>> SymbolsOrErr = makeTargetSymbolTable();
860+
if (!SymbolsOrErr)
861+
return SymbolsOrErr.takeError();
862+
863+
if (!SymbolsOrErr->empty()) {
864+
// Add section with symbols names to fat object.
865+
Expected<StringRef> SymbolsFileOrErr =
866+
TempFiles.Create(makeArrayRef(*SymbolsOrErr));
867+
if (!SymbolsFileOrErr)
868+
return SymbolsFileOrErr.takeError();
869+
870+
ObjcopyArgs.push_back(SS.save(Twine("--add-section=") +
871+
SYMBOLS_SECTION_NAME + "=" +
872+
*SymbolsFileOrErr));
873+
}
874+
796875
ObjcopyArgs.push_back(InputFileNames[HostInputIndex]);
797876
ObjcopyArgs.push_back(IntermediateObj);
798877

0 commit comments

Comments
 (0)