diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2024-07-27 23:34:35 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2024-10-23 18:26:01 +0000 |
| commit | 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583 (patch) | |
| tree | 6cf5ab1f05330c6773b1f3f64799d56a9c7a1faa /contrib/llvm-project/llvm/lib/Object | |
| parent | 6b9f7133aba44189d9625c352bc2c2a59baf18ef (diff) | |
| parent | ac9a064cb179f3425b310fa2847f8764ac970a4d (diff) | |
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Object')
19 files changed, 1142 insertions, 371 deletions
diff --git a/contrib/llvm-project/llvm/lib/Object/Archive.cpp b/contrib/llvm-project/llvm/lib/Object/Archive.cpp index e447e5b23316..e798bbdd16f1 100644 --- a/contrib/llvm-project/llvm/lib/Object/Archive.cpp +++ b/contrib/llvm-project/llvm/lib/Object/Archive.cpp @@ -269,11 +269,11 @@ Expected<StringRef> ArchiveMemberHeader::getName(uint64_t Size) const { return Name; // System libraries from the Windows SDK for Windows 11 contain this symbol. // It looks like a CFG guard: we just skip it for now. - if (Name.equals("/<XFGHASHMAP>/")) + if (Name == "/<XFGHASHMAP>/") return Name; // Some libraries (e.g., arm64rt.lib) from the Windows WDK // (version 10.0.22000.0) contain this undocumented special member. - if (Name.equals("/<ECSYMBOLS>/")) + if (Name == "/<ECSYMBOLS>/") return Name; // It's a long name. // Get the string table offset. @@ -969,12 +969,19 @@ Archive::Archive(MemoryBufferRef Source, Error &Err) Err = Error::success(); } -object::Archive::Kind Archive::getDefaultKindForHost() { - Triple HostTriple(sys::getProcessTriple()); - return HostTriple.isOSDarwin() - ? object::Archive::K_DARWIN - : (HostTriple.isOSAIX() ? object::Archive::K_AIXBIG - : object::Archive::K_GNU); +object::Archive::Kind Archive::getDefaultKindForTriple(Triple &T) { + if (T.isOSDarwin()) + return object::Archive::K_DARWIN; + if (T.isOSAIX()) + return object::Archive::K_AIXBIG; + if (T.isOSWindows()) + return object::Archive::K_COFF; + return object::Archive::K_GNU; +} + +object::Archive::Kind Archive::getDefaultKind() { + Triple HostTriple(sys::getDefaultTargetTriple()); + return getDefaultKindForTriple(HostTriple); } Archive::child_iterator Archive::child_begin(Error &Err, diff --git a/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp b/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp index 1a7ed2db5439..114045561366 100644 --- a/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ArchiveWriter.cpp @@ -48,7 +48,7 @@ using namespace llvm; using namespace llvm::object; struct SymMap { - bool UseECMap; + bool UseECMap = false; std::map<std::string, uint16_t> Map; std::map<std::string, uint16_t> ECMap; }; @@ -62,12 +62,16 @@ object::Archive::Kind NewArchiveMember::detectKindFromObject() const { Expected<std::unique_ptr<object::ObjectFile>> OptionalObject = object::ObjectFile::createObjectFile(MemBufferRef); - if (OptionalObject) - return isa<object::MachOObjectFile>(**OptionalObject) - ? object::Archive::K_DARWIN - : (isa<object::XCOFFObjectFile>(**OptionalObject) - ? object::Archive::K_AIXBIG - : object::Archive::K_GNU); + if (OptionalObject) { + if (isa<object::MachOObjectFile>(**OptionalObject)) + return object::Archive::K_DARWIN; + if (isa<object::XCOFFObjectFile>(**OptionalObject)) + return object::Archive::K_AIXBIG; + if (isa<object::COFFObjectFile>(**OptionalObject) || + isa<object::COFFImportFile>(**OptionalObject)) + return object::Archive::K_COFF; + return object::Archive::K_GNU; + } // Squelch the error in case we had a non-object file. consumeError(OptionalObject.takeError()); @@ -80,17 +84,14 @@ object::Archive::Kind NewArchiveMember::detectKindFromObject() const { MemBufferRef, file_magic::bitcode, &Context)) { auto &IRObject = cast<object::IRObjectFile>(**ObjOrErr); auto TargetTriple = Triple(IRObject.getTargetTriple()); - return TargetTriple.isOSDarwin() - ? object::Archive::K_DARWIN - : (TargetTriple.isOSAIX() ? object::Archive::K_AIXBIG - : object::Archive::K_GNU); + return object::Archive::getDefaultKindForTriple(TargetTriple); } else { // Squelch the error in case this was not a SymbolicFile. consumeError(ObjOrErr.takeError()); } } - return object::Archive::getDefaultKindForHost(); + return object::Archive::getDefaultKind(); } Expected<NewArchiveMember> @@ -481,7 +482,8 @@ static uint64_t computeHeadersSize(object::Archive::Kind Kind, } static Expected<std::unique_ptr<SymbolicFile>> -getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { +getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context, + object::Archive::Kind Kind, function_ref<void(Error)> Warn) { const file_magic Type = identify_magic(Buf.getBuffer()); // Don't attempt to read non-symbolic file types. if (!object::SymbolicFile::isSymbolicFile(Type, &Context)) @@ -489,8 +491,36 @@ getSymbolicFile(MemoryBufferRef Buf, LLVMContext &Context) { if (Type == file_magic::bitcode) { auto ObjOrErr = object::SymbolicFile::createSymbolicFile( Buf, file_magic::bitcode, &Context); - if (!ObjOrErr) - return ObjOrErr.takeError(); + // An error reading a bitcode file most likely indicates that the file + // was created by a compiler from the future. Normally we don't try to + // implement forwards compatibility for bitcode files, but when creating an + // archive we can implement best-effort forwards compatibility by treating + // the file as a blob and not creating symbol index entries for it. lld and + // mold ignore the archive symbol index, so provided that you use one of + // these linkers, LTO will work as long as lld or the gold plugin is newer + // than the compiler. We only ignore errors if the archive format is one + // that is supported by a linker that is known to ignore the index, + // otherwise there's no chance of this working so we may as well error out. + // We print a warning on read failure so that users of linkers that rely on + // the symbol index can diagnose the issue. + // + // This is the same behavior as GNU ar when the linker plugin returns an + // error when reading the input file. If the bitcode file is actually + // malformed, it will be diagnosed at link time. + if (!ObjOrErr) { + switch (Kind) { + case object::Archive::K_BSD: + case object::Archive::K_GNU: + case object::Archive::K_GNU64: + Warn(ObjOrErr.takeError()); + return nullptr; + case object::Archive::K_AIXBIG: + case object::Archive::K_COFF: + case object::Archive::K_DARWIN: + case object::Archive::K_DARWIN64: + return ObjOrErr.takeError(); + } + } return std::move(*ObjOrErr); } else { auto ObjOrErr = object::SymbolicFile::createSymbolicFile(Buf); @@ -677,6 +707,25 @@ static bool isECObject(object::SymbolicFile &Obj) { return false; } +static bool isAnyArm64COFF(object::SymbolicFile &Obj) { + if (Obj.isCOFF()) + return COFF::isAnyArm64(cast<COFFObjectFile>(&Obj)->getMachine()); + + if (Obj.isCOFFImportFile()) + return COFF::isAnyArm64(cast<COFFImportFile>(&Obj)->getMachine()); + + if (Obj.isIR()) { + Expected<std::string> TripleStr = + getBitcodeTargetTriple(Obj.getMemoryBufferRef()); + if (!TripleStr) + return false; + Triple T(*TripleStr); + return T.isOSWindows() && T.getArch() == Triple::aarch64; + } + + return false; +} + bool isImportDescriptor(StringRef Name) { return Name.starts_with(ImportDescriptorPrefix) || Name == StringRef{NullImportDescriptorSymbolName} || @@ -730,7 +779,8 @@ static Expected<std::vector<MemberData>> computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, object::Archive::Kind Kind, bool Thin, bool Deterministic, SymtabWritingMode NeedSymbols, SymMap *SymMap, - LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers) { + LLVMContext &Context, ArrayRef<NewArchiveMember> NewMembers, + std::optional<bool> IsEC, function_ref<void(Error)> Warn) { static char PaddingData[8] = {'\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n'}; uint64_t MemHeadPadSize = 0; uint64_t Pos = @@ -794,23 +844,57 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, Entry.second = Entry.second > 1 ? 1 : 0; } + std::vector<std::unique_ptr<SymbolicFile>> SymFiles; + + if (NeedSymbols != SymtabWritingMode::NoSymtab || isAIXBigArchive(Kind)) { + for (const NewArchiveMember &M : NewMembers) { + Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr = getSymbolicFile( + M.Buf->getMemBufferRef(), Context, Kind, [&](Error Err) { + Warn(createFileError(M.MemberName, std::move(Err))); + }); + if (!SymFileOrErr) + return createFileError(M.MemberName, SymFileOrErr.takeError()); + SymFiles.push_back(std::move(*SymFileOrErr)); + } + } + + if (SymMap) { + if (IsEC) { + SymMap->UseECMap = *IsEC; + } else { + // When IsEC is not specified by the caller, use it when we have both + // any ARM64 object (ARM64 or ARM64EC) and any EC object (ARM64EC or + // AMD64). This may be a single ARM64EC object, but may also be separate + // ARM64 and AMD64 objects. + bool HaveArm64 = false, HaveEC = false; + for (std::unique_ptr<SymbolicFile> &SymFile : SymFiles) { + if (!SymFile) + continue; + if (!HaveArm64) + HaveArm64 = isAnyArm64COFF(*SymFile); + if (!HaveEC) + HaveEC = isECObject(*SymFile); + if (HaveArm64 && HaveEC) { + SymMap->UseECMap = true; + break; + } + } + } + } + // The big archive format needs to know the offset of the previous member // header. uint64_t PrevOffset = 0; uint64_t NextMemHeadPadSize = 0; - std::unique_ptr<SymbolicFile> CurSymFile; - std::unique_ptr<SymbolicFile> NextSymFile; - uint16_t Index = 0; - for (auto M = NewMembers.begin(); M < NewMembers.end(); ++M) { + for (uint32_t Index = 0; Index < NewMembers.size(); ++Index) { + const NewArchiveMember *M = &NewMembers[Index]; std::string Header; raw_string_ostream Out(Header); 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 @@ -836,29 +920,9 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, std::move(StringMsg), object::object_error::parse_failed); } - if (NeedSymbols != SymtabWritingMode::NoSymtab || isAIXBigArchive(Kind)) { - auto SetNextSymFile = [&NextSymFile, - &Context](MemoryBufferRef Buf, - StringRef MemberName) -> Error { - Expected<std::unique_ptr<SymbolicFile>> SymFileOrErr = - getSymbolicFile(Buf, Context); - if (!SymFileOrErr) - return createFileError(MemberName, SymFileOrErr.takeError()); - NextSymFile = std::move(*SymFileOrErr); - return Error::success(); - }; - - if (M == NewMembers.begin()) - if (Error Err = SetNextSymFile(Buf, M->MemberName)) - return std::move(Err); - - CurSymFile = std::move(NextSymFile); - - if ((M + 1) != NewMembers.end()) - if (Error Err = SetNextSymFile((M + 1)->Buf->getMemBufferRef(), - (M + 1)->MemberName)) - return std::move(Err); - } + std::unique_ptr<SymbolicFile> CurSymFile; + if (!SymFiles.empty()) + CurSymFile = std::move(SymFiles[Index]); // In the big archive file format, we need to calculate and include the next // member offset and previous member offset in the file member header. @@ -879,13 +943,13 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, // If there is another member file after this, we need to calculate the // padding before the header. - if ((M + 1) != NewMembers.end()) { - uint64_t OffsetToNextMemData = NextOffset + - sizeof(object::BigArMemHdrType) + - alignTo((M + 1)->MemberName.size(), 2); + if (Index + 1 != SymFiles.size()) { + uint64_t OffsetToNextMemData = + NextOffset + sizeof(object::BigArMemHdrType) + + alignTo(NewMembers[Index + 1].MemberName.size(), 2); NextMemHeadPadSize = alignToPowerOf2(OffsetToNextMemData, - getMemberAlignment(NextSymFile.get())) - + getMemberAlignment(SymFiles[Index + 1].get())) - OffsetToNextMemData; NextOffset += NextMemHeadPadSize; } @@ -901,7 +965,7 @@ computeMemberData(raw_ostream &StringTable, raw_ostream &SymNames, std::vector<unsigned> Symbols; if (NeedSymbols != SymtabWritingMode::NoSymtab) { Expected<std::vector<unsigned>> SymbolsOrErr = - getSymbols(CurSymFile.get(), Index, SymNames, SymMap); + getSymbols(CurSymFile.get(), Index + 1, SymNames, SymMap); if (!SymbolsOrErr) return createFileError(M->MemberName, SymbolsOrErr.takeError()); Symbols = std::move(*SymbolsOrErr); @@ -937,7 +1001,7 @@ Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) { ErrorOr<SmallString<128>> PathToOrErr = canonicalizePath(To); ErrorOr<SmallString<128>> DirFromOrErr = canonicalizePath(From); if (!PathToOrErr || !DirFromOrErr) - return errorCodeToError(std::error_code(errno, std::generic_category())); + return errorCodeToError(errnoAsErrorCode()); const SmallString<128> &PathTo = *PathToOrErr; const SmallString<128> &DirFrom = sys::path::parent_path(*DirFromOrErr); @@ -964,11 +1028,12 @@ Expected<std::string> computeArchiveRelativePath(StringRef From, StringRef To) { return std::string(Relative); } -static Error writeArchiveToStream(raw_ostream &Out, - ArrayRef<NewArchiveMember> NewMembers, - SymtabWritingMode WriteSymtab, - object::Archive::Kind Kind, - bool Deterministic, bool Thin, bool IsEC) { +Error writeArchiveToStream(raw_ostream &Out, + ArrayRef<NewArchiveMember> NewMembers, + SymtabWritingMode WriteSymtab, + object::Archive::Kind Kind, bool Deterministic, + bool Thin, std::optional<bool> IsEC, + function_ref<void(Error)> Warn) { assert((!Thin || !isBSDLike(Kind)) && "Only the gnu format has a thin mode"); SmallString<0> SymNamesBuf; @@ -976,20 +1041,21 @@ static Error writeArchiveToStream(raw_ostream &Out, SmallString<0> StringTableBuf; raw_svector_ostream StringTable(StringTableBuf); SymMap SymMap; + bool ShouldWriteSymtab = WriteSymtab != SymtabWritingMode::NoSymtab; // 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) + // many members. COFF format also requires symbol table presence, so use + // GNU format when NoSymtab is requested. + if (isCOFFArchive(Kind) && (NewMembers.size() > 0xfffe || !ShouldWriteSymtab)) Kind = object::Archive::K_GNU; // In the scenario when LLVMContext is populated SymbolicFile will contain a // reference to it, thus SymbolicFile should be destroyed first. LLVMContext Context; - SymMap.UseECMap = IsEC; Expected<std::vector<MemberData>> DataOrErr = computeMemberData( StringTable, SymNames, Kind, Thin, Deterministic, WriteSymtab, - isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers); + isCOFFArchive(Kind) ? &SymMap : nullptr, Context, NewMembers, IsEC, Warn); if (Error E = DataOrErr.takeError()) return E; std::vector<MemberData> &Data = *DataOrErr; @@ -1008,7 +1074,6 @@ static Error writeArchiveToStream(raw_ostream &Out, uint64_t LastMemberHeaderOffset = 0; uint64_t NumSyms = 0; uint64_t NumSyms32 = 0; // Store symbol number of 32-bit member files. - bool ShouldWriteSymtab = WriteSymtab != SymtabWritingMode::NoSymtab; for (const auto &M : Data) { // Record the start of the member's offset @@ -1233,10 +1298,15 @@ static Error writeArchiveToStream(raw_ostream &Out, return Error::success(); } +void warnToStderr(Error Err) { + llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "warning: "); +} + Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, bool Deterministic, bool Thin, - std::unique_ptr<MemoryBuffer> OldArchiveBuf, bool IsEC) { + std::unique_ptr<MemoryBuffer> OldArchiveBuf, + std::optional<bool> IsEC, function_ref<void(Error)> Warn) { Expected<sys::fs::TempFile> Temp = sys::fs::TempFile::create(ArcName + ".temp-archive-%%%%%%%.a"); if (!Temp) @@ -1244,7 +1314,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, IsEC)) { + Deterministic, Thin, IsEC, Warn)) { if (Error DiscardError = Temp->discard()) return joinErrors(std::move(E), std::move(DiscardError)); return E; @@ -1268,12 +1338,14 @@ Error writeArchive(StringRef ArcName, ArrayRef<NewArchiveMember> NewMembers, Expected<std::unique_ptr<MemoryBuffer>> writeArchiveToBuffer(ArrayRef<NewArchiveMember> NewMembers, SymtabWritingMode WriteSymtab, object::Archive::Kind Kind, - bool Deterministic, bool Thin) { + bool Deterministic, bool Thin, + function_ref<void(Error)> Warn) { SmallVector<char, 0> ArchiveBufferVector; raw_svector_ostream ArchiveStream(ArchiveBufferVector); - if (Error E = writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab, - Kind, Deterministic, Thin, false)) + if (Error E = + writeArchiveToStream(ArchiveStream, NewMembers, WriteSymtab, Kind, + Deterministic, Thin, std::nullopt, Warn)) return std::move(E); return std::make_unique<SmallVectorMemoryBuffer>( diff --git a/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp b/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp index d3b5cf2d9f7b..e67b02405a3a 100644 --- a/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/COFFImportFile.cpp @@ -12,6 +12,8 @@ #include "llvm/Object/COFFImportFile.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringMap.h" #include "llvm/ADT/Twine.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" @@ -52,18 +54,12 @@ StringRef COFFImportFile::getFileFormatName() const { } } -StringRef COFFImportFile::getExportName() const { - const coff_import_header *hdr = getCOFFImportHeader(); - StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first; - +static StringRef applyNameType(ImportNameType Type, StringRef name) { auto ltrim1 = [](StringRef s, StringRef chars) { return !s.empty() && chars.contains(s[0]) ? s.substr(1) : s; }; - switch (hdr->getNameType()) { - case IMPORT_ORDINAL: - name = ""; - break; + switch (Type) { case IMPORT_NAME_NOPREFIX: name = ltrim1(name, "?@_"); break; @@ -71,6 +67,24 @@ StringRef COFFImportFile::getExportName() const { name = ltrim1(name, "?@_"); name = name.substr(0, name.find('@')); break; + default: + break; + } + return name; +} + +StringRef COFFImportFile::getExportName() const { + const coff_import_header *hdr = getCOFFImportHeader(); + StringRef name = Data.getBuffer().substr(sizeof(*hdr)).split('\0').first; + + switch (hdr->getNameType()) { + case IMPORT_ORDINAL: + name = ""; + break; + case IMPORT_NAME_NOPREFIX: + case IMPORT_NAME_UNDECORATE: + name = applyNameType(static_cast<ImportNameType>(hdr->getNameType()), name); + break; case IMPORT_NAME_EXPORTAS: { // Skip DLL name name = Data.getBuffer().substr(sizeof(*hdr) + name.size() + 1); @@ -84,6 +98,27 @@ StringRef COFFImportFile::getExportName() const { return name; } +Error COFFImportFile::printSymbolName(raw_ostream &OS, DataRefImpl Symb) const { + switch (Symb.p) { + case ImpSymbol: + OS << "__imp_"; + break; + case ECAuxSymbol: + OS << "__imp_aux_"; + break; + } + const char *Name = Data.getBufferStart() + sizeof(coff_import_header); + if (Symb.p != ECThunkSymbol && COFF::isArm64EC(getMachine())) { + if (std::optional<std::string> DemangledName = + getArm64ECDemangledFunctionName(Name)) { + OS << StringRef(*DemangledName); + return Error::success(); + } + } + OS << StringRef(Name); + return Error::success(); +} + static uint16_t getImgRelRelocation(MachineTypes Machine) { switch (Machine) { default: @@ -623,10 +658,14 @@ NewArchiveMember ObjectFactory::createWeakExternal(StringRef Sym, Error writeImportLibrary(StringRef ImportName, StringRef Path, ArrayRef<COFFShortExport> Exports, - MachineTypes Machine, bool MinGW) { + MachineTypes Machine, bool MinGW, + ArrayRef<COFFShortExport> NativeExports) { - MachineTypes NativeMachine = - isArm64EC(Machine) ? IMAGE_FILE_MACHINE_ARM64 : Machine; + MachineTypes NativeMachine = Machine; + if (isArm64EC(Machine)) { + NativeMachine = IMAGE_FILE_MACHINE_ARM64; + Machine = IMAGE_FILE_MACHINE_ARM64EC; + } std::vector<NewArchiveMember> Members; ObjectFactory OF(llvm::sys::path::filename(ImportName), NativeMachine); @@ -640,66 +679,117 @@ Error writeImportLibrary(StringRef ImportName, StringRef Path, std::vector<uint8_t> NullThunk; Members.push_back(OF.createNullThunk(NullThunk)); - for (const COFFShortExport &E : Exports) { - if (E.Private) - continue; - - ImportType ImportType = IMPORT_CODE; - if (E.Data) - ImportType = IMPORT_DATA; - if (E.Constant) - ImportType = IMPORT_CONST; - - StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; - std::string Name; - - if (E.ExtName.empty()) { - Name = std::string(SymbolName); - } else { - Expected<std::string> ReplacedName = - replace(SymbolName, E.Name, E.ExtName); - if (!ReplacedName) - return ReplacedName.takeError(); - Name.swap(*ReplacedName); - } - - if (!E.AliasTarget.empty() && Name != E.AliasTarget) { - Members.push_back( - OF.createWeakExternal(E.AliasTarget, Name, false, Machine)); - Members.push_back( - OF.createWeakExternal(E.AliasTarget, Name, true, Machine)); - continue; - } + auto addExports = [&](ArrayRef<COFFShortExport> Exp, + MachineTypes M) -> Error { + StringMap<std::string> RegularImports; + struct Deferred { + std::string Name; + ImportType ImpType; + const COFFShortExport *Export; + }; + SmallVector<Deferred, 0> Renames; + for (const COFFShortExport &E : Exp) { + if (E.Private) + continue; + + ImportType ImportType = IMPORT_CODE; + if (E.Data) + ImportType = IMPORT_DATA; + if (E.Constant) + ImportType = IMPORT_CONST; + + StringRef SymbolName = E.SymbolName.empty() ? E.Name : E.SymbolName; + std::string Name; + + if (E.ExtName.empty()) { + Name = std::string(SymbolName); + } else { + Expected<std::string> ReplacedName = + replace(SymbolName, E.Name, E.ExtName); + if (!ReplacedName) + return ReplacedName.takeError(); + Name.swap(*ReplacedName); + } - ImportNameType NameType; - std::string ExportName; - if (E.Noname) { - NameType = IMPORT_ORDINAL; - } else { - NameType = getNameType(SymbolName, E.Name, Machine, MinGW); - } + ImportNameType NameType; + std::string ExportName; + if (E.Noname) { + NameType = IMPORT_ORDINAL; + } else if (!E.ExportAs.empty()) { + NameType = IMPORT_NAME_EXPORTAS; + ExportName = E.ExportAs; + } else if (!E.ImportName.empty()) { + // If we need to import from a specific ImportName, we may need to use + // a weak alias (which needs another import to point at). But if we can + // express ImportName based on the symbol name and a specific NameType, + // prefer that over an alias. + if (Machine == IMAGE_FILE_MACHINE_I386 && + applyNameType(IMPORT_NAME_UNDECORATE, Name) == E.ImportName) + NameType = IMPORT_NAME_UNDECORATE; + else if (Machine == IMAGE_FILE_MACHINE_I386 && + applyNameType(IMPORT_NAME_NOPREFIX, Name) == E.ImportName) + NameType = IMPORT_NAME_NOPREFIX; + else if (isArm64EC(M)) { + NameType = IMPORT_NAME_EXPORTAS; + ExportName = E.ImportName; + } else if (Name == E.ImportName) + NameType = IMPORT_NAME; + else { + Deferred D; + D.Name = Name; + D.ImpType = ImportType; + D.Export = &E; + Renames.push_back(D); + continue; + } + } else { + NameType = getNameType(SymbolName, E.Name, M, MinGW); + } - // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. - if (ImportType == IMPORT_CODE && isArm64EC(Machine)) { - if (std::optional<std::string> MangledName = - getArm64ECMangledFunctionName(Name)) { - if (ExportName.empty()) { + // On ARM64EC, use EXPORTAS to import demangled name for mangled symbols. + if (ImportType == IMPORT_CODE && isArm64EC(M)) { + if (std::optional<std::string> MangledName = + getArm64ECMangledFunctionName(Name)) { + if (!E.Noname && ExportName.empty()) { + NameType = IMPORT_NAME_EXPORTAS; + ExportName.swap(Name); + } + Name = std::move(*MangledName); + } else if (!E.Noname && ExportName.empty()) { NameType = IMPORT_NAME_EXPORTAS; - ExportName.swap(Name); + ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); } - Name = std::move(*MangledName); - } else if (ExportName.empty()) { - NameType = IMPORT_NAME_EXPORTAS; - ExportName = std::move(*getArm64ECDemangledFunctionName(Name)); + } + + RegularImports[applyNameType(NameType, Name)] = Name; + Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, + NameType, ExportName, M)); + } + for (const auto &D : Renames) { + auto It = RegularImports.find(D.Export->ImportName); + if (It != RegularImports.end()) { + // We have a regular import entry for a symbol with the name we + // want to reference; produce an alias pointing at that. + StringRef Symbol = It->second; + if (D.ImpType == IMPORT_CODE) + Members.push_back(OF.createWeakExternal(Symbol, D.Name, false, M)); + Members.push_back(OF.createWeakExternal(Symbol, D.Name, true, M)); + } else { + Members.push_back(OF.createShortImport(D.Name, D.Export->Ordinal, + D.ImpType, IMPORT_NAME_EXPORTAS, + D.Export->ImportName, M)); } } + return Error::success(); + }; - Members.push_back(OF.createShortImport(Name, E.Ordinal, ImportType, - NameType, ExportName, Machine)); - } + if (Error e = addExports(Exports, Machine)) + return e; + if (Error e = addExports(NativeExports, NativeMachine)) + return e; return writeArchive(Path, Members, SymtabWritingMode::NormalSymtab, - MinGW ? object::Archive::K_GNU : object::Archive::K_COFF, + object::Archive::K_COFF, /*Deterministic*/ true, /*Thin*/ false, /*OldArchiveBuf*/ nullptr, isArm64EC(Machine)); } diff --git a/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp b/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp index 648f01f823d0..82c18539658e 100644 --- a/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp +++ b/contrib/llvm-project/llvm/lib/Object/COFFModuleDefinition.cpp @@ -39,6 +39,7 @@ enum Kind { KwConstant, KwData, KwExports, + KwExportAs, KwHeapsize, KwLibrary, KwName, @@ -97,10 +98,8 @@ public: } case '=': Buf = Buf.drop_front(); - if (Buf.starts_with("=")) { - Buf = Buf.drop_front(); + if (Buf.consume_front("=")) return Token(EqualEqual, "=="); - } return Token(Equal, "="); case ',': Buf = Buf.drop_front(); @@ -118,6 +117,7 @@ public: .Case("CONSTANT", KwConstant) .Case("DATA", KwData) .Case("EXPORTS", KwExports) + .Case("EXPORTAS", KwExportAs) .Case("HEAPSIZE", KwHeapsize) .Case("LIBRARY", KwLibrary) .Case("NAME", KwName) @@ -281,12 +281,19 @@ private: } if (Tok.K == EqualEqual) { read(); - E.AliasTarget = std::string(Tok.Value); - if (AddUnderscores && !isDecorated(E.AliasTarget, MingwDef)) - E.AliasTarget = std::string("_").append(E.AliasTarget); + E.ImportName = std::string(Tok.Value); continue; } - unget(); + // EXPORTAS must be at the end of export definition + if (Tok.K == KwExportAs) { + read(); + if (Tok.K == Eof) + return createError( + "unexpected end of file, EXPORTAS identifier expected"); + E.ExportAs = std::string(Tok.Value); + } else { + unget(); + } Info.Exports.push_back(E); return Error::success(); } diff --git a/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp index 8700912614db..5a85b8e00c63 100644 --- a/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/COFFObjectFile.cpp @@ -14,18 +14,17 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/BinaryFormat/COFF.h" #include "llvm/Object/Binary.h" #include "llvm/Object/COFF.h" #include "llvm/Object/Error.h" #include "llvm/Object/ObjectFile.h" +#include "llvm/Object/WindowsMachineFlag.h" #include "llvm/Support/BinaryStreamReader.h" #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #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> @@ -295,7 +294,7 @@ COFFObjectFile::getSectionContents(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); ArrayRef<uint8_t> Res; if (Error E = getSectionContents(Sec, Res)) - return std::move(E); + return E; return Res; } @@ -808,7 +807,7 @@ Expected<std::unique_ptr<COFFObjectFile>> COFFObjectFile::create(MemoryBufferRef Object) { std::unique_ptr<COFFObjectFile> Obj(new COFFObjectFile(std::move(Object))); if (Error E = Obj->initialize()) - return std::move(E); + return E; return std::move(Obj); } @@ -1072,20 +1071,7 @@ StringRef COFFObjectFile::getFileFormatName() const { } Triple::ArchType COFFObjectFile::getArch() const { - switch (getMachine()) { - case COFF::IMAGE_FILE_MACHINE_I386: - return Triple::x86; - case COFF::IMAGE_FILE_MACHINE_AMD64: - return Triple::x86_64; - case COFF::IMAGE_FILE_MACHINE_ARMNT: - 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; - } + return getMachineArchType(getMachine()); } Expected<uint64_t> COFFObjectFile::getStartAddress() const { @@ -1320,8 +1306,8 @@ COFFObjectFile::getRelocations(const coff_section *Sec) const { return #reloc_type; StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { - switch (getMachine()) { - case COFF::IMAGE_FILE_MACHINE_AMD64: + switch (getArch()) { + case Triple::x86_64: switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_AMD64_ADDR64); @@ -1344,7 +1330,7 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { return "Unknown"; } break; - case COFF::IMAGE_FILE_MACHINE_ARMNT: + case Triple::thumb: switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM_ADDR32); @@ -1367,9 +1353,7 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { return "Unknown"; } break; - case COFF::IMAGE_FILE_MACHINE_ARM64: - case COFF::IMAGE_FILE_MACHINE_ARM64EC: - case COFF::IMAGE_FILE_MACHINE_ARM64X: + case Triple::aarch64: switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_ARM64_ADDR32); @@ -1393,7 +1377,7 @@ StringRef COFFObjectFile::getRelocationTypeName(uint16_t Type) const { return "Unknown"; } break; - case COFF::IMAGE_FILE_MACHINE_I386: + case Triple::x86: switch (Type) { LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_ABSOLUTE); LLVM_COFF_SWITCH_RELOC_TYPE_NAME(IMAGE_REL_I386_DIR16); @@ -1941,19 +1925,17 @@ ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) { // the expected type. const coff_relocation &R = **RelocsForOffset.first; uint16_t RVAReloc; - switch (Obj->getMachine()) { - case COFF::IMAGE_FILE_MACHINE_I386: + switch (Obj->getArch()) { + case Triple::x86: RVAReloc = COFF::IMAGE_REL_I386_DIR32NB; break; - case COFF::IMAGE_FILE_MACHINE_AMD64: + case Triple::x86_64: RVAReloc = COFF::IMAGE_REL_AMD64_ADDR32NB; break; - case COFF::IMAGE_FILE_MACHINE_ARMNT: + case Triple::thumb: RVAReloc = COFF::IMAGE_REL_ARM_ADDR32NB; break; - case COFF::IMAGE_FILE_MACHINE_ARM64: - case COFF::IMAGE_FILE_MACHINE_ARM64EC: - case COFF::IMAGE_FILE_MACHINE_ARM64X: + case Triple::aarch64: RVAReloc = COFF::IMAGE_REL_ARM64_ADDR32NB; break; default: @@ -1977,7 +1959,7 @@ ResourceSectionRef::getContents(const coff_resource_data_entry &Entry) { uint64_t Offset = Entry.DataRVA + Sym->getValue(); ArrayRef<uint8_t> Contents; if (Error E = Obj->getSectionContents(*Section, Contents)) - return std::move(E); + return E; if (Offset + Entry.DataSize > Contents.size()) return createStringError(object_error::parse_failed, "data outside of section"); diff --git a/contrib/llvm-project/llvm/lib/Object/DXContainer.cpp b/contrib/llvm-project/llvm/lib/Object/DXContainer.cpp index 4aabe9cea3e5..3b1a6203a1f8 100644 --- a/contrib/llvm-project/llvm/lib/Object/DXContainer.cpp +++ b/contrib/llvm-project/llvm/lib/Object/DXContainer.cpp @@ -72,13 +72,13 @@ Error DXContainer::parseDXILHeader(StringRef Part) { return Error::success(); } -Error DXContainer::parseShaderFlags(StringRef Part) { - if (ShaderFlags) +Error DXContainer::parseShaderFeatureFlags(StringRef Part) { + if (ShaderFeatureFlags) return parseFailed("More than one SFI0 part is present in the file"); uint64_t FlagValue = 0; if (Error Err = readInteger(Part, Part.begin(), FlagValue)) return Err; - ShaderFlags = FlagValue; + ShaderFeatureFlags = FlagValue; return Error::success(); } @@ -168,7 +168,7 @@ Error DXContainer::parsePartOffsets() { return Err; break; case dxbc::PartType::SFI0: - if (Error Err = parseShaderFlags(PartData)) + if (Error Err = parseShaderFeatureFlags(PartData)) return Err; break; case dxbc::PartType::HASH: @@ -247,7 +247,14 @@ Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) { const uint32_t PSVVersion = getVersion(); // Detect the PSVVersion by looking at the size field. - if (PSVVersion == 2) { + if (PSVVersion == 3) { + v3::RuntimeInfo Info; + if (Error Err = readStruct(PSVInfoData, Current, Info)) + return Err; + if (sys::IsBigEndianHost) + Info.swapBytes(ShaderStage); + BasicInfo = Info; + } else if (PSVVersion == 2) { v2::RuntimeInfo Info; if (Error Err = readStruct(PSVInfoData, Current, Info)) return Err; @@ -341,7 +348,8 @@ Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) { SigOutputElements.Stride = SigPatchOrPrimElements.Stride = SigInputElements.Stride; - if (Data.end() - Current < ElementCount * SigInputElements.Stride) + if (Data.end() - Current < + (ptrdiff_t)(ElementCount * SigInputElements.Stride)) return parseFailed( "Signature elements extend beyond the size of the part"); @@ -424,6 +432,8 @@ Error DirectX::PSVRuntimeInfo::parse(uint16_t ShaderKind) { } uint8_t DirectX::PSVRuntimeInfo::getSigInputCount() const { + if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo)) + return P->SigInputElements; if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) return P->SigInputElements; if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) @@ -432,6 +442,8 @@ uint8_t DirectX::PSVRuntimeInfo::getSigInputCount() const { } uint8_t DirectX::PSVRuntimeInfo::getSigOutputCount() const { + if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo)) + return P->SigOutputElements; if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) return P->SigOutputElements; if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) @@ -440,6 +452,8 @@ uint8_t DirectX::PSVRuntimeInfo::getSigOutputCount() const { } uint8_t DirectX::PSVRuntimeInfo::getSigPatchOrPrimCount() const { + if (const auto *P = std::get_if<dxbc::PSV::v3::RuntimeInfo>(&BasicInfo)) + return P->SigPatchOrPrimElements; if (const auto *P = std::get_if<dxbc::PSV::v2::RuntimeInfo>(&BasicInfo)) return P->SigPatchOrPrimElements; if (const auto *P = std::get_if<dxbc::PSV::v1::RuntimeInfo>(&BasicInfo)) diff --git a/contrib/llvm-project/llvm/lib/Object/ELF.cpp b/contrib/llvm-project/llvm/lib/Object/ELF.cpp index f24395b02043..e47a40b8715d 100644 --- a/contrib/llvm-project/llvm/lib/Object/ELF.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ELF.cpp @@ -251,7 +251,10 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { } break; case ELF::EM_HEXAGON: - switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_HEX_ORDERED); } + switch (Type) { + STRINGIFY_ENUM_CASE(ELF, SHT_HEX_ORDERED); + STRINGIFY_ENUM_CASE(ELF, SHT_HEXAGON_ATTRIBUTES); + } break; case ELF::EM_X86_64: switch (Type) { STRINGIFY_ENUM_CASE(ELF, SHT_X86_64_UNWIND); } @@ -300,6 +303,7 @@ StringRef llvm::object::getELFSectionTypeName(uint32_t Machine, unsigned Type) { STRINGIFY_ENUM_CASE(ELF, SHT_GROUP); STRINGIFY_ENUM_CASE(ELF, SHT_SYMTAB_SHNDX); STRINGIFY_ENUM_CASE(ELF, SHT_RELR); + STRINGIFY_ENUM_CASE(ELF, SHT_CREL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_REL); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELA); STRINGIFY_ENUM_CASE(ELF, SHT_ANDROID_RELR); @@ -390,6 +394,58 @@ ELFFile<ELFT>::decode_relrs(Elf_Relr_Range relrs) const { } template <class ELFT> +Expected<uint64_t> +ELFFile<ELFT>::getCrelHeader(ArrayRef<uint8_t> Content) const { + DataExtractor Data(Content, isLE(), sizeof(typename ELFT::Addr)); + Error Err = Error::success(); + uint64_t Hdr = 0; + Hdr = Data.getULEB128(&Hdr, &Err); + if (Err) + return Err; + return Hdr; +} + +template <class ELFT> +Expected<typename ELFFile<ELFT>::RelsOrRelas> +ELFFile<ELFT>::decodeCrel(ArrayRef<uint8_t> Content) const { + std::vector<Elf_Rel> Rels; + std::vector<Elf_Rela> Relas; + size_t I = 0; + bool HasAddend; + Error Err = object::decodeCrel<ELFT::Is64Bits>( + Content, + [&](uint64_t Count, bool HasA) { + HasAddend = HasA; + if (HasAddend) + Relas.resize(Count); + else + Rels.resize(Count); + }, + [&](Elf_Crel Crel) { + if (HasAddend) { + Relas[I].r_offset = Crel.r_offset; + Relas[I].setSymbolAndType(Crel.r_symidx, Crel.r_type, false); + Relas[I++].r_addend = Crel.r_addend; + } else { + Rels[I].r_offset = Crel.r_offset; + Rels[I++].setSymbolAndType(Crel.r_symidx, Crel.r_type, false); + } + }); + if (Err) + return std::move(Err); + return std::make_pair(std::move(Rels), std::move(Relas)); +} + +template <class ELFT> +Expected<typename ELFFile<ELFT>::RelsOrRelas> +ELFFile<ELFT>::crels(const Elf_Shdr &Sec) const { + Expected<ArrayRef<uint8_t>> ContentsOrErr = getSectionContents(Sec); + if (!ContentsOrErr) + return ContentsOrErr.takeError(); + return decodeCrel(*ContentsOrErr); +} + +template <class ELFT> Expected<std::vector<typename ELFT::Rela>> ELFFile<ELFT>::android_relas(const Elf_Shdr &Sec) const { // This function reads relocations in Android's packed relocation format, @@ -557,7 +613,11 @@ Expected<typename ELFT::DynRange> ELFFile<ELFT>::dynamicEntries() const { for (const Elf_Phdr &Phdr : *ProgramHeadersOrError) { if (Phdr.p_type == ELF::PT_DYNAMIC) { - Dyn = ArrayRef(reinterpret_cast<const Elf_Dyn *>(base() + Phdr.p_offset), + const uint8_t *DynOffset = base() + Phdr.p_offset; + if (DynOffset > end()) + return createError( + "dynamic section offset past file size: corrupted ELF"); + Dyn = ArrayRef(reinterpret_cast<const Elf_Dyn *>(DynOffset), Phdr.p_filesz / sizeof(Elf_Dyn)); break; } @@ -693,6 +753,17 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF, for (typename ELFFile<ELFT>::Elf_Rela Rela : *Relas) FunctionOffsetTranslations[Rela.r_offset] = Rela.r_addend; } + auto GetAddressForRelocation = + [&](unsigned RelocationOffsetInSection) -> Expected<unsigned> { + auto FOTIterator = + FunctionOffsetTranslations.find(RelocationOffsetInSection); + if (FOTIterator == FunctionOffsetTranslations.end()) { + return createError("failed to get relocation data for offset: " + + Twine::utohexstr(RelocationOffsetInSection) + + " in section " + describe(EF, Sec)); + } + return FOTIterator->second; + }; Expected<ArrayRef<uint8_t>> ContentsOrErr = EF.getSectionContents(Sec); if (!ContentsOrErr) return ContentsOrErr.takeError(); @@ -704,9 +775,26 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF, Error ULEBSizeErr = Error::success(); Error MetadataDecodeErr = Error::success(); + // Helper lampda to extract the (possiblly relocatable) address stored at Cur. + auto ExtractAddress = [&]() -> Expected<typename ELFFile<ELFT>::uintX_t> { + uint64_t RelocationOffsetInSection = Cur.tell(); + auto Address = + static_cast<typename ELFFile<ELFT>::uintX_t>(Data.getAddress(Cur)); + if (!Cur) + return Cur.takeError(); + if (!IsRelocatable) + return Address; + assert(Address == 0); + Expected<unsigned> AddressOrErr = + GetAddressForRelocation(RelocationOffsetInSection); + if (!AddressOrErr) + return AddressOrErr.takeError(); + return *AddressOrErr; + }; + uint8_t Version = 0; uint8_t Feature = 0; - PGOAnalysisMap::Features FeatEnable{}; + BBAddrMap::Features FeatEnable{}; while (!ULEBSizeErr && !MetadataDecodeErr && Cur && Cur.tell() < Content.size()) { if (Sec.sh_type == ELF::SHT_LLVM_BB_ADDR_MAP) { @@ -719,11 +807,10 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF, Feature = Data.getU8(Cur); // Feature byte if (!Cur) break; - auto FeatEnableOrErr = PGOAnalysisMap::Features::decode(Feature); + auto FeatEnableOrErr = BBAddrMap::Features::decode(Feature); if (!FeatEnableOrErr) return FeatEnableOrErr.takeError(); - FeatEnable = - FeatEnableOrErr ? *FeatEnableOrErr : PGOAnalysisMap::Features{}; + FeatEnable = *FeatEnableOrErr; if (Feature != 0 && Version < 2 && Cur) return createError( "version should be >= 2 for SHT_LLVM_BB_ADDR_MAP when " @@ -731,50 +818,65 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF, Twine(static_cast<int>(Version)) + " feature = " + Twine(static_cast<int>(Feature))); } - uint64_t SectionOffset = Cur.tell(); - auto Address = - static_cast<typename ELFFile<ELFT>::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(EF, Sec)); - } - Address = FOTIterator->second; - } - uint32_t NumBlocks = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); - + uint32_t NumBlocksInBBRange = 0; + uint32_t NumBBRanges = 1; + typename ELFFile<ELFT>::uintX_t RangeBaseAddress = 0; std::vector<BBAddrMap::BBEntry> BBEntries; - uint32_t PrevBBEndOffset = 0; - for (uint32_t BlockIndex = 0; - !MetadataDecodeErr && !ULEBSizeErr && Cur && (BlockIndex < NumBlocks); - ++BlockIndex) { - uint32_t ID = Version >= 2 - ? readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr) - : BlockIndex; - uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); - uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); - uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); - if (Version >= 1) { - // Offset is calculated relative to the end of the previous BB. - Offset += PrevBBEndOffset; - PrevBBEndOffset = Offset + Size; - } - Expected<BBAddrMap::BBEntry::Metadata> MetadataOrErr = - BBAddrMap::BBEntry::Metadata::decode(MD); - if (!MetadataOrErr) { - MetadataDecodeErr = MetadataOrErr.takeError(); + if (FeatEnable.MultiBBRange) { + NumBBRanges = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); + if (!Cur || ULEBSizeErr) break; + if (!NumBBRanges) + return createError("invalid zero number of BB ranges at offset " + + Twine::utohexstr(Cur.tell()) + " in " + + describe(EF, Sec)); + } else { + auto AddressOrErr = ExtractAddress(); + if (!AddressOrErr) + return AddressOrErr.takeError(); + RangeBaseAddress = *AddressOrErr; + NumBlocksInBBRange = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); + } + std::vector<BBAddrMap::BBRangeEntry> BBRangeEntries; + uint32_t TotalNumBlocks = 0; + for (uint32_t BBRangeIndex = 0; BBRangeIndex < NumBBRanges; + ++BBRangeIndex) { + uint32_t PrevBBEndOffset = 0; + if (FeatEnable.MultiBBRange) { + auto AddressOrErr = ExtractAddress(); + if (!AddressOrErr) + return AddressOrErr.takeError(); + RangeBaseAddress = *AddressOrErr; + NumBlocksInBBRange = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); + } + for (uint32_t BlockIndex = 0; !MetadataDecodeErr && !ULEBSizeErr && Cur && + (BlockIndex < NumBlocksInBBRange); + ++BlockIndex) { + uint32_t ID = Version >= 2 + ? readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr) + : BlockIndex; + uint32_t Offset = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); + uint32_t Size = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); + uint32_t MD = readULEB128As<uint32_t>(Data, Cur, ULEBSizeErr); + if (Version >= 1) { + // Offset is calculated relative to the end of the previous BB. + Offset += PrevBBEndOffset; + PrevBBEndOffset = Offset + Size; + } + Expected<BBAddrMap::BBEntry::Metadata> MetadataOrErr = + BBAddrMap::BBEntry::Metadata::decode(MD); + if (!MetadataOrErr) { + MetadataDecodeErr = MetadataOrErr.takeError(); + break; + } + BBEntries.push_back({ID, Offset, Size, *MetadataOrErr}); } - BBEntries.push_back({ID, Offset, Size, *MetadataOrErr}); + TotalNumBlocks += BBEntries.size(); + BBRangeEntries.push_back({RangeBaseAddress, std::move(BBEntries)}); } - FunctionEntries.emplace_back(Address, std::move(BBEntries)); + FunctionEntries.push_back({std::move(BBRangeEntries)}); - if (PGOAnalyses || FeatEnable.anyEnabled()) { + if (PGOAnalyses || FeatEnable.hasPGOAnalysis()) { // Function entry count uint64_t FuncEntryCount = FeatEnable.FuncEntryCount @@ -783,8 +885,8 @@ decodeBBAddrMapImpl(const ELFFile<ELFT> &EF, std::vector<PGOAnalysisMap::PGOBBEntry> PGOBBEntries; for (uint32_t BlockIndex = 0; - (FeatEnable.BBFreq || FeatEnable.BrProb) && !MetadataDecodeErr && - !ULEBSizeErr && Cur && (BlockIndex < NumBlocks); + FeatEnable.hasPGOAnalysisBBData() && !MetadataDecodeErr && + !ULEBSizeErr && Cur && (BlockIndex < TotalNumBlocks); ++BlockIndex) { // Block frequency uint64_t BBF = FeatEnable.BBFreq diff --git a/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp index 28b96c341e3f..53c3de06d118 100644 --- a/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ELFObjectFile.cpp @@ -20,10 +20,11 @@ #include "llvm/Support/ARMAttributeParser.h" #include "llvm/Support/ARMBuildAttributes.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/HexagonAttributeParser.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/RISCVAttributeParser.h" #include "llvm/Support/RISCVAttributes.h" -#include "llvm/Support/RISCVISAInfo.h" +#include "llvm/TargetParser/RISCVISAInfo.h" #include "llvm/TargetParser/SubtargetFeature.h" #include "llvm/TargetParser/Triple.h" #include <algorithm> @@ -287,12 +288,87 @@ SubtargetFeatures ELFObjectFileBase::getARMFeatures() const { return Features; } +static std::optional<std::string> hexagonAttrToFeatureString(unsigned Attr) { + switch (Attr) { + case 5: + return "v5"; + case 55: + return "v55"; + case 60: + return "v60"; + case 62: + return "v62"; + case 65: + return "v65"; + case 67: + return "v67"; + case 68: + return "v68"; + case 69: + return "v69"; + case 71: + return "v71"; + case 73: + return "v73"; + default: + return {}; + } +} + +SubtargetFeatures ELFObjectFileBase::getHexagonFeatures() const { + SubtargetFeatures Features; + HexagonAttributeParser Parser; + if (Error E = getBuildAttributes(Parser)) { + // Return no attributes if none can be read. + // This behavior is important for backwards compatibility. + consumeError(std::move(E)); + return Features; + } + std::optional<unsigned> Attr; + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::ARCH))) { + if (std::optional<std::string> FeatureString = + hexagonAttrToFeatureString(*Attr)) + Features.AddFeature(*FeatureString); + } + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXARCH))) { + std::optional<std::string> FeatureString = + hexagonAttrToFeatureString(*Attr); + // There is no corresponding hvx arch for v5 and v55. + if (FeatureString && *Attr >= 60) + Features.AddFeature("hvx" + *FeatureString); + } + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXIEEEFP))) + if (*Attr) + Features.AddFeature("hvx-ieee-fp"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::HVXQFLOAT))) + if (*Attr) + Features.AddFeature("hvx-qfloat"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::ZREG))) + if (*Attr) + Features.AddFeature("zreg"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::AUDIO))) + if (*Attr) + Features.AddFeature("audio"); + + if ((Attr = Parser.getAttributeValue(HexagonAttrs::CABAC))) + if (*Attr) + Features.AddFeature("cabac"); + + return Features; +} + Expected<SubtargetFeatures> ELFObjectFileBase::getRISCVFeatures() const { SubtargetFeatures Features; unsigned PlatformFlags = getPlatformFlags(); if (PlatformFlags & ELF::EF_RISCV_RVC) { - Features.AddFeature("c"); + Features.AddFeature("zca"); } RISCVAttributeParser Attributes; @@ -349,6 +425,8 @@ Expected<SubtargetFeatures> ELFObjectFileBase::getFeatures() const { return getRISCVFeatures(); case ELF::EM_LOONGARCH: return getLoongArchFeatures(); + case ELF::EM_HEXAGON: + return getHexagonFeatures(); default: return SubtargetFeatures(); } @@ -508,12 +586,26 @@ StringRef ELFObjectFileBase::getAMDGPUCPUName() const { return "gfx1150"; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1151: return "gfx1151"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1152: + return "gfx1152"; // AMDGCN GFX12. case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1200: return "gfx1200"; case ELF::EF_AMDGPU_MACH_AMDGCN_GFX1201: return "gfx1201"; + + // Generic AMDGCN targets + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX9_GENERIC: + return "gfx9-generic"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX10_1_GENERIC: + return "gfx10-1-generic"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX10_3_GENERIC: + return "gfx10-3-generic"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX11_GENERIC: + return "gfx11-generic"; + case ELF::EF_AMDGPU_MACH_AMDGCN_GFX12_GENERIC: + return "gfx12-generic"; default: llvm_unreachable("Unknown EF_AMDGPU_MACH value"); } @@ -805,7 +897,10 @@ Expected<std::vector<BBAddrMap>> static readBBAddrMapImpl( return createError("unable to get the linked-to section for " + describe(EF, Sec) + ": " + toString(TextSecOrErr.takeError())); - if (*TextSectionIndex != std::distance(Sections.begin(), *TextSecOrErr)) + assert(*TextSecOrErr >= Sections.begin() && + "Text section pointer outside of bounds"); + if (*TextSectionIndex != + (unsigned)std::distance(Sections.begin(), *TextSecOrErr)) return false; return true; }; @@ -918,3 +1013,14 @@ Expected<std::vector<BBAddrMap>> ELFObjectFileBase::readBBAddrMap( return readBBAddrMapImpl(cast<ELF64BEObjectFile>(this)->getELFFile(), TextSectionIndex, PGOAnalyses); } + +StringRef ELFObjectFileBase::getCrelDecodeProblem(SectionRef Sec) const { + auto Data = Sec.getRawDataRefImpl(); + if (const auto *Obj = dyn_cast<ELF32LEObjectFile>(this)) + return Obj->getCrelDecodeProblem(Data); + if (const auto *Obj = dyn_cast<ELF32BEObjectFile>(this)) + return Obj->getCrelDecodeProblem(Data); + if (const auto *Obj = dyn_cast<ELF64LEObjectFile>(this)) + return Obj->getCrelDecodeProblem(Data); + return cast<ELF64BEObjectFile>(this)->getCrelDecodeProblem(Data); +} diff --git a/contrib/llvm-project/llvm/lib/Object/GOFFObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/GOFFObjectFile.cpp index 76a13559ebfe..3b8704f28fdb 100644 --- a/contrib/llvm-project/llvm/lib/Object/GOFFObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/GOFFObjectFile.cpp @@ -104,16 +104,13 @@ GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err) PrevContinuationBits = I[1] & 0x03; continue; } - -#ifndef NDEBUG - for (size_t J = 0; J < GOFF::RecordLength; ++J) { + LLVM_DEBUG(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. @@ -168,6 +165,11 @@ GOFFObjectFile::GOFFObjectFile(MemoryBufferRef Object, Error &Err) LLVM_DEBUG(dbgs() << " -- ESD " << EsdId << "\n"); break; } + case GOFF::RT_TXT: + // Save TXT records. + TextPtrs.emplace_back(I); + LLVM_DEBUG(dbgs() << " -- TXT\n"); + break; case GOFF::RT_END: LLVM_DEBUG(dbgs() << " -- END (GOFF record type) unhandled\n"); break; @@ -364,6 +366,13 @@ GOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { std::to_string(SymEdId)); } +uint64_t GOFFObjectFile::getSymbolSize(DataRefImpl Symb) const { + const uint8_t *Record = getSymbolEsdRecord(Symb); + uint32_t Length; + ESDRecord::getLength(Record, Length); + return Length; +} + const uint8_t *GOFFObjectFile::getSectionEdEsdRecord(DataRefImpl &Sec) const { SectionEntryImpl EsdIds = SectionList[Sec.d.a]; const uint8_t *EsdRecord = EsdPtrs[EsdIds.d.a]; @@ -394,6 +403,154 @@ GOFFObjectFile::getSectionPrEsdRecord(uint32_t SectionIndex) const { return EsdRecord; } +uint32_t GOFFObjectFile::getSectionDefEsdId(DataRefImpl &Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + uint32_t Length; + ESDRecord::getLength(EsdRecord, Length); + if (Length == 0) { + const uint8_t *PrEsdRecord = getSectionPrEsdRecord(Sec); + if (PrEsdRecord) + EsdRecord = PrEsdRecord; + } + + uint32_t DefEsdId; + ESDRecord::getEsdId(EsdRecord, DefEsdId); + LLVM_DEBUG(dbgs() << "Got def EsdId: " << DefEsdId << '\n'); + return DefEsdId; +} + +void GOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { + Sec.d.a++; + if ((Sec.d.a) >= SectionList.size()) + Sec.d.a = 0; +} + +Expected<StringRef> GOFFObjectFile::getSectionName(DataRefImpl Sec) const { + DataRefImpl EdSym; + SectionEntryImpl EsdIds = SectionList[Sec.d.a]; + EdSym.d.a = EsdIds.d.a; + Expected<StringRef> Name = getSymbolName(EdSym); + if (Name) { + StringRef Res = *Name; + LLVM_DEBUG(dbgs() << "Got section: " << Res << '\n'); + LLVM_DEBUG(dbgs() << "Final section name: " << Res << '\n'); + Name = Res; + } + return Name; +} + +uint64_t GOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { + uint32_t Offset; + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + ESDRecord::getOffset(EsdRecord, Offset); + return Offset; +} + +uint64_t GOFFObjectFile::getSectionSize(DataRefImpl Sec) const { + uint32_t Length; + uint32_t DefEsdId = getSectionDefEsdId(Sec); + const uint8_t *EsdRecord = EsdPtrs[DefEsdId]; + ESDRecord::getLength(EsdRecord, Length); + LLVM_DEBUG(dbgs() << "Got section size: " << Length << '\n'); + return static_cast<uint64_t>(Length); +} + +// Unravel TXT records and expand fill characters to produce +// a contiguous sequence of bytes. +Expected<ArrayRef<uint8_t>> +GOFFObjectFile::getSectionContents(DataRefImpl Sec) const { + if (SectionDataCache.count(Sec.d.a)) { + auto &Buf = SectionDataCache[Sec.d.a]; + return ArrayRef<uint8_t>(Buf); + } + uint64_t SectionSize = getSectionSize(Sec); + uint32_t DefEsdId = getSectionDefEsdId(Sec); + + const uint8_t *EdEsdRecord = getSectionEdEsdRecord(Sec); + bool FillBytePresent; + ESDRecord::getFillBytePresent(EdEsdRecord, FillBytePresent); + uint8_t FillByte = '\0'; + if (FillBytePresent) + ESDRecord::getFillByteValue(EdEsdRecord, FillByte); + + // Initialize section with fill byte. + SmallVector<uint8_t> Data(SectionSize, FillByte); + + // Replace section with content from text records. + for (const uint8_t *TxtRecordInt : TextPtrs) { + const uint8_t *TxtRecordPtr = TxtRecordInt; + uint32_t TxtEsdId; + TXTRecord::getElementEsdId(TxtRecordPtr, TxtEsdId); + LLVM_DEBUG(dbgs() << "Got txt EsdId: " << TxtEsdId << '\n'); + + if (TxtEsdId != DefEsdId) + continue; + + uint32_t TxtDataOffset; + TXTRecord::getOffset(TxtRecordPtr, TxtDataOffset); + + uint16_t TxtDataSize; + TXTRecord::getDataLength(TxtRecordPtr, TxtDataSize); + + LLVM_DEBUG(dbgs() << "Record offset " << TxtDataOffset << ", data size " + << TxtDataSize << "\n"); + + SmallString<256> CompleteData; + CompleteData.reserve(TxtDataSize); + if (Error Err = TXTRecord::getData(TxtRecordPtr, CompleteData)) + return std::move(Err); + assert(CompleteData.size() == TxtDataSize && "Wrong length of data"); + std::copy(CompleteData.data(), CompleteData.data() + TxtDataSize, + Data.begin() + TxtDataOffset); + } + SectionDataCache[Sec.d.a] = Data; + return ArrayRef<uint8_t>(SectionDataCache[Sec.d.a]); +} + +uint64_t GOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDAlignment Pow2Alignment; + ESDRecord::getAlignment(EsdRecord, Pow2Alignment); + return 1ULL << static_cast<uint64_t>(Pow2Alignment); +} + +bool GOFFObjectFile::isSectionText(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDExecutable Executable; + ESDRecord::getExecutable(EsdRecord, Executable); + return Executable == GOFF::ESD_EXE_CODE; +} + +bool GOFFObjectFile::isSectionData(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDExecutable Executable; + ESDRecord::getExecutable(EsdRecord, Executable); + return Executable == GOFF::ESD_EXE_DATA; +} + +bool GOFFObjectFile::isSectionNoLoad(DataRefImpl Sec) const { + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDLoadingBehavior LoadingBehavior; + ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior); + return LoadingBehavior == GOFF::ESD_LB_NoLoad; +} + +bool GOFFObjectFile::isSectionReadOnlyData(DataRefImpl Sec) const { + if (!isSectionData(Sec)) + return false; + + const uint8_t *EsdRecord = getSectionEdEsdRecord(Sec); + GOFF::ESDLoadingBehavior LoadingBehavior; + ESDRecord::getLoadingBehavior(EsdRecord, LoadingBehavior); + return LoadingBehavior == GOFF::ESD_LB_Initial; +} + +bool GOFFObjectFile::isSectionZeroInit(DataRefImpl Sec) const { + // GOFF uses fill characters and fill characters are applied + // on getSectionContents() - so we say false to zero init. + return false; +} + section_iterator GOFFObjectFile::section_begin() const { DataRefImpl Sec; moveSectionNext(Sec); @@ -476,6 +633,13 @@ Error ESDRecord::getData(const uint8_t *Record, return getContinuousData(Record, DataSize, 72, CompleteData); } +Error TXTRecord::getData(const uint8_t *Record, + SmallString<256> &CompleteData) { + uint16_t Length; + getDataLength(Record, Length); + return getContinuousData(Record, Length, 24, CompleteData); +} + Error ENDRecord::getData(const uint8_t *Record, SmallString<256> &CompleteData) { uint16_t Length = getNameLength(Record); diff --git a/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp b/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp index 18fc2e4d4a37..2a2b235461a5 100644 --- a/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp +++ b/contrib/llvm-project/llvm/lib/Object/IRSymtab.cpp @@ -22,6 +22,7 @@ #include "llvm/IR/Mangler.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" +#include "llvm/IR/RuntimeLibcalls.h" #include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/ModuleSymbolTable.h" #include "llvm/Object/SymbolicFile.h" @@ -46,9 +47,6 @@ static cl::opt<bool> DisableBitcodeVersionUpgrade( cl::desc("Disable automatic bitcode upgrade for version mismatch")); static const char *PreservedSymbols[] = { -#define HANDLE_LIBCALL(code, name) name, -#include "llvm/IR/RuntimeLibcalls.def" -#undef HANDLE_LIBCALL // There are global variables, so put it here instead of in // RuntimeLibcalls.def. // TODO: Are there similar such variables? @@ -215,9 +213,16 @@ Expected<int> Builder::getComdatIndex(const Comdat *C, const Module *M) { return P.first->second; } -static DenseSet<StringRef> buildPreservedSymbolsSet() { - return DenseSet<StringRef>(std::begin(PreservedSymbols), - std::end(PreservedSymbols)); +static DenseSet<StringRef> buildPreservedSymbolsSet(const Triple &TT) { + DenseSet<StringRef> PreservedSymbolSet(std::begin(PreservedSymbols), + std::end(PreservedSymbols)); + + RTLIB::RuntimeLibcallsInfo Libcalls(TT); + for (const char *Name : Libcalls.getLibcallNames()) { + if (Name) + PreservedSymbolSet.insert(Name); + } + return PreservedSymbolSet; } Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, @@ -276,7 +281,8 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, setStr(Sym.IRName, GV->getName()); static const DenseSet<StringRef> PreservedSymbolsSet = - buildPreservedSymbolsSet(); + buildPreservedSymbolsSet( + llvm::Triple(GV->getParent()->getTargetTriple())); bool IsPreservedSymbol = PreservedSymbolsSet.contains(GV->getName()); if (Used.count(GV) || IsPreservedSymbol) @@ -295,7 +301,7 @@ Error Builder::addSymbol(const ModuleSymbolTable &Msymtab, return make_error<StringError>("Only variables can have common linkage!", inconvertibleErrorCode()); Uncommon().CommonSize = - GV->getParent()->getDataLayout().getTypeAllocSize(GV->getValueType()); + GV->getDataLayout().getTypeAllocSize(GV->getValueType()); Uncommon().CommonAlign = GVar->getAlign() ? GVar->getAlign()->value() : 0; } diff --git a/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp index 1cfd0a069463..812b2c00ba69 100644 --- a/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/MachOObjectFile.cpp @@ -399,7 +399,7 @@ static Error parseSegmentLoadCommand( return malformedError("load command " + Twine(LoadCommandIndex) + " filesize field in " + CmdName + " greater than vmsize field"); - IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname); + IsPageZeroSegment |= StringRef("__PAGEZERO") == S.segname; } else return SegOrErr.takeError(); @@ -3104,7 +3104,7 @@ void ExportEntry::pushNode(uint64_t offset) { } } } - if(ExportStart + ExportInfoSize != State.Current) { + if (ExportStart + ExportInfoSize < State.Current) { *E = malformedError( "inconsistent export info size: 0x" + Twine::utohexstr(ExportInfoSize) + " where actual size was: 0x" + @@ -3256,13 +3256,13 @@ MachOAbstractFixupEntry::MachOAbstractFixupEntry(Error *E, for (const auto &Command : O->load_commands()) { if (Command.C.cmd == MachO::LC_SEGMENT) { MachO::segment_command SLC = O->getSegmentLoadCommand(Command); - if (StringRef(SLC.segname) == StringRef("__TEXT")) { + if (StringRef(SLC.segname) == "__TEXT") { TextAddress = SLC.vmaddr; break; } } else if (Command.C.cmd == MachO::LC_SEGMENT_64) { MachO::segment_command_64 SLC_64 = O->getSegment64LoadCommand(Command); - if (StringRef(SLC_64.segname) == StringRef("__TEXT")) { + if (StringRef(SLC_64.segname) == "__TEXT") { TextAddress = SLC_64.vmaddr; break; } @@ -3501,21 +3501,23 @@ void MachORebaseEntry::moveNext() { --RemainingLoopCount; return; } - // REBASE_OPCODE_DONE is only used for padding if we are not aligned to - // pointer size. Therefore it is possible to reach the end without ever having - // seen REBASE_OPCODE_DONE. - if (Ptr == Opcodes.end()) { - Done = true; - return; - } + bool More = true; while (More) { + // REBASE_OPCODE_DONE is only used for padding if we are not aligned to + // pointer size. Therefore it is possible to reach the end without ever + // having seen REBASE_OPCODE_DONE. + if (Ptr == Opcodes.end()) { + Done = true; + return; + } + // Parse next opcode and set up next loop. const uint8_t *OpcodeStart = Ptr; uint8_t Byte = *Ptr++; uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK; uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK; - uint32_t Count, Skip; + uint64_t Count, Skip; const char *error = nullptr; switch (Opcode) { case MachO::REBASE_OPCODE_DONE: @@ -3838,15 +3840,17 @@ void MachOBindEntry::moveNext() { --RemainingLoopCount; return; } - // BIND_OPCODE_DONE is only used for padding if we are not aligned to - // pointer size. Therefore it is possible to reach the end without ever having - // seen BIND_OPCODE_DONE. - if (Ptr == Opcodes.end()) { - Done = true; - return; - } + bool More = true; while (More) { + // BIND_OPCODE_DONE is only used for padding if we are not aligned to + // pointer size. Therefore it is possible to reach the end without ever + // having seen BIND_OPCODE_DONE. + if (Ptr == Opcodes.end()) { + Done = true; + return; + } + // Parse next opcode and set up next loop. const uint8_t *OpcodeStart = Ptr; uint8_t Byte = *Ptr++; @@ -3854,7 +3858,7 @@ void MachOBindEntry::moveNext() { uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK; int8_t SignExtended; const uint8_t *SymStart; - uint32_t Count, Skip; + uint64_t Count, Skip; const char *error = nullptr; switch (Opcode) { case MachO::BIND_OPCODE_DONE: @@ -4364,7 +4368,7 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { Info.Size = Section.getSize(); Info.SegmentName = Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl()); - if (!Info.SegmentName.equals(CurSegName)) { + if (Info.SegmentName != CurSegName) { ++CurSegIndex; CurSegName = Info.SegmentName; CurSegAddress = Info.Address; @@ -4384,18 +4388,18 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { // that fully contains a pointer at that location. Multiple fixups in a bind // (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can // be tested via the Count and Skip parameters. -const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex, - uint64_t SegOffset, - uint8_t PointerSize, - uint32_t Count, - uint32_t Skip) { +const char *BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex, + uint64_t SegOffset, + uint8_t PointerSize, + uint64_t Count, + uint64_t Skip) { if (SegIndex == -1) return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"; if (SegIndex >= MaxSegIndex) return "bad segIndex (too large)"; - for (uint32_t i = 0; i < Count; ++i) { - uint32_t Start = SegOffset + i * (PointerSize + Skip); - uint32_t End = Start + PointerSize; + for (uint64_t i = 0; i < Count; ++i) { + uint64_t Start = SegOffset + i * (PointerSize + Skip); + uint64_t End = Start + PointerSize; bool Found = false; for (const SectionInfo &SI : Sections) { if (SI.SegmentIndex != SegIndex) diff --git a/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp b/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp index 07f76688fa43..d8f520ad02c2 100644 --- a/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp +++ b/contrib/llvm-project/llvm/lib/Object/ModuleSymbolTable.cpp @@ -175,6 +175,20 @@ void ModuleSymbolTable::CollectAsmSymbols( AsmSymbol(Key, BasicSymbolRef::Flags(Res)); } }); + + // In ELF, object code generated for x86-32 and some code models of x86-64 may + // reference the special symbol _GLOBAL_OFFSET_TABLE_ that is not used in the + // IR. Record it like inline asm symbols. + Triple TT(M.getTargetTriple()); + if (!TT.isOSBinFormatELF() || !TT.isX86()) + return; + auto CM = M.getCodeModel(); + if (TT.getArch() == Triple::x86 || CM == CodeModel::Medium || + CM == CodeModel::Large) { + AsmSymbol("_GLOBAL_OFFSET_TABLE_", + BasicSymbolRef::Flags(BasicSymbolRef::SF_Undefined | + BasicSymbolRef::SF_Global)); + } } void ModuleSymbolTable::CollectAsmSymvers( diff --git a/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp b/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp index bfc35e41fe65..89dc12551494 100644 --- a/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp +++ b/contrib/llvm-project/llvm/lib/Object/OffloadBinary.cpp @@ -83,7 +83,7 @@ Error extractFromObject(const ObjectFile &Obj, if (!NameOrErr) return NameOrErr.takeError(); - if (!NameOrErr->equals(".llvm.offloading")) + if (!NameOrErr->starts_with(".llvm.offloading")) continue; } @@ -189,7 +189,10 @@ OffloadBinary::create(MemoryBufferRef Buf) { return errorCodeToError(object_error::parse_failed); if (TheHeader->Size > Buf.getBufferSize() || - TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) || + TheHeader->Size < sizeof(Entry) || TheHeader->Size < sizeof(Header)) + return errorCodeToError(object_error::unexpected_eof); + + if (TheHeader->EntryOffset > TheHeader->Size - sizeof(Entry) || TheHeader->EntrySize > TheHeader->Size - sizeof(Header)) return errorCodeToError(object_error::unexpected_eof); @@ -355,6 +358,10 @@ bool object::areTargetsCompatible(const OffloadFile::TargetID &LHS, if (LHS.first != RHS.first) return false; + // If the architecture is "all" we assume it is always compatible. + if (LHS.second == "generic" || RHS.second == "generic") + return true; + // Only The AMDGPU target requires additional checks. llvm::Triple T(LHS.first); if (!T.isAMDGPU()) diff --git a/contrib/llvm-project/llvm/lib/Object/SymbolSize.cpp b/contrib/llvm-project/llvm/lib/Object/SymbolSize.cpp index cb20feffb710..635cd8373afb 100644 --- a/contrib/llvm-project/llvm/lib/Object/SymbolSize.cpp +++ b/contrib/llvm-project/llvm/lib/Object/SymbolSize.cpp @@ -65,6 +65,13 @@ llvm::object::computeSymbolSizes(const ObjectFile &O) { return Ret; } + if (const auto *E = dyn_cast<WasmObjectFile>(&O)) { + for (SymbolRef Sym : E->symbols()) { + Ret.push_back({Sym, E->getSymbolSize(Sym)}); + } + return Ret; + } + // Collect sorted symbol addresses. Include dummy addresses for the end // of each section. std::vector<SymEntry> Addresses; diff --git a/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp b/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp index fcf61541941e..4eaacc48e7ce 100644 --- a/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/TapiFile.cpp @@ -56,11 +56,11 @@ TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &Interface, continue; switch (Symbol->getKind()) { - case SymbolKind::GlobalSymbol: + case EncodeKind::GlobalSymbol: Symbols.emplace_back(StringRef(), Symbol->getName(), getFlags(Symbol), ::getType(Symbol)); break; - case SymbolKind::ObjectiveCClass: + case EncodeKind::ObjectiveCClass: if (Interface.getPlatforms().count(PLATFORM_MACOS) && Arch == AK_i386) { Symbols.emplace_back(ObjC1ClassNamePrefix, Symbol->getName(), getFlags(Symbol), ::getType(Symbol)); @@ -71,11 +71,11 @@ TapiFile::TapiFile(MemoryBufferRef Source, const InterfaceFile &Interface, getFlags(Symbol), ::getType(Symbol)); } break; - case SymbolKind::ObjectiveCClassEHType: + case EncodeKind::ObjectiveCClassEHType: Symbols.emplace_back(ObjC2EHTypePrefix, Symbol->getName(), getFlags(Symbol), ::getType(Symbol)); break; - case SymbolKind::ObjectiveCInstanceVariable: + case EncodeKind::ObjectiveCInstanceVariable: Symbols.emplace_back(ObjC2IVarPrefix, Symbol->getName(), getFlags(Symbol), ::getType(Symbol)); break; diff --git a/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp b/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp index bf96b57f0321..4db5841a8f34 100644 --- a/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp +++ b/contrib/llvm-project/llvm/lib/Object/TapiUniversal.cpp @@ -47,9 +47,9 @@ TapiUniversal::~TapiUniversal() = default; Expected<std::unique_ptr<TapiFile>> TapiUniversal::ObjectForArch::getAsObjectFile() const { - return std::unique_ptr<TapiFile>(new TapiFile(Parent->getMemoryBufferRef(), - *Parent->ParsedFile, - Parent->Libraries[Index].Arch)); + return std::make_unique<TapiFile>(Parent->getMemoryBufferRef(), + *Parent->ParsedFile, + Parent->Libraries[Index].Arch); } Expected<std::unique_ptr<TapiUniversal>> diff --git a/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp index b9a8e970216b..f244099d664d 100644 --- a/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/WasmObjectFile.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/Endian.h" #include "llvm/Support/Error.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/Format.h" #include "llvm/Support/LEB128.h" #include "llvm/Support/ScopedPrinter.h" #include "llvm/TargetParser/SubtargetFeature.h" @@ -29,6 +30,7 @@ #include <cassert> #include <cstdint> #include <cstring> +#include <limits> #define DEBUG_TYPE "wasm-object" @@ -173,6 +175,27 @@ static uint8_t readOpcode(WasmObjectFile::ReadContext &Ctx) { return readUint8(Ctx); } +static wasm::ValType parseValType(WasmObjectFile::ReadContext &Ctx, + uint32_t Code) { + // only directly encoded FUNCREF/EXTERNREF/EXNREF are supported + // (not ref null func, ref null extern, or ref null exn) + switch (Code) { + case wasm::WASM_TYPE_I32: + case wasm::WASM_TYPE_I64: + case wasm::WASM_TYPE_F32: + case wasm::WASM_TYPE_F64: + case wasm::WASM_TYPE_V128: + case wasm::WASM_TYPE_FUNCREF: + case wasm::WASM_TYPE_EXTERNREF: + case wasm::WASM_TYPE_EXNREF: + return wasm::ValType(Code); + } + if (Code == wasm::WASM_TYPE_NULLABLE || Code == wasm::WASM_TYPE_NONNULLABLE) { + /* Discard HeapType */ readVarint64(Ctx); + } + return wasm::ValType(wasm::ValType::OTHERREF); +} + static Error readInitExpr(wasm::WasmInitExpr &Expr, WasmObjectFile::ReadContext &Ctx) { auto Start = Ctx.Ptr; @@ -196,11 +219,7 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, Expr.Inst.Value.Global = readULEB128(Ctx); break; case wasm::WASM_OPCODE_REF_NULL: { - wasm::ValType Ty = static_cast<wasm::ValType>(readULEB128(Ctx)); - if (Ty != wasm::ValType::EXTERNREF) { - return make_error<GenericBinaryError>("invalid type for ref.null", - object_error::parse_failed); - } + /* Discard type */ parseValType(Ctx, readVaruint32(Ctx)); break; } default: @@ -221,10 +240,15 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, case wasm::WASM_OPCODE_I32_CONST: case wasm::WASM_OPCODE_GLOBAL_GET: case wasm::WASM_OPCODE_REF_NULL: + case wasm::WASM_OPCODE_REF_FUNC: case wasm::WASM_OPCODE_I64_CONST: + readULEB128(Ctx); + break; case wasm::WASM_OPCODE_F32_CONST: + readFloat32(Ctx); + break; case wasm::WASM_OPCODE_F64_CONST: - readULEB128(Ctx); + readFloat64(Ctx); break; case wasm::WASM_OPCODE_I32_ADD: case wasm::WASM_OPCODE_I32_SUB: @@ -233,6 +257,23 @@ static Error readInitExpr(wasm::WasmInitExpr &Expr, case wasm::WASM_OPCODE_I64_SUB: case wasm::WASM_OPCODE_I64_MUL: break; + case wasm::WASM_OPCODE_GC_PREFIX: + break; + // The GC opcodes are in a separate (prefixed space). This flat switch + // structure works as long as there is no overlap between the GC and + // general opcodes used in init exprs. + case wasm::WASM_OPCODE_STRUCT_NEW: + case wasm::WASM_OPCODE_STRUCT_NEW_DEFAULT: + case wasm::WASM_OPCODE_ARRAY_NEW: + case wasm::WASM_OPCODE_ARRAY_NEW_DEFAULT: + readULEB128(Ctx); // heap type index + break; + case wasm::WASM_OPCODE_ARRAY_NEW_FIXED: + readULEB128(Ctx); // heap type index + readULEB128(Ctx); // array size + break; + case wasm::WASM_OPCODE_REF_I31: + break; case wasm::WASM_OPCODE_END: Expr.Body = ArrayRef<uint8_t>(Start, Ctx.Ptr - Start); return Error::success(); @@ -258,7 +299,8 @@ static wasm::WasmLimits readLimits(WasmObjectFile::ReadContext &Ctx) { static wasm::WasmTableType readTableType(WasmObjectFile::ReadContext &Ctx) { wasm::WasmTableType TableType; - TableType.ElemType = wasm::ValType(readVaruint32(Ctx)); + auto ElemType = parseValType(Ctx, readVaruint32(Ctx)); + TableType.ElemType = ElemType; TableType.Limits = readLimits(Ctx); return TableType; } @@ -467,10 +509,20 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { llvm::DenseSet<uint64_t> SeenGlobals; llvm::DenseSet<uint64_t> SeenSegments; + // If we have linking section (symbol table) or if we are parsing a DSO + // then we don't use the name section for symbol information. + bool PopulateSymbolTable = !HasLinkingSection && !HasDylinkSection; + + // If we are using the name section for symbol information then it will + // supersede any symbols created by the export section. + if (PopulateSymbolTable) + Symbols.clear(); + while (Ctx.Ptr < Ctx.End) { uint8_t Type = readUint8(Ctx); uint32_t Size = readVaruint32(Ctx); const uint8_t *SubSectionEnd = Ctx.Ptr + Size; + switch (Type) { case wasm::WASM_NAMES_FUNCTION: case wasm::WASM_NAMES_GLOBAL: @@ -480,6 +532,16 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { uint32_t Index = readVaruint32(Ctx); StringRef Name = readString(Ctx); wasm::NameType nameType = wasm::NameType::FUNCTION; + wasm::WasmSymbolInfo Info{Name, + /*Kind */ wasm::WASM_SYMBOL_TYPE_FUNCTION, + /* Flags */ 0, + /* ImportModule */ std::nullopt, + /* ImportName */ std::nullopt, + /* ExportName */ std::nullopt, + {/* ElementIndex */ Index}}; + const wasm::WasmSignature *Signature = nullptr; + const wasm::WasmGlobalType *GlobalType = nullptr; + const wasm::WasmTableType *TableType = nullptr; if (Type == wasm::WASM_NAMES_FUNCTION) { if (!SeenFunctions.insert(Index).second) return make_error<GenericBinaryError>( @@ -488,26 +550,50 @@ Error WasmObjectFile::parseNameSection(ReadContext &Ctx) { return make_error<GenericBinaryError>("invalid function name entry", object_error::parse_failed); - if (isDefinedFunctionIndex(Index)) - getDefinedFunction(Index).DebugName = Name; + if (isDefinedFunctionIndex(Index)) { + wasm::WasmFunction &F = getDefinedFunction(Index); + F.DebugName = Name; + Signature = &Signatures[F.SigIndex]; + if (F.ExportName) { + Info.ExportName = F.ExportName; + Info.Flags |= wasm::WASM_SYMBOL_BINDING_GLOBAL; + } else { + Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; + } + } else { + Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED; + } } else if (Type == wasm::WASM_NAMES_GLOBAL) { - nameType = wasm::NameType::GLOBAL; if (!SeenGlobals.insert(Index).second) return make_error<GenericBinaryError>("global named more than once", object_error::parse_failed); if (!isValidGlobalIndex(Index) || Name.empty()) return make_error<GenericBinaryError>("invalid global name entry", object_error::parse_failed); + nameType = wasm::NameType::GLOBAL; + Info.Kind = wasm::WASM_SYMBOL_TYPE_GLOBAL; + if (isDefinedGlobalIndex(Index)) { + GlobalType = &getDefinedGlobal(Index).Type; + } else { + Info.Flags |= wasm::WASM_SYMBOL_UNDEFINED; + } } else { - nameType = wasm::NameType::DATA_SEGMENT; if (!SeenSegments.insert(Index).second) return make_error<GenericBinaryError>( "segment named more than once", object_error::parse_failed); if (Index > DataSegments.size()) return make_error<GenericBinaryError>("invalid data segment name entry", object_error::parse_failed); + nameType = wasm::NameType::DATA_SEGMENT; + Info.Kind = wasm::WASM_SYMBOL_TYPE_DATA; + Info.Flags |= wasm::WASM_SYMBOL_BINDING_LOCAL; + assert(Index < DataSegments.size()); + Info.DataRef = wasm::WasmDataReference{ + Index, 0, DataSegments[Index].Data.Content.size()}; } DebugNames.push_back(wasm::WasmDebugName{nameType, Index, Name}); + if (PopulateSymbolTable) + Symbols.emplace_back(Info, GlobalType, TableType, Signature); } break; } @@ -601,9 +687,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { uint32_t Count = readVaruint32(Ctx); // Clear out any symbol information that was derived from the exports // section. - LinkingData.SymbolTable.clear(); Symbols.clear(); - LinkingData.SymbolTable.reserve(Count); Symbols.reserve(Count); StringSet<> SymbolNames; @@ -803,9 +887,7 @@ Error WasmObjectFile::parseLinkingSectionSymtab(ReadContext &Ctx) { return make_error<GenericBinaryError>("duplicate symbol name " + Twine(Info.Name), object_error::parse_failed); - LinkingData.SymbolTable.emplace_back(Info); - Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, TableType, - Signature); + Symbols.emplace_back(Info, GlobalType, TableType, Signature); LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n"); } @@ -956,6 +1038,13 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { if (Reloc.Offset < PreviousOffset) return make_error<GenericBinaryError>("relocations not in offset order", object_error::parse_failed); + + auto badReloc = [&](StringRef msg) { + return make_error<GenericBinaryError>( + msg + ": " + Twine(Symbols[Reloc.Index].Info.Name), + object_error::parse_failed); + }; + PreviousOffset = Reloc.Offset; Reloc.Index = readVaruint32(Ctx); switch (type) { @@ -968,18 +1057,15 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { case wasm::R_WASM_TABLE_INDEX_REL_SLEB: case wasm::R_WASM_TABLE_INDEX_REL_SLEB64: if (!isValidFunctionSymbol(Reloc.Index)) - return make_error<GenericBinaryError>( - "invalid relocation function index", object_error::parse_failed); + return badReloc("invalid function relocation"); break; case wasm::R_WASM_TABLE_NUMBER_LEB: if (!isValidTableSymbol(Reloc.Index)) - return make_error<GenericBinaryError>("invalid relocation table index", - object_error::parse_failed); + return badReloc("invalid table relocation"); break; case wasm::R_WASM_TYPE_INDEX_LEB: if (Reloc.Index >= Signatures.size()) - return make_error<GenericBinaryError>("invalid relocation type index", - object_error::parse_failed); + return badReloc("invalid relocation type index"); break; case wasm::R_WASM_GLOBAL_INDEX_LEB: // R_WASM_GLOBAL_INDEX_LEB are can be used against function and data @@ -987,18 +1073,15 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { if (!isValidGlobalSymbol(Reloc.Index) && !isValidDataSymbol(Reloc.Index) && !isValidFunctionSymbol(Reloc.Index)) - return make_error<GenericBinaryError>("invalid relocation global index", - object_error::parse_failed); + return badReloc("invalid global relocation"); break; case wasm::R_WASM_GLOBAL_INDEX_I32: if (!isValidGlobalSymbol(Reloc.Index)) - return make_error<GenericBinaryError>("invalid relocation global index", - object_error::parse_failed); + return badReloc("invalid global relocation"); break; case wasm::R_WASM_TAG_INDEX_LEB: if (!isValidTagSymbol(Reloc.Index)) - return make_error<GenericBinaryError>("invalid relocation tag index", - object_error::parse_failed); + return badReloc("invalid tag relocation"); break; case wasm::R_WASM_MEMORY_ADDR_LEB: case wasm::R_WASM_MEMORY_ADDR_SLEB: @@ -1007,8 +1090,7 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB: case wasm::R_WASM_MEMORY_ADDR_LOCREL_I32: if (!isValidDataSymbol(Reloc.Index)) - return make_error<GenericBinaryError>("invalid relocation data index", - object_error::parse_failed); + return badReloc("invalid data relocation"); Reloc.Addend = readVarint32(Ctx); break; case wasm::R_WASM_MEMORY_ADDR_LEB64: @@ -1017,26 +1099,22 @@ Error WasmObjectFile::parseRelocSection(StringRef Name, ReadContext &Ctx) { case wasm::R_WASM_MEMORY_ADDR_REL_SLEB64: case wasm::R_WASM_MEMORY_ADDR_TLS_SLEB64: if (!isValidDataSymbol(Reloc.Index)) - return make_error<GenericBinaryError>("invalid relocation data index", - object_error::parse_failed); + return badReloc("invalid data relocation"); Reloc.Addend = readVarint64(Ctx); break; case wasm::R_WASM_FUNCTION_OFFSET_I32: if (!isValidFunctionSymbol(Reloc.Index)) - return make_error<GenericBinaryError>( - "invalid relocation function index", object_error::parse_failed); + return badReloc("invalid function relocation"); Reloc.Addend = readVarint32(Ctx); break; case wasm::R_WASM_FUNCTION_OFFSET_I64: if (!isValidFunctionSymbol(Reloc.Index)) - return make_error<GenericBinaryError>( - "invalid relocation function index", object_error::parse_failed); + return badReloc("invalid function relocation"); Reloc.Addend = readVarint64(Ctx); break; case wasm::R_WASM_SECTION_OFFSET_I32: if (!isValidSectionSymbol(Reloc.Index)) - return make_error<GenericBinaryError>( - "invalid relocation section index", object_error::parse_failed); + return badReloc("invalid section relocation"); Reloc.Addend = readVarint32(Ctx); break; default: @@ -1104,26 +1182,75 @@ Error WasmObjectFile::parseCustomSection(WasmSection &Sec, ReadContext &Ctx) { } Error WasmObjectFile::parseTypeSection(ReadContext &Ctx) { + auto parseFieldDef = [&]() { + uint32_t TypeCode = readVaruint32((Ctx)); + /* Discard StorageType */ parseValType(Ctx, TypeCode); + /* Discard Mutability */ readVaruint32(Ctx); + }; + uint32_t Count = readVaruint32(Ctx); Signatures.reserve(Count); while (Count--) { wasm::WasmSignature Sig; uint8_t Form = readUint8(Ctx); + if (Form == wasm::WASM_TYPE_REC) { + // Rec groups expand the type index space (beyond what was declared at + // the top of the section, and also consume one element in that space. + uint32_t RecSize = readVaruint32(Ctx); + if (RecSize == 0) + return make_error<GenericBinaryError>("Rec group size cannot be 0", + object_error::parse_failed); + Signatures.reserve(Signatures.size() + RecSize); + Count += RecSize; + Sig.Kind = wasm::WasmSignature::Placeholder; + Signatures.push_back(std::move(Sig)); + HasUnmodeledTypes = true; + continue; + } if (Form != wasm::WASM_TYPE_FUNC) { - return make_error<GenericBinaryError>("invalid signature type", - object_error::parse_failed); + // Currently LLVM only models function types, and not other composite + // types. Here we parse the type declarations just enough to skip past + // them in the binary. + if (Form == wasm::WASM_TYPE_SUB || Form == wasm::WASM_TYPE_SUB_FINAL) { + uint32_t Supers = readVaruint32(Ctx); + if (Supers > 0) { + if (Supers != 1) + return make_error<GenericBinaryError>( + "Invalid number of supertypes", object_error::parse_failed); + /* Discard SuperIndex */ readVaruint32(Ctx); + } + Form = readVaruint32(Ctx); + } + if (Form == wasm::WASM_TYPE_STRUCT) { + uint32_t FieldCount = readVaruint32(Ctx); + while (FieldCount--) { + parseFieldDef(); + } + } else if (Form == wasm::WASM_TYPE_ARRAY) { + parseFieldDef(); + } else { + return make_error<GenericBinaryError>("bad form", + object_error::parse_failed); + } + Sig.Kind = wasm::WasmSignature::Placeholder; + Signatures.push_back(std::move(Sig)); + HasUnmodeledTypes = true; + continue; } + uint32_t ParamCount = readVaruint32(Ctx); Sig.Params.reserve(ParamCount); while (ParamCount--) { uint32_t ParamType = readUint8(Ctx); - Sig.Params.push_back(wasm::ValType(ParamType)); + Sig.Params.push_back(parseValType(Ctx, ParamType)); + continue; } uint32_t ReturnCount = readVaruint32(Ctx); while (ReturnCount--) { uint32_t ReturnType = readUint8(Ctx); - Sig.Returns.push_back(wasm::ValType(ReturnType)); + Sig.Returns.push_back(parseValType(Ctx, ReturnType)); } + Signatures.push_back(std::move(Sig)); } if (Ctx.Ptr != Ctx.End) @@ -1164,7 +1291,9 @@ Error WasmObjectFile::parseImportSection(ReadContext &Ctx) { NumImportedTables++; auto ElemType = Im.Table.ElemType; if (ElemType != wasm::ValType::FUNCREF && - ElemType != wasm::ValType::EXTERNREF) + ElemType != wasm::ValType::EXTERNREF && + ElemType != wasm::ValType::EXNREF && + ElemType != wasm::ValType::OTHERREF) return make_error<GenericBinaryError>("invalid table element type", object_error::parse_failed); break; @@ -1221,7 +1350,9 @@ Error WasmObjectFile::parseTableSection(ReadContext &Ctx) { Tables.push_back(T); auto ElemType = Tables.back().Type.ElemType; if (ElemType != wasm::ValType::FUNCREF && - ElemType != wasm::ValType::EXTERNREF) { + ElemType != wasm::ValType::EXTERNREF && + ElemType != wasm::ValType::EXNREF && + ElemType != wasm::ValType::OTHERREF) { return make_error<GenericBinaryError>("invalid table element type", object_error::parse_failed); } @@ -1263,6 +1394,7 @@ Error WasmObjectFile::parseTagSection(ReadContext &Ctx) { wasm::WasmTag Tag; Tag.Index = NumImportedTags + Tags.size(); Tag.SigIndex = Type; + Signatures[Type].Kind = wasm::WasmSignature::Tag; Tags.push_back(Tag); } @@ -1274,15 +1406,20 @@ Error WasmObjectFile::parseTagSection(ReadContext &Ctx) { Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) { GlobalSection = Sections.size(); + const uint8_t *SectionStart = Ctx.Ptr; uint32_t Count = readVaruint32(Ctx); Globals.reserve(Count); while (Count--) { wasm::WasmGlobal Global; Global.Index = NumImportedGlobals + Globals.size(); - Global.Type.Type = readUint8(Ctx); + const uint8_t *GlobalStart = Ctx.Ptr; + Global.Offset = static_cast<uint32_t>(GlobalStart - SectionStart); + auto GlobalOpcode = readVaruint32(Ctx); + Global.Type.Type = (uint8_t)parseValType(Ctx, GlobalOpcode); Global.Type.Mutable = readVaruint1(Ctx); if (Error Err = readInitExpr(Global.InitExpr, Ctx)) return Err; + Global.Size = static_cast<uint32_t>(Ctx.Ptr - GlobalStart); Globals.push_back(Global); } if (Ctx.Ptr != Ctx.End) @@ -1294,7 +1431,6 @@ Error WasmObjectFile::parseGlobalSection(ReadContext &Ctx) { Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { uint32_t Count = readVaruint32(Ctx); Exports.reserve(Count); - LinkingData.SymbolTable.reserve(Count); Symbols.reserve(Count); for (uint32_t I = 0; I < Count; I++) { wasm::WasmExport Ex; @@ -1359,9 +1495,7 @@ Error WasmObjectFile::parseExportSection(ReadContext &Ctx) { } Exports.push_back(Ex); if (Ex.Kind != wasm::WASM_EXTERNAL_MEMORY) { - LinkingData.SymbolTable.emplace_back(Info); - Symbols.emplace_back(LinkingData.SymbolTable.back(), GlobalType, - TableType, Signature); + Symbols.emplace_back(Info, GlobalType, TableType, Signature); LLVM_DEBUG(dbgs() << "Adding symbol: " << Symbols.back() << "\n"); } } @@ -1438,7 +1572,7 @@ WasmObjectFile::getDefinedFunction(uint32_t Index) const { return Functions[Index - NumImportedFunctions]; } -wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) { +const wasm::WasmGlobal &WasmObjectFile::getDefinedGlobal(uint32_t Index) const { assert(isDefinedGlobalIndex(Index)); return Globals[Index - NumImportedGlobals]; } @@ -1516,15 +1650,28 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { return make_error<GenericBinaryError>( "Unsupported flags for element segment", object_error::parse_failed); - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER) + bool IsPassive = (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) != 0; + bool IsDeclarative = + IsPassive && (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_DECLARATIVE); + bool HasTableNumber = + !IsPassive && + (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_TABLE_NUMBER); + bool HasInitExprs = + (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS); + bool HasElemKind = + (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) && + !HasInitExprs; + + if (HasTableNumber) Segment.TableNumber = readVaruint32(Ctx); else Segment.TableNumber = 0; + if (!isValidTableNumber(Segment.TableNumber)) return make_error<GenericBinaryError>("invalid TableNumber", object_error::parse_failed); - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_IS_PASSIVE) { + if (IsPassive || IsDeclarative) { Segment.Offset.Extended = false; Segment.Offset.Inst.Opcode = wasm::WASM_OPCODE_I32_CONST; Segment.Offset.Inst.Value.Int32 = 0; @@ -1533,33 +1680,42 @@ Error WasmObjectFile::parseElemSection(ReadContext &Ctx) { return Err; } - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_MASK_HAS_ELEM_KIND) { + if (HasElemKind) { auto ElemKind = readVaruint32(Ctx); if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) { - Segment.ElemKind = wasm::ValType(ElemKind); + Segment.ElemKind = parseValType(Ctx, ElemKind); if (Segment.ElemKind != wasm::ValType::FUNCREF && - Segment.ElemKind != wasm::ValType::EXTERNREF) { - return make_error<GenericBinaryError>("invalid reference type", + Segment.ElemKind != wasm::ValType::EXTERNREF && + Segment.ElemKind != wasm::ValType::EXNREF && + Segment.ElemKind != wasm::ValType::OTHERREF) { + return make_error<GenericBinaryError>("invalid elem type", object_error::parse_failed); } } else { if (ElemKind != 0) - return make_error<GenericBinaryError>("invalid elemtype", + return make_error<GenericBinaryError>("invalid elem type", object_error::parse_failed); Segment.ElemKind = wasm::ValType::FUNCREF; } + } else if (HasInitExprs) { + auto ElemType = parseValType(Ctx, readVaruint32(Ctx)); + Segment.ElemKind = ElemType; } else { Segment.ElemKind = wasm::ValType::FUNCREF; } - if (Segment.Flags & wasm::WASM_ELEM_SEGMENT_HAS_INIT_EXPRS) - return make_error<GenericBinaryError>( - "elem segment init expressions not yet implemented", - object_error::parse_failed); - uint32_t NumElems = readVaruint32(Ctx); - while (NumElems--) { - Segment.Functions.push_back(readVaruint32(Ctx)); + + if (HasInitExprs) { + while (NumElems--) { + wasm::WasmInitExpr Expr; + if (Error Err = readInitExpr(Expr, Ctx)) + return Err; + } + } else { + while (NumElems--) { + Segment.Functions.push_back(readVaruint32(Ctx)); + } } ElemSegments.push_back(Segment); } @@ -1668,18 +1824,22 @@ Expected<StringRef> WasmObjectFile::getSymbolName(DataRefImpl Symb) const { Expected<uint64_t> WasmObjectFile::getSymbolAddress(DataRefImpl Symb) const { auto &Sym = getWasmSymbol(Symb); + if (!Sym.isDefined()) + return 0; + Expected<section_iterator> Sec = getSymbolSection(Symb); + if (!Sec) + return Sec.takeError(); + uint32_t SectionAddress = getSectionAddress(Sec.get()->getRawDataRefImpl()); if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_FUNCTION && isDefinedFunctionIndex(Sym.Info.ElementIndex)) { - // For object files, use the section offset. The linker relies on this. - // For linked files, use the file offset. This behavior matches the way - // browsers print stack traces and is useful for binary size analysis. - // (see https://webassembly.github.io/spec/web-api/index.html#conventions) - uint32_t Adjustment = isRelocatableObject() || isSharedObject() - ? 0 - : Sections[CodeSection].Offset; return getDefinedFunction(Sym.Info.ElementIndex).CodeSectionOffset + - Adjustment; + SectionAddress; } + if (Sym.Info.Kind == wasm::WASM_SYMBOL_TYPE_GLOBAL && + isDefinedGlobalIndex(Sym.Info.ElementIndex)) { + return getDefinedGlobal(Sym.Info.ElementIndex).Offset + SectionAddress; + } + return getSymbolValue(Symb); } @@ -1785,6 +1945,22 @@ uint32_t WasmObjectFile::getSymbolSectionIdImpl(const WasmSymbol &Sym) const { } } +uint32_t WasmObjectFile::getSymbolSize(SymbolRef Symb) const { + const WasmSymbol &Sym = getWasmSymbol(Symb); + if (!Sym.isDefined()) + return 0; + if (Sym.isTypeGlobal()) + return getDefinedGlobal(Sym.Info.ElementIndex).Size; + if (Sym.isTypeData()) + return Sym.Info.DataRef.Size; + if (Sym.isTypeFunction()) + return functions()[Sym.Info.ElementIndex - getNumImportedFunctions()].Size; + // Currently symbol size is only tracked for data segments and functions. In + // principle we could also track size (e.g. binary size) for tables, globals + // and element segments etc too. + return 0; +} + void WasmObjectFile::moveSectionNext(DataRefImpl &Sec) const { Sec.d.a++; } Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const { @@ -1796,7 +1972,13 @@ Expected<StringRef> WasmObjectFile::getSectionName(DataRefImpl Sec) const { return wasm::sectionTypeToString(S.Type); } -uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { return 0; } +uint64_t WasmObjectFile::getSectionAddress(DataRefImpl Sec) const { + // For object files, use 0 for section addresses, and section offsets for + // symbol addresses. For linked files, use file offsets. + // See also getSymbolAddress. + return isRelocatableObject() || isSharedObject() ? 0 + : Sections[Sec.d.a].Offset; +} uint64_t WasmObjectFile::getSectionIndex(DataRefImpl Sec) const { return Sec.d.a; diff --git a/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp b/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp index 61ca49e290da..306e8ec54206 100644 --- a/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp +++ b/contrib/llvm-project/llvm/lib/Object/WindowsResource.cpp @@ -12,6 +12,7 @@ #include "llvm/Object/WindowsResource.h" #include "llvm/Object/COFF.h" +#include "llvm/Object/WindowsMachineFlag.h" #include "llvm/Support/FormatVariadic.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/ScopedPrinter.h" @@ -79,7 +80,7 @@ Expected<ResourceEntryRef> ResourceEntryRef::create(BinaryStreamRef BSR, const WindowsResource *Owner) { auto Ref = ResourceEntryRef(BSR, Owner); if (auto E = Ref.loadNext()) - return std::move(E); + return E; return Ref; } @@ -978,19 +979,17 @@ void WindowsResourceCOFFWriter::writeFirstSectionRelocations() { reinterpret_cast<coff_relocation *>(BufferStart + CurrentOffset); Reloc->VirtualAddress = RelocationAddresses[i]; Reloc->SymbolTableIndex = NextSymbolIndex++; - switch (MachineType) { - case COFF::IMAGE_FILE_MACHINE_ARMNT: + switch (getMachineArchType(MachineType)) { + case Triple::thumb: Reloc->Type = COFF::IMAGE_REL_ARM_ADDR32NB; break; - case COFF::IMAGE_FILE_MACHINE_AMD64: + case Triple::x86_64: Reloc->Type = COFF::IMAGE_REL_AMD64_ADDR32NB; break; - case COFF::IMAGE_FILE_MACHINE_I386: + case Triple::x86: Reloc->Type = COFF::IMAGE_REL_I386_DIR32NB; break; - case COFF::IMAGE_FILE_MACHINE_ARM64: - case COFF::IMAGE_FILE_MACHINE_ARM64EC: - case COFF::IMAGE_FILE_MACHINE_ARM64X: + case Triple::aarch64: Reloc->Type = COFF::IMAGE_REL_ARM64_ADDR32NB; break; default: @@ -1007,7 +1006,7 @@ writeWindowsResourceCOFF(COFF::MachineTypes MachineType, Error E = Error::success(); WindowsResourceCOFFWriter Writer(MachineType, Parser, E); if (E) - return std::move(E); + return E; return Writer.write(TimeDateStamp); } diff --git a/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp b/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp index 3fbd51887831..6efb8759d13f 100644 --- a/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/contrib/llvm-project/llvm/lib/Object/XCOFFObjectFile.cpp @@ -65,6 +65,12 @@ template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const { } template <typename T> +uint32_t XCOFFSectionHeader<T>::getSectionSubtype() const { + const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); + return DerivedXCOFFSectionHeader.Flags & ~SectionFlagsTypeMask; +} + +template <typename T> bool XCOFFSectionHeader<T>::isReservedSectionType() const { return getSectionType() & SectionFlagsReservedMask; } @@ -731,9 +737,11 @@ bool XCOFFObjectFile::isRelocatableObject() const { } Expected<uint64_t> XCOFFObjectFile::getStartAddress() const { - // TODO FIXME Should get from auxiliary_header->o_entry when support for the - // auxiliary_header is added. - return 0; + if (AuxiliaryHeader == nullptr) + return 0; + + return is64Bit() ? auxiliaryHeader64()->getEntryPointAddr() + : auxiliaryHeader32()->getEntryPointAddr(); } StringRef XCOFFObjectFile::mapDebugSectionName(StringRef Name) const { @@ -1361,7 +1369,7 @@ Expected<StringRef> XCOFFSymbolRef::getName() const { return getObject()->getStringTableEntry(getSymbol64()->Offset); } -// Explictly instantiate template classes. +// Explicitly instantiate template classes. template struct XCOFFSectionHeader<XCOFFSectionHeader32>; template struct XCOFFSectionHeader<XCOFFSectionHeader64>; |
