aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Object
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2023-07-26 19:03:47 +0000
committerDimitry Andric <dim@FreeBSD.org>2023-07-26 19:04:23 +0000
commit7fa27ce4a07f19b07799a767fc29416f3b625afb (patch)
tree27825c83636c4de341eb09a74f49f5d38a15d165 /llvm/lib/Object
parente3b557809604d036af6e00c60f012c2025b59a5e (diff)
downloadsrc-7fa27ce4a07f19b07799a767fc29416f3b625afb.tar.gz
src-7fa27ce4a07f19b07799a767fc29416f3b625afb.zip
Vendor import of llvm-project main llvmorg-17-init-19304-gd0b54bb50e51,vendor/llvm-project/llvmorg-17-init-19304-gd0b54bb50e51
the last commit before the upstream release/17.x branch was created.
Diffstat (limited to 'llvm/lib/Object')
-rw-r--r--llvm/lib/Object/Archive.cpp298
-rw-r--r--llvm/lib/Object/ArchiveWriter.cpp482
-rw-r--r--llvm/lib/Object/BuildID.cpp31
-rw-r--r--llvm/lib/Object/COFFImportFile.cpp5
-rw-r--r--llvm/lib/Object/COFFModuleDefinition.cpp17
-rw-r--r--llvm/lib/Object/COFFObjectFile.cpp55
-rw-r--r--llvm/lib/Object/DXContainer.cpp89
-rw-r--r--llvm/lib/Object/Decompressor.cpp1
-rw-r--r--llvm/lib/Object/ELF.cpp111
-rw-r--r--llvm/lib/Object/ELFObjectFile.cpp162
-rw-r--r--llvm/lib/Object/GOFFObjectFile.cpp483
-rw-r--r--llvm/lib/Object/IRSymtab.cpp8
-rw-r--r--llvm/lib/Object/MachOObjectFile.cpp4
-rw-r--r--llvm/lib/Object/MachOUniversalWriter.cpp6
-rw-r--r--llvm/lib/Object/ModuleSymbolTable.cpp14
-rw-r--r--llvm/lib/Object/ObjectFile.cpp6
-rw-r--r--llvm/lib/Object/OffloadBinary.cpp8
-rw-r--r--llvm/lib/Object/RelocationResolver.cpp21
-rw-r--r--llvm/lib/Object/TapiFile.cpp36
-rw-r--r--llvm/lib/Object/WasmObjectFile.cpp19
-rw-r--r--llvm/lib/Object/WindowsMachineFlag.cpp3
-rw-r--r--llvm/lib/Object/WindowsResource.cpp1
-rw-r--r--llvm/lib/Object/XCOFFObjectFile.cpp26
23 files changed, 1612 insertions, 274 deletions
diff --git a/llvm/lib/Object/Archive.cpp b/llvm/lib/Object/Archive.cpp
index 2cf924123888..9920145a2f3c 100644
--- a/llvm/lib/Object/Archive.cpp
+++ b/llvm/lib/Object/Archive.cpp
@@ -18,14 +18,15 @@
#include "llvm/Object/Error.h"
#include "llvm/Support/Chrono.h"
#include "llvm/Support/Endian.h"
+#include "llvm/Support/EndianStream.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
@@ -135,6 +136,13 @@ BigArchiveMemberHeader::BigArchiveMemberHeader(const Archive *Parent,
return;
ErrorAsOutParameter ErrAsOutParam(Err);
+ if (RawHeaderPtr + getSizeOf() >= Parent->getData().end()) {
+ if (Err)
+ *Err = malformedError("malformed AIX big archive: remaining buffer is "
+ "unable to contain next archive member");
+ return;
+ }
+
if (Size < getSizeOf()) {
Error SubErr = createMemberHeaderParseError(this, RawHeaderPtr, Size);
if (Err)
@@ -461,6 +469,7 @@ Archive::Child::Child(const Archive *Parent, const char *Start, Error *Err)
: Parent(Parent) {
if (!Start) {
Header = nullptr;
+ StartOfFile = -1;
return;
}
@@ -926,6 +935,34 @@ Archive::Archive(MemoryBufferRef Source, Error &Err)
StringTable = BufOrErr.get();
if (Increment())
return;
+
+ if (I == E) {
+ setFirstRegular(*C);
+ Err = Error::success();
+ return;
+ }
+
+ NameOrErr = C->getRawName();
+ if (!NameOrErr) {
+ Err = NameOrErr.takeError();
+ return;
+ }
+ Name = NameOrErr.get();
+ }
+
+ if (Name == "/<ECSYMBOLS>/") {
+ // ARM64EC-aware libraries contain an additional special member with
+ // an EC symbol map after the string table. Its format is similar to a
+ // regular symbol map, except it doesn't contain member offsets. Its indexes
+ // refer to member offsets from the regular symbol table instead.
+ Expected<StringRef> BufOrErr = C->getBuffer();
+ if (!BufOrErr) {
+ Err = BufOrErr.takeError();
+ return;
+ }
+ ECSymbolTable = BufOrErr.get();
+ if (Increment())
+ return;
}
setFirstRegular(*C);
@@ -960,7 +997,17 @@ Archive::child_iterator Archive::child_end() const {
return child_iterator::end(Child(nullptr, nullptr, nullptr));
}
+bool Archive::Symbol::isECSymbol() const {
+ // Symbols use SymbolCount..SymbolCount+getNumberOfECSymbols() for EC symbol
+ // indexes.
+ uint32_t SymbolCount = Parent->getNumberOfSymbols();
+ return SymbolCount <= SymbolIndex &&
+ SymbolIndex < SymbolCount + Parent->getNumberOfECSymbols();
+}
+
StringRef Archive::Symbol::getName() const {
+ if (isECSymbol())
+ return Parent->ECSymbolTable.begin() + StringIndex;
return Parent->getSymbolTable().begin() + StringIndex;
}
@@ -999,15 +1046,24 @@ Expected<Archive::Child> Archive::Symbol::getMember() const {
Buf += MemberCount * 4 + 4;
uint32_t SymbolCount = read32le(Buf);
- if (SymbolIndex >= SymbolCount)
+ uint16_t OffsetIndex;
+ if (SymbolIndex < SymbolCount) {
+ // Skip SymbolCount to get to the indices table.
+ const char *Indices = Buf + 4;
+
+ // Get the index of the offset in the file member offset table for this
+ // symbol.
+ OffsetIndex = read16le(Indices + SymbolIndex * 2);
+ } else if (isECSymbol()) {
+ // Skip SymbolCount to get to the indices table.
+ const char *Indices = Parent->ECSymbolTable.begin() + 4;
+
+ // Get the index of the offset in the file member offset table for this
+ // symbol.
+ OffsetIndex = read16le(Indices + (SymbolIndex - SymbolCount) * 2);
+ } else {
return errorCodeToError(object_error::parse_failed);
-
- // Skip SymbolCount to get to the indices table.
- const char *Indices = Buf + 4;
-
- // Get the index of the offset in the file member offset table for this
- // symbol.
- uint16_t OffsetIndex = read16le(Indices + SymbolIndex * 2);
+ }
// Subtract 1 since OffsetIndex is 1 based.
--OffsetIndex;
@@ -1056,6 +1112,9 @@ Archive::Symbol Archive::Symbol::getNext() const {
t.StringIndex -= CurRanStrx;
t.StringIndex += NextRanStrx;
}
+ } else if (t.isECSymbol()) {
+ // Go to one past next null.
+ t.StringIndex = Parent->ECSymbolTable.find('\0', t.StringIndex) + 1;
} else {
// Go to one past next null.
t.StringIndex = Parent->getSymbolTable().find('\0', t.StringIndex) + 1;
@@ -1126,6 +1185,51 @@ Archive::symbol_iterator Archive::symbol_end() const {
return symbol_iterator(Symbol(this, getNumberOfSymbols(), 0));
}
+Expected<iterator_range<Archive::symbol_iterator>> Archive::ec_symbols() const {
+ uint32_t Count = 0;
+
+ // Validate EC symbol table.
+ if (!ECSymbolTable.empty()) {
+ if (ECSymbolTable.size() < sizeof(uint32_t))
+ return malformedError("invalid EC symbols size (" +
+ Twine(ECSymbolTable.size()) + ")");
+ if (SymbolTable.size() < sizeof(uint32_t))
+ return malformedError("invalid symbols size (" +
+ Twine(ECSymbolTable.size()) + ")");
+
+ Count = read32le(ECSymbolTable.begin());
+ size_t StringIndex = sizeof(uint32_t) + Count * sizeof(uint16_t);
+ if (ECSymbolTable.size() < StringIndex)
+ return malformedError("invalid EC symbols size. Size was " +
+ Twine(ECSymbolTable.size()) + ", but expected " +
+ Twine(StringIndex));
+
+ uint32_t MemberCount = read32le(SymbolTable.begin());
+ const char *Indexes = ECSymbolTable.begin() + sizeof(uint32_t);
+
+ for (uint32_t i = 0; i < Count; ++i) {
+ uint16_t Index = read16le(Indexes + i * sizeof(uint16_t));
+ if (!Index)
+ return malformedError("invalid EC symbol index 0");
+ if (Index > MemberCount)
+ return malformedError("invalid EC symbol index " + Twine(Index) +
+ " is larger than member count " +
+ Twine(MemberCount));
+
+ StringIndex = ECSymbolTable.find('\0', StringIndex);
+ if (StringIndex == StringRef::npos)
+ return malformedError("malformed EC symbol names: not null-terminated");
+ ++StringIndex;
+ }
+ }
+
+ uint32_t SymbolCount = getNumberOfSymbols();
+ return make_range(
+ symbol_iterator(Symbol(this, SymbolCount,
+ sizeof(uint32_t) + Count * sizeof(uint16_t))),
+ symbol_iterator(Symbol(this, SymbolCount + Count, 0)));
+}
+
uint32_t Archive::getNumberOfSymbols() const {
if (!hasSymbolTable())
return 0;
@@ -1144,6 +1248,12 @@ uint32_t Archive::getNumberOfSymbols() const {
return read32le(buf);
}
+uint32_t Archive::getNumberOfECSymbols() const {
+ if (ECSymbolTable.size() < sizeof(uint32_t))
+ return 0;
+ return read32le(ECSymbolTable.begin());
+}
+
Expected<std::optional<Archive::Child>> Archive::findSym(StringRef name) const {
Archive::symbol_iterator bs = symbol_begin();
Archive::symbol_iterator es = symbol_end();
@@ -1167,11 +1277,78 @@ bool Archive::isEmpty() const {
bool Archive::hasSymbolTable() const { return !SymbolTable.empty(); }
+static Error getGlobalSymtabLocAndSize(const MemoryBufferRef &Data,
+ uint64_t GlobalSymtabOffset,
+ const char *&GlobalSymtabLoc,
+ uint64_t &Size, const char *BitMessage) {
+ uint64_t BufferSize = Data.getBufferSize();
+ uint64_t GlobalSymtabContentOffset =
+ GlobalSymtabOffset + sizeof(BigArMemHdrType);
+ if (GlobalSymtabContentOffset > BufferSize)
+ return malformedError(
+ Twine(BitMessage) + " global symbol table header at offset 0x" +
+ Twine::utohexstr(GlobalSymtabOffset) + " and size 0x" +
+ Twine::utohexstr(sizeof(BigArMemHdrType)) +
+ " goes past the end of file");
+
+ GlobalSymtabLoc = Data.getBufferStart() + GlobalSymtabOffset;
+ const BigArMemHdrType *GlobalSymHdr =
+ reinterpret_cast<const BigArMemHdrType *>(GlobalSymtabLoc);
+ StringRef RawOffset = getFieldRawString(GlobalSymHdr->Size);
+ if (RawOffset.getAsInteger(10, Size))
+ return malformedError(Twine(BitMessage) + " global symbol table size \"" +
+ RawOffset + "\" is not a number");
+
+ if (GlobalSymtabContentOffset + Size > BufferSize)
+ return malformedError(
+ Twine(BitMessage) + " global symbol table content at offset 0x" +
+ Twine::utohexstr(GlobalSymtabContentOffset) + " and size 0x" +
+ Twine::utohexstr(Size) + " goes past the end of file");
+
+ return Error::success();
+}
+
+struct GlobalSymtabInfo {
+ uint64_t SymNum;
+ StringRef SymbolTable;
+ StringRef SymbolOffsetTable;
+ StringRef StringTable;
+};
+
+static void
+appendGlobalSymbolTableInfo(SmallVector<GlobalSymtabInfo> &SymtabInfos,
+ const char *GlobalSymtabLoc, uint64_t Size) {
+ // In a big archive, a global symbol table contains the following information:
+ // - The number of symbols.
+ // - The array of offsets into the archive file. The length is eight
+ // times the number of symbols.
+ // - The name-string table. The size is:
+ // Size-(8*(the number of symbols + 1)).
+
+ StringRef SymbolTable =
+ StringRef(GlobalSymtabLoc + sizeof(BigArMemHdrType), Size);
+ uint64_t SymNum = read64be(GlobalSymtabLoc + sizeof(BigArMemHdrType));
+ StringRef SymbolOffsetTable = StringRef(SymbolTable.data() + 8, 8 * SymNum);
+ unsigned SymOffsetsSize = 8 * (SymNum + 1);
+ uint64_t SymbolTableStringSize = Size - SymOffsetsSize;
+ StringRef StringTable =
+ StringRef(SymbolTable.data() + SymOffsetsSize, SymbolTableStringSize);
+ SymtabInfos.push_back({SymNum, SymbolTable, SymbolOffsetTable, StringTable});
+}
+
BigArchive::BigArchive(MemoryBufferRef Source, Error &Err)
: Archive(Source, Err) {
ErrorAsOutParameter ErrAsOutParam(&Err);
StringRef Buffer = Data.getBuffer();
ArFixLenHdr = reinterpret_cast<const FixLenHdr *>(Buffer.data());
+ uint64_t BufferSize = Data.getBufferSize();
+
+ if (BufferSize < sizeof(FixLenHdr)) {
+ Err = malformedError("malformed AIX big archive: incomplete fixed length "
+ "header, the archive is only" +
+ Twine(BufferSize) + " byte(s)");
+ return;
+ }
StringRef RawOffset = getFieldRawString(ArFixLenHdr->FirstChildOffset);
if (RawOffset.getAsInteger(10, FirstChildOffset))
@@ -1185,56 +1362,73 @@ BigArchive::BigArchive(MemoryBufferRef Source, Error &Err)
Err = malformedError("malformed AIX big archive: last member offset \"" +
RawOffset + "\" is not a number");
- // Calculate the global symbol table.
- uint64_t GlobSymOffset = 0;
+ uint64_t GlobSymtab32Offset = 0;
RawOffset = getFieldRawString(ArFixLenHdr->GlobSymOffset);
- if (RawOffset.getAsInteger(10, GlobSymOffset))
- // TODO: add test case.
- Err = malformedError(
- "malformed AIX big archive: global symbol table offset \"" + RawOffset +
- "\" is not a number");
+ if (RawOffset.getAsInteger(10, GlobSymtab32Offset)) {
+ Err = malformedError("global symbol table "
+ "offset of 32-bit members \"" +
+ RawOffset + "\" is not a number");
+ return;
+ }
- if (Err)
+ uint64_t GlobSymtab64Offset = 0;
+ RawOffset = getFieldRawString(ArFixLenHdr->GlobSym64Offset);
+ if (RawOffset.getAsInteger(10, GlobSymtab64Offset)) {
+ Err = malformedError("global symbol table "
+ "offset of 64-bit members\"" +
+ RawOffset + "\" is not a number");
return;
+ }
- if (GlobSymOffset > 0) {
- uint64_t BufferSize = Data.getBufferSize();
- uint64_t GlobalSymTblContentOffset =
- GlobSymOffset + sizeof(BigArMemHdrType);
- if (GlobalSymTblContentOffset > BufferSize) {
- Err = malformedError("global symbol table header at offset 0x" +
- Twine::utohexstr(GlobSymOffset) + " and size 0x" +
- Twine::utohexstr(sizeof(BigArMemHdrType)) +
- " goes past the end of file");
- return;
- }
+ const char *GlobSymtab32Loc = nullptr;
+ const char *GlobSymtab64Loc = nullptr;
+ uint64_t GlobSymtab32Size = 0;
+ uint64_t GlobSymtab64Size = 0;
+ const MemoryBufferRef &MemBuffRef = getMemoryBufferRef();
- const char *GlobSymTblLoc = Data.getBufferStart() + GlobSymOffset;
- const BigArMemHdrType *GlobalSymHdr =
- reinterpret_cast<const BigArMemHdrType *>(GlobSymTblLoc);
- RawOffset = getFieldRawString(GlobalSymHdr->Size);
- uint64_t Size;
- if (RawOffset.getAsInteger(10, Size)) {
- // TODO: add test case.
- Err = malformedError(
- "malformed AIX big archive: global symbol table size \"" + RawOffset +
- "\" is not a number");
+ if (GlobSymtab32Offset) {
+ Err =
+ getGlobalSymtabLocAndSize(MemBuffRef, GlobSymtab32Offset,
+ GlobSymtab32Loc, GlobSymtab32Size, "32-bit");
+ if (Err)
return;
- }
- if (GlobalSymTblContentOffset + Size > BufferSize) {
- Err = malformedError("global symbol table content at offset 0x" +
- Twine::utohexstr(GlobalSymTblContentOffset) +
- " and size 0x" + Twine::utohexstr(Size) +
- " goes past the end of file");
+ }
+
+ if (GlobSymtab64Offset) {
+ Err =
+ getGlobalSymtabLocAndSize(MemBuffRef, GlobSymtab64Offset,
+ GlobSymtab64Loc, GlobSymtab64Size, "64-bit");
+ if (Err)
return;
- }
- SymbolTable = StringRef(GlobSymTblLoc + sizeof(BigArMemHdrType), Size);
- unsigned SymNum = getNumberOfSymbols();
- unsigned SymOffsetsSize = 8 * (SymNum + 1);
- uint64_t SymbolTableStringSize = Size - SymOffsetsSize;
- StringTable =
- StringRef(GlobSymTblLoc + sizeof(BigArMemHdrType) + SymOffsetsSize,
- SymbolTableStringSize);
+ }
+
+ SmallVector<GlobalSymtabInfo> SymtabInfos;
+
+ if (GlobSymtab32Offset)
+ appendGlobalSymbolTableInfo(SymtabInfos, GlobSymtab32Loc, GlobSymtab32Size);
+ if (GlobSymtab64Offset)
+ appendGlobalSymbolTableInfo(SymtabInfos, GlobSymtab64Loc, GlobSymtab64Size);
+
+ if (SymtabInfos.size() == 1) {
+ SymbolTable = SymtabInfos[0].SymbolTable;
+ StringTable = SymtabInfos[0].StringTable;
+ } else if (SymtabInfos.size() == 2) {
+ // In order to let the Archive::Symbol::getNext() work for both 32-bit and
+ // 64-bit global symbol tables, we need to merge them into a single table.
+ raw_string_ostream Out(MergedGlobalSymtabBuf);
+ uint64_t SymNum = SymtabInfos[0].SymNum + SymtabInfos[1].SymNum;
+ write(Out, SymNum, support::big);
+ // Merge symbol offset.
+ Out << SymtabInfos[0].SymbolOffsetTable;
+ Out << SymtabInfos[1].SymbolOffsetTable;
+ // Merge string table.
+ Out << SymtabInfos[0].StringTable;
+ Out << SymtabInfos[1].StringTable;
+ SymbolTable = MergedGlobalSymtabBuf;
+ // The size of the symbol offset to the member file is 8 bytes.
+ StringTable = StringRef(SymbolTable.begin() + (SymNum + 1) * 8,
+ SymtabInfos[0].StringTable.size() +
+ SymtabInfos[1].StringTable.size());
}
child_iterator I = child_begin(Err, false);
diff --git a/llvm/lib/Object/ArchiveWriter.cpp b/llvm/lib/Object/ArchiveWriter.cpp
index 0d3aad658fe4..d79a5c6bef30 100644
--- a/llvm/lib/Object/ArchiveWriter.cpp
+++ b/llvm/lib/Object/ArchiveWriter.cpp
@@ -17,6 +17,7 @@
#include "llvm/BinaryFormat/Magic.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Object/Archive.h"
+#include "llvm/Object/COFF.h"
#include "llvm/Object/Error.h"
#include "llvm/Object/IRObjectFile.h"
#include "llvm/Object/MachO.h"
@@ -33,6 +34,7 @@
#include "llvm/Support/SmallVectorMemoryBuffer.h"
#include "llvm/Support/raw_ostream.h"
+#include <cerrno>
#include <map>
#if !defined(_MSC_VER) && !defined(__MINGW32__)
@@ -42,6 +44,13 @@
#endif
using namespace llvm;
+using namespace llvm::object;
+
+struct SymMap {
+ bool UseECMap;
+ std::map<std::string, uint16_t> Map;
+ std::map<std::string, uint16_t> ECMap;
+};
NewArchiveMember::NewArchiveMember(MemoryBufferRef BufRef)
: Buf(MemoryBuffer::getMemBuffer(BufRef, false)),
@@ -69,9 +78,11 @@ object::Archive::Kind NewArchiveMember::detectKindFromObject() const {
if (auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
MemBufferRef, file_magic::bitcode, &Context)) {
auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr);
- return Triple(IRObject.getTargetTriple()).isOSDarwin()
+ auto TargetTriple = Triple(IRObject.getTargetTriple());
+ return TargetTriple.isOSDarwin()
? object::Archive::K_DARWIN
- : object::Archive::K_GNU;
+ : (TargetTriple.isOSAIX() ? object::Archive::K_AIXBIG
+ : object::Archive::K_GNU);
} else {
// Squelch the error in case this was not a SymbolicFile.
consumeError(ObjOrErr.takeError());
@@ -169,18 +180,21 @@ static bool isAIXBigArchive(object::Archive::Kind Kind) {
return Kind == object::Archive::K_AIXBIG;
}
+static bool isCOFFArchive(object::Archive::Kind Kind) {
+ return Kind == object::Archive::K_COFF;
+}
+
static bool isBSDLike(object::Archive::Kind Kind) {
switch (Kind) {
case object::Archive::K_GNU:
case object::Archive::K_GNU64:
case object::Archive::K_AIXBIG:
+ case object::Archive::K_COFF:
return false;
case object::Archive::K_BSD:
case object::Archive::K_DARWIN:
case object::Archive::K_DARWIN64:
return true;
- case object::Archive::K_COFF:
- break;
}
llvm_unreachable("not supported for writting");
}
@@ -191,6 +205,10 @@ static void print(raw_ostream &Out, object::Archive::Kind Kind, T Val) {
isBSDLike(Kind) ? support::little : support::big);
}
+template <class T> static void printLE(raw_ostream &Out, T Val) {
+ support::endian::write(Out, Val, support::little);
+}
+
static void printRestOfMemberHeader(
raw_ostream &Out, const sys::TimePoint<std::chrono::seconds> &ModTime,
unsigned UID, unsigned GID, unsigned Perms, uint64_t Size) {
@@ -235,8 +253,8 @@ static void
printBigArchiveMemberHeader(raw_ostream &Out, StringRef Name,
const sys::TimePoint<std::chrono::seconds> &ModTime,
unsigned UID, unsigned GID, unsigned Perms,
- uint64_t Size, unsigned PrevOffset,
- unsigned NextOffset) {
+ uint64_t Size, uint64_t PrevOffset,
+ uint64_t NextOffset) {
unsigned NameLen = Name.size();
printWithSpacePadding(Out, Size, 20); // File member size
@@ -295,7 +313,11 @@ printMemberHeader(raw_ostream &Out, uint64_t Pos, raw_ostream &StringTable,
auto Insertion = MemberNames.insert({M.MemberName, uint64_t(0)});
if (Insertion.second) {
Insertion.first->second = StringTable.tell();
- StringTable << M.MemberName << "/\n";
+ StringTable << M.MemberName;
+ if (isCOFFArchive(Kind))
+ StringTable << '\0';
+ else
+ StringTable << "/\n";
}
NamePos = Insertion.first->second;
}
@@ -356,7 +378,7 @@ static void printNBits(raw_ostream &Out, object::Archive::Kind Kind,
static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
uint64_t NumSyms, uint64_t OffsetSize,
- StringRef StringTable,
+ uint64_t StringTableSize,
uint32_t *Padding = nullptr) {
assert((OffsetSize == 4 || OffsetSize == 8) && "Unsupported OffsetSize");
uint64_t Size = OffsetSize; // Number of entries
@@ -366,7 +388,7 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
Size += NumSyms * OffsetSize; // Table
if (isBSDLike(Kind))
Size += OffsetSize; // byte count
- Size += StringTable.size();
+ Size += StringTableSize;
// ld64 expects the members to be 8-byte aligned for 64-bit content and at
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
// uniformly.
@@ -376,6 +398,36 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
uint32_t Pad = isAIXBigArchive(Kind)
? 0
: offsetToAlignment(Size, Align(isBSDLike(Kind) ? 8 : 2));
+
+ Size += Pad;
+ if (Padding)
+ *Padding = Pad;
+ return Size;
+}
+
+static uint64_t computeSymbolMapSize(uint64_t NumObj, SymMap &SymMap,
+ uint32_t *Padding = nullptr) {
+ uint64_t Size = sizeof(uint32_t) * 2; // Number of symbols and objects entries
+ Size += NumObj * sizeof(uint32_t); // Offset table
+
+ for (auto S : SymMap.Map)
+ Size += sizeof(uint16_t) + S.first.length() + 1;
+
+ uint32_t Pad = offsetToAlignment(Size, Align(2));
+ Size += Pad;
+ if (Padding)
+ *Padding = Pad;
+ return Size;
+}
+
+static uint64_t computeECSymbolsSize(SymMap &SymMap,
+ uint32_t *Padding = nullptr) {
+ uint64_t Size = sizeof(uint32_t); // Number of symbols
+
+ for (auto S : SymMap.ECMap)
+ Size += sizeof(uint16_t) + S.first.length() + 1;
+
+ uint32_t Pad = offsetToAlignment(Size, Align(2));
Size += Pad;
if (Padding)
*Padding = Pad;
@@ -384,47 +436,121 @@ static uint64_t computeSymbolTableSize(object::Archive::Kind Kind,
static void writeSymbolTableHeader(raw_ostream &Out, object::Archive::Kind Kind,
bool Deterministic, uint64_t Size,
- uint64_t PrevMemberOffset = 0) {
+ uint64_t PrevMemberOffset = 0,
+ uint64_t NextMemberOffset = 0) {
if (isBSDLike(Kind)) {
const char *Name = is64BitKind(Kind) ? "__.SYMDEF_64" : "__.SYMDEF";
printBSDMemberHeader(Out, Out.tell(), Name, now(Deterministic), 0, 0, 0,
Size);
} else if (isAIXBigArchive(Kind)) {
- printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0,
- 0, Size, PrevMemberOffset, 0);
+ printBigArchiveMemberHeader(Out, "", now(Deterministic), 0, 0, 0, Size,
+ PrevMemberOffset, NextMemberOffset);
} else {
const char *Name = is64BitKind(Kind) ? "/SYM64" : "";
printGNUSmallMemberHeader(Out, Name, now(Deterministic), 0, 0, 0, Size);
}
}
+static uint64_t computeHeadersSize(object::Archive::Kind Kind,
+ uint64_t NumMembers,
+ uint64_t StringMemberSize, uint64_t NumSyms,
+ uint64_t SymNamesSize, SymMap *SymMap) {
+ uint32_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
+ uint64_t SymtabSize =
+ computeSymbolTableSize(Kind, NumSyms, OffsetSize, SymNamesSize);
+ auto computeSymbolTableHeaderSize = [=] {
+ SmallString<0> TmpBuf;
+ raw_svector_ostream Tmp(TmpBuf);
+ writeSymbolTableHeader(Tmp, Kind, true, SymtabSize);
+ return TmpBuf.size();
+ };
+ uint32_t HeaderSize = computeSymbolTableHeaderSize();
+ uint64_t Size = strlen("!<arch>\n") + HeaderSize + SymtabSize;
+
+ if (SymMap) {
+ Size += HeaderSize + computeSymbolMapSize(NumMembers, *SymMap);
+ if (SymMap->ECMap.size())
+ Size += HeaderSize + computeECSymbolsSize(*SymMap);
+ }
+
+ return Size + StringMemberSize;
+}
+
+static Expected<std::unique_ptr<SymbolicFile>>
+getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) {
+ const file_magic Type = identify_magic(Buf.getBuffer());
+ // Don't attempt to read non-symbolic file types.
+ if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
+ return nullptr;
+ if (Type == file_magic::bitcode) {
+ auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
+ Buf, file_magic::bitcode, &Context);
+ if (!ObjOrErr)
+ return ObjOrErr.takeError();
+ return std::move(*ObjOrErr);
+ } else {
+ auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
+ if (!ObjOrErr)
+ return ObjOrErr.takeError();
+ return std::move(*ObjOrErr);
+ }
+}
+
+static Expected<bool> is64BitSymbolicFile(const StringRef &ObjStringRef) {
+ MemoryBufferRef ObjMbf(ObjStringRef, "");
+ // In the scenario when LLVMContext is populated SymbolicFile will contain a
+ // reference to it, thus SymbolicFile should be destroyed first.
+ LLVMContext Context;
+ Expected<std::unique_ptr<SymbolicFile>> ObjOrErr =
+ getSymbolicFile(ObjMbf, Context);
+ if (!ObjOrErr)
+ return ObjOrErr.takeError();
+
+ // Treat non-symbolic file types as not 64-bits.
+ if (!*ObjOrErr)
+ return false;
+
+ return (*ObjOrErr)->is64Bit();
+}
+
static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
bool Deterministic, ArrayRef<MemberData> Members,
- StringRef StringTable,
- uint64_t PrevMemberOffset = 0) {
+ StringRef StringTable, uint64_t MembersOffset,
+ unsigned NumSyms, uint64_t PrevMemberOffset = 0,
+ uint64_t NextMemberOffset = 0,
+ bool Is64Bit = false) {
// We don't write a symbol table on an archive with no members -- except on
// Darwin, where the linker will abort unless the archive has a symbol table.
- if (StringTable.empty() && !isDarwin(Kind))
+ if (StringTable.empty() && !isDarwin(Kind) && !isCOFFArchive(Kind))
return;
- unsigned NumSyms = 0;
- for (const MemberData &M : Members)
- NumSyms += M.Symbols.size();
-
uint64_t OffsetSize = is64BitKind(Kind) ? 8 : 4;
uint32_t Pad;
- uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize, StringTable, &Pad);
- writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset);
-
- uint64_t Pos = isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr)
- : Out.tell() + Size;
+ uint64_t Size = computeSymbolTableSize(Kind, NumSyms, OffsetSize,
+ StringTable.size(), &Pad);
+ writeSymbolTableHeader(Out, Kind, Deterministic, Size, PrevMemberOffset,
+ NextMemberOffset);
if (isBSDLike(Kind))
printNBits(Out, Kind, NumSyms * 2 * OffsetSize);
else
printNBits(Out, Kind, NumSyms);
+ uint64_t Pos = MembersOffset;
for (const MemberData &M : Members) {
+ if (isAIXBigArchive(Kind)) {
+ Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data);
+ // If there is an error, the error will have been emitted when
+ // 'computeMemberData' called the 'getSymbol' function, so don't need to
+ // handle it here.
+ if (!Is64BitOrErr)
+ cantFail(Is64BitOrErr.takeError());
+ if (*Is64BitOrErr != Is64Bit) {
+ Pos += M.Header.size() + M.Data.size() + M.Padding.size();
+ continue;
+ }
+ }
+
for (unsigned StringOffset : M.Symbols) {
if (isBSDLike(Kind))
printNBits(Out, Kind, StringOffset);
@@ -442,40 +568,111 @@ static void writeSymbolTable(raw_ostream &Out, object::Archive::Kind Kind,
Out.write(uint8_t(0));
}
-static Expected<std::vector<unsigned>>
-getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
- std::vector<unsigned> Ret;
+static void writeSymbolMap(raw_ostream &Out, object::Archive::Kind Kind,
+ bool Deterministic, ArrayRef<MemberData> Members,
+ SymMap &SymMap, uint64_t MembersOffset) {
+ uint32_t Pad;
+ uint64_t Size = computeSymbolMapSize(Members.size(), SymMap, &Pad);
+ writeSymbolTableHeader(Out, Kind, Deterministic, Size, 0);
+
+ uint32_t Pos = MembersOffset;
+
+ printLE<uint32_t>(Out, Members.size());
+ for (const MemberData &M : Members) {
+ printLE(Out, Pos); // member offset
+ Pos += M.Header.size() + M.Data.size() + M.Padding.size();
+ }
+
+ printLE<uint32_t>(Out, SymMap.Map.size());
+
+ for (auto S : SymMap.Map)
+ printLE(Out, S.second);
+ for (auto S : SymMap.Map)
+ Out << S.first << '\0';
+
+ while (Pad--)
+ Out.write(uint8_t(0));
+}
+
+static void writeECSymbols(raw_ostream &Out, object::Archive::Kind Kind,
+ bool Deterministic, ArrayRef<MemberData> Members,
+ SymMap &SymMap) {
+ uint32_t Pad;
+ uint64_t Size = computeECSymbolsSize(SymMap, &Pad);
+ printGNUSmallMemberHeader(Out, "/<ECSYMBOLS>", now(Deterministic), 0, 0, 0,
+ Size);
+ printLE<uint32_t>(Out, SymMap.ECMap.size());
+
+ for (auto S : SymMap.ECMap)
+ printLE(Out, S.second);
+ for (auto S : SymMap.ECMap)
+ Out << S.first << '\0';
+ while (Pad--)
+ Out.write(uint8_t(0));
+}
+
+static bool isECObject(object::SymbolicFile &Obj) {
+ if (Obj.isCOFF())
+ return cast<llvm::object::COFFObjectFile>(&Obj)->getMachine() !=
+ COFF::IMAGE_FILE_MACHINE_ARM64;
+
+ if (Obj.isIR()) {
+ Expected<std::string> TripleStr =
+ getBitcodeTargetTriple(Obj.getMemoryBufferRef());
+ if (!TripleStr)
+ return false;
+ Triple T(*TripleStr);
+ return T.isWindowsArm64EC() || T.getArch() == Triple::x86_64;
+ }
+
+ return false;
+}
+
+static Expected<std::vector<unsigned>>
+getSymbols(MemoryBufferRef Buf, uint16_t Index, raw_ostream &SymNames,
+ SymMap *SymMap, bool &HasObject) {
// In the scenario when LLVMContext is populated SymbolicFile will contain a
// reference to it, thus SymbolicFile should be destroyed first.
LLVMContext Context;
- std::unique_ptr<object::SymbolicFile> Obj;
- const file_magic Type = identify_magic(Buf.getBuffer());
- // Treat unsupported file types as having no symbols.
- if (!object::SymbolicFile::isSymbolicFile(Type, &Context))
+ std::vector<unsigned> Ret;
+ Expected<std::unique_ptr<SymbolicFile>> ObjOrErr =
+ getSymbolicFile(Buf, Context);
+ if (!ObjOrErr)
+ return ObjOrErr.takeError();
+
+ // If the member is non-symbolic file, treat it as having no symbols.
+ if (!*ObjOrErr)
return Ret;
- if (Type == file_magic::bitcode) {
- auto ObjOrErr = object::SymbolicFile::createSymbolicFile(
- Buf, file_magic::bitcode, &Context);
- if (!ObjOrErr)
- return ObjOrErr.takeError();
- Obj = std::move(*ObjOrErr);
- } else {
- auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf);
- if (!ObjOrErr)
- return ObjOrErr.takeError();
- Obj = std::move(*ObjOrErr);
- }
+ std::unique_ptr<object::SymbolicFile> Obj = std::move(*ObjOrErr);
+
+ std::map<std::string, uint16_t> *Map = nullptr;
+ if (SymMap)
+ Map = SymMap->UseECMap && isECObject(*Obj) ? &SymMap->ECMap : &SymMap->Map;
HasObject = true;
for (const object::BasicSymbolRef &S : Obj->symbols()) {
if (!isArchiveSymbol(S))
continue;
- Ret.push_back(SymNames.tell());
- if (Error E = S.printName(SymNames))
- return std::move(E);
- SymNames << '\0';
+ if (Map) {
+ std::string Name;
+ raw_string_ostream NameStream(Name);
+ if (Error E = S.printName(NameStream))
+ return std::move(E);
+ if (Map->find(Name) != Map->end())
+ continue; // ignore duplicated symbol
+ (*Map)[Name] = Index;
+ if (Map == &SymMap->Map) {
+ Ret.push_back(SymNames.tell());
+ SymNames << Name << '\0';
+ }
+ } else {
+ Ret.push_back(SymNames.tell());
+ if (Error E = S.printName(SymNames))
+ return std::move(E);
+ SymNames << '\0';
+ }
}
return Ret;
}
@@ -483,7 +680,8 @@ getSymbols(MemoryBufferRef Buf, raw_ostream &SymNames, bool &HasObject) {
static Expected<std::vector<MemberData>>
computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
object::Archive::Kind Kind, bool Thin, bool Deterministic,
- bool NeedSymbols, ArrayRef<NewArchiveMember> NewMembers) {
+ bool NeedSymbols, SymMap *SymMap,
+ ArrayRef<NewArchiveMember> NewMembers) {
static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'};
uint64_t Pos =
@@ -549,7 +747,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
// The big archive format needs to know the offset of the previous member
// header.
- unsigned PrevOffset = 0;
+ uint64_t PrevOffset = 0;
+ uint16_t Index = 0;
for (const NewArchiveMember &M : NewMembers) {
std::string Header;
raw_string_ostream Out(Header);
@@ -557,6 +756,8 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
MemoryBufferRef Buf = M.Buf->getMemBufferRef();
StringRef Data = Thin ? "" : Buf.getBuffer();
+ Index++;
+
// ld64 expects the members to be 8-byte aligned for 64-bit content and at
// least 4-byte aligned for 32-bit content. Opt for the larger encoding
// uniformly. This matches the behaviour with cctools and ensures that ld64
@@ -583,7 +784,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
}
if (isAIXBigArchive(Kind)) {
- unsigned NextOffset = Pos + sizeof(object::BigArMemHdrType) +
+ uint64_t NextOffset = Pos + sizeof(object::BigArMemHdrType) +
alignTo(M.MemberName.size(), 2) + alignTo(Size, 2);
printBigArchiveMemberHeader(Out, M.MemberName, ModTime, M.UID, M.GID,
M.Perms, Size, PrevOffset, NextOffset);
@@ -597,7 +798,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
std::vector<unsigned> Symbols;
if (NeedSymbols) {
Expected<std::vector<unsigned>> SymbolsOrErr =
- getSymbols(Buf, SymNames, HasObject);
+ getSymbols(Buf, Index, SymNames, SymMap, HasObject);
if (!SymbolsOrErr)
return createFileError(M.MemberName, SymbolsOrErr.takeError());
Symbols = std::move(*SymbolsOrErr);
@@ -609,7 +810,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames,
// If there are no symbols, emit an empty symbol table, to satisfy Solaris
// tools, older versions of which expect a symbol table in a non-empty
// archive, regardless of whether there are any symbols in it.
- if (HasObject && SymNames.tell() == 0)
+ if (HasObject && SymNames.tell() == 0 && !isCOFFArchive(Kind))
SymNames << '\0' << '\0' << '\0';
return Ret;
}
@@ -660,50 +861,74 @@ Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) {
static Error writeArchiveToStream(raw_ostream &Out,
ArrayRef<NewArchiveMember> NewMembers,
bool WriteSymtab, object::Archive::Kind Kind,
- bool Deterministic, bool Thin) {
+ bool Deterministic, bool Thin, bool IsEC) {
assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode");
SmallString<0> SymNamesBuf;
raw_svector_ostream SymNames(SymNamesBuf);
SmallString<0> StringTableBuf;
raw_svector_ostream StringTable(StringTableBuf);
+ SymMap SymMap;
+
+ // COFF symbol map uses 16-bit indexes, so we can't use it if there are too
+ // many members.
+ if (isCOFFArchive(Kind) && NewMembers.size() > 0xfffe)
+ Kind = object::Archive::K_GNU;
- Expected<std::vector<MemberData>> DataOrErr =
- computeMemberData(StringTable, SymNames, Kind, Thin, Deterministic,
- WriteSymtab, NewMembers);
+ SymMap.UseECMap = IsEC;
+ Expected<std::vector<MemberData>> DataOrErr = computeMemberData(
+ StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab,
+ isCOFFArchive(Kind) ? &SymMap : nullptr, NewMembers);
if (Error E = DataOrErr.takeError())
return E;
std::vector<MemberData> &Data = *DataOrErr;
- if (!StringTableBuf.empty() && !isAIXBigArchive(Kind))
- Data.insert(Data.begin(), computeStringTable(StringTableBuf));
+ uint64_t StringTableSize = 0;
+ MemberData StringTableMember;
+ if (!StringTableBuf.empty() && !isAIXBigArchive(Kind)) {
+ StringTableMember = computeStringTable(StringTableBuf);
+ StringTableSize = StringTableMember.Header.size() +
+ StringTableMember.Data.size() +
+ StringTableMember.Padding.size();
+ }
// We would like to detect if we need to switch to a 64-bit symbol table.
- uint64_t LastMemberEndOffset =
- isAIXBigArchive(Kind) ? sizeof(object::BigArchive::FixLenHdr) : 8;
- uint64_t LastMemberHeaderOffset = LastMemberEndOffset;
+ uint64_t LastMemberEndOffset = 0;
+ uint64_t LastMemberHeaderOffset = 0;
uint64_t NumSyms = 0;
+ uint64_t NumSyms32 = 0; // Store symbol number of 32-bit member files.
+
for (const auto &M : Data) {
// Record the start of the member's offset
LastMemberHeaderOffset = LastMemberEndOffset;
// Account for the size of each part associated with the member.
LastMemberEndOffset += M.Header.size() + M.Data.size() + M.Padding.size();
NumSyms += M.Symbols.size();
+
+ // AIX big archive files may contain two global symbol tables. The
+ // first global symbol table locates 32-bit file members that define global
+ // symbols; the second global symbol table does the same for 64-bit file
+ // members. As a big archive can have both 32-bit and 64-bit file members,
+ // we need to know the number of symbols in each symbol table individually.
+ if (isAIXBigArchive(Kind) && WriteSymtab) {
+ Expected<bool> Is64BitOrErr = is64BitSymbolicFile(M.Data);
+ if (Error E = Is64BitOrErr.takeError())
+ return E;
+
+ if (!*Is64BitOrErr)
+ NumSyms32 += M.Symbols.size();
+ }
}
+ std::optional<uint64_t> HeadersSize;
+
// The symbol table is put at the end of the big archive file. The symbol
// table is at the start of the archive file for other archive formats.
- if (WriteSymtab && !isAIXBigArchive(Kind)) {
+ if (WriteSymtab && !is64BitKind(Kind)) {
// We assume 32-bit offsets to see if 32-bit symbols are possible or not.
- uint64_t SymtabSize = computeSymbolTableSize(Kind, NumSyms, 4, SymNamesBuf);
- auto computeSymbolTableHeaderSize =
- [=] {
- SmallString<0> TmpBuf;
- raw_svector_ostream Tmp(TmpBuf);
- writeSymbolTableHeader(Tmp, Kind, Deterministic, SymtabSize);
- return TmpBuf.size();
- };
- LastMemberHeaderOffset += computeSymbolTableHeaderSize() + SymtabSize;
+ HeadersSize = computeHeadersSize(Kind, Data.size(), StringTableSize,
+ NumSyms, SymNamesBuf.size(),
+ isCOFFArchive(Kind) ? &SymMap : nullptr);
// The SYM64 format is used when an archive's member offsets are larger than
// 32-bits can hold. The need for this shift in format is detected by
@@ -720,11 +945,12 @@ static Error writeArchiveToStream(raw_ostream &Out,
// If LastMemberHeaderOffset isn't going to fit in a 32-bit varible we need
// to switch to 64-bit. Note that the file can be larger than 4GB as long as
// the last member starts before the 4GB offset.
- if (LastMemberHeaderOffset >= Sym64Threshold) {
+ if (*HeadersSize + LastMemberHeaderOffset >= Sym64Threshold) {
if (Kind == object::Archive::K_DARWIN)
Kind = object::Archive::K_DARWIN64;
else
Kind = object::Archive::K_GNU64;
+ HeadersSize.reset();
}
}
@@ -736,11 +962,32 @@ static Error writeArchiveToStream(raw_ostream &Out,
Out << "!<arch>\n";
if (!isAIXBigArchive(Kind)) {
- if (WriteSymtab)
- writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf);
+ if (WriteSymtab) {
+ if (!HeadersSize)
+ HeadersSize = computeHeadersSize(
+ Kind, Data.size(), StringTableSize, NumSyms, SymNamesBuf.size(),
+ isCOFFArchive(Kind) ? &SymMap : nullptr);
+ writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf,
+ *HeadersSize, NumSyms);
+
+ if (isCOFFArchive(Kind))
+ writeSymbolMap(Out, Kind, Deterministic, Data, SymMap, *HeadersSize);
+ }
+
+ if (StringTableSize)
+ Out << StringTableMember.Header << StringTableMember.Data
+ << StringTableMember.Padding;
+
+ if (WriteSymtab && SymMap.ECMap.size())
+ writeECSymbols(Out, Kind, Deterministic, Data, SymMap);
+
for (const MemberData &M : Data)
Out << M.Header << M.Data << M.Padding;
} else {
+ HeadersSize = sizeof(object::BigArchive::FixLenHdr);
+ LastMemberEndOffset += *HeadersSize;
+ LastMemberHeaderOffset += *HeadersSize;
+
// For the big archive (AIX) format, compute a table of member names and
// offsets, used in the member table.
uint64_t MemberTableNameStrTblSize = 0;
@@ -761,25 +1008,61 @@ static Error writeArchiveToStream(raw_ostream &Out,
}
// AIX member table size.
- unsigned MemberTableSize = 20 + // Number of members field
+ uint64_t MemberTableSize = 20 + // Number of members field
20 * MemberOffsets.size() +
MemberTableNameStrTblSize;
- unsigned GlobalSymbolOffset =
- (WriteSymtab && NumSyms > 0)
- ? LastMemberEndOffset +
- alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2)
- : 0;
+ SmallString<0> SymNamesBuf32;
+ SmallString<0> SymNamesBuf64;
+ raw_svector_ostream SymNames32(SymNamesBuf32);
+ raw_svector_ostream SymNames64(SymNamesBuf64);
+
+ if (WriteSymtab && NumSyms)
+ // Generate the symbol names for the members.
+ for (const NewArchiveMember &M : NewMembers) {
+ MemoryBufferRef Buf = M.Buf->getMemBufferRef();
+ Expected<bool> Is64BitOrErr = is64BitSymbolicFile(Buf.getBuffer());
+ if (!Is64BitOrErr)
+ return Is64BitOrErr.takeError();
+
+ bool HasObject;
+ Expected<std::vector<unsigned>> SymbolsOrErr =
+ getSymbols(Buf, 0, *Is64BitOrErr ? SymNames64 : SymNames32, nullptr,
+ HasObject);
+ if (!SymbolsOrErr)
+ return SymbolsOrErr.takeError();
+ }
+
+ uint64_t MemberTableEndOffset =
+ LastMemberEndOffset +
+ alignTo(sizeof(object::BigArMemHdrType) + MemberTableSize, 2);
+
+ // In AIX OS, The 'GlobSymOffset' field in the fixed-length header contains
+ // the offset to the 32-bit global symbol table, and the 'GlobSym64Offset'
+ // contains the offset to the 64-bit global symbol table.
+ uint64_t GlobalSymbolOffset =
+ (WriteSymtab && NumSyms32 > 0) ? MemberTableEndOffset : 0;
+
+ uint64_t GlobalSymbolOffset64 = 0;
+ uint64_t NumSyms64 = NumSyms - NumSyms32;
+ if (WriteSymtab && NumSyms64 > 0) {
+ if (GlobalSymbolOffset == 0)
+ GlobalSymbolOffset64 = MemberTableEndOffset;
+ else
+ // If there is a global symbol table for 32-bit members,
+ // the 64-bit global symbol table is after the 32-bit one.
+ GlobalSymbolOffset64 =
+ GlobalSymbolOffset + sizeof(object::BigArMemHdrType) +
+ (NumSyms32 + 1) * 8 + alignTo(SymNamesBuf32.size(), 2);
+ }
// Fixed Sized Header.
printWithSpacePadding(Out, NewMembers.size() ? LastMemberEndOffset : 0,
20); // Offset to member table
// If there are no file members in the archive, there will be no global
// symbol table.
- printWithSpacePadding(Out, NewMembers.size() ? GlobalSymbolOffset : 0, 20);
- printWithSpacePadding(
- Out, 0,
- 20); // Offset to 64 bits global symbol table - Not supported yet
+ printWithSpacePadding(Out, GlobalSymbolOffset, 20);
+ printWithSpacePadding(Out, GlobalSymbolOffset64, 20);
printWithSpacePadding(
Out, NewMembers.size() ? sizeof(object::BigArchive::FixLenHdr) : 0,
20); // Offset to first archive member
@@ -799,7 +1082,8 @@ static Error writeArchiveToStream(raw_ostream &Out,
// Member table.
printBigArchiveMemberHeader(Out, "", sys::toTimePoint(0), 0, 0, 0,
MemberTableSize, LastMemberHeaderOffset,
- GlobalSymbolOffset);
+ GlobalSymbolOffset ? GlobalSymbolOffset
+ : GlobalSymbolOffset64);
printWithSpacePadding(Out, MemberOffsets.size(), 20); // Number of members
for (uint64_t MemberOffset : MemberOffsets)
printWithSpacePadding(Out, MemberOffset,
@@ -811,9 +1095,25 @@ static Error writeArchiveToStream(raw_ostream &Out,
Out << '\0'; // Name table must be tail padded to an even number of
// bytes.
- if (WriteSymtab && NumSyms > 0)
- writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf,
- LastMemberEndOffset);
+ if (WriteSymtab) {
+ // Write global symbol table for 32-bit file members.
+ if (GlobalSymbolOffset) {
+ writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf32,
+ *HeadersSize, NumSyms32, LastMemberEndOffset,
+ GlobalSymbolOffset64);
+ // Add padding between the symbol tables, if needed.
+ if (GlobalSymbolOffset64 && (SymNamesBuf32.size() % 2))
+ Out << '\0';
+ }
+
+ // Write global symbol table for 64-bit file members.
+ if (GlobalSymbolOffset64)
+ writeSymbolTable(Out, Kind, Deterministic, Data, SymNamesBuf64,
+ *HeadersSize, NumSyms64,
+ GlobalSymbolOffset ? GlobalSymbolOffset
+ : LastMemberEndOffset,
+ 0, true);
+ }
}
}
Out.flush();
@@ -823,7 +1123,7 @@ static Error writeArchiveToStream(raw_ostream &Out,
Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
bool WriteSymtab, object::Archive::Kind Kind,
bool Deterministic, bool Thin,
- std::unique_ptr<MemoryBuffer> OldArchiveBuf) {
+ std::unique_ptr<MemoryBuffer> OldArchiveBuf, bool IsEC) {
Expected<sys::fs::TempFile> Temp =
sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a");
if (!Temp)
@@ -831,7 +1131,7 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers,
raw_fd_ostream Out(Temp->FD, false);
if (Error E = writeArchiveToStream(Out, NewMembers, WriteSymtab, Kind,
- Deterministic, Thin)) {
+ Deterministic, Thin, IsEC)) {
if (Error DiscardError = Temp->discard())
return joinErrors(std::move(E), std::move(DiscardError));
return E;
@@ -860,7 +1160,7 @@ writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, bool WriteSymtab,
raw_svector_ostream ArchiveStream(ArchiveBufferVector);
if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab,
- Kind, Deterministic, Thin))
+ Kind, Deterministic, Thin, false))
return std::move(E);
return std::make_unique<SmallVectorMemoryBuffer>(
diff --git a/llvm/lib/Object/BuildID.cpp b/llvm/lib/Object/BuildID.cpp
index 795c22e769aa..ef21458060ab 100644
--- a/llvm/lib/Object/BuildID.cpp
+++ b/llvm/lib/Object/BuildID.cpp
@@ -18,13 +18,12 @@
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
-namespace llvm {
-namespace object {
+using namespace llvm;
+using namespace llvm::object;
namespace {
-template <typename ELFT>
-std::optional<BuildIDRef> getBuildID(const ELFFile<ELFT> &Obj) {
+template <typename ELFT> BuildIDRef getBuildID(const ELFFile<ELFT> &Obj) {
auto PhdrsOrErr = Obj.program_headers();
if (!PhdrsOrErr) {
consumeError(PhdrsOrErr.takeError());
@@ -37,7 +36,7 @@ std::optional<BuildIDRef> getBuildID(const ELFFile<ELFT> &Obj) {
for (auto N : Obj.notes(P, Err))
if (N.getType() == ELF::NT_GNU_BUILD_ID &&
N.getName() == ELF::ELF_NOTE_GNU)
- return N.getDesc();
+ return N.getDesc(P.p_align);
consumeError(std::move(Err));
}
return {};
@@ -45,15 +44,24 @@ std::optional<BuildIDRef> getBuildID(const ELFFile<ELFT> &Obj) {
} // namespace
-std::optional<BuildIDRef> getBuildID(const ObjectFile *Obj) {
+BuildID llvm::object::parseBuildID(StringRef Str) {
+ std::string Bytes;
+ if (!tryGetFromHex(Str, Bytes))
+ return {};
+ ArrayRef<uint8_t> BuildID(reinterpret_cast<const uint8_t *>(Bytes.data()),
+ Bytes.size());
+ return SmallVector<uint8_t>(BuildID.begin(), BuildID.end());
+}
+
+BuildIDRef llvm::object::getBuildID(const ObjectFile *Obj) {
if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
- return getBuildID(O->getELFFile());
+ return ::getBuildID(O->getELFFile());
if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
- return getBuildID(O->getELFFile());
+ return ::getBuildID(O->getELFFile());
if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
- return getBuildID(O->getELFFile());
+ return ::getBuildID(O->getELFFile());
if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
- return getBuildID(O->getELFFile());
+ return ::getBuildID(O->getELFFile());
return std::nullopt;
}
@@ -88,6 +96,3 @@ std::optional<std::string> BuildIDFetcher::fetch(BuildIDRef BuildID) const {
}
return std::nullopt;
}
-
-} // namespace object
-} // namespace llvm
diff --git a/llvm/lib/Object/COFFImportFile.cpp b/llvm/lib/Object/COFFImportFile.cpp
index 7090d3ca5618..765c12cc076c 100644
--- a/llvm/lib/Object/COFFImportFile.cpp
+++ b/llvm/lib/Object/COFFImportFile.cpp
@@ -39,6 +39,7 @@ static bool is32bit(MachineTypes Machine) {
llvm_unreachable("unsupported machine");
case IMAGE_FILE_MACHINE_ARM64:
case IMAGE_FILE_MACHINE_ARM64EC:
+ case IMAGE_FILE_MACHINE_ARM64X:
case IMAGE_FILE_MACHINE_AMD64:
return false;
case IMAGE_FILE_MACHINE_ARMNT:
@@ -57,6 +58,7 @@ static uint16_t getImgRelRelocation(MachineTypes Machine) {
return IMAGE_REL_ARM_ADDR32NB;
case IMAGE_FILE_MACHINE_ARM64:
case IMAGE_FILE_MACHINE_ARM64EC:
+ case IMAGE_FILE_MACHINE_ARM64X:
return IMAGE_REL_ARM64_ADDR32NB;
case IMAGE_FILE_MACHINE_I386:
return IMAGE_REL_I386_DIR32NB;
@@ -86,7 +88,8 @@ static void writeStringTable(std::vector<uint8_t> &B,
for (const auto &S : Strings) {
B.resize(Pos + S.length() + 1);
- strcpy(reinterpret_cast<char *>(&B[Pos]), S.c_str());
+ std::copy(S.begin(), S.end(), std::next(B.begin(), Pos));
+ B[Pos + S.length()] = 0;
Pos += S.length() + 1;
}
diff --git a/llvm/lib/Object/COFFModuleDefinition.cpp b/llvm/lib/Object/COFFModuleDefinition.cpp
index 0666970d5c60..a33949733c8e 100644
--- a/llvm/lib/Object/COFFModuleDefinition.cpp
+++ b/llvm/lib/Object/COFFModuleDefinition.cpp
@@ -138,8 +138,11 @@ private:
class Parser {
public:
- explicit Parser(StringRef S, MachineTypes M, bool B)
- : Lex(S), Machine(M), MingwDef(B) {}
+ explicit Parser(StringRef S, MachineTypes M, bool B, bool AU)
+ : Lex(S), Machine(M), MingwDef(B), AddUnderscores(AU) {
+ if (Machine != IMAGE_FILE_MACHINE_I386)
+ AddUnderscores = false;
+ }
Expected<COFFModuleDefinition> parse() {
do {
@@ -234,7 +237,7 @@ private:
unget();
}
- if (Machine == IMAGE_FILE_MACHINE_I386) {
+ if (AddUnderscores) {
if (!isDecorated(E.Name, MingwDef))
E.Name = (std::string("_").append(E.Name));
if (!E.ExtName.empty() && !isDecorated(E.ExtName, MingwDef))
@@ -279,7 +282,7 @@ private:
if (Tok.K == EqualEqual) {
read();
E.AliasTarget = std::string(Tok.Value);
- if (Machine == IMAGE_FILE_MACHINE_I386 && !isDecorated(E.AliasTarget, MingwDef))
+ if (AddUnderscores && !isDecorated(E.AliasTarget, MingwDef))
E.AliasTarget = std::string("_").append(E.AliasTarget);
continue;
}
@@ -349,12 +352,14 @@ private:
MachineTypes Machine;
COFFModuleDefinition Info;
bool MingwDef;
+ bool AddUnderscores;
};
Expected<COFFModuleDefinition> parseCOFFModuleDefinition(MemoryBufferRef MB,
MachineTypes Machine,
- bool MingwDef) {
- return Parser(MB.getBuffer(), Machine, MingwDef).parse();
+ bool MingwDef,
+ bool AddUnderscores) {
+ return Parser(MB.getBuffer(), Machine, MingwDef, AddUnderscores).parse();
}
} // namespace object
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp
index b159ae1bba14..08eb0d034c53 100644
--- a/llvm/lib/Object/COFFObjectFile.cpp
+++ b/llvm/lib/Object/COFFObjectFile.cpp
@@ -13,7 +13,6 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/Object/Binary.h"
@@ -26,6 +25,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MemoryBufferRef.h"
+#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#include <cassert>
#include <cinttypes>
@@ -753,6 +753,54 @@ Error COFFObjectFile::initLoadConfigPtr() {
return E;
LoadConfig = (const void *)IntPtr;
+
+ if (is64()) {
+ auto Config = getLoadConfig64();
+ if (Config->Size >=
+ offsetof(coff_load_configuration64, CHPEMetadataPointer) +
+ sizeof(Config->CHPEMetadataPointer) &&
+ Config->CHPEMetadataPointer) {
+ uint64_t ChpeOff = Config->CHPEMetadataPointer;
+ if (Error E =
+ getRvaPtr(ChpeOff - getImageBase(), IntPtr, "CHPE metadata"))
+ return E;
+ if (Error E = checkOffset(Data, IntPtr, sizeof(CHPEMetadata)))
+ return E;
+
+ CHPEMetadata = reinterpret_cast<const chpe_metadata *>(IntPtr);
+
+ // Validate CHPE metadata
+ if (CHPEMetadata->CodeMapCount) {
+ if (Error E = getRvaPtr(CHPEMetadata->CodeMap, IntPtr, "CHPE code map"))
+ return E;
+ if (Error E = checkOffset(Data, IntPtr,
+ CHPEMetadata->CodeMapCount *
+ sizeof(chpe_range_entry)))
+ return E;
+ }
+
+ if (CHPEMetadata->CodeRangesToEntryPointsCount) {
+ if (Error E = getRvaPtr(CHPEMetadata->CodeRangesToEntryPoints, IntPtr,
+ "CHPE entry point ranges"))
+ return E;
+ if (Error E = checkOffset(Data, IntPtr,
+ CHPEMetadata->CodeRangesToEntryPointsCount *
+ sizeof(chpe_code_range_entry)))
+ return E;
+ }
+
+ if (CHPEMetadata->RedirectionMetadataCount) {
+ if (Error E = getRvaPtr(CHPEMetadata->RedirectionMetadata, IntPtr,
+ "CHPE redirection metadata"))
+ return E;
+ if (Error E = checkOffset(Data, IntPtr,
+ CHPEMetadata->RedirectionMetadataCount *
+ sizeof(chpe_redirection_entry)))
+ return E;
+ }
+ }
+ }
+
return Error::success();
}
@@ -1016,6 +1064,8 @@ StringRef COFFObjectFile::getFileFormatName() const {
return "COFF-ARM64";
case COFF::IMAGE_FILE_MACHINE_ARM64EC:
return "COFF-ARM64EC";
+ case COFF::IMAGE_FILE_MACHINE_ARM64X:
+ return "COFF-ARM64X";
default:
return "COFF-<unknown arch>";
}
@@ -1031,6 +1081,7 @@ Triple::ArchType COFFObjectFile::getArch() const {
return Triple::thumb;
case COFF::IMAGE_FILE_MACHINE_ARM64:
case COFF::IMAGE_FILE_MACHINE_ARM64EC:
+ case COFF::IMAGE_FILE_MACHINE_ARM64X:
return Triple::aarch64;
default:
return Triple::UnknownArch;
@@ -1318,6 +1369,7 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const {
break;
case COFF::IMAGE_FILE_MACHINE_ARM64:
case COFF::IMAGE_FILE_MACHINE_ARM64EC:
+ case COFF::IMAGE_FILE_MACHINE_ARM64X:
switch (Type) {
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE);
LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32);
@@ -1901,6 +1953,7 @@ ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) {
break;
case COFF::IMAGE_FILE_MACHINE_ARM64:
case COFF::IMAGE_FILE_MACHINE_ARM64EC:
+ case COFF::IMAGE_FILE_MACHINE_ARM64X:
RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB;
break;
default:
diff --git a/llvm/lib/Object/DXContainer.cpp b/llvm/lib/Object/DXContainer.cpp
index 4d8f261fe4cc..48932afea84b 100644
--- a/llvm/lib/Object/DXContainer.cpp
+++ b/llvm/lib/Object/DXContainer.cpp
@@ -91,6 +91,15 @@ Error DXContainer::parseHash(StringRef Part) {
return Error::success();
}
+Error DXContainer::parsePSVInfo(StringRef Part) {
+ if (PSVInfo)
+ return parseFailed("More than one PSV0 part is present in the file");
+ PSVInfo = DirectX::PSVRuntimeInfo(Part);
+ // Parsing the PSVRuntime info occurs late because we need to read data from
+ // other parts first.
+ return Error::success();
+}
+
Error DXContainer::parsePartOffsets() {
uint32_t LastOffset =
sizeof(dxbc::Header) + (Header.PartCount * sizeof(uint32_t));
@@ -140,10 +149,24 @@ Error DXContainer::parsePartOffsets() {
if (Error Err = parseHash(PartData))
return Err;
break;
+ case dxbc::PartType::PSV0:
+ if (Error Err = parsePSVInfo(PartData))
+ return Err;
+ break;
case dxbc::PartType::Unknown:
break;
}
}
+
+ // Fully parsing the PSVInfo requires knowing the shader kind which we read
+ // out of the program header in the DXIL part.
+ if (PSVInfo) {
+ if (!DXIL)
+ return parseFailed("Cannot fully parse pipeline state validation "
+ "information without DXIL part.");
+ if (Error Err = PSVInfo->parse(DXIL->first.ShaderKind))
+ return Err;
+ }
return Error::success();
}
@@ -166,3 +189,69 @@ void DXContainer::PartIterator::updateIteratorImpl(const uint32_t Offset) {
StringRef(Current + sizeof(dxbc::PartHeader), IteratorState.Part.Size);
IteratorState.Offset = Offset;
}
+
+Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) {
+ Triple::EnvironmentType ShaderStage = dxbc::getShaderStage(ShaderKind);
+
+ const char *Current = Data.begin();
+ if (Error Err = readInteger(Data, Current, Size))
+ return Err;
+ Current += sizeof(uint32_t);
+
+ StringRef PSVInfoData = Data.substr(sizeof(uint32_t), Size);
+
+ if (PSVInfoData.size() < Size)
+ return parseFailed(
+ "Pipeline state data extends beyond the bounds of the part");
+
+ using namespace dxbc::PSV;
+
+ const uint32_t PSVVersion = getVersion();
+
+ // Detect the PSVVersion by looking at the size field.
+ if (PSVVersion == 2) {
+ v2::RuntimeInfo Info;
+ if (Error Err = readStruct(PSVInfoData, Current, Info))
+ return Err;
+ if (sys::IsBigEndianHost)
+ Info.swapBytes(ShaderStage);
+ BasicInfo = Info;
+ } else if (PSVVersion == 1) {
+ v1::RuntimeInfo Info;
+ if (Error Err = readStruct(PSVInfoData, Current, Info))
+ return Err;
+ if (sys::IsBigEndianHost)
+ Info.swapBytes(ShaderStage);
+ BasicInfo = Info;
+ } else {
+ v0::RuntimeInfo Info;
+ if (Error Err = readStruct(PSVInfoData, Current, Info))
+ return Err;
+ if (sys::IsBigEndianHost)
+ Info.swapBytes(ShaderStage);
+ BasicInfo = Info;
+ }
+ Current += Size;
+
+ uint32_t ResourceCount = 0;
+ if (Error Err = readInteger(Data, Current, ResourceCount))
+ return Err;
+ Current += sizeof(uint32_t);
+
+ if (ResourceCount > 0) {
+ if (Error Err = readInteger(Data, Current, Resources.Stride))
+ return Err;
+ Current += sizeof(uint32_t);
+
+ size_t BindingDataSize = Resources.Stride * ResourceCount;
+ Resources.Data = Data.substr(Current - Data.begin(), BindingDataSize);
+
+ if (Resources.Data.size() < BindingDataSize)
+ return parseFailed(
+ "Resource binding data extends beyond the bounds of the part");
+
+ Current += BindingDataSize;
+ }
+
+ return Error::success();
+}
diff --git a/llvm/lib/Object/Decompressor.cpp b/llvm/lib/Object/Decompressor.cpp
index f38c0e69e850..39baf2f0cb0f 100644
--- a/llvm/lib/Object/Decompressor.cpp
+++ b/llvm/lib/Object/Decompressor.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Object/Decompressor.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Object/ObjectFile.h"
#include "llvm/Support/Compression.h"
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 81c9a097170d..0d1862e57371 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/Object/ELF.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/Support/DataExtractor.h"
@@ -270,6 +271,11 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
case ELF::EM_RISCV:
switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_RISCV_ATTRIBUTES); }
break;
+ case ELF::EM_AARCH64:
+ switch (Type) {
+ STRINGIFY_ENUM_CASE(ELF, SHT_AARCH64_MEMTAG_GLOBALS_DYNAMIC);
+ STRINGIFY_ENUM_CASE(ELF, SHT_AARCH64_MEMTAG_GLOBALS_STATIC);
+ }
default:
break;
}
@@ -307,6 +313,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) {
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP_V0);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_BB_ADDR_MAP);
STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_OFFLOADING);
+ STRINGIFY_ENUM_CASE(ELF, SHT_LLVM_LTO);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_ATTRIBUTES);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_HASH);
STRINGIFY_ENUM_CASE(ELF, SHT_GNU_verdef);
@@ -640,7 +647,26 @@ ELFFile<ELFT>::toMappedAddr(uint64_t VAddr, WarningHandler WarnHandler) const {
template <class ELFT>
Expected<std::vector<BBAddrMap>>
-ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
+ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec,
+ const Elf_Shdr *RelaSec) const {
+ bool IsRelocatable = getHeader().e_type == ELF::ET_REL;
+
+ // This DenseMap maps the offset of each function (the location of the
+ // reference to the function in the SHT_LLVM_BB_ADDR_MAP section) to the
+ // addend (the location of the function in the text section).
+ llvm::DenseMap<uint64_t, uint64_t> FunctionOffsetTranslations;
+ if (IsRelocatable && RelaSec) {
+ assert(RelaSec &&
+ "Can't read a SHT_LLVM_BB_ADDR_MAP section in a relocatable "
+ "object file without providing a relocation section.");
+ Expected<Elf_Rela_Range> Relas = this->relas(*RelaSec);
+ if (!Relas)
+ return createError("unable to read relocations for section " +
+ describe(*this, Sec) + ": " +
+ toString(Relas.takeError()));
+ for (Elf_Rela Rela : *Relas)
+ FunctionOffsetTranslations[Rela.r_offset] = Rela.r_addend;
+ }
Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec);
if (!ContentsOrErr)
return ContentsOrErr.takeError();
@@ -650,6 +676,7 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
DataExtractor::Cursor Cur(0);
Error ULEBSizeErr = Error::success();
+ Error MetadataDecodeErr = Error::success();
// Helper to extract and decode the next ULEB128 value as uint32_t.
// Returns zero and sets ULEBSizeErr if the ULEB128 value exceeds the uint32_t
// limit.
@@ -670,7 +697,8 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
};
uint8_t Version = 0;
- while (!ULEBSizeErr && Cur && Cur.tell() < Content.size()) {
+ while (!ULEBSizeErr && !MetadataDecodeErr && Cur &&
+ Cur.tell() < Content.size()) {
if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) {
Version = Data.getU8(Cur);
if (!Cur)
@@ -680,32 +708,97 @@ ELFFile<ELFT>::decodeBBAddrMap(const Elf_Shdr &Sec) const {
Twine(static_cast<int>(Version)));
Data.getU8(Cur); // Feature byte
}
+ uint64_t SectionOffset = Cur.tell();
uintX_t Address = static_cast<uintX_t>(Data.getAddress(Cur));
+ if (!Cur)
+ return Cur.takeError();
+ if (IsRelocatable) {
+ assert(Address == 0);
+ auto FOTIterator = FunctionOffsetTranslations.find(SectionOffset);
+ if (FOTIterator == FunctionOffsetTranslations.end()) {
+ return createError("failed to get relocation data for offset: " +
+ Twine::utohexstr(SectionOffset) + " in section " +
+ describe(*this, Sec));
+ }
+ Address = FOTIterator->second;
+ }
uint32_t NumBlocks = ReadULEB128AsUInt32();
std::vector<BBAddrMap::BBEntry> BBEntries;
uint32_t PrevBBEndOffset = 0;
for (uint32_t BlockIndex = 0;
- !ULEBSizeErr && Cur && (BlockIndex < NumBlocks); ++BlockIndex) {
+ !MetadataDecodeErr && !ULEBSizeErr && Cur && (BlockIndex < NumBlocks);
+ ++BlockIndex) {
uint32_t ID = Version >= 2 ? ReadULEB128AsUInt32() : BlockIndex;
uint32_t Offset = ReadULEB128AsUInt32();
uint32_t Size = ReadULEB128AsUInt32();
- uint32_t Metadata = ReadULEB128AsUInt32();
+ uint32_t MD = ReadULEB128AsUInt32();
if (Version >= 1) {
// Offset is calculated relative to the end of the previous BB.
Offset += PrevBBEndOffset;
PrevBBEndOffset = Offset + Size;
}
- BBEntries.push_back({ID, Offset, Size, Metadata});
+ Expected<BBAddrMap::BBEntry::Metadata> MetadataOrErr =
+ BBAddrMap::BBEntry::Metadata::decode(MD);
+ if (!MetadataOrErr) {
+ MetadataDecodeErr = MetadataOrErr.takeError();
+ break;
+ }
+ BBEntries.push_back({ID, Offset, Size, *MetadataOrErr});
}
FunctionEntries.push_back({Address, std::move(BBEntries)});
}
- // Either Cur is in the error state, or ULEBSizeError is set (not both), but
- // we join the two errors here to be safe.
- if (!Cur || ULEBSizeErr)
- return joinErrors(Cur.takeError(), std::move(ULEBSizeErr));
+ // Either Cur is in the error state, or we have an error in ULEBSizeErr or
+ // MetadataDecodeErr (but not both), but we join all errors here to be safe.
+ if (!Cur || ULEBSizeErr || MetadataDecodeErr)
+ return joinErrors(joinErrors(Cur.takeError(), std::move(ULEBSizeErr)),
+ std::move(MetadataDecodeErr));
return FunctionEntries;
}
+template <class ELFT>
+Expected<
+ MapVector<const typename ELFT::Shdr *, const typename ELFT::Shdr *>>
+ELFFile<ELFT>::getSectionAndRelocations(
+ std::function<Expected<bool>(const Elf_Shdr &)> IsMatch) const {
+ MapVector<const Elf_Shdr *, const Elf_Shdr *> SecToRelocMap;
+ Error Errors = Error::success();
+ for (const Elf_Shdr &Sec : cantFail(this->sections())) {
+ Expected<bool> DoesSectionMatch = IsMatch(Sec);
+ if (!DoesSectionMatch) {
+ Errors = joinErrors(std::move(Errors), DoesSectionMatch.takeError());
+ continue;
+ }
+ if (*DoesSectionMatch) {
+ if (SecToRelocMap.insert(std::make_pair(&Sec, (const Elf_Shdr *)nullptr))
+ .second)
+ continue;
+ }
+
+ if (Sec.sh_type != ELF::SHT_RELA && Sec.sh_type != ELF::SHT_REL)
+ continue;
+
+ Expected<const Elf_Shdr *> RelSecOrErr = this->getSection(Sec.sh_info);
+ if (!RelSecOrErr) {
+ Errors = joinErrors(std::move(Errors),
+ createError(describe(*this, Sec) +
+ ": failed to get a relocated section: " +
+ toString(RelSecOrErr.takeError())));
+ continue;
+ }
+ const Elf_Shdr *ContentsSec = *RelSecOrErr;
+ Expected<bool> DoesRelTargetMatch = IsMatch(*ContentsSec);
+ if (!DoesRelTargetMatch) {
+ Errors = joinErrors(std::move(Errors), DoesRelTargetMatch.takeError());
+ continue;
+ }
+ if (*DoesRelTargetMatch)
+ SecToRelocMap[ContentsSec] = &Sec;
+ }
+ if(Errors)
+ return std::move(Errors);
+ return SecToRelocMap;
+}
+
template class llvm::object::ELFFile<ELF32LE>;
template class llvm::object::ELFFile<ELF32BE>;
template class llvm::object::ELFFile<ELF64LE>;
diff --git a/llvm/lib/Object/ELFObjectFile.cpp b/llvm/lib/Object/ELFObjectFile.cpp
index ebc57bd04be7..143f9d37849d 100644
--- a/llvm/lib/Object/ELFObjectFile.cpp
+++ b/llvm/lib/Object/ELFObjectFile.cpp
@@ -11,10 +11,8 @@
//===----------------------------------------------------------------------===//
#include "llvm/Object/ELFObjectFile.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCInstrAnalysis.h"
-#include "llvm/MC/SubtargetFeature.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/ELF.h"
#include "llvm/Object/ELFTypes.h"
@@ -26,6 +24,8 @@
#include "llvm/Support/RISCVAttributeParser.h"
#include "llvm/Support/RISCVAttributes.h"
#include "llvm/Support/RISCVISAInfo.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
+#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#include <cstddef>
#include <cstdint>
@@ -73,7 +73,7 @@ ObjectFile::createELFObjectFile(MemoryBufferRef Obj, bool InitContent) {
std::pair<unsigned char, unsigned char> Ident =
getElfArchType(Obj.getBuffer());
std::size_t MaxAlignment =
- 1ULL << countTrailingZeros(
+ 1ULL << llvm::countr_zero(
reinterpret_cast<uintptr_t>(Obj.getBufferStart()));
if (MaxAlignment < 2)
@@ -303,12 +303,7 @@ Expected<SubtargetFeatures> ELFObjectFileBase::getRISCVFeatures() const {
std::optional<StringRef> Attr =
Attributes.getAttributeString(RISCVAttrs::ARCH);
if (Attr) {
- // Suppress version checking for experimental extensions to prevent erroring
- // when getting any unknown version of experimental extension.
- auto ParseResult = RISCVISAInfo::parseArchString(
- *Attr, /*EnableExperimentalExtension=*/true,
- /*ExperimentalExtensionVersionCheck=*/false,
- /*IgnoreUnknown=*/true);
+ auto ParseResult = RISCVISAInfo::parseNormalizedArchString(*Attr);
if (!ParseResult)
return ParseResult.takeError();
auto &ISAInfo = *ParseResult;
@@ -363,6 +358,7 @@ std::optional<StringRef> ELFObjectFileBase::tryGetCPUName() const {
switch (getEMachine()) {
case ELF::EM_AMDGPU:
return getAMDGPUCPUName();
+ case ELF::EM_PPC:
case ELF::EM_PPC64:
return StringRef("future");
default:
@@ -468,6 +464,10 @@ StringRef ELFObjectFileBase::getAMDGPUCPUName() const {
return "gfx90c";
case ELF::EF_AMDGPU_MACH_AMDGCN_GFX940:
return "gfx940";
+ case ELF::EF_AMDGPU_MACH_AMDGCN_GFX941:
+ return "gfx941";
+ case ELF::EF_AMDGPU_MACH_AMDGCN_GFX942:
+ return "gfx942";
// AMDGCN GFX10.
case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1010:
@@ -502,6 +502,10 @@ StringRef ELFObjectFileBase::getAMDGPUCPUName() const {
return "gfx1102";
case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1103:
return "gfx1103";
+ case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1150:
+ return "gfx1150";
+ case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1151:
+ return "gfx1151";
default:
llvm_unreachable("Unknown EF_AMDGPU_MACH value");
}
@@ -602,20 +606,21 @@ void ELFObjectFileBase::setARMSubArch(Triple &TheTriple) const {
TheTriple.setArchName(Triple);
}
-std::vector<std::pair<std::optional<DataRefImpl>, uint64_t>>
-ELFObjectFileBase::getPltAddresses() const {
+std::vector<ELFPltEntry> ELFObjectFileBase::getPltEntries() const {
std::string Err;
const auto Triple = makeTriple();
const auto *T = TargetRegistry::lookupTarget(Triple.str(), Err);
if (!T)
return {};
- uint64_t JumpSlotReloc = 0;
+ uint32_t JumpSlotReloc = 0, GlobDatReloc = 0;
switch (Triple.getArch()) {
case Triple::x86:
JumpSlotReloc = ELF::R_386_JUMP_SLOT;
+ GlobDatReloc = ELF::R_386_GLOB_DAT;
break;
case Triple::x86_64:
JumpSlotReloc = ELF::R_X86_64_JUMP_SLOT;
+ GlobDatReloc = ELF::R_X86_64_GLOB_DAT;
break;
case Triple::aarch64:
case Triple::aarch64_be:
@@ -629,7 +634,9 @@ ELFObjectFileBase::getPltAddresses() const {
T->createMCInstrAnalysis(MII.get()));
if (!MIA)
return {};
- std::optional<SectionRef> Plt, RelaPlt, GotPlt;
+ std::vector<std::pair<uint64_t, uint64_t>> PltEntries;
+ std::optional<SectionRef> RelaPlt, RelaDyn;
+ uint64_t GotBaseVA = 0;
for (const SectionRef &Section : sections()) {
Expected<StringRef> NameOrErr = Section.getName();
if (!NameOrErr) {
@@ -638,42 +645,66 @@ ELFObjectFileBase::getPltAddresses() const {
}
StringRef Name = *NameOrErr;
- if (Name == ".plt")
- Plt = Section;
- else if (Name == ".rela.plt" || Name == ".rel.plt")
+ if (Name == ".rela.plt" || Name == ".rel.plt") {
RelaPlt = Section;
- else if (Name == ".got.plt")
- GotPlt = Section;
- }
- if (!Plt || !RelaPlt || !GotPlt)
- return {};
- Expected<StringRef> PltContents = Plt->getContents();
- if (!PltContents) {
- consumeError(PltContents.takeError());
- return {};
+ } else if (Name == ".rela.dyn" || Name == ".rel.dyn") {
+ RelaDyn = Section;
+ } else if (Name == ".got.plt") {
+ GotBaseVA = Section.getAddress();
+ } else if (Name == ".plt" || Name == ".plt.got") {
+ Expected<StringRef> PltContents = Section.getContents();
+ if (!PltContents) {
+ consumeError(PltContents.takeError());
+ return {};
+ }
+ llvm::append_range(
+ PltEntries,
+ MIA->findPltEntries(Section.getAddress(),
+ arrayRefFromStringRef(*PltContents), Triple));
+ }
}
- auto PltEntries = MIA->findPltEntries(Plt->getAddress(),
- arrayRefFromStringRef(*PltContents),
- GotPlt->getAddress(), Triple);
+
// Build a map from GOT entry virtual address to PLT entry virtual address.
DenseMap<uint64_t, uint64_t> GotToPlt;
- for (const auto &Entry : PltEntries)
- GotToPlt.insert(std::make_pair(Entry.second, Entry.first));
+ for (auto [Plt, GotPlt] : PltEntries) {
+ uint64_t GotPltEntry = GotPlt;
+ // An x86-32 PIC PLT uses jmp DWORD PTR [ebx-offset]. Add
+ // _GLOBAL_OFFSET_TABLE_ (EBX) to get the .got.plt (or .got) entry address.
+ // See X86MCTargetDesc.cpp:findPltEntries for the 1 << 32 bit.
+ if (GotPltEntry & (uint64_t(1) << 32) && getEMachine() == ELF::EM_386)
+ GotPltEntry = static_cast<int32_t>(GotPltEntry) + GotBaseVA;
+ GotToPlt.insert(std::make_pair(GotPltEntry, Plt));
+ }
+
// Find the relocations in the dynamic relocation table that point to
// locations in the GOT for which we know the corresponding PLT entry.
- std::vector<std::pair<std::optional<DataRefImpl>, uint64_t>> Result;
- for (const auto &Relocation : RelaPlt->relocations()) {
- if (Relocation.getType() != JumpSlotReloc)
- continue;
- auto PltEntryIter = GotToPlt.find(Relocation.getOffset());
- if (PltEntryIter != GotToPlt.end()) {
- symbol_iterator Sym = Relocation.getSymbol();
- if (Sym == symbol_end())
- Result.emplace_back(std::nullopt, PltEntryIter->second);
- else
- Result.emplace_back(Sym->getRawDataRefImpl(), PltEntryIter->second);
+ std::vector<ELFPltEntry> Result;
+ auto handleRels = [&](iterator_range<relocation_iterator> Rels,
+ uint32_t RelType, StringRef PltSec) {
+ for (const auto &R : Rels) {
+ if (R.getType() != RelType)
+ continue;
+ auto PltEntryIter = GotToPlt.find(R.getOffset());
+ if (PltEntryIter != GotToPlt.end()) {
+ symbol_iterator Sym = R.getSymbol();
+ if (Sym == symbol_end())
+ Result.push_back(
+ ELFPltEntry{PltSec, std::nullopt, PltEntryIter->second});
+ else
+ Result.push_back(ELFPltEntry{PltSec, Sym->getRawDataRefImpl(),
+ PltEntryIter->second});
+ }
}
- }
+ };
+
+ if (RelaPlt)
+ handleRels(RelaPlt->relocations(), JumpSlotReloc, ".plt");
+
+ // If a symbol needing a PLT entry also needs a GLOB_DAT relocation, GNU ld's
+ // x86 port places the PLT entry in the .plt.got section.
+ if (RelaDyn)
+ handleRels(RelaDyn->relocations(), GlobDatReloc, ".plt.got");
+
return Result;
}
@@ -681,24 +712,39 @@ template <class ELFT>
Expected<std::vector<BBAddrMap>> static readBBAddrMapImpl(
const ELFFile<ELFT> &EF, std::optional<unsigned> TextSectionIndex) {
using Elf_Shdr = typename ELFT::Shdr;
+ bool IsRelocatable = EF.getHeader().e_type == ELF::ET_REL;
std::vector<BBAddrMap> BBAddrMaps;
+
const auto &Sections = cantFail(EF.sections());
- for (const Elf_Shdr &Sec : Sections) {
+ auto IsMatch = [&](const Elf_Shdr &Sec) -> Expected<bool> {
if (Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP &&
Sec.sh_type != ELF::SHT_LLVM_BB_ADDR_MAP_V0)
- continue;
- if (TextSectionIndex) {
- Expected<const Elf_Shdr *> TextSecOrErr = EF.getSection(Sec.sh_link);
- if (!TextSecOrErr)
- return createError("unable to get the linked-to section for " +
- describe(EF, Sec) + ": " +
- toString(TextSecOrErr.takeError()));
- if (*TextSectionIndex != std::distance(Sections.begin(), *TextSecOrErr))
- continue;
- }
- Expected<std::vector<BBAddrMap>> BBAddrMapOrErr = EF.decodeBBAddrMap(Sec);
+ return false;
+ if (!TextSectionIndex)
+ return true;
+ Expected<const Elf_Shdr *> TextSecOrErr = EF.getSection(Sec.sh_link);
+ if (!TextSecOrErr)
+ return createError("unable to get the linked-to section for " +
+ describe(EF, Sec) + ": " +
+ toString(TextSecOrErr.takeError()));
+ if (*TextSectionIndex != std::distance(Sections.begin(), *TextSecOrErr))
+ return false;
+ return true;
+ };
+
+ Expected<MapVector<const Elf_Shdr *, const Elf_Shdr *>> SectionRelocMapOrErr =
+ EF.getSectionAndRelocations(IsMatch);
+ if (!SectionRelocMapOrErr)
+ return SectionRelocMapOrErr.takeError();
+
+ for (auto const &[Sec, RelocSec] : *SectionRelocMapOrErr) {
+ if (IsRelocatable && !RelocSec)
+ return createError("unable to get relocation section for " +
+ describe(EF, *Sec));
+ Expected<std::vector<BBAddrMap>> BBAddrMapOrErr =
+ EF.decodeBBAddrMap(*Sec, RelocSec);
if (!BBAddrMapOrErr)
- return createError("unable to read " + describe(EF, Sec) + ": " +
+ return createError("unable to read " + describe(EF, *Sec) + ": " +
toString(BBAddrMapOrErr.takeError()));
std::move(BBAddrMapOrErr->begin(), BBAddrMapOrErr->end(),
std::back_inserter(BBAddrMaps));
@@ -783,8 +829,6 @@ Expected<std::vector<BBAddrMap>> ELFObjectFileBase::readBBAddrMap(
return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex);
if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(this))
return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex);
- if (const auto *Obj = cast<ELF64BEObjectFile>(this))
- return readBBAddrMapImpl(Obj->getELFFile(), TextSectionIndex);
- else
- llvm_unreachable("Unsupported binary format");
+ return readBBAddrMapImpl(cast<ELF64BEObjectFile>(this)->getELFFile(),
+ TextSectionIndex);
}
diff --git a/llvm/lib/Object/GOFFObjectFile.cpp b/llvm/lib/Object/GOFFObjectFile.cpp
new file mode 100644
index 000000000000..76a13559ebfe
--- /dev/null
+++ b/llvm/lib/Object/GOFFObjectFile.cpp
@@ -0,0 +1,483 @@
+//===- GOFFObjectFile.cpp - GOFF object file implementation -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of the GOFFObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/GOFFObjectFile.h"
+#include "llvm/BinaryFormat/GOFF.h"
+#include "llvm/Object/GOFF.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/raw_ostream.h"
+
+#ifndef DEBUG_TYPE
+#define DEBUG_TYPE "goff"
+#endif
+
+using namespace llvm::object;
+using namespace llvm;
+
+Expected<std::unique_ptr<ObjectFile>>
+ObjectFile::createGOFFObjectFile(MemoryBufferRef Object) {
+ Error Err = Error::success();
+ std::unique_ptr<GOFFObjectFile> Ret(new GOFFObjectFile(Object, Err));
+ if (Err)
+ return std::move(Err);
+ return std::move(Ret);
+}
+
+GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err)
+ : ObjectFile(Binary::ID_GOFF, Object) {
+ ErrorAsOutParameter ErrAsOutParam(&Err);
+ // Object file isn't the right size, bail out early.
+ if ((Object.getBufferSize() % GOFF::RecordLength) != 0) {
+ Err = createStringError(
+ object_error::unexpected_eof,
+ "object file is not the right size. Must be a multiple "
+ "of 80 bytes, but is " +
+ std::to_string(Object.getBufferSize()) + " bytes");
+ return;
+ }
+ // Object file doesn't start/end with HDR/END records.
+ // Bail out early.
+ if (Object.getBufferSize() != 0) {
+ if ((base()[1] & 0xF0) >> 4 != GOFF::RT_HDR) {
+ Err = createStringError(object_error::parse_failed,
+ "object file must start with HDR record");
+ return;
+ }
+ if ((base()[Object.getBufferSize() - GOFF::RecordLength + 1] & 0xF0) >> 4 !=
+ GOFF::RT_END) {
+ Err = createStringError(object_error::parse_failed,
+ "object file must end with END record");
+ return;
+ }
+ }
+
+ SectionEntryImpl DummySection;
+ SectionList.emplace_back(DummySection); // Dummy entry at index 0.
+
+ uint8_t PrevRecordType = 0;
+ uint8_t PrevContinuationBits = 0;
+ const uint8_t *End = reinterpret_cast<const uint8_t *>(Data.getBufferEnd());
+ for (const uint8_t *I = base(); I < End; I += GOFF::RecordLength) {
+ uint8_t RecordType = (I[1] & 0xF0) >> 4;
+ bool IsContinuation = I[1] & 0x02;
+ bool PrevWasContinued = PrevContinuationBits & 0x01;
+ size_t RecordNum = (I - base()) / GOFF::RecordLength;
+
+ // If the previous record was continued, the current record should be a
+ // continuation.
+ if (PrevWasContinued && !IsContinuation) {
+ if (PrevRecordType == RecordType) {
+ Err = createStringError(object_error::parse_failed,
+ "record " + std::to_string(RecordNum) +
+ " is not a continuation record but the "
+ "preceding record is continued");
+ return;
+ }
+ }
+ // Don't parse continuations records, only parse initial record.
+ if (IsContinuation) {
+ if (RecordType != PrevRecordType) {
+ Err = createStringError(object_error::parse_failed,
+ "record " + std::to_string(RecordNum) +
+ " is a continuation record that does not "
+ "match the type of the previous record");
+ return;
+ }
+ if (!PrevWasContinued) {
+ Err = createStringError(object_error::parse_failed,
+ "record " + std::to_string(RecordNum) +
+ " is a continuation record that is not "
+ "preceded by a continued record");
+ return;
+ }
+ PrevRecordType = RecordType;
+ PrevContinuationBits = I[1] & 0x03;
+ continue;
+ }
+
+#ifndef NDEBUG
+ for (size_t J = 0; J < GOFF::RecordLength; ++J) {
+ const uint8_t *P = I + J;
+ if (J % 8 == 0)
+ dbgs() << " ";
+
+ dbgs() << format("%02hhX", *P);
+ }
+#endif
+ switch (RecordType) {
+ case GOFF::RT_ESD: {
+ // Save ESD record.
+ uint32_t EsdId;
+ ESDRecord::getEsdId(I, EsdId);
+ EsdPtrs.grow(EsdId);
+ EsdPtrs[EsdId] = I;
+
+ // Determine and save the "sections" in GOFF.
+ // A section is saved as a tuple of the form
+ // case (1): (ED,child PR)
+ // - where the PR must have non-zero length.
+ // case (2a) (ED,0)
+ // - where the ED is of non-zero length.
+ // case (2b) (ED,0)
+ // - where the ED is zero length but
+ // contains a label (LD).
+ GOFF::ESDSymbolType SymbolType;
+ ESDRecord::getSymbolType(I, SymbolType);
+ SectionEntryImpl Section;
+ uint32_t Length;
+ ESDRecord::getLength(I, Length);
+ if (SymbolType == GOFF::ESD_ST_ElementDefinition) {
+ // case (2a)
+ if (Length != 0) {
+ Section.d.a = EsdId;
+ SectionList.emplace_back(Section);
+ }
+ } else if (SymbolType == GOFF::ESD_ST_PartReference) {
+ // case (1)
+ if (Length != 0) {
+ uint32_t SymEdId;
+ ESDRecord::getParentEsdId(I, SymEdId);
+ Section.d.a = SymEdId;
+ Section.d.b = EsdId;
+ SectionList.emplace_back(Section);
+ }
+ } else if (SymbolType == GOFF::ESD_ST_LabelDefinition) {
+ // case (2b)
+ uint32_t SymEdId;
+ ESDRecord::getParentEsdId(I, SymEdId);
+ const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
+ uint32_t EdLength;
+ ESDRecord::getLength(SymEdRecord, EdLength);
+ if (!EdLength) { // [ EDID, PRID ]
+ // LD child of a zero length parent ED.
+ // Add the section ED which was previously ignored.
+ Section.d.a = SymEdId;
+ SectionList.emplace_back(Section);
+ }
+ }
+ LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n");
+ break;
+ }
+ case GOFF::RT_END:
+ LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n");
+ break;
+ case GOFF::RT_HDR:
+ LLVM_DEBUG(dbgs() << " -- HDR (GOFF record type) unhandled\n");
+ break;
+ default:
+ llvm_unreachable("Unknown record type");
+ }
+ PrevRecordType = RecordType;
+ PrevContinuationBits = I[1] & 0x03;
+ }
+}
+
+const uint8_t *GOFFObjectFile::getSymbolEsdRecord(DataRefImpl Symb) const {
+ const uint8_t *EsdRecord = EsdPtrs[Symb.d.a];
+ return EsdRecord;
+}
+
+Expected<StringRef> GOFFObjectFile::getSymbolName(DataRefImpl Symb) const {
+ if (EsdNamesCache.count(Symb.d.a)) {
+ auto &StrPtr = EsdNamesCache[Symb.d.a];
+ return StringRef(StrPtr.second.get(), StrPtr.first);
+ }
+
+ SmallString<256> SymbolName;
+ if (auto Err = ESDRecord::getData(getSymbolEsdRecord(Symb), SymbolName))
+ return std::move(Err);
+
+ SmallString<256> SymbolNameConverted;
+ ConverterEBCDIC::convertToUTF8(SymbolName, SymbolNameConverted);
+
+ size_t Size = SymbolNameConverted.size();
+ auto StrPtr = std::make_pair(Size, std::make_unique<char[]>(Size));
+ char *Buf = StrPtr.second.get();
+ memcpy(Buf, SymbolNameConverted.data(), Size);
+ EsdNamesCache[Symb.d.a] = std::move(StrPtr);
+ return StringRef(Buf, Size);
+}
+
+Expected<StringRef> GOFFObjectFile::getSymbolName(SymbolRef Symbol) const {
+ return getSymbolName(Symbol.getRawDataRefImpl());
+}
+
+Expected<uint64_t> GOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const {
+ uint32_t Offset;
+ const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
+ ESDRecord::getOffset(EsdRecord, Offset);
+ return static_cast<uint64_t>(Offset);
+}
+
+uint64_t GOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const {
+ uint32_t Offset;
+ const uint8_t *EsdRecord = getSymbolEsdRecord(Symb);
+ ESDRecord::getOffset(EsdRecord, Offset);
+ return static_cast<uint64_t>(Offset);
+}
+
+uint64_t GOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const {
+ return 0;
+}
+
+bool GOFFObjectFile::isSymbolUnresolved(DataRefImpl Symb) const {
+ const uint8_t *Record = getSymbolEsdRecord(Symb);
+ GOFF::ESDSymbolType SymbolType;
+ ESDRecord::getSymbolType(Record, SymbolType);
+
+ if (SymbolType == GOFF::ESD_ST_ExternalReference)
+ return true;
+ if (SymbolType == GOFF::ESD_ST_PartReference) {
+ uint32_t Length;
+ ESDRecord::getLength(Record, Length);
+ if (Length == 0)
+ return true;
+ }
+ return false;
+}
+
+bool GOFFObjectFile::isSymbolIndirect(DataRefImpl Symb) const {
+ const uint8_t *Record = getSymbolEsdRecord(Symb);
+ bool Indirect;
+ ESDRecord::getIndirectReference(Record, Indirect);
+ return Indirect;
+}
+
+Expected<uint32_t> GOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const {
+ uint32_t Flags = 0;
+ if (isSymbolUnresolved(Symb))
+ Flags |= SymbolRef::SF_Undefined;
+
+ const uint8_t *Record = getSymbolEsdRecord(Symb);
+
+ GOFF::ESDBindingStrength BindingStrength;
+ ESDRecord::getBindingStrength(Record, BindingStrength);
+ if (BindingStrength == GOFF::ESD_BST_Weak)
+ Flags |= SymbolRef::SF_Weak;
+
+ GOFF::ESDBindingScope BindingScope;
+ ESDRecord::getBindingScope(Record, BindingScope);
+
+ if (BindingScope != GOFF::ESD_BSC_Section) {
+ Expected<StringRef> Name = getSymbolName(Symb);
+ if (Name && *Name != " ") { // Blank name is local.
+ Flags |= SymbolRef::SF_Global;
+ if (BindingScope == GOFF::ESD_BSC_ImportExport)
+ Flags |= SymbolRef::SF_Exported;
+ else if (!(Flags & SymbolRef::SF_Undefined))
+ Flags |= SymbolRef::SF_Hidden;
+ }
+ }
+
+ return Flags;
+}
+
+Expected<SymbolRef::Type>
+GOFFObjectFile::getSymbolType(DataRefImpl Symb) const {
+ const uint8_t *Record = getSymbolEsdRecord(Symb);
+ GOFF::ESDSymbolType SymbolType;
+ ESDRecord::getSymbolType(Record, SymbolType);
+ GOFF::ESDExecutable Executable;
+ ESDRecord::getExecutable(Record, Executable);
+
+ if (SymbolType != GOFF::ESD_ST_SectionDefinition &&
+ SymbolType != GOFF::ESD_ST_ElementDefinition &&
+ SymbolType != GOFF::ESD_ST_LabelDefinition &&
+ SymbolType != GOFF::ESD_ST_PartReference &&
+ SymbolType != GOFF::ESD_ST_ExternalReference) {
+ uint32_t EsdId;
+ ESDRecord::getEsdId(Record, EsdId);
+ return createStringError(llvm::errc::invalid_argument,
+ "ESD record %" PRIu32
+ " has invalid symbol type 0x%02" PRIX8,
+ EsdId, SymbolType);
+ }
+ switch (SymbolType) {
+ case GOFF::ESD_ST_SectionDefinition:
+ case GOFF::ESD_ST_ElementDefinition:
+ return SymbolRef::ST_Other;
+ case GOFF::ESD_ST_LabelDefinition:
+ case GOFF::ESD_ST_PartReference:
+ case GOFF::ESD_ST_ExternalReference:
+ if (Executable != GOFF::ESD_EXE_CODE && Executable != GOFF::ESD_EXE_DATA &&
+ Executable != GOFF::ESD_EXE_Unspecified) {
+ uint32_t EsdId;
+ ESDRecord::getEsdId(Record, EsdId);
+ return createStringError(llvm::errc::invalid_argument,
+ "ESD record %" PRIu32
+ " has unknown Executable type 0x%02X",
+ EsdId, Executable);
+ }
+ switch (Executable) {
+ case GOFF::ESD_EXE_CODE:
+ return SymbolRef::ST_Function;
+ case GOFF::ESD_EXE_DATA:
+ return SymbolRef::ST_Data;
+ case GOFF::ESD_EXE_Unspecified:
+ return SymbolRef::ST_Unknown;
+ }
+ llvm_unreachable("Unhandled ESDExecutable");
+ }
+ llvm_unreachable("Unhandled ESDSymbolType");
+}
+
+Expected<section_iterator>
+GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const {
+ DataRefImpl Sec;
+
+ if (isSymbolUnresolved(Symb))
+ return section_iterator(SectionRef(Sec, this));
+
+ const uint8_t *SymEsdRecord = EsdPtrs[Symb.d.a];
+ uint32_t SymEdId;
+ ESDRecord::getParentEsdId(SymEsdRecord, SymEdId);
+ const uint8_t *SymEdRecord = EsdPtrs[SymEdId];
+
+ for (size_t I = 0, E = SectionList.size(); I < E; ++I) {
+ bool Found;
+ const uint8_t *SectionPrRecord = getSectionPrEsdRecord(I);
+ if (SectionPrRecord) {
+ Found = SymEsdRecord == SectionPrRecord;
+ } else {
+ const uint8_t *SectionEdRecord = getSectionEdEsdRecord(I);
+ Found = SymEdRecord == SectionEdRecord;
+ }
+
+ if (Found) {
+ Sec.d.a = I;
+ return section_iterator(SectionRef(Sec, this));
+ }
+ }
+ return createStringError(llvm::errc::invalid_argument,
+ "symbol with ESD id " + std::to_string(Symb.d.a) +
+ " refers to invalid section with ESD id " +
+ std::to_string(SymEdId));
+}
+
+const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const {
+ SectionEntryImpl EsdIds = SectionList[Sec.d.a];
+ const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a];
+ return EsdRecord;
+}
+
+const uint8_t *GOFFObjectFile::getSectionPrEsdRecord(DataRefImpl &Sec) const {
+ SectionEntryImpl EsdIds = SectionList[Sec.d.a];
+ const uint8_t *EsdRecord = nullptr;
+ if (EsdIds.d.b)
+ EsdRecord = EsdPtrs[EsdIds.d.b];
+ return EsdRecord;
+}
+
+const uint8_t *
+GOFFObjectFile::getSectionEdEsdRecord(uint32_t SectionIndex) const {
+ DataRefImpl Sec;
+ Sec.d.a = SectionIndex;
+ const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec);
+ return EsdRecord;
+}
+
+const uint8_t *
+GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const {
+ DataRefImpl Sec;
+ Sec.d.a = SectionIndex;
+ const uint8_t *EsdRecord = getSectionPrEsdRecord(Sec);
+ return EsdRecord;
+}
+
+section_iterator GOFFObjectFile::section_begin() const {
+ DataRefImpl Sec;
+ moveSectionNext(Sec);
+ return section_iterator(SectionRef(Sec, this));
+}
+
+section_iterator GOFFObjectFile::section_end() const {
+ DataRefImpl Sec;
+ return section_iterator(SectionRef(Sec, this));
+}
+
+void GOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const {
+ for (uint32_t I = Symb.d.a + 1, E = EsdPtrs.size(); I < E; ++I) {
+ if (EsdPtrs[I]) {
+ const uint8_t *EsdRecord = EsdPtrs[I];
+ GOFF::ESDSymbolType SymbolType;
+ ESDRecord::getSymbolType(EsdRecord, SymbolType);
+ // Skip EDs - i.e. section symbols.
+ bool IgnoreSpecialGOFFSymbols = true;
+ bool SkipSymbol = ((SymbolType == GOFF::ESD_ST_ElementDefinition) ||
+ (SymbolType == GOFF::ESD_ST_SectionDefinition)) &&
+ IgnoreSpecialGOFFSymbols;
+ if (!SkipSymbol) {
+ Symb.d.a = I;
+ return;
+ }
+ }
+ }
+ Symb.d.a = 0;
+}
+
+basic_symbol_iterator GOFFObjectFile::symbol_begin() const {
+ DataRefImpl Symb;
+ moveSymbolNext(Symb);
+ return basic_symbol_iterator(SymbolRef(Symb, this));
+}
+
+basic_symbol_iterator GOFFObjectFile::symbol_end() const {
+ DataRefImpl Symb;
+ return basic_symbol_iterator(SymbolRef(Symb, this));
+}
+
+Error Record::getContinuousData(const uint8_t *Record, uint16_t DataLength,
+ int DataIndex, SmallString<256> &CompleteData) {
+ // First record.
+ const uint8_t *Slice = Record + DataIndex;
+ size_t SliceLength =
+ std::min(DataLength, (uint16_t)(GOFF::RecordLength - DataIndex));
+ CompleteData.append(Slice, Slice + SliceLength);
+ DataLength -= SliceLength;
+ Slice += SliceLength;
+
+ // Continuation records.
+ for (; DataLength > 0;
+ DataLength -= SliceLength, Slice += GOFF::PayloadLength) {
+ // Slice points to the start of the new record.
+ // Check that this block is a Continuation.
+ assert(Record::isContinuation(Slice) && "Continuation bit must be set");
+ // Check that the last Continuation is terminated correctly.
+ if (DataLength <= 77 && Record::isContinued(Slice))
+ return createStringError(object_error::parse_failed,
+ "continued bit should not be set");
+
+ SliceLength = std::min(DataLength, (uint16_t)GOFF::PayloadLength);
+ Slice += GOFF::RecordPrefixLength;
+ CompleteData.append(Slice, Slice + SliceLength);
+ }
+ return Error::success();
+}
+
+Error HDRRecord::getData(const uint8_t *Record,
+ SmallString<256> &CompleteData) {
+ uint16_t Length = getPropertyModuleLength(Record);
+ return getContinuousData(Record, Length, 60, CompleteData);
+}
+
+Error ESDRecord::getData(const uint8_t *Record,
+ SmallString<256> &CompleteData) {
+ uint16_t DataSize = getNameLength(Record);
+ return getContinuousData(Record, DataSize, 72, CompleteData);
+}
+
+Error ENDRecord::getData(const uint8_t *Record,
+ SmallString<256> &CompleteData) {
+ uint16_t Length = getNameLength(Record);
+ return getContinuousData(Record, Length, 26, CompleteData);
+}
diff --git a/llvm/lib/Object/IRSymtab.cpp b/llvm/lib/Object/IRSymtab.cpp
index 54ee000b302f..14db7a10f310 100644
--- a/llvm/lib/Object/IRSymtab.cpp
+++ b/llvm/lib/Object/IRSymtab.cpp
@@ -13,7 +13,6 @@
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Bitcode/BitcodeReader.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/Comdat.h"
@@ -33,6 +32,7 @@
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VCSRevision.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
#include <cassert>
#include <string>
#include <utility>
@@ -41,8 +41,8 @@
using namespace llvm;
using namespace irsymtab;
-cl::opt<bool> DisableBitcodeVersionUpgrade(
- "disable-bitcode-version-upgrade", cl::init(false), cl::Hidden,
+static cl::opt<bool> DisableBitcodeVersionUpgrade(
+ "disable-bitcode-version-upgrade", cl::Hidden,
cl::desc("Disable automatic bitcode upgrade for version mismatch"));
static const char *PreservedSymbols[] = {
@@ -259,7 +259,7 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab,
Sym.Flags |= 1 << storage::Symbol::FB_executable;
Sym.ComdatIndex = -1;
- auto *GV = Msym.dyn_cast<GlobalValue *>();
+ auto *GV = dyn_cast_if_present<GlobalValue *>(Msym);
if (!GV) {
// Undefined module asm symbols act as GC roots and are implicitly used.
if (Flags & object::BasicSymbolRef::SF_Undefined)
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 9c0b85cf7416..6ca83a955d5a 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -16,7 +16,6 @@
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/bit.h"
#include "llvm/BinaryFormat/MachO.h"
@@ -32,12 +31,13 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.h"
-#include "llvm/Support/Host.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
+#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#include <cassert>
#include <cstddef>
diff --git a/llvm/lib/Object/MachOUniversalWriter.cpp b/llvm/lib/Object/MachOUniversalWriter.cpp
index 333706baf8c1..909a10b2c072 100644
--- a/llvm/lib/Object/MachOUniversalWriter.cpp
+++ b/llvm/lib/Object/MachOUniversalWriter.cpp
@@ -14,7 +14,6 @@
#include "llvm/Object/MachOUniversalWriter.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallVector.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/Object/Archive.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/IRObjectFile.h"
@@ -27,6 +26,7 @@
#include "llvm/Support/MemoryBufferRef.h"
#include "llvm/Support/SwapByteOrder.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
using namespace llvm;
using namespace object;
@@ -54,8 +54,8 @@ static uint32_t calculateFileAlignment(const MachOObjectFile &O) {
}
} else {
P2CurrentAlignment =
- countTrailingZeros(Is64Bit ? O.getSegment64LoadCommand(LC).vmaddr
- : O.getSegmentLoadCommand(LC).vmaddr);
+ llvm::countr_zero(Is64Bit ? O.getSegment64LoadCommand(LC).vmaddr
+ : O.getSegmentLoadCommand(LC).vmaddr);
}
P2MinAlignment = std::min(P2MinAlignment, P2CurrentAlignment);
}
diff --git a/llvm/lib/Object/ModuleSymbolTable.cpp b/llvm/lib/Object/ModuleSymbolTable.cpp
index 11274a7fcc16..0290a819e5de 100644
--- a/llvm/lib/Object/ModuleSymbolTable.cpp
+++ b/llvm/lib/Object/ModuleSymbolTable.cpp
@@ -17,7 +17,6 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalValue.h"
@@ -42,6 +41,7 @@
#include "llvm/Support/SMLoc.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -174,12 +174,12 @@ void ModuleSymbolTable::CollectAsmSymvers(
}
void ModuleSymbolTable::printSymbolName(raw_ostream &OS, Symbol S) const {
- if (S.is<AsmSymbol *>()) {
- OS << S.get<AsmSymbol *>()->first;
+ if (isa<AsmSymbol *>(S)) {
+ OS << cast<AsmSymbol *>(S)->first;
return;
}
- auto *GV = S.get<GlobalValue *>();
+ auto *GV = cast<GlobalValue *>(S);
if (GV->hasDLLImportStorageClass())
OS << "__imp_";
@@ -187,10 +187,10 @@ void ModuleSymbolTable::printSymbolName(raw_ostream &OS, Symbol S) const {
}
uint32_t ModuleSymbolTable::getSymbolFlags(Symbol S) const {
- if (S.is<AsmSymbol *>())
- return S.get<AsmSymbol *>()->second;
+ if (isa<AsmSymbol *>(S))
+ return cast<AsmSymbol *>(S)->second;
- auto *GV = S.get<GlobalValue *>();
+ auto *GV = cast<GlobalValue *>(S);
uint32_t Res = BasicSymbolRef::SF_None;
if (GV->isDeclarationForLinker())
diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp
index 56a1d09097d4..0820187f32e1 100644
--- a/llvm/lib/Object/ObjectFile.cpp
+++ b/llvm/lib/Object/ObjectFile.cpp
@@ -79,7 +79,7 @@ uint32_t ObjectFile::getSymbolAlignment(DataRefImpl DRI) const { return 0; }
bool ObjectFile::isSectionBitcode(DataRefImpl Sec) const {
Expected<StringRef> NameOrErr = getSectionName(Sec);
if (NameOrErr)
- return *NameOrErr == ".llvmbc";
+ return *NameOrErr == ".llvmbc" || *NameOrErr == ".llvm.lto";
consumeError(NameOrErr.takeError());
return false;
}
@@ -130,6 +130,10 @@ Triple ObjectFile::makeTriple() const {
TheTriple.setOS(Triple::AIX);
TheTriple.setObjectFormat(Triple::XCOFF);
}
+ else if (isGOFF()) {
+ TheTriple.setOS(Triple::ZOS);
+ TheTriple.setObjectFormat(Triple::GOFF);
+ }
return TheTriple;
}
diff --git a/llvm/lib/Object/OffloadBinary.cpp b/llvm/lib/Object/OffloadBinary.cpp
index d8cdcdc21d39..342327daf7e4 100644
--- a/llvm/lib/Object/OffloadBinary.cpp
+++ b/llvm/lib/Object/OffloadBinary.cpp
@@ -209,8 +209,8 @@ OffloadBinary::write(const OffloadingImage &OffloadingData) {
// Create a null-terminated string table with all the used strings.
StringTableBuilder StrTab(StringTableBuilder::ELF);
for (auto &KeyAndValue : OffloadingData.StringData) {
- StrTab.add(KeyAndValue.getKey());
- StrTab.add(KeyAndValue.getValue());
+ StrTab.add(KeyAndValue.first);
+ StrTab.add(KeyAndValue.second);
}
StrTab.finalize();
@@ -250,8 +250,8 @@ OffloadBinary::write(const OffloadingImage &OffloadingData) {
OS << StringRef(reinterpret_cast<char *>(&TheEntry), sizeof(Entry));
for (auto &KeyAndValue : OffloadingData.StringData) {
uint64_t Offset = sizeof(Header) + sizeof(Entry) + StringEntrySize;
- StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.getKey()),
- Offset + StrTab.getOffset(KeyAndValue.getValue())};
+ StringEntry Map{Offset + StrTab.getOffset(KeyAndValue.first),
+ Offset + StrTab.getOffset(KeyAndValue.second)};
OS << StringRef(reinterpret_cast<char *>(&Map), sizeof(StringEntry));
}
StrTab.write(OS);
diff --git a/llvm/lib/Object/RelocationResolver.cpp b/llvm/lib/Object/RelocationResolver.cpp
index 13a7a9851137..03ac59289528 100644
--- a/llvm/lib/Object/RelocationResolver.cpp
+++ b/llvm/lib/Object/RelocationResolver.cpp
@@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//
#include "llvm/Object/RelocationResolver.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/ADT/Twine.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/ELF.h"
@@ -24,6 +23,7 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TargetParser/Triple.h"
#include <cassert>
#include <vector>
@@ -252,6 +252,19 @@ static uint64_t resolveSparc64(uint64_t Type, uint64_t Offset, uint64_t S,
}
}
+/// Returns true if \c Obj is an AMDGPU code object based solely on the value
+/// of e_machine.
+///
+/// AMDGPU code objects with an e_machine of EF_AMDGPU_MACH_NONE do not
+/// identify their arch as either r600 or amdgcn, but we can still handle
+/// their relocations. When we identify an ELF object with an UnknownArch,
+/// we use isAMDGPU to check for this case.
+static bool isAMDGPU(const ObjectFile &Obj) {
+ if (const auto *ELFObj = dyn_cast<ELFObjectFileBase>(&Obj))
+ return ELFObj->getEMachine() == ELF::EM_AMDGPU;
+ return false;
+}
+
static bool supportsAmdgpu(uint64_t Type) {
switch (Type) {
case ELF::R_AMDGPU_ABS32:
@@ -789,6 +802,8 @@ getRelocationResolver(const ObjectFile &Obj) {
case Triple::riscv64:
return {supportsRISCV, resolveRISCV};
default:
+ if (isAMDGPU(Obj))
+ return {supportsAmdgpu, resolveAmdgpu};
return {nullptr, nullptr};
}
}
@@ -821,11 +836,15 @@ getRelocationResolver(const ObjectFile &Obj) {
return {supportsSparc32, resolveSparc32};
case Triple::hexagon:
return {supportsHexagon, resolveHexagon};
+ case Triple::r600:
+ return {supportsAmdgpu, resolveAmdgpu};
case Triple::riscv32:
return {supportsRISCV, resolveRISCV};
case Triple::csky:
return {supportsCSKY, resolveCSKY};
default:
+ if (isAMDGPU(Obj))
+ return {supportsAmdgpu, resolveAmdgpu};
return {nullptr, nullptr};
}
} else if (Obj.isMachO()) {
diff --git a/llvm/lib/Object/TapiFile.cpp b/llvm/lib/Object/TapiFile.cpp
index 596445a09e85..b5f4d277bbfe 100644
--- a/llvm/lib/Object/TapiFile.cpp
+++ b/llvm/lib/Object/TapiFile.cpp
@@ -37,35 +37,46 @@ static uint32_t getFlags(const Symbol *Sym) {
return Flags;
}
-TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &interface,
+static SymbolRef::Type getType(const Symbol *Sym) {
+ SymbolRef::Type Type = SymbolRef::ST_Unknown;
+ if (Sym->isData())
+ Type = SymbolRef::ST_Data;
+ else if (Sym->isText())
+ Type = SymbolRef::ST_Function;
+
+ return Type;
+}
+
+TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &Interface,
Architecture Arch)
: SymbolicFile(ID_TapiFile, Source), Arch(Arch) {
- for (const auto *Symbol : interface.symbols()) {
+ for (const auto *Symbol : Interface.symbols()) {
if (!Symbol->getArchitectures().has(Arch))
continue;
switch (Symbol->getKind()) {
case SymbolKind::GlobalSymbol:
- Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol));
+ Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol),
+ ::getType(Symbol));
break;
case SymbolKind::ObjectiveCClass:
- if (interface.getPlatforms().count(PLATFORM_MACOS) && Arch == AK_i386) {
+ if (Interface.getPlatforms().count(PLATFORM_MACOS) && Arch == AK_i386) {
Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(),
- getFlags(Symbol));
+ getFlags(Symbol), ::getType(Symbol));
} else {
Symbols.emplace_back(ObjC2ClassNamePrefix, Symbol->getName(),
- getFlags(Symbol));
+ getFlags(Symbol), ::getType(Symbol));
Symbols.emplace_back(ObjC2MetaClassNamePrefix, Symbol->getName(),
- getFlags(Symbol));
+ getFlags(Symbol), ::getType(Symbol));
}
break;
case SymbolKind::ObjectiveCClassEHType:
Symbols.emplace_back(ObjC2EHTypePrefix, Symbol->getName(),
- getFlags(Symbol));
+ getFlags(Symbol), ::getType(Symbol));
break;
case SymbolKind::ObjectiveCInstanceVariable:
- Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(),
- getFlags(Symbol));
+ Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(), getFlags(Symbol),
+ ::getType(Symbol));
break;
}
}
@@ -82,6 +93,11 @@ Error TapiFile::printSymbolName(raw_ostream &OS, DataRefImpl DRI) const {
return Error::success();
}
+Expected<SymbolRef::Type> TapiFile::getSymbolType(DataRefImpl DRI) const {
+ assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds");
+ return Symbols[DRI.d.a].Type;
+}
+
Expected<uint32_t> TapiFile::getSymbolFlags(DataRefImpl DRI) const {
assert(DRI.d.a < Symbols.size() && "Attempt to access symbol out of bounds");
return Symbols[DRI.d.a].Flags;
diff --git a/llvm/lib/Object/WasmObjectFile.cpp b/llvm/lib/Object/WasmObjectFile.cpp
index 1e98de7cd42e..a72242bc4ac2 100644
--- a/llvm/lib/Object/WasmObjectFile.cpp
+++ b/llvm/lib/Object/WasmObjectFile.cpp
@@ -12,9 +12,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/ADT/Triple.h"
#include "llvm/BinaryFormat/Wasm.h"
-#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Object/Binary.h"
#include "llvm/Object/Error.h"
#include "llvm/Object/ObjectFile.h"
@@ -25,6 +23,8 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/LEB128.h"
#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
+#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#include <cassert>
#include <cstdint>
@@ -38,7 +38,18 @@ using namespace object;
void WasmSymbol::print(raw_ostream &Out) const {
Out << "Name=" << Info.Name
<< ", Kind=" << toString(wasm::WasmSymbolType(Info.Kind)) << ", Flags=0x"
- << Twine::utohexstr(Info.Flags);
+ << Twine::utohexstr(Info.Flags) << " [";
+ switch (getBinding()) {
+ case wasm::WASM_SYMBOL_BINDING_GLOBAL: Out << "global"; break;
+ case wasm::WASM_SYMBOL_BINDING_LOCAL: Out << "local"; break;
+ case wasm::WASM_SYMBOL_BINDING_WEAK: Out << "weak"; break;
+ }
+ if (isHidden()) {
+ Out << ", hidden";
+ } else {
+ Out << ", default";
+ }
+ Out << "]";
if (!isTypeData()) {
Out << ", ElemIndex=" << Info.ElementIndex;
} else if (isDefined()) {
@@ -937,6 +948,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
Reloc.Index = readVaruint32(Ctx);
switch (type) {
case wasm::R_WASM_FUNCTION_INDEX_LEB:
+ case wasm::R_WASM_FUNCTION_INDEX_I32:
case wasm::R_WASM_TABLE_INDEX_SLEB:
case wasm::R_WASM_TABLE_INDEX_SLEB64:
case wasm::R_WASM_TABLE_INDEX_I32:
@@ -1034,6 +1046,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) {
Reloc.Type == wasm::R_WASM_MEMORY_ADDR_LOCREL_I32 ||
Reloc.Type == wasm::R_WASM_SECTION_OFFSET_I32 ||
Reloc.Type == wasm::R_WASM_FUNCTION_OFFSET_I32 ||
+ Reloc.Type == wasm::R_WASM_FUNCTION_INDEX_I32 ||
Reloc.Type == wasm::R_WASM_GLOBAL_INDEX_I32)
Size = 4;
if (Reloc.Type == wasm::R_WASM_TABLE_INDEX_I64 ||
diff --git a/llvm/lib/Object/WindowsMachineFlag.cpp b/llvm/lib/Object/WindowsMachineFlag.cpp
index 8335ea745548..b9f818775768 100644
--- a/llvm/lib/Object/WindowsMachineFlag.cpp
+++ b/llvm/lib/Object/WindowsMachineFlag.cpp
@@ -27,6 +27,7 @@ COFF::MachineTypes llvm::getMachineType(StringRef S) {
.Case("arm", COFF::IMAGE_FILE_MACHINE_ARMNT)
.Case("arm64", COFF::IMAGE_FILE_MACHINE_ARM64)
.Case("arm64ec", COFF::IMAGE_FILE_MACHINE_ARM64EC)
+ .Case("arm64x", COFF::IMAGE_FILE_MACHINE_ARM64X)
.Default(COFF::IMAGE_FILE_MACHINE_UNKNOWN);
}
@@ -38,6 +39,8 @@ StringRef llvm::machineToStr(COFF::MachineTypes MT) {
return "arm64";
case COFF::IMAGE_FILE_MACHINE_ARM64EC:
return "arm64ec";
+ case COFF::IMAGE_FILE_MACHINE_ARM64X:
+ return "arm64x";
case COFF::IMAGE_FILE_MACHINE_AMD64:
return "x64";
case COFF::IMAGE_FILE_MACHINE_I386:
diff --git a/llvm/lib/Object/WindowsResource.cpp b/llvm/lib/Object/WindowsResource.cpp
index 089a3fa0f91f..0764dc8f7523 100644
--- a/llvm/lib/Object/WindowsResource.cpp
+++ b/llvm/lib/Object/WindowsResource.cpp
@@ -990,6 +990,7 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() {
break;
case COFF::IMAGE_FILE_MACHINE_ARM64:
case COFF::IMAGE_FILE_MACHINE_ARM64EC:
+ case COFF::IMAGE_FILE_MACHINE_ARM64X:
Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB;
break;
default:
diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp
index 68baefcd6eaa..fa4917e354e9 100644
--- a/llvm/lib/Object/XCOFFObjectFile.cpp
+++ b/llvm/lib/Object/XCOFFObjectFile.cpp
@@ -12,8 +12,8 @@
#include "llvm/Object/XCOFFObjectFile.h"
#include "llvm/ADT/StringSwitch.h"
-#include "llvm/MC/SubtargetFeature.h"
#include "llvm/Support/DataExtractor.h"
+#include "llvm/TargetParser/SubtargetFeature.h"
#include <cstddef>
#include <cstring>
@@ -1217,6 +1217,10 @@ ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef,
return XCOFFObjectFile::create(FileType, MemBufRef);
}
+std::optional<StringRef> XCOFFObjectFile::tryGetCPUName() const {
+ return StringRef("future");
+}
+
bool XCOFFSymbolRef::isFunction() const {
if (!isCsectSymbol())
return false;
@@ -1394,18 +1398,18 @@ bool TBVectorExt::hasVMXInstruction() const {
#undef GETVALUEWITHMASK
#undef GETVALUEWITHMASKSHIFT
-Expected<XCOFFTracebackTable> XCOFFTracebackTable::create(const uint8_t *Ptr,
- uint64_t &Size) {
+Expected<XCOFFTracebackTable>
+XCOFFTracebackTable::create(const uint8_t *Ptr, uint64_t &Size, bool Is64Bit) {
Error Err = Error::success();
- XCOFFTracebackTable TBT(Ptr, Size, Err);
+ XCOFFTracebackTable TBT(Ptr, Size, Err, Is64Bit);
if (Err)
return std::move(Err);
return TBT;
}
XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size,
- Error &Err)
- : TBPtr(Ptr) {
+ Error &Err, bool Is64Bit)
+ : TBPtr(Ptr), Is64BitObj(Is64Bit) {
ErrorAsOutParameter EAO(&Err);
DataExtractor DE(ArrayRef<uint8_t>(Ptr, Size), /*IsLittleEndian=*/false,
/*AddressSize=*/0);
@@ -1460,6 +1464,8 @@ XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size,
}
VecExt = TBVecExtOrErr.get();
VectorParmsNum = VecExt->getNumberOfVectorParms();
+ // Skip two bytes of padding after vector info.
+ DE.skip(Cur, 2);
}
}
@@ -1480,9 +1486,15 @@ XCOFFTracebackTable::XCOFFTracebackTable(const uint8_t *Ptr, uint64_t &Size,
ParmsType = ParmsTypeOrError.get();
}
- if (Cur && hasExtensionTable())
+ if (Cur && hasExtensionTable()) {
ExtensionTable = DE.getU8(Cur);
+ if (*ExtensionTable & ExtendedTBTableFlag::TB_EH_INFO) {
+ // eh_info displacement must be 4-byte aligned.
+ Cur.seek(alignTo(Cur.tell(), 4));
+ EhInfoDisp = Is64BitObj ? DE.getU64(Cur) : DE.getU32(Cur);
+ }
+ }
if (!Cur)
Err = Cur.takeError();