ClangOffloadWrapper.cpp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. //===-- clang-offload-wrapper/ClangOffloadWrapper.cpp -----------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. ///
  9. /// \file
  10. /// Implementation of the offload wrapper tool. It takes offload target binaries
  11. /// as input and creates wrapper bitcode file containing target binaries
  12. /// packaged as data. Wrapper bitcode also includes initialization code which
  13. /// registers target binaries in offloading runtime at program startup.
  14. ///
  15. //===----------------------------------------------------------------------===//
  16. #include "clang/Basic/Version.h"
  17. #include "llvm/ADT/ArrayRef.h"
  18. #include "llvm/ADT/Triple.h"
  19. #include "llvm/BinaryFormat/ELF.h"
  20. #include "llvm/Bitcode/BitcodeWriter.h"
  21. #include "llvm/IR/Constants.h"
  22. #include "llvm/IR/GlobalVariable.h"
  23. #include "llvm/IR/IRBuilder.h"
  24. #include "llvm/IR/LLVMContext.h"
  25. #include "llvm/IR/Module.h"
  26. #include "llvm/Object/ELFObjectFile.h"
  27. #include "llvm/Object/ObjectFile.h"
  28. #include "llvm/Support/CommandLine.h"
  29. #include "llvm/Support/EndianStream.h"
  30. #include "llvm/Support/Errc.h"
  31. #include "llvm/Support/Error.h"
  32. #include "llvm/Support/ErrorOr.h"
  33. #include "llvm/Support/FileSystem.h"
  34. #include "llvm/Support/MemoryBuffer.h"
  35. #include "llvm/Support/Path.h"
  36. #include "llvm/Support/Program.h"
  37. #include "llvm/Support/Signals.h"
  38. #include "llvm/Support/ToolOutputFile.h"
  39. #include "llvm/Support/VCSRevision.h"
  40. #include "llvm/Support/WithColor.h"
  41. #include "llvm/Support/raw_ostream.h"
  42. #include "llvm/Transforms/Utils/ModuleUtils.h"
  43. #include <cassert>
  44. #include <cstdint>
  45. #define OPENMP_OFFLOAD_IMAGE_VERSION "1.0"
  46. using namespace llvm;
  47. using namespace llvm::object;
  48. static cl::opt<bool> Help("h", cl::desc("Alias for -help"), cl::Hidden);
  49. // Mark all our options with this category, everything else (except for -version
  50. // and -help) will be hidden.
  51. static cl::OptionCategory
  52. ClangOffloadWrapperCategory("clang-offload-wrapper options");
  53. static cl::opt<std::string> Output("o", cl::Required,
  54. cl::desc("Output filename"),
  55. cl::value_desc("filename"),
  56. cl::cat(ClangOffloadWrapperCategory));
  57. static cl::list<std::string> Inputs(cl::Positional, cl::OneOrMore,
  58. cl::desc("<input files>"),
  59. cl::cat(ClangOffloadWrapperCategory));
  60. static cl::opt<std::string>
  61. Target("target", cl::Required,
  62. cl::desc("Target triple for the output module"),
  63. cl::value_desc("triple"), cl::cat(ClangOffloadWrapperCategory));
  64. static cl::opt<bool> SaveTemps(
  65. "save-temps",
  66. cl::desc("Save temporary files that may be produced by the tool. "
  67. "This option forces print-out of the temporary files' names."),
  68. cl::Hidden);
  69. static cl::opt<bool> AddOpenMPOffloadNotes(
  70. "add-omp-offload-notes",
  71. cl::desc("Add LLVMOMPOFFLOAD ELF notes to ELF device images."), cl::Hidden);
  72. namespace {
  73. class BinaryWrapper {
  74. LLVMContext C;
  75. Module M;
  76. StructType *EntryTy = nullptr;
  77. StructType *ImageTy = nullptr;
  78. StructType *DescTy = nullptr;
  79. std::string ToolName;
  80. std::string ObjcopyPath;
  81. // Temporary file names that may be created during adding notes
  82. // to ELF offload images. Use -save-temps to keep them and also
  83. // see their names. A temporary file's name includes the name
  84. // of the original input ELF image, so you can easily match
  85. // them, if you have multiple inputs.
  86. std::vector<std::string> TempFiles;
  87. private:
  88. IntegerType *getSizeTTy() {
  89. switch (M.getDataLayout().getPointerTypeSize(Type::getInt8PtrTy(C))) {
  90. case 4u:
  91. return Type::getInt32Ty(C);
  92. case 8u:
  93. return Type::getInt64Ty(C);
  94. }
  95. llvm_unreachable("unsupported pointer type size");
  96. }
  97. // struct __tgt_offload_entry {
  98. // void *addr;
  99. // char *name;
  100. // size_t size;
  101. // int32_t flags;
  102. // int32_t reserved;
  103. // };
  104. StructType *getEntryTy() {
  105. if (!EntryTy)
  106. EntryTy = StructType::create("__tgt_offload_entry", Type::getInt8PtrTy(C),
  107. Type::getInt8PtrTy(C), getSizeTTy(),
  108. Type::getInt32Ty(C), Type::getInt32Ty(C));
  109. return EntryTy;
  110. }
  111. PointerType *getEntryPtrTy() { return PointerType::getUnqual(getEntryTy()); }
  112. // struct __tgt_device_image {
  113. // void *ImageStart;
  114. // void *ImageEnd;
  115. // __tgt_offload_entry *EntriesBegin;
  116. // __tgt_offload_entry *EntriesEnd;
  117. // };
  118. StructType *getDeviceImageTy() {
  119. if (!ImageTy)
  120. ImageTy = StructType::create("__tgt_device_image", Type::getInt8PtrTy(C),
  121. Type::getInt8PtrTy(C), getEntryPtrTy(),
  122. getEntryPtrTy());
  123. return ImageTy;
  124. }
  125. PointerType *getDeviceImagePtrTy() {
  126. return PointerType::getUnqual(getDeviceImageTy());
  127. }
  128. // struct __tgt_bin_desc {
  129. // int32_t NumDeviceImages;
  130. // __tgt_device_image *DeviceImages;
  131. // __tgt_offload_entry *HostEntriesBegin;
  132. // __tgt_offload_entry *HostEntriesEnd;
  133. // };
  134. StructType *getBinDescTy() {
  135. if (!DescTy)
  136. DescTy = StructType::create("__tgt_bin_desc", Type::getInt32Ty(C),
  137. getDeviceImagePtrTy(), getEntryPtrTy(),
  138. getEntryPtrTy());
  139. return DescTy;
  140. }
  141. PointerType *getBinDescPtrTy() {
  142. return PointerType::getUnqual(getBinDescTy());
  143. }
  144. /// Creates binary descriptor for the given device images. Binary descriptor
  145. /// is an object that is passed to the offloading runtime at program startup
  146. /// and it describes all device images available in the executable or shared
  147. /// library. It is defined as follows
  148. ///
  149. /// __attribute__((visibility("hidden")))
  150. /// extern __tgt_offload_entry *__start_omp_offloading_entries;
  151. /// __attribute__((visibility("hidden")))
  152. /// extern __tgt_offload_entry *__stop_omp_offloading_entries;
  153. ///
  154. /// static const char Image0[] = { <Bufs.front() contents> };
  155. /// ...
  156. /// static const char ImageN[] = { <Bufs.back() contents> };
  157. ///
  158. /// static const __tgt_device_image Images[] = {
  159. /// {
  160. /// Image0, /*ImageStart*/
  161. /// Image0 + sizeof(Image0), /*ImageEnd*/
  162. /// __start_omp_offloading_entries, /*EntriesBegin*/
  163. /// __stop_omp_offloading_entries /*EntriesEnd*/
  164. /// },
  165. /// ...
  166. /// {
  167. /// ImageN, /*ImageStart*/
  168. /// ImageN + sizeof(ImageN), /*ImageEnd*/
  169. /// __start_omp_offloading_entries, /*EntriesBegin*/
  170. /// __stop_omp_offloading_entries /*EntriesEnd*/
  171. /// }
  172. /// };
  173. ///
  174. /// static const __tgt_bin_desc BinDesc = {
  175. /// sizeof(Images) / sizeof(Images[0]), /*NumDeviceImages*/
  176. /// Images, /*DeviceImages*/
  177. /// __start_omp_offloading_entries, /*HostEntriesBegin*/
  178. /// __stop_omp_offloading_entries /*HostEntriesEnd*/
  179. /// };
  180. ///
  181. /// Global variable that represents BinDesc is returned.
  182. GlobalVariable *createBinDesc(ArrayRef<ArrayRef<char>> Bufs) {
  183. // Create external begin/end symbols for the offload entries table.
  184. auto *EntriesB = new GlobalVariable(
  185. M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage,
  186. /*Initializer*/ nullptr, "__start_omp_offloading_entries");
  187. EntriesB->setVisibility(GlobalValue::HiddenVisibility);
  188. auto *EntriesE = new GlobalVariable(
  189. M, getEntryTy(), /*isConstant*/ true, GlobalValue::ExternalLinkage,
  190. /*Initializer*/ nullptr, "__stop_omp_offloading_entries");
  191. EntriesE->setVisibility(GlobalValue::HiddenVisibility);
  192. // We assume that external begin/end symbols that we have created above will
  193. // be defined by the linker. But linker will do that only if linker inputs
  194. // have section with "omp_offloading_entries" name which is not guaranteed.
  195. // So, we just create dummy zero sized object in the offload entries section
  196. // to force linker to define those symbols.
  197. auto *DummyInit =
  198. ConstantAggregateZero::get(ArrayType::get(getEntryTy(), 0u));
  199. auto *DummyEntry = new GlobalVariable(
  200. M, DummyInit->getType(), true, GlobalVariable::ExternalLinkage,
  201. DummyInit, "__dummy.omp_offloading.entry");
  202. DummyEntry->setSection("omp_offloading_entries");
  203. DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
  204. auto *Zero = ConstantInt::get(getSizeTTy(), 0u);
  205. Constant *ZeroZero[] = {Zero, Zero};
  206. // Create initializer for the images array.
  207. SmallVector<Constant *, 4u> ImagesInits;
  208. ImagesInits.reserve(Bufs.size());
  209. for (ArrayRef<char> Buf : Bufs) {
  210. auto *Data = ConstantDataArray::get(C, Buf);
  211. auto *Image = new GlobalVariable(M, Data->getType(), /*isConstant*/ true,
  212. GlobalVariable::InternalLinkage, Data,
  213. ".omp_offloading.device_image");
  214. Image->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
  215. auto *Size = ConstantInt::get(getSizeTTy(), Buf.size());
  216. Constant *ZeroSize[] = {Zero, Size};
  217. auto *ImageB = ConstantExpr::getGetElementPtr(Image->getValueType(),
  218. Image, ZeroZero);
  219. auto *ImageE = ConstantExpr::getGetElementPtr(Image->getValueType(),
  220. Image, ZeroSize);
  221. ImagesInits.push_back(ConstantStruct::get(getDeviceImageTy(), ImageB,
  222. ImageE, EntriesB, EntriesE));
  223. }
  224. // Then create images array.
  225. auto *ImagesData = ConstantArray::get(
  226. ArrayType::get(getDeviceImageTy(), ImagesInits.size()), ImagesInits);
  227. auto *Images =
  228. new GlobalVariable(M, ImagesData->getType(), /*isConstant*/ true,
  229. GlobalValue::InternalLinkage, ImagesData,
  230. ".omp_offloading.device_images");
  231. Images->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
  232. auto *ImagesB = ConstantExpr::getGetElementPtr(Images->getValueType(),
  233. Images, ZeroZero);
  234. // And finally create the binary descriptor object.
  235. auto *DescInit = ConstantStruct::get(
  236. getBinDescTy(),
  237. ConstantInt::get(Type::getInt32Ty(C), ImagesInits.size()), ImagesB,
  238. EntriesB, EntriesE);
  239. return new GlobalVariable(M, DescInit->getType(), /*isConstant*/ true,
  240. GlobalValue::InternalLinkage, DescInit,
  241. ".omp_offloading.descriptor");
  242. }
  243. void createRegisterFunction(GlobalVariable *BinDesc) {
  244. auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
  245. auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
  246. ".omp_offloading.descriptor_reg", &M);
  247. Func->setSection(".text.startup");
  248. // Get __tgt_register_lib function declaration.
  249. auto *RegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(),
  250. /*isVarArg*/ false);
  251. FunctionCallee RegFuncC =
  252. M.getOrInsertFunction("__tgt_register_lib", RegFuncTy);
  253. // Construct function body
  254. IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
  255. Builder.CreateCall(RegFuncC, BinDesc);
  256. Builder.CreateRetVoid();
  257. // Add this function to constructors.
  258. // Set priority to 1 so that __tgt_register_lib is executed AFTER
  259. // __tgt_register_requires (we want to know what requirements have been
  260. // asked for before we load a libomptarget plugin so that by the time the
  261. // plugin is loaded it can report how many devices there are which can
  262. // satisfy these requirements).
  263. appendToGlobalCtors(M, Func, /*Priority*/ 1);
  264. }
  265. void createUnregisterFunction(GlobalVariable *BinDesc) {
  266. auto *FuncTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg*/ false);
  267. auto *Func = Function::Create(FuncTy, GlobalValue::InternalLinkage,
  268. ".omp_offloading.descriptor_unreg", &M);
  269. Func->setSection(".text.startup");
  270. // Get __tgt_unregister_lib function declaration.
  271. auto *UnRegFuncTy = FunctionType::get(Type::getVoidTy(C), getBinDescPtrTy(),
  272. /*isVarArg*/ false);
  273. FunctionCallee UnRegFuncC =
  274. M.getOrInsertFunction("__tgt_unregister_lib", UnRegFuncTy);
  275. // Construct function body
  276. IRBuilder<> Builder(BasicBlock::Create(C, "entry", Func));
  277. Builder.CreateCall(UnRegFuncC, BinDesc);
  278. Builder.CreateRetVoid();
  279. // Add this function to global destructors.
  280. // Match priority of __tgt_register_lib
  281. appendToGlobalDtors(M, Func, /*Priority*/ 1);
  282. }
  283. public:
  284. BinaryWrapper(StringRef Target, StringRef ToolName)
  285. : M("offload.wrapper.object", C), ToolName(ToolName) {
  286. M.setTargetTriple(Target);
  287. // Look for llvm-objcopy in the same directory, from which
  288. // clang-offload-wrapper is invoked. This helps OpenMP offload
  289. // LIT tests.
  290. // This just needs to be some symbol in the binary; C++ doesn't
  291. // allow taking the address of ::main however.
  292. void *P = (void *)(intptr_t)&Help;
  293. std::string COWPath = sys::fs::getMainExecutable(ToolName.str().c_str(), P);
  294. if (!COWPath.empty()) {
  295. auto COWDir = sys::path::parent_path(COWPath);
  296. ErrorOr<std::string> ObjcopyPathOrErr =
  297. sys::findProgramByName("llvm-objcopy", {COWDir});
  298. if (ObjcopyPathOrErr) {
  299. ObjcopyPath = *ObjcopyPathOrErr;
  300. return;
  301. }
  302. // Otherwise, look through PATH environment.
  303. }
  304. ErrorOr<std::string> ObjcopyPathOrErr =
  305. sys::findProgramByName("llvm-objcopy");
  306. if (!ObjcopyPathOrErr) {
  307. WithColor::warning(errs(), ToolName)
  308. << "cannot find llvm-objcopy[.exe] in PATH; ELF notes cannot be "
  309. "added.\n";
  310. return;
  311. }
  312. ObjcopyPath = *ObjcopyPathOrErr;
  313. }
  314. ~BinaryWrapper() {
  315. if (TempFiles.empty())
  316. return;
  317. StringRef ToolNameRef(ToolName);
  318. auto warningOS = [ToolNameRef]() -> raw_ostream & {
  319. return WithColor::warning(errs(), ToolNameRef);
  320. };
  321. for (auto &F : TempFiles) {
  322. if (SaveTemps) {
  323. warningOS() << "keeping temporary file " << F << "\n";
  324. continue;
  325. }
  326. auto EC = sys::fs::remove(F, false);
  327. if (EC)
  328. warningOS() << "cannot remove temporary file " << F << ": "
  329. << EC.message().c_str() << "\n";
  330. }
  331. }
  332. const Module &wrapBinaries(ArrayRef<ArrayRef<char>> Binaries) {
  333. GlobalVariable *Desc = createBinDesc(Binaries);
  334. assert(Desc && "no binary descriptor");
  335. createRegisterFunction(Desc);
  336. createUnregisterFunction(Desc);
  337. return M;
  338. }
  339. std::unique_ptr<MemoryBuffer> addELFNotes(std::unique_ptr<MemoryBuffer> Buf,
  340. StringRef OriginalFileName) {
  341. // Cannot add notes, if llvm-objcopy is not available.
  342. //
  343. // I did not find a clean way to add a new notes section into an existing
  344. // ELF file. llvm-objcopy seems to recreate a new ELF from scratch,
  345. // and we just try to use llvm-objcopy here.
  346. if (ObjcopyPath.empty())
  347. return Buf;
  348. StringRef ToolNameRef(ToolName);
  349. // Helpers to emit warnings.
  350. auto warningOS = [ToolNameRef]() -> raw_ostream & {
  351. return WithColor::warning(errs(), ToolNameRef);
  352. };
  353. auto handleErrorAsWarning = [&warningOS](Error E) {
  354. logAllUnhandledErrors(std::move(E), warningOS());
  355. };
  356. Expected<std::unique_ptr<ObjectFile>> BinOrErr =
  357. ObjectFile::createELFObjectFile(Buf->getMemBufferRef(),
  358. /*InitContent=*/false);
  359. if (Error E = BinOrErr.takeError()) {
  360. consumeError(std::move(E));
  361. // This warning is questionable, but let it be here,
  362. // assuming that most OpenMP offload models use ELF offload images.
  363. warningOS() << OriginalFileName
  364. << " is not an ELF image, so notes cannot be added to it.\n";
  365. return Buf;
  366. }
  367. // If we fail to add the note section, we just pass through the original
  368. // ELF image for wrapping. At some point we should enforce the note section
  369. // and start emitting errors vs warnings.
  370. support::endianness Endianness;
  371. if (isa<ELF64LEObjectFile>(BinOrErr->get()) ||
  372. isa<ELF32LEObjectFile>(BinOrErr->get())) {
  373. Endianness = support::little;
  374. } else if (isa<ELF64BEObjectFile>(BinOrErr->get()) ||
  375. isa<ELF32BEObjectFile>(BinOrErr->get())) {
  376. Endianness = support::big;
  377. } else {
  378. warningOS() << OriginalFileName
  379. << " is an ELF image of unrecognized format.\n";
  380. return Buf;
  381. }
  382. // Create temporary file for the data of a new SHT_NOTE section.
  383. // We fill it in with data and then pass to llvm-objcopy invocation
  384. // for reading.
  385. Twine NotesFileModel = OriginalFileName + Twine(".elfnotes.%%%%%%%.tmp");
  386. Expected<sys::fs::TempFile> NotesTemp =
  387. sys::fs::TempFile::create(NotesFileModel);
  388. if (Error E = NotesTemp.takeError()) {
  389. handleErrorAsWarning(createFileError(NotesFileModel, std::move(E)));
  390. return Buf;
  391. }
  392. TempFiles.push_back(NotesTemp->TmpName);
  393. // Create temporary file for the updated ELF image.
  394. // This is an empty file that we pass to llvm-objcopy invocation
  395. // for writing.
  396. Twine ELFFileModel = OriginalFileName + Twine(".elfwithnotes.%%%%%%%.tmp");
  397. Expected<sys::fs::TempFile> ELFTemp =
  398. sys::fs::TempFile::create(ELFFileModel);
  399. if (Error E = ELFTemp.takeError()) {
  400. handleErrorAsWarning(createFileError(ELFFileModel, std::move(E)));
  401. return Buf;
  402. }
  403. TempFiles.push_back(ELFTemp->TmpName);
  404. // Keep the new ELF image file to reserve the name for the future
  405. // llvm-objcopy invocation.
  406. std::string ELFTmpFileName = ELFTemp->TmpName;
  407. if (Error E = ELFTemp->keep(ELFTmpFileName)) {
  408. handleErrorAsWarning(createFileError(ELFTmpFileName, std::move(E)));
  409. return Buf;
  410. }
  411. // Write notes to the *elfnotes*.tmp file.
  412. raw_fd_ostream NotesOS(NotesTemp->FD, false);
  413. struct NoteTy {
  414. // Note name is a null-terminated "LLVMOMPOFFLOAD".
  415. std::string Name;
  416. // Note type defined in llvm/include/llvm/BinaryFormat/ELF.h.
  417. uint32_t Type = 0;
  418. // Each note has type-specific associated data.
  419. std::string Desc;
  420. NoteTy(std::string &&Name, uint32_t Type, std::string &&Desc)
  421. : Name(std::move(Name)), Type(Type), Desc(std::move(Desc)) {}
  422. };
  423. // So far we emit just three notes.
  424. SmallVector<NoteTy, 3> Notes;
  425. // Version of the offload image identifying the structure of the ELF image.
  426. // Version 1.0 does not have any specific requirements.
  427. // We may come up with some structure that has to be honored by all
  428. // offload implementations in future (e.g. to let libomptarget
  429. // get some information from the offload image).
  430. Notes.emplace_back("LLVMOMPOFFLOAD", ELF::NT_LLVM_OPENMP_OFFLOAD_VERSION,
  431. OPENMP_OFFLOAD_IMAGE_VERSION);
  432. // This is a producer identification string. We are LLVM!
  433. Notes.emplace_back("LLVMOMPOFFLOAD", ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER,
  434. "LLVM");
  435. // This is a producer version. Use the same format that is used
  436. // by clang to report the LLVM version.
  437. Notes.emplace_back("LLVMOMPOFFLOAD",
  438. ELF::NT_LLVM_OPENMP_OFFLOAD_PRODUCER_VERSION,
  439. LLVM_VERSION_STRING
  440. #ifdef LLVM_REVISION
  441. " " LLVM_REVISION
  442. #endif
  443. );
  444. // Return the amount of padding required for a blob of N bytes
  445. // to be aligned to Alignment bytes.
  446. auto getPadAmount = [](uint32_t N, uint32_t Alignment) -> uint32_t {
  447. uint32_t Mod = (N % Alignment);
  448. if (Mod == 0)
  449. return 0;
  450. return Alignment - Mod;
  451. };
  452. auto emitPadding = [&getPadAmount](raw_ostream &OS, uint32_t Size) {
  453. for (uint32_t I = 0; I < getPadAmount(Size, 4); ++I)
  454. OS << '\0';
  455. };
  456. // Put notes into the file.
  457. for (auto &N : Notes) {
  458. assert(!N.Name.empty() && "We should not create notes with empty names.");
  459. // Name must be null-terminated.
  460. if (N.Name.back() != '\0')
  461. N.Name += '\0';
  462. uint32_t NameSz = N.Name.size();
  463. uint32_t DescSz = N.Desc.size();
  464. // A note starts with three 4-byte values:
  465. // NameSz
  466. // DescSz
  467. // Type
  468. // These three fields are endian-sensitive.
  469. support::endian::write<uint32_t>(NotesOS, NameSz, Endianness);
  470. support::endian::write<uint32_t>(NotesOS, DescSz, Endianness);
  471. support::endian::write<uint32_t>(NotesOS, N.Type, Endianness);
  472. // Next, we have a null-terminated Name padded to a 4-byte boundary.
  473. NotesOS << N.Name;
  474. emitPadding(NotesOS, NameSz);
  475. if (DescSz == 0)
  476. continue;
  477. // Finally, we have a descriptor, which is an arbitrary flow of bytes.
  478. NotesOS << N.Desc;
  479. emitPadding(NotesOS, DescSz);
  480. }
  481. NotesOS.flush();
  482. // Keep the notes file.
  483. std::string NotesTmpFileName = NotesTemp->TmpName;
  484. if (Error E = NotesTemp->keep(NotesTmpFileName)) {
  485. handleErrorAsWarning(createFileError(NotesTmpFileName, std::move(E)));
  486. return Buf;
  487. }
  488. // Run llvm-objcopy like this:
  489. // llvm-objcopy --add-section=.note.openmp=<notes-tmp-file-name> \
  490. // <orig-file-name> <elf-tmp-file-name>
  491. //
  492. // This will add a SHT_NOTE section on top of the original ELF.
  493. std::vector<StringRef> Args;
  494. Args.push_back(ObjcopyPath);
  495. std::string Option("--add-section=.note.openmp=" + NotesTmpFileName);
  496. Args.push_back(Option);
  497. Args.push_back(OriginalFileName);
  498. Args.push_back(ELFTmpFileName);
  499. bool ExecutionFailed = false;
  500. std::string ErrMsg;
  501. (void)sys::ExecuteAndWait(ObjcopyPath, Args,
  502. /*Env=*/llvm::None, /*Redirects=*/{},
  503. /*SecondsToWait=*/0,
  504. /*MemoryLimit=*/0, &ErrMsg, &ExecutionFailed);
  505. if (ExecutionFailed) {
  506. warningOS() << ErrMsg << "\n";
  507. return Buf;
  508. }
  509. // Substitute the original ELF with new one.
  510. ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
  511. MemoryBuffer::getFile(ELFTmpFileName);
  512. if (!BufOrErr) {
  513. handleErrorAsWarning(
  514. createFileError(ELFTmpFileName, BufOrErr.getError()));
  515. return Buf;
  516. }
  517. return std::move(*BufOrErr);
  518. }
  519. };
  520. } // anonymous namespace
  521. int main(int argc, const char **argv) {
  522. sys::PrintStackTraceOnErrorSignal(argv[0]);
  523. cl::HideUnrelatedOptions(ClangOffloadWrapperCategory);
  524. cl::SetVersionPrinter([](raw_ostream &OS) {
  525. OS << clang::getClangToolFullVersion("clang-offload-wrapper") << '\n';
  526. });
  527. cl::ParseCommandLineOptions(
  528. argc, argv,
  529. "A tool to create a wrapper bitcode for offload target binaries. Takes "
  530. "offload\ntarget binaries as input and produces bitcode file containing "
  531. "target binaries packaged\nas data and initialization code which "
  532. "registers target binaries in offload runtime.\n");
  533. if (Help) {
  534. cl::PrintHelpMessage();
  535. return 0;
  536. }
  537. auto reportError = [argv](Error E) {
  538. logAllUnhandledErrors(std::move(E), WithColor::error(errs(), argv[0]));
  539. };
  540. if (Triple(Target).getArch() == Triple::UnknownArch) {
  541. reportError(createStringError(
  542. errc::invalid_argument, "'" + Target + "': unsupported target triple"));
  543. return 1;
  544. }
  545. BinaryWrapper Wrapper(Target, argv[0]);
  546. // Read device binaries.
  547. SmallVector<std::unique_ptr<MemoryBuffer>, 4u> Buffers;
  548. SmallVector<ArrayRef<char>, 4u> Images;
  549. Buffers.reserve(Inputs.size());
  550. Images.reserve(Inputs.size());
  551. for (const std::string &File : Inputs) {
  552. ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
  553. MemoryBuffer::getFileOrSTDIN(File);
  554. if (!BufOrErr) {
  555. reportError(createFileError(File, BufOrErr.getError()));
  556. return 1;
  557. }
  558. std::unique_ptr<MemoryBuffer> Buffer(std::move(*BufOrErr));
  559. if (File != "-" && AddOpenMPOffloadNotes) {
  560. // Adding ELF notes for STDIN is not supported yet.
  561. Buffer = Wrapper.addELFNotes(std::move(Buffer), File);
  562. }
  563. const std::unique_ptr<MemoryBuffer> &Buf =
  564. Buffers.emplace_back(std::move(Buffer));
  565. Images.emplace_back(Buf->getBufferStart(), Buf->getBufferSize());
  566. }
  567. // Create the output file to write the resulting bitcode to.
  568. std::error_code EC;
  569. ToolOutputFile Out(Output, EC, sys::fs::OF_None);
  570. if (EC) {
  571. reportError(createFileError(Output, EC));
  572. return 1;
  573. }
  574. // Create a wrapper for device binaries and write its bitcode to the file.
  575. WriteBitcodeToFile(
  576. Wrapper.wrapBinaries(makeArrayRef(Images.data(), Images.size())),
  577. Out.os());
  578. if (Out.os().has_error()) {
  579. reportError(createFileError(Output, Out.os().error()));
  580. return 1;
  581. }
  582. // Success.
  583. Out.keep();
  584. return 0;
  585. }