diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:03:47 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2023-07-26 19:04:23 +0000 |
commit | 7fa27ce4a07f19b07799a767fc29416f3b625afb (patch) | |
tree | 27825c83636c4de341eb09a74f49f5d38a15d165 /llvm/lib/Object | |
parent | e3b557809604d036af6e00c60f012c2025b59a5e (diff) | |
download | src-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')
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(); |