LLVM 24.0.0git
OffloadBinary.cpp
Go to the documentation of this file.
1//===- OffloadBinary.cpp - Utilities for handling offloading code ---------===//
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
10
13#include "llvm/IR/Constants.h"
14#include "llvm/IR/Module.h"
17#include "llvm/Object/Archive.h"
18#include "llvm/Object/Binary.h"
20#include "llvm/Object/Error.h"
26
27using namespace llvm;
28using namespace llvm::object;
29
30namespace {
31
32/// A MemoryBuffer that shares ownership of the underlying memory.
33/// This allows multiple OffloadBinary instances to share the same buffer.
34class SharedMemoryBuffer : public MemoryBuffer {
35public:
36 SharedMemoryBuffer(std::shared_ptr<MemoryBuffer> Buf)
37 : SharedBuf(std::move(Buf)) {
38 init(SharedBuf->getBufferStart(), SharedBuf->getBufferEnd(),
39 /*RequiresNullTerminator=*/false);
40 }
41
42 BufferKind getBufferKind() const override { return MemoryBuffer_Malloc; }
43
44 StringRef getBufferIdentifier() const override {
45 return SharedBuf->getBufferIdentifier();
46 }
47
48private:
49 const std::shared_ptr<MemoryBuffer> SharedBuf;
50};
51
52/// Attempts to extract all the embedded device images contained inside the
53/// buffer \p Contents. The buffer is expected to contain a valid offloading
54/// binary format.
55Error extractOffloadFiles(MemoryBufferRef Contents,
57 uint64_t Offset = 0;
58 // There could be multiple offloading binaries stored at this section.
59 while (Offset < Contents.getBufferSize()) {
60 std::unique_ptr<MemoryBuffer> Buffer =
62 /*RequiresNullTerminator*/ false);
64 Buffer->getBufferStart()))
65 Buffer = MemoryBuffer::getMemBufferCopy(Buffer->getBuffer(),
66 Buffer->getBufferIdentifier());
67
68 auto HeaderOrErr = OffloadBinary::extractHeader(*Buffer);
69 if (!HeaderOrErr)
70 return HeaderOrErr.takeError();
71 const OffloadBinary::Header *Header = *HeaderOrErr;
72
73 // Create a copy of original memory containing only the current binary.
74 std::unique_ptr<MemoryBuffer> BufferCopy = MemoryBuffer::getMemBufferCopy(
75 Buffer->getBuffer().take_front(Header->Size),
76 Contents.getBufferIdentifier());
77
78 auto BinariesOrErr = OffloadBinary::create(*BufferCopy);
79 if (!BinariesOrErr)
80 return BinariesOrErr.takeError();
81
82 // Share ownership among multiple OffloadFiles.
83 std::shared_ptr<MemoryBuffer> SharedBuffer =
84 std::shared_ptr<MemoryBuffer>(std::move(BufferCopy));
85
86 for (auto &Binary : *BinariesOrErr) {
87 std::unique_ptr<SharedMemoryBuffer> SharedBufferPtr =
88 std::make_unique<SharedMemoryBuffer>(SharedBuffer);
89 Binaries.emplace_back(std::move(Binary), std::move(SharedBufferPtr));
90 }
91
92 Offset += Header->Size;
93 }
94
95 return Error::success();
96}
97
98// Extract offloading binaries from an Object file \p Obj.
99Error extractFromObject(const ObjectFile &Obj,
101 assert((Obj.isELF() || Obj.isCOFF()) && "Invalid file type");
102
103 for (SectionRef Sec : Obj.sections()) {
104 // ELF files contain a section with the LLVM_OFFLOADING type.
105 if (Obj.isELF() &&
106 static_cast<ELFSectionRef>(Sec).getType() != ELF::SHT_LLVM_OFFLOADING)
107 continue;
108
109 // COFF has no section types so we rely on the name of the section.
110 if (Obj.isCOFF()) {
111 Expected<StringRef> NameOrErr = Sec.getName();
112 if (!NameOrErr)
113 return NameOrErr.takeError();
114
115 if (!NameOrErr->starts_with(".llvm.offloading"))
116 continue;
117 }
118
119 Expected<StringRef> Buffer = Sec.getContents();
120 if (!Buffer)
121 return Buffer.takeError();
122
123 MemoryBufferRef Contents(*Buffer, Obj.getFileName());
124 if (Error Err = extractOffloadFiles(Contents, Binaries))
125 return Err;
126 }
127
128 return Error::success();
129}
130
131Error extractFromBitcode(MemoryBufferRef Buffer,
133 LLVMContext Context;
134 SMDiagnostic Err;
135 std::unique_ptr<Module> M = getLazyIRModule(
136 MemoryBuffer::getMemBuffer(Buffer, /*RequiresNullTerminator=*/false), Err,
137 Context);
138 if (!M)
140 "Failed to create module");
141
142 // Extract offloading data from globals referenced by the
143 // `llvm.embedded.object` metadata with the `.llvm.offloading` section.
144 auto *MD = M->getNamedMetadata("llvm.embedded.objects");
145 if (!MD)
146 return Error::success();
147
148 for (const MDNode *Op : MD->operands()) {
149 if (Op->getNumOperands() < 2)
150 continue;
151
152 MDString *SectionID = dyn_cast<MDString>(Op->getOperand(1));
153 if (!SectionID || SectionID->getString() != ".llvm.offloading")
154 continue;
155
156 GlobalVariable *GV =
158 if (!GV)
159 continue;
160
162 if (!CDS)
163 continue;
164
165 MemoryBufferRef Contents(CDS->getAsString(), M->getName());
166 if (Error Err = extractOffloadFiles(Contents, Binaries))
167 return Err;
168 }
169
170 return Error::success();
171}
172
173Error extractFromArchive(const Archive &Library,
175 // Try to extract device code from each file stored in the static archive.
176 Error Err = Error::success();
177 for (auto Child : Library.children(Err)) {
178 auto ChildBufferOrErr = Child.getMemoryBufferRef();
179 if (!ChildBufferOrErr)
180 return ChildBufferOrErr.takeError();
181 std::unique_ptr<MemoryBuffer> ChildBuffer =
182 MemoryBuffer::getMemBuffer(*ChildBufferOrErr, false);
183
184 // Check if the buffer has the required alignment.
186 ChildBuffer->getBufferStart()))
187 ChildBuffer = MemoryBuffer::getMemBufferCopy(
188 ChildBufferOrErr->getBuffer(),
189 ChildBufferOrErr->getBufferIdentifier());
190
191 if (Error Err = extractOffloadBinaries(*ChildBuffer, Binaries))
192 return Err;
193 }
194
195 if (Err)
196 return Err;
197 return Error::success();
198}
199
200} // namespace
201
204 if (Buf.getBufferSize() < sizeof(Header) + sizeof(Entry))
206
207 // Check for 0x10FF1OAD magic bytes.
210
211 // Make sure that the data has sufficient alignment.
214
215 const char *Start = Buf.getBufferStart();
216 const Header *TheHeader = reinterpret_cast<const Header *>(Start);
217 if (TheHeader->Version == 0 || TheHeader->Version > OffloadBinary::Version)
219
220 if (TheHeader->Size > Buf.getBufferSize() ||
221 TheHeader->Size < sizeof(Entry) || TheHeader->Size < sizeof(Header))
223
224 uint64_t EntriesCount =
225 (TheHeader->Version == 1) ? 1 : TheHeader->EntriesCount;
226 uint64_t EntriesSize = sizeof(Entry) * EntriesCount;
227 if (TheHeader->EntriesOffset > TheHeader->Size - EntriesSize ||
228 EntriesSize > TheHeader->Size - sizeof(Header))
230
231 return TheHeader;
232}
233
235OffloadBinary::create(MemoryBufferRef Buf, std::optional<uint64_t> Index) {
236 auto HeaderOrErr = OffloadBinary::extractHeader(Buf);
237 if (!HeaderOrErr)
238 return HeaderOrErr.takeError();
239 const Header *TheHeader = *HeaderOrErr;
240
241 const char *Start = Buf.getBufferStart();
242 const Entry *Entries =
243 reinterpret_cast<const Entry *>(&Start[TheHeader->EntriesOffset]);
244
245 auto validateEntry = [&](const Entry *TheEntry) -> Error {
246 if (TheEntry->ImageOffset > Buf.getBufferSize() ||
247 TheEntry->StringOffset > Buf.getBufferSize() ||
248 TheEntry->StringOffset + TheEntry->NumStrings * sizeof(StringEntry) >
249 Buf.getBufferSize())
251 return Error::success();
252 };
253
255 if (TheHeader->Version > 1 && Index.has_value()) {
256 if (*Index >= TheHeader->EntriesCount)
258 const Entry *TheEntry = &Entries[*Index];
259 if (auto Err = validateEntry(TheEntry))
260 return std::move(Err);
261
262 Binaries.emplace_back(new OffloadBinary(Buf, TheHeader, TheEntry, *Index));
263 return std::move(Binaries);
264 }
265
266 uint64_t EntriesCount = TheHeader->Version == 1 ? 1 : TheHeader->EntriesCount;
267 for (uint64_t I = 0; I < EntriesCount; ++I) {
268 const Entry *TheEntry = &Entries[I];
269 if (auto Err = validateEntry(TheEntry))
270 return std::move(Err);
271
272 Binaries.emplace_back(new OffloadBinary(Buf, TheHeader, TheEntry, I));
273 }
274
275 return std::move(Binaries);
276}
277
279 uint64_t EntriesCount = OffloadingData.size();
280 assert(EntriesCount > 0 && "At least one offloading image is required");
281
282 // Create a null-terminated string table with all the used strings.
283 // Also calculate total size of images.
285 uint64_t TotalStringEntries = 0;
286 uint64_t TotalImagesSize = 0;
287 for (const OffloadingImage &Img : OffloadingData) {
288 for (auto &KeyAndValue : Img.StringData) {
289 StrTab.add(KeyAndValue.first);
290 StrTab.add(KeyAndValue.second);
291 }
292 TotalStringEntries += Img.StringData.size();
293 TotalImagesSize += Img.Image->getBufferSize();
294 }
295 StrTab.finalize();
296
297 uint64_t StringEntrySize = sizeof(StringEntry) * TotalStringEntries;
298 uint64_t EntriesSize = sizeof(Entry) * EntriesCount;
299 uint64_t StrTabOffset = sizeof(Header) + EntriesSize + StringEntrySize;
300
301 // Make sure the image we're wrapping around is aligned as well.
302 uint64_t BinaryDataSize =
303 alignTo(StrTabOffset + StrTab.getSize(), getAlignment());
304
305 // Create the header and fill in the offsets. The entries will be directly
306 // placed after the header in memory. Align the size to the alignment of the
307 // header so this can be placed contiguously in a single section.
308 Header TheHeader;
309 TheHeader.Size = alignTo(BinaryDataSize + TotalImagesSize, getAlignment());
310 TheHeader.EntriesOffset = sizeof(Header);
311 TheHeader.EntriesCount = EntriesCount;
312
314 Data.reserve(TheHeader.Size);
316 OS << StringRef(reinterpret_cast<char *>(&TheHeader), sizeof(Header));
317
318 // Create the entries using the string table offsets. The string table will be
319 // placed directly after the set of entries in memory, and all the images are
320 // after that.
321 uint64_t StringEntryOffset = sizeof(Header) + EntriesSize;
322 uint64_t ImageOffset = BinaryDataSize;
323 for (const OffloadingImage &Img : OffloadingData) {
324 Entry TheEntry;
325
326 TheEntry.TheImageKind = Img.TheImageKind;
327 TheEntry.TheOffloadKind = Img.TheOffloadKind;
328 TheEntry.Flags = Img.Flags;
329
330 TheEntry.StringOffset = StringEntryOffset;
331 StringEntryOffset += sizeof(StringEntry) * Img.StringData.size();
332 TheEntry.NumStrings = Img.StringData.size();
333
334 TheEntry.ImageOffset = ImageOffset;
335 ImageOffset += Img.Image->getBufferSize();
336 TheEntry.ImageSize = Img.Image->getBufferSize();
337
338 OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry));
339 }
340
341 // Create the string map entries.
342 for (const OffloadingImage &Img : OffloadingData) {
343 for (auto &KeyAndValue : Img.StringData) {
344 StringEntry Map{StrTabOffset + StrTab.getOffset(KeyAndValue.first),
345 StrTabOffset + StrTab.getOffset(KeyAndValue.second),
346 KeyAndValue.second.size()};
347 OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry));
348 }
349 }
350
351 StrTab.write(OS);
352 // Add padding to required image alignment.
353 OS.write_zeros(BinaryDataSize - OS.tell());
354
355 for (const OffloadingImage &Img : OffloadingData)
356 OS << Img.Image->getBuffer();
357
358 // Add final padding to required alignment.
359 assert(TheHeader.Size >= OS.tell() && "Too much data written?");
360 OS.write_zeros(TheHeader.Size - OS.tell());
361 assert(TheHeader.Size == OS.tell() && "Size mismatch");
362
363 return Data;
364}
365
369 switch (Type) {
371 return extractFromBitcode(Buffer, Binaries);
378 if (!ObjFile)
379 return ObjFile.takeError();
380 return extractFromObject(*ObjFile->get(), Binaries);
381 }
382 case file_magic::archive: {
385 if (!LibFile)
386 return LibFile.takeError();
387 return extractFromArchive(*LibFile->get(), Binaries);
388 }
390 return extractOffloadFiles(Buffer, Binaries);
391 default:
392 return Error::success();
393 }
394}
395
398 .Case("openmp", OFK_OpenMP)
399 .Case("cuda", OFK_Cuda)
400 .Case("hip", OFK_HIP)
401 .Case("sycl", OFK_SYCL)
403}
404
406 switch (Kind) {
407 case OFK_OpenMP:
408 return "openmp";
409 case OFK_Cuda:
410 return "cuda";
411 case OFK_HIP:
412 return "hip";
413 case OFK_SYCL:
414 return "sycl";
415 default:
416 return "none";
417 }
418}
419
422 .Case("o", IMG_Object)
423 .Case("bc", IMG_Bitcode)
424 .Case("cubin", IMG_Cubin)
425 .Case("fatbin", IMG_Fatbinary)
426 .Case("s", IMG_PTX)
427 .Case("spv", IMG_SPIRV)
429}
430
432 switch (Kind) {
433 case IMG_Object:
434 return "o";
435 case IMG_Bitcode:
436 return "bc";
437 case IMG_Cubin:
438 return "cubin";
439 case IMG_Fatbinary:
440 return "fatbin";
441 case IMG_PTX:
442 return "s";
443 case IMG_SPIRV:
444 return "spv";
445 default:
446 return "";
447 }
448}
449
451 const OffloadFile::TargetID &RHS) {
452 llvm::Triple LHSTT(LHS.first);
453 llvm::Triple RHSTT(RHS.first);
454
455 // Check for logical AMDGPU target-id equivalence.
456 if (LHSTT.isAMDGPU()) {
457 AMDGPU::TargetID LHSID(LHSTT, LHS.second);
458 AMDGPU::TargetID RHSID(RHSTT, RHS.second);
459 return LHSID.isEquivalent(RHSID);
460 }
461
462 // For other targets the triples must be compatible and the arch must match.
463 return LHSTT.isCompatibleWith(RHSTT) && LHS.second == RHS.second;
464}
465
467 const OffloadFile::TargetID &Requested) {
468 llvm::Triple ProvidedTT(Provided.first);
469 llvm::Triple RequestedTT(Requested.first);
470
471 // The AMDGPU target requires target-id aware checks (base processor plus
472 // xnack/sramecc features).
473 if (ProvidedTT.isAMDGPU()) {
474 AMDGPU::TargetID ProvidedID(ProvidedTT, Provided.second);
475 AMDGPU::TargetID RequestedID(RequestedTT, Requested.second);
476 return ProvidedID.providesFor(RequestedID);
477 }
478
479 // For other targets the triples must be compatible.
480 if (!ProvidedTT.isCompatibleWith(RequestedTT))
481 return false;
482
483 // If the architecture is "generic" we assume it is always compatible.
484 if (Provided.second == "generic" || Requested.second == "generic")
485 return true;
486
487 return Provided.second == Requested.second;
488}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
Module.h This file contains the declarations for the Module class.
#define I(x, y, z)
Definition MD5.cpp:57
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
bool isEquivalent(const TargetID &Other) const
Returns true if Other denotes the same target as *this, i.e.
bool providesFor(const TargetID &Other) const
Returns true if a device image for *this can provide the device code for a request for Other.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
size_t size() const
Get the array size.
Definition ArrayRef.h:141
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
Tagged union holding either a T or a Error.
Definition Error.h:485
Error takeError()
Take ownership of the stored error.
Definition Error.h:612
reference get()
Returns a reference to the stored T value.
Definition Error.h:582
const Constant * getInitializer() const
getInitializer - Return the initializer for this global variable.
This is an important class for using LLVM in a threaded context.
Definition LLVMContext.h:68
Metadata node.
Definition Metadata.h:1069
A single uniqued string.
Definition Metadata.h:722
LLVM_ABI StringRef getString() const
Definition Metadata.cpp:632
size_t getBufferSize() const
StringRef getBufferIdentifier() const
const char * getBufferStart() const
StringRef getBuffer() const
This interface provides simple read-only access to a block of memory, and provides simple methods for...
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
static std::unique_ptr< MemoryBuffer > getMemBufferCopy(StringRef InputData, const Twine &BufferName="")
Open the specified memory range as a MemoryBuffer, copying the contents and taking ownership of it.
Instances of this class encapsulate one diagnostic report, allowing printing to a raw_ostream as a ca...
Definition SourceMgr.h:303
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition SmallString.h:26
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
reference emplace_back(ArgTypes &&... Args)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Represent a constant reference to a string, i.e.
Definition StringRef.h:56
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
Definition StringRef.h:635
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
Utility for building string tables with deduplicated suffixes.
LLVM_ABI size_t getOffset(CachedHashStringRef S) const
Get the offest of a string in the string table.
LLVM_ABI size_t add(CachedHashStringRef S, uint8_t Priority=0)
Add a string to the builder.
LLVM_ABI void write(raw_ostream &OS) const
LLVM_ABI void finalize()
Analyze the strings and build the final table.
Triple - Helper class for working with autoconf configuration names.
Definition Triple.h:48
bool isAMDGPU() const
Definition Triple.h:992
LLVM_ABI bool isCompatibleWith(const Triple &Other) const
Test whether target triples are compatible.
Definition Triple.cpp:2312
The instances of the Type class are immutable: once they are created, they are never changed.
Definition Type.h:46
iterator_range< child_iterator > children(Error &Err, bool SkipInternal=true) const
Definition Archive.h:404
static Expected< std::unique_ptr< Archive > > create(MemoryBufferRef Source)
Definition Archive.cpp:785
MemoryBufferRef Data
Definition Binary.h:38
This class is the base class for all object file types.
Definition ObjectFile.h:231
static Expected< OwningBinary< ObjectFile > > createObjectFile(StringRef ObjectPath)
static uint64_t getAlignment()
static LLVM_ABI Expected< SmallVector< std::unique_ptr< OffloadBinary > > > create(MemoryBufferRef Buf, std::optional< uint64_t > Index=std::nullopt)
Attempt to parse the offloading binary stored in Buf.
static LLVM_ABI SmallString< 0 > write(ArrayRef< OffloadingImage > OffloadingData)
Serialize the contents of OffloadingData to a binary buffer to be read later.
static LLVM_ABI Expected< const Header * > extractHeader(MemoryBufferRef Buf)
Attempt to extract and validate the header from the offloading binary in Buf.
static const uint32_t Version
The current version of the binary used for backwards compatibility.
std::pair< StringRef, StringRef > TargetID
This is a value type class that represents a single section in the list of sections in the object fil...
Definition ObjectFile.h:83
raw_ostream & write_zeros(unsigned NumZeros)
write_zeros - Insert 'NumZeros' nulls.
uint64_t tell() const
tell - Return the current offset with the file.
A raw_ostream that writes to an SmallVector or SmallString.
@ SHT_LLVM_OFFLOADING
Definition ELF.h:1194
initializer< Ty > init(const Ty &Val)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > dyn_extract_or_null(Y &&MD)
Extract a Value from Metadata, if any, allowing null.
Definition Metadata.h:709
LLVM_ABI bool areTargetsEquivalent(const OffloadFile::TargetID &LHS, const OffloadFile::TargetID &RHS)
Returns true if LHS and RHS denote the same logical target, i.e.
LLVM_ABI bool areTargetsCompatible(const OffloadFile::TargetID &Provided, const OffloadFile::TargetID &Requested)
Returns true if an image built for target Provided can provide the device code for a request for targ...
LLVM_ABI Error extractOffloadBinaries(MemoryBufferRef Buffer, SmallVectorImpl< OffloadFile > &Binaries)
Extracts embedded device offloading code from a memory Buffer to a list of Binaries.
LLVM_ABI ImageKind getImageKind(StringRef Name)
Convert a string Name to an image kind.
OffloadKind
The producer of the associated offloading image.
LLVM_ABI OffloadKind getOffloadKind(StringRef Name)
Convert a string Name to an offload kind.
LLVM_ABI StringRef getImageKindName(ImageKind Name)
Convert an image kind to its string representation.
ImageKind
The type of contents the offloading image contains.
LLVM_ABI StringRef getOffloadKindName(OffloadKind Name)
Convert an offload kind to its string representation.
This is an optimization pass for GlobalISel generic memory operations.
LLVM_ABI file_magic identify_magic(StringRef magic)
Identify the type of a binary file based on how magical it is.
Definition Magic.cpp:33
@ Offset
Definition DWP.cpp:578
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
LLVM_ABI std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition Error.cpp:94
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition Error.h:1321
constexpr uint64_t alignTo(uint64_t Size, Align A)
Returns a multiple of A needed to store Size bytes.
Definition Alignment.h:144
DWARFExpression::Operation Op
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1917
LLVM_ABI Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
Definition Error.cpp:107
bool isAddrAligned(Align Lhs, const void *Addr)
Checks that Addr is a multiple of the alignment.
Definition Alignment.h:139
LLVM_ABI std::unique_ptr< Module > getLazyIRModule(std::unique_ptr< MemoryBuffer > Buffer, SMDiagnostic &Err, LLVMContext &Context, bool ShouldLazyLoadMetadata=false)
If the given MemoryBuffer holds a bitcode image, return a Module for it which does lazy deserializati...
Definition IRReader.cpp:33
This struct is a compact representation of a valid (non-zero power of two) alignment.
Definition Alignment.h:39
file_magic - An "enum class" enumeration of file types based on magic (the first N bytes of the file)...
Definition Magic.h:21
@ elf_relocatable
ELF Relocatable object file.
Definition Magic.h:28
@ archive
ar style archive file
Definition Magic.h:26
@ elf_shared_object
ELF dynamically linked shared lib.
Definition Magic.h:30
@ elf_executable
ELF Executable image.
Definition Magic.h:29
@ offload_binary
LLVM offload object file.
Definition Magic.h:58
@ bitcode
Bitcode file.
Definition Magic.h:24
@ coff_object
COFF object file.
Definition Magic.h:48
The offloading metadata that will be serialized to a memory buffer.