1//===- COFFObjectFile.cpp - COFF object file implementation ---------------===// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7//===----------------------------------------------------------------------===// 9// This file declares the COFFObjectFile class. 11//===----------------------------------------------------------------------===// 35#include <system_error> 45// Returns false if size is greater than the buffer size. And sets ec. 47if (M.getBufferSize() <
Size) {
48 EC = object_error::unexpected_eof;
54// Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. 55// Returns unexpected_eof if error. 59 uintptr_t
Addr =
reinterpret_cast<uintptr_t
>(
Ptr);
62 Obj =
reinterpret_cast<constT *
>(
Addr);
66// Decode a string table entry in base 64 (//AAAAAA). Expects \arg Str without 69assert(Str.size() <= 6 &&
"String too long, possible overflow.");
76if (Str[0] >=
'A' && Str[0] <=
'Z')
// 0..25 77 CharVal = Str[0] -
'A';
78elseif (Str[0] >=
'a' && Str[0] <=
'z')
// 26..51 79 CharVal = Str[0] -
'a' + 26;
80elseif (Str[0] >=
'0' && Str[0] <=
'9')
// 52..61 81 CharVal = Str[0] -
'0' + 52;
82elseif (Str[0] ==
'+')
// 62 84elseif (Str[0] ==
'/')
// 63 93if (
Value > std::numeric_limits<uint32_t>::max())
100template <
typename coff_symbol_type>
101const coff_symbol_type *COFFObjectFile::toSymb(
DataRefImplRef)
const{
102const coff_symbol_type *
Addr =
103reinterpret_cast<constcoff_symbol_type *
>(
Ref.p);
107// Verify that the symbol points to a valid entry in the symbol table. 109reinterpret_cast<uintptr_t
>(
Addr) -
reinterpret_cast<uintptr_t
>(
base());
112"Symbol did not point to the beginning of a symbol");
122// Verify that the section points to a valid entry in the section table. 126 uintptr_t
Offset =
reinterpret_cast<uintptr_t
>(
Addr) -
127reinterpret_cast<uintptr_t
>(SectionTable);
129"Section did not point to the beginning of a section");
140Ref.p = std::min(
reinterpret_cast<uintptr_t
>(Symb),
End);
141 }
elseif (SymbolTable32) {
144Ref.p = std::min(
reinterpret_cast<uintptr_t
>(Symb),
End);
159// MSVC/link.exe seems to align symbols to the next-power-of-2 176return Section.takeError();
177 Result += (*Section)->VirtualAddress;
179// The section VirtualAddress does not include ImageBase, and we want to 180// return virtual addresses. 199// TODO: perhaps we need a new symbol type ST_Section. 254 Ret.p =
reinterpret_cast<uintptr_t
>(*Sec);
266Ref.p =
reinterpret_cast<uintptr_t
>(Sec);
278// The section VirtualAddress does not include ImageBase, and we want to 279// return virtual addresses. 285return toSec(Sec) - SectionTable;
328// The .debug sections are the only debug sections for COFF 329// (\see MCObjectFileInfo.cpp). 332if (!SectionNameOrErr) {
333// TODO: Report the error message properly. 350// In COFF, a virtual section won't have any in-file 351// content, so the file pointer to the content will be zero. 357// The field for the number of relocations in COFF section table is only 358// 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to 359// NumberOfRelocations field, and the actual relocation count is stored in the 360// VirtualAddress field in the first relocation entry. 369// -1 to exclude this first relocation entry. 383// Skip the first relocation entry repurposed to store the number of 401 Ret.p =
reinterpret_cast<uintptr_t
>(begin);
411 Ret.p =
reinterpret_cast<uintptr_t
>(
I);
415// Initialize the pointer to the symbol table. 416Error COFFObjectFile::initSymbolTablePtr() {
429// Find string table. The first four byte of the string table contains the 430// total size of the string table, including the size field itself. If the 431// string table is empty, the value of the first four byte would be 4. 435const ulittle32_t *StringTableSizePtr;
438 StringTableSize = *StringTableSizePtr;
442// Treat table sizes < 4 as empty because contrary to the PECOFF spec, some 443// tools like cvtres write a size of 0 for an empty table instead of 4. 444if (StringTableSize < 4)
447// Check that the string table is null terminated if has any in it. 448if (StringTableSize > 4 &&
StringTable[StringTableSize - 1] != 0)
450"string table missing null terminator");
457elseif (PE32PlusHeader)
459// This actually comes up in practice. 463// Returns the file offset for the given VA. 471// Returns the file offset for the given RVA. 473constchar *ErrorContext)
const{
476uint32_t SectionStart = Section->VirtualAddress;
477uint32_t SectionEnd = Section->VirtualAddress + Section->VirtualSize;
478if (SectionStart <=
Addr &&
Addr < SectionEnd) {
479// A table/directory entry can be pointing to somewhere in a stripped 480// section, in an object that went through `objcopy --only-keep-debug`. 481// In this case we don't want to cause the parsing of the object file to 482// fail, otherwise it will be impossible to use this object as debug info 483// in LLDB. Return SectionStrippedError here so that 484// COFFObjectFile::initialize can ignore the error. 485// Somewhat common binaries may have RVAs pointing outside of the 486// provided raw data. Instead of rejecting the binaries, just 487// treat the section as stripped for these purposes. 488if (Section->SizeOfRawData < Section->VirtualSize &&
489Addr >= SectionStart + Section->SizeOfRawData) {
490return make_error<SectionStrippedError>();
493 Res =
reinterpret_cast<uintptr_t
>(
base()) + Section->PointerToRawData +
500"RVA 0x%" PRIx32
" for %s not found",
Addr,
503"RVA 0x%" PRIx32
" not found",
Addr);
508constchar *ErrorContext)
const{
511uint32_t SectionStart = Section->VirtualAddress;
512// Check if this RVA is within the section bounds. Be careful about integer 514uint32_t OffsetIntoSection = RVA - SectionStart;
515if (SectionStart <= RVA && OffsetIntoSection < Section->VirtualSize &&
516 Size <= Section->VirtualSize - OffsetIntoSection) {
517 uintptr_t Begin =
reinterpret_cast<uintptr_t
>(
base()) +
518 Section->PointerToRawData + OffsetIntoSection;
526"RVA 0x%" PRIx32
" for %s not found", RVA,
529"RVA 0x%" PRIx32
" not found", RVA);
532// Returns hint and name fields, assuming \p Rva is pointing to a Hint/Name 536 uintptr_t IntPtr = 0;
540 Hint = *
reinterpret_cast<constulittle16_t *
>(
Ptr);
551 InfoBytes,
"PDB info"))
553if (InfoBytes.
size() <
sizeof(*PDBInfo) + 1)
556 InfoBytes = InfoBytes.
drop_front(
sizeof(*PDBInfo));
557 PDBFileName =
StringRef(
reinterpret_cast<constchar *
>(InfoBytes.
data()),
559// Truncate the name at the first null byte. Ignore any padding. 560 PDBFileName = PDBFileName.
split(
'\0').first;
569// If we get here, there is no PDB info to return. 575// Find the import table. 576Error COFFObjectFile::initImportTablePtr() {
577// First, we get the RVA of the import table. If the file lacks a pointer to 578// the import table, do nothing. 583// Do nothing if the pointer to import table is NULL. 589// Find the section that contains the RVA. This is needed because the RVA is 590// the import table's memory address which is different from its file offset. 591 uintptr_t IntPtr = 0;
596 ImportDirectory =
reinterpret_cast< 601// Initializes DelayImportDirectory and NumberOfDelayImportDirectory. 602Error COFFObjectFile::initDelayImportTablePtr() {
611 NumberOfDelayImportDirectory = DataEntry->
Size /
614 uintptr_t IntPtr = 0;
620 DelayImportDirectory =
reinterpret_cast< 625// Find the export table. 626Error COFFObjectFile::initExportTablePtr() {
627// First, we get the RVA of the export table. If the file lacks a pointer to 628// the export table, do nothing. 633// Do nothing if the pointer to export table is NULL. 638 uintptr_t IntPtr = 0;
649Error COFFObjectFile::initBaseRelocPtr() {
657 uintptr_t IntPtr = 0;
667 IntPtr + DataEntry->
Size);
668// FIXME: Verify the section containing BaseRelocHeader has at least 669// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress. 673Error COFFObjectFile::initDebugDirectoryPtr() {
674// Get the RVA of the debug directory. Do nothing if it does not exist. 679// Do nothing if the RVA is NULL. 683// Check that the size is a multiple of the entry size. 686"debug directory has uneven size");
688 uintptr_t IntPtr = 0;
697 IntPtr + DataEntry->
Size);
698// FIXME: Verify the section containing DebugDirectoryBegin has at least 699// DataEntry->Size bytes after DataEntry->RelativeVirtualAddress. 703Error COFFObjectFile::initTLSDirectoryPtr() {
704// Get the RVA of the TLS directory. Do nothing if it does not exist. 709// Do nothing if the RVA is NULL. 716// Check that the size is correct. 717if (DataEntry->
Size != DirSize)
720"TLS Directory size (%u) is not the expected size (%" PRIu64
").",
723 uintptr_t IntPtr = 0;
738Error COFFObjectFile::initLoadConfigPtr() {
739// Get the RVA of the debug directory. Do nothing if it does not exist. 744// Do nothing if the RVA is NULL. 747 uintptr_t IntPtr = 0;
754 LoadConfig = (
constvoid *)IntPtr;
760sizeof(
Config->CHPEMetadataPointer) &&
761Config->CHPEMetadataPointer) {
769 CHPEMetadata =
reinterpret_cast<constchpe_metadata *
>(IntPtr);
771// Validate CHPE metadata 783"CHPE entry point ranges"))
793"CHPE redirection metadata"))
804sizeof(
Config->DynamicValueRelocTableSection))
805if (
Error E = initDynamicRelocPtr(
Config->DynamicValueRelocTableSection,
806Config->DynamicValueRelocTableOffset))
812sizeof(
Config->DynamicValueRelocTableSection)) {
813if (
Error E = initDynamicRelocPtr(
Config->DynamicValueRelocTableSection,
814Config->DynamicValueRelocTableOffset))
821Error COFFObjectFile::initDynamicRelocPtr(
uint32_t SectionIndex,
829// Interpret and validate dynamic relocations. 834 Contents = Contents.
drop_front(SectionOffset);
837"Too large DynamicValueRelocTableOffset (" +
838Twine(SectionOffset) +
")");
843if (DynamicRelocTable->
Version != 1 && DynamicRelocTable->
Version != 2)
845"Unsupported dynamic relocations table version (" +
847if (DynamicRelocTable->
Size > Contents.
size() -
sizeof(*DynamicRelocTable))
849"Indvalid dynamic relocations directory size (" +
853if (
Error e = DynReloc.validate())
862 std::unique_ptr<COFFObjectFile> Obj(
newCOFFObjectFile(std::move(Object)));
863if (
Error E = Obj->initialize())
865return std::move(Obj);
870 COFFBigObjHeader(nullptr), PE32Header(nullptr), PE32PlusHeader(nullptr),
871 DataDirectory(nullptr), SectionTable(nullptr), SymbolTable16(nullptr),
872 SymbolTable32(nullptr),
StringTable(nullptr), StringTableSize(0),
873 ImportDirectory(nullptr), DelayImportDirectory(nullptr),
874 NumberOfDelayImportDirectory(0), ExportDirectory(nullptr),
875 BaseRelocHeader(nullptr), BaseRelocEnd(nullptr),
876 DebugDirectoryBegin(nullptr), DebugDirectoryEnd(nullptr),
877 TLSDirectory32(nullptr), TLSDirectory64(nullptr) {}
887Error COFFObjectFile::initialize() {
888// Check that we at least have enough room for a header. 893// The current location in the file where we are looking at. 896// PE header is optional and is present only in executables. If it exists, 897// it is placed right after COFF header. 898bool HasPEHeader =
false;
900// Check if this is a PE/COFF file. 902// PE/COFF, seek through MS-DOS compatibility stub and 4-byte 903// PE signature to find 'normal' COFF header. 905if (DH->Magic[0] ==
'M' && DH->Magic[1] ==
'Z') {
906 CurPtr = DH->AddressOfNewExeHeader;
907// Check the PE magic bytes. ("PE\0\0") 910"incorrect PE magic");
920// It might be a bigobj file, let's check. Note that COFF bigobj and COFF 921// import libraries share a common prefix but bigobj is more restrictive. 928// Verify that we are dealing with bigobj. 936 COFFBigObjHeader =
nullptr;
940// The prior checkSize call may have failed. This isn't a hard error 941// because we were just trying to sniff out bigobj. 942EC = std::error_code();
965// It's neither PE32 nor PE32+. 967"incorrect PE magic");
976assert(COFFHeader || COFFBigObjHeader);
983// Initialize the pointer to the symbol table. 985if (
Error E = initSymbolTablePtr()) {
986// Recover from errors reading the symbol table. 988 SymbolTable16 =
nullptr;
989 SymbolTable32 =
nullptr;
994// We had better not have any symbols if we don't have a symbol table. 997"symbol table missing");
1001// Initialize the pointer to the beginning of the import table. 1007// Initialize the pointer to the export table. 1011// Initialize the pointer to the base relocation table. 1015// Initialize the pointer to the debug directory. 1019// Initialize the pointer to the TLS directory. 1036// The symbol table ends where the string table begins. 1043if (!ImportDirectory)
1045if (ImportDirectory->
isNull())
1066 DelayImportDirectory, NumberOfDelayImportDirectory,
this));
1075if (!ExportDirectory)
1084 Ret.p =
reinterpret_cast<uintptr_t
>(SectionTable);
1092 Ret.p =
reinterpret_cast<uintptr_t
>(SectionTable + NumSections);
1105constvoid *Header = DynamicRelocTable ? DynamicRelocTable + 1 :
nullptr;
1110constvoid *Header =
nullptr;
1111if (DynamicRelocTable)
1112 Header =
reinterpret_cast<constuint8_t *
>(DynamicRelocTable + 1) +
1113 DynamicRelocTable->
Size;
1132return"COFF-ARM64EC";
1138return"COFF-<unknown arch>";
1179assert(PE32Header || PE32PlusHeader);
1184return &DataDirectory[Index];
1188// Perhaps getting the section of a reserved section index should be an error, 1189// but callers rely on this to return null. 1193// We already verified the section table data, so no need to check again. 1194return SectionTable + (Index - 1);
1197"section index out of bounds");
1201if (StringTableSize <= 4)
1202// Tried to get a string from an empty string table. 1204if (
Offset >= StringTableSize)
1215// Check for string table entry. First 4 bytes are 0. 1216if (Symbol->Name.Offset.Zeroes == 0)
1217return getString(Symbol->Name.Offset.Offset);
1219// Null terminated, let ::strlen figure out the length. 1223// Not null terminated, use all 8 bytes. 1232if (Symbol.getNumberOfAuxSymbols() > 0) {
1233// AUX data comes immediately after the symbol in COFF 1234 Aux =
reinterpret_cast<constuint8_t *
>(Symbol.getRawPtr()) + SymbolSize;
1236// Verify that the Aux symbol points to a valid entry in the symbol table. 1237 uintptr_t
Offset = uintptr_t(Aux) - uintptr_t(
base());
1244"Aux Symbol data did not point to the beginning of a symbol");
1247returnArrayRef(Aux, Symbol.getNumberOfAuxSymbols() * SymbolSize);
1252reinterpret_cast<uintptr_t
>(Symbol.getRawPtr()) -
getSymbolTable();
1254"Symbol did not point to the beginning of a symbol");
1264// Check for string table entry. First byte is '/'. 1265if (
Name.starts_with(
"/")) {
1267if (
Name.starts_with(
"//")) {
1270"invalid section name");
1274"invalid section name");
1283// SizeOfRawData and VirtualSize change what they represent depending on 1284// whether or not we have an executable image. 1286// For object files, SizeOfRawData contains the size of section's data; 1287// VirtualSize should be zero but isn't due to buggy COFF writers. 1289// For executables, SizeOfRawData *must* be a multiple of FileAlignment; the 1290// actual section size is in VirtualSize. It is possible for VirtualSize to 1291// be greater than SizeOfRawData; the contents past that point should be 1292// considered to be zero. 1300// In COFF, a virtual section won't have any in-file 1301// content, so the file pointer to the content will be zero. 1304// The only thing that we need to verify is that the contents is contained 1305// within the file bounds. We don't need to make sure it doesn't cover other 1306// data, as there's nothing that says that is not allowed. 1307 uintptr_t ConStart =
1312 Res =
ArrayRef(
reinterpret_cast<constuint8_t *
>(ConStart), SectionSize);
1321 Rel.
p =
reinterpret_cast<uintptr_t
>(
1327return R->VirtualAddress;
1336Ref.p =
reinterpret_cast<uintptr_t
>(SymbolTable16 + R->SymbolTableIndex);
1337elseif (SymbolTable32)
1338Ref.p =
reinterpret_cast<uintptr_t
>(SymbolTable32 + R->SymbolTableIndex);
1351return toSec(Section.getRawDataRefImpl());
1356return toSymb<coff_symbol16>(
Ref);
1358return toSymb<coff_symbol32>(
Ref);
1377#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type) \ 1378 case COFF::reloc_type: \ 1496#undef LLVM_COFF_SWITCH_RELOC_TYPE_NAME 1502 Result.append(Res.
begin(), Res.
end());
1506return !DataDirectory;
1511 .
Case(
"eh_fram",
"eh_frame")
1519 std::unique_ptr<WritableMemoryBuffer> HybridView;
1525for (
auto reloc : DynReloc.arm64x_relocs()) {
1538Ptr = HybridView->getBufferStart() + IntPtr -
1539reinterpret_cast<uintptr_t
>(
base());
1541// PE header relocation. 1542Ptr = HybridView->getBufferStart() + RVA;
1545switch (reloc.getType()) {
1547 memset(
Ptr, 0, reloc.getSize());
1550autoValue =
static_cast<ulittle64_t
>(reloc.getValue());
1551 memcpy(
Ptr, &
Value, reloc.getSize());
1555 *
reinterpret_cast<ulittle32_t *
>(
Ptr) += reloc.getValue();
1565return ImportTable ==
Other.ImportTable && Index ==
Other.Index;
1570if (ImportTable[Index].isNull()) {
1572 ImportTable =
nullptr;
1578returngetObject(Result, OwningObject->
Data, ImportTable + Index);
1583 uintptr_t
Ptr,
int Index) {
1584if (Object->getBytesInAddress() == 4) {
1594 uintptr_t IntPtr = 0;
1595// FIXME: Handle errors. 1596cantFail(Object->getRvaPtr(RVA, IntPtr));
1602 uintptr_t IntPtr = 0;
1603// FIXME: Handle errors. 1604cantFail(Object->getRvaPtr(RVA, IntPtr));
1605// Forward the pointer to the last entry which is null. 1607if (Object->getBytesInAddress() == 4) {
1608auto *Entry =
reinterpret_cast<ulittle32_t *
>(IntPtr);
1612auto *Entry =
reinterpret_cast<ulittle64_t *
>(IntPtr);
1652 uintptr_t IntPtr = 0;
1654"import directory name"))
1656 Result =
StringRef(
reinterpret_cast<constchar *
>(IntPtr));
1674return Table ==
Other.Table && Index ==
Other.Index;
1699 uintptr_t IntPtr = 0;
1701"delay import directory name"))
1703 Result =
StringRef(
reinterpret_cast<constchar *
>(IntPtr));
1709 Result = &Table[Index];
1716 AddrIndex * (OwningObject->
is64() ? 8 : 4);
1717 uintptr_t IntPtr = 0;
1718if (
Error E = OwningObject->
getRvaPtr(RVA, IntPtr,
"import address"))
1720if (OwningObject->
is64())
1721 Result = *
reinterpret_cast<constulittle64_t *
>(IntPtr);
1723 Result = *
reinterpret_cast<constulittle32_t *
>(IntPtr);
1729return ExportTable ==
Other.ExportTable && Index ==
Other.Index;
1736// Returns the name of the current export symbol. If the symbol is exported only 1737// by ordinal, the empty string is set as a result. 1739 uintptr_t IntPtr = 0;
1743 Result =
StringRef(
reinterpret_cast<constchar *
>(IntPtr));
1747// Returns the starting ordinal number. 1753// Returns the export ordinal of the current export symbol. 1759// Returns the address of the current export symbol. 1761 uintptr_t IntPtr = 0;
1763 IntPtr,
"export address"))
1771// Returns the name of the current export symbol. If the symbol is exported only 1772// by ordinal, the empty string is set as a result. 1775 uintptr_t IntPtr = 0;
1777"export ordinal table"))
1779const ulittle16_t *Start =
reinterpret_cast<constulittle16_t *
>(IntPtr);
1783for (
const ulittle16_t *
I = Start, *E = Start + NumEntries;
1788"export table entry"))
1790const ulittle32_t *NamePtr =
reinterpret_cast<constulittle32_t *
>(IntPtr);
1792"export symbol name"))
1794 Result =
StringRef(
reinterpret_cast<constchar *
>(IntPtr));
1806"export table missing");
1812 Result = (Begin <= RVA && RVA <
End);
1820 uintptr_t IntPtr = 0;
1821if (
auto EC = OwningObject->
getRvaPtr(RVA, IntPtr,
"export forward target"))
1823 Result =
StringRef(
reinterpret_cast<constchar *
>(IntPtr));
1829return Entry32 ==
Other.Entry32 && Entry64 ==
Other.Entry64
1830 && Index ==
Other.Index;
1840// If a symbol is imported only by ordinal, it has no name. 1849 uintptr_t IntPtr = 0;
1850if (
Error EC = OwningObject->
getRvaPtr(RVA, IntPtr,
"import symbol name"))
1852// +2 because the first two bytes is hint. 1853 Result =
StringRef(
reinterpret_cast<constchar *
>(IntPtr + 2));
1888 uintptr_t IntPtr = 0;
1889if (
Error EC = OwningObject->
getRvaPtr(RVA, IntPtr,
"import symbol ordinal"))
1891 Result = *
reinterpret_cast<constulittle16_t *
>(IntPtr);
1901return Header ==
Other.Header && Index ==
Other.Index;
1905// Header->BlockSize is the size of the current block, including the 1906// size of the header itself. 1909if (
Size == Header->BlockSize) {
1910// .reloc contains a list of base relocation blocks. Each block 1911// consists of the header followed by entries. The header contains 1912// how many entories will follow. When we reach the end of the 1913// current block, proceed to the next block. 1924Type = Entry[Index].getType();
1930 Result = Header->PageRVA + Entry[Index].getOffset();
1935return Header ==
Other.Header;
1939switch (Obj->getDynamicRelocTable()->Version) {
1943 Header +=
sizeof(*H) +
H->BaseRelocSize;
1946 Header +=
sizeof(*H) +
H->BaseRelocSize;
1952 Header +=
H->HeaderSize +
H->FixupInfoSize;
1955 Header +=
H->HeaderSize +
H->FixupInfoSize;
1962switch (Obj->getDynamicRelocTable()->Version) {
1987switch (Obj->getDynamicRelocTable()->Version) {
2009Error DynamicRelocRef::validate()
const{
2011size_t ContentsSize =
2012reinterpret_cast<constuint8_t *
>(Table + 1) + Table->
Size - Header;
2020if (HeaderSize > ContentsSize)
2022"Unexpected end of dynamic relocations data");
2031if (Size < HeaderSize || Size > ContentsSize)
2033"Invalid dynamic relocation header size (" +
2040if (Contents.
size() > ContentsSize - HeaderSize)
2042"Too large dynamic relocation size (" +
2048if (
Error E = Reloc.validate(Obj))
2080return Header ==
Other.Header && Index ==
Other.Index;
2083uint8_t Arm64XRelocRef::getEntrySize()
const{
2086return (1ull << getArg()) /
sizeof(
uint16_t) + 1;
2095 Index += getEntrySize();
2096if (
sizeof(*Header) + Index *
sizeof(
uint16_t) < Header->BlockSize &&
2098 ++Index;
// Skip padding 2099if (
sizeof(*Header) + Index *
sizeof(
uint16_t) == Header->BlockSize) {
2100// The end of the block, move to the next one. 2111return 1 << getArg();
2119autoPtr =
reinterpret_cast<constulittle16_t *
>(Header + 1) + Index + 1;
2123 ulittle64_t
Value(0);
2133 delta *= (arg & 2) ? 8 : 4;
2144size_t ContentsSize =
reinterpret_cast<constuint8_t *
>(Table + 1) +
2146reinterpret_cast<constuint8_t *
>(Header);
2149"Unexpected end of ARM64X relocations data");
2150if (Header->BlockSize <=
sizeof(*Header))
2152"ARM64X relocations block size (" +
2153Twine(Header->BlockSize) +
") is too small");
2154if (Header->BlockSize %
sizeof(
uint32_t))
2156"Unaligned ARM64X relocations block size (" +
2157Twine(Header->BlockSize) +
")");
2158if (Header->BlockSize > ContentsSize)
2160"ARM64X relocations block size (" +
2161Twine(Header->BlockSize) +
") is too large");
2162if (Header->PageRVA & 0xfff)
2164"Unaligned ARM64X relocations page RVA (" +
2165Twine(Header->PageRVA) +
")");
2168switch ((getReloc() >> 12) & 3) {
2175"Invalid ARM64X relocation value size (0)");
2179"Invalid relocation type");
2183 (Header->BlockSize -
sizeof(*Header)) /
sizeof(
uint16_t);
2184uint16_t EntrySize = getEntrySize();
2186 (Index + EntrySize + 1 < RelocsSize && !getReloc(EntrySize)))
2188"Unexpected ARM64X relocations terminator");
2189if (Index + EntrySize > RelocsSize)
2191"Unexpected end of ARM64X relocations");
2194"Unaligned ARM64X relocation RVA (" +
2196if (Header->PageRVA) {
2203#define RETURN_IF_ERROR(Expr) \ 2207 return std::move(E); \ 2223return getDirStringAtOffset(Entry.Identifier.getNameOffset());
2231 Reader.setOffset(
Offset);
2242 Reader.setOffset(
Offset);
2253 Reader.setOffset(
Offset);
2261assert(Entry.Offset.isSubDir());
2262return getTableAtOffset(Entry.Offset.value());
2267assert(!Entry.Offset.isSubDir());
2268return getDataEntryAtOffset(Entry.Offset.value());
2272return getTableAtOffset(0);
2282return getTableEntryAtOffset(TableOffset +
sizeof(Table) +
2290returnName.takeError();
2292if (*
Name ==
".rsrc" || *
Name ==
".rsrc$01")
2296"no resource section found");
2308 Relocs.reserve(OrigRelocs.
size());
2310 Relocs.push_back(&R);
2312returnA->VirtualAddress <
B->VirtualAddress;
2322// Find a potential relocation at the DataRVA field (first member of 2323// the coff_resource_data_entry struct). 2328auto RelocsForOffset =
2329 std::equal_range(Relocs.begin(), Relocs.end(), &RelocTarget,
2331 return A->VirtualAddress < B->VirtualAddress;
2334if (RelocsForOffset.first != RelocsForOffset.second) {
2335// We found a relocation with the right offset. Check that it does have 2336// the expected type. 2354"unsupported architecture");
2356if (R.Type != RVAReloc)
2358"unexpected relocation type");
2359// Get the relocation's symbol 2362returnSym.takeError();
2363// And the symbol's section 2367return Section.takeError();
2368// Add the initial value of DataRVA to the symbol's offset to find the 2369// data it points at. 2374if (
Offset + Entry.DataSize > Contents.
size())
2376"data outside of section");
2377// Return a reference to the data inside the section. 2381// Relocatable objects need a relocation for the DataRVA field. 2384"no relocation found for DataRVA");
2386// Locate the section that contains the address that DataRVA points at. 2389if (VA >= S.getAddress() &&
2390 VA + Entry.DataSize <= S.getAddress() + S.getSize()) {
2395return Contents->substr(
Offset, Entry.DataSize);
2399"address not found in image");
AMDGPU Mark last scratch load
#define offsetof(TYPE, MEMBER)
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
static imported_symbol_iterator importedSymbolEnd(uint32_t RVA, const COFFObjectFile *Object)
static uint32_t getNumberOfRelocations(const coff_section *Sec, MemoryBufferRef M, const uint8_t *base)
static Error getObject(const T *&Obj, MemoryBufferRef M, const void *Ptr, const uint64_t Size=sizeof(T))
static imported_symbol_iterator makeImportedSymbolIterator(const COFFObjectFile *Object, uintptr_t Ptr, int Index)
#define LLVM_COFF_SWITCH_RELOC_TYPE_NAME(reloc_type)
static const coff_relocation * getFirstReloc(const coff_section *Sec, MemoryBufferRef M, const uint8_t *Base)
static imported_symbol_iterator importedSymbolBegin(uint32_t RVA, const COFFObjectFile *Object)
static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Size)
#define RETURN_IF_ERROR(Expr)
static bool decodeBase64StringEntry(StringRef Str, uint32_t &Result)
static Error ignoreStrippedErrors(Error E)
Merge contiguous icmps into a memcmp
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
ArrayRef< T > drop_front(size_t N=1) const
Drop the first N elements of the array.
size_t size() const
size - Get the array size.
An implementation of BinaryStream which holds its entire data set in a single contiguous buffer.
ArrayRef< uint8_t > data() const
Provides read only access to a subclass of BinaryStream.
Error readInteger(T &Dest)
Read an integer of the specified endianness into Dest and update the stream's offset.
void setOffset(uint64_t Off)
Error readArray(ArrayRef< T > &Array, uint32_t NumElements)
Get a reference to a NumElements element array of objects of type T from the underlying stream as if ...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
bool isA() const
Check whether one error is a subclass of another.
Tagged union holding either a T or a Error.
Error takeError()
Take ownership of the stored error.
reference get()
Returns a reference to the stored T value.
size_t getBufferSize() const
const char * getBufferStart() const
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
StringRef - Represent a constant reference to a string, i.e.
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
A table of densely packed, null-terminated strings indexed by offset.
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
The instances of the Type class are immutable: once they are created, they are never changed.
LLVM Value Representation.
static std::unique_ptr< WritableMemoryBuffer > getNewUninitMemBuffer(size_t Size, const Twine &BufferName="", std::optional< Align > Alignment=std::nullopt)
Allocate a new MemoryBuffer of the specified size that is not initialized.
A range adaptor for a pair of iterators.
bool operator==(const Arm64XRelocRef &Other) const
COFF::Arm64XFixupType getType() const
uint64_t getValue() const
Error getType(uint8_t &Type) const
bool operator==(const BaseRelocRef &Other) const
Error getRVA(uint32_t &Result) const
static Error checkOffset(MemoryBufferRef M, uintptr_t Addr, const uint64_t Size)
const dos_header * getDOSHeader() const
uint64_t getSectionSize(DataRefImpl Sec) const override
Expected< StringRef > getSectionName(DataRefImpl Sec) const override
uint64_t getSectionIndex(DataRefImpl Sec) const override
dynamic_reloc_iterator dynamic_reloc_begin() const
std::unique_ptr< MemoryBuffer > getHybridObjectView() const
uint32_t getSymbolAlignment(DataRefImpl Symb) const override
bool isSectionCompressed(DataRefImpl Sec) const override
void moveRelocationNext(DataRefImpl &Rel) const override
Expected< section_iterator > getSymbolSection(DataRefImpl Symb) const override
uint8_t getBytesInAddress() const override
The number of bytes used to represent an address in this object file format.
export_directory_iterator export_directory_begin() const
delay_import_directory_iterator delay_import_directory_end() const
base_reloc_iterator base_reloc_begin() const
section_iterator section_end() const override
Expected< COFFSymbolRef > getSymbol(uint32_t index) const
Error getVaPtr(uint64_t VA, uintptr_t &Res) const
uint64_t getRelocationType(DataRefImpl Rel) const override
void moveSymbolNext(DataRefImpl &Symb) const override
uint64_t getCommonSymbolSizeImpl(DataRefImpl Symb) const override
iterator_range< delay_import_directory_iterator > delay_import_directories() const
import_directory_iterator import_directory_end() const
uint32_t getPointerToSymbolTable() const
const coff_relocation * getCOFFRelocation(const RelocationRef &Reloc) const
Expected< StringRef > getSymbolName(DataRefImpl Symb) const override
bool isDebugSection(DataRefImpl Sec) const override
iterator_range< const debug_directory * > debug_directories() const
const coff_dynamic_reloc_table * getDynamicRelocTable() const
StringRef getRelocationTypeName(uint16_t Type) const
bool isSectionBSS(DataRefImpl Sec) const override
base_reloc_iterator base_reloc_end() const
uint64_t getSectionAddress(DataRefImpl Sec) const override
Expected< uint64_t > getSymbolAddress(DataRefImpl Symb) const override
uint32_t getNumberOfSymbols() const
section_iterator section_begin() const override
Expected< SymbolRef::Type > getSymbolType(DataRefImpl Symb) const override
size_t getSymbolTableEntrySize() const
friend class ImportDirectoryEntryRef
export_directory_iterator export_directory_end() const
Error getHintName(uint32_t Rva, uint16_t &Hint, StringRef &Name) const
uintptr_t getSymbolTable() const
static Expected< std::unique_ptr< COFFObjectFile > > create(MemoryBufferRef Object)
bool isSectionVirtual(DataRefImpl Sec) const override
unsigned getSectionID(SectionRef Sec) const
relocation_iterator section_rel_begin(DataRefImpl Sec) const override
iterator_range< import_directory_iterator > import_directories() const
delay_import_directory_iterator delay_import_directory_begin() const
basic_symbol_iterator symbol_end() const override
Error getRvaAndSizeAsBytes(uint32_t RVA, uint32_t Size, ArrayRef< uint8_t > &Contents, const char *ErrorContext=nullptr) const
Given an RVA base and size, returns a valid array of bytes or an error code if the RVA and size is no...
const coff_load_configuration64 * getLoadConfig64() const
iterator_range< export_directory_iterator > export_directories() const
uint32_t getNumberOfSections() const
uint64_t getRelocationOffset(DataRefImpl Rel) const override
basic_symbol_iterator symbol_begin() const override
Triple::ArchType getArch() const override
bool isRelocatableObject() const override
True if this is a relocatable object (.o/.obj).
Expected< uint32_t > getSymbolFlags(DataRefImpl Symb) const override
Expected< const coff_section * > getSection(int32_t index) const
bool isSectionText(DataRefImpl Sec) const override
Expected< ArrayRef< uint8_t > > getSectionContents(DataRefImpl Sec) const override
const data_directory * getDataDirectory(uint32_t index) const
StringRef mapDebugSectionName(StringRef Name) const override
Maps a debug section name to a standard DWARF section name.
ArrayRef< uint8_t > getSymbolAuxData(COFFSymbolRef Symbol) const
uint64_t getImageBase() const
const coff_load_configuration32 * getLoadConfig32() const
const coff_section * getCOFFSection(const SectionRef &Section) const
import_directory_iterator import_directory_begin() const
void moveSectionNext(DataRefImpl &Sec) const override
relocation_iterator section_rel_end(DataRefImpl Sec) const override
dynamic_reloc_iterator dynamic_reloc_end() const
ArrayRef< coff_relocation > getRelocations(const coff_section *Sec) const
uint64_t getSymbolValueImpl(DataRefImpl Symb) const override
Error getRvaPtr(uint32_t Rva, uintptr_t &Res, const char *ErrorContext=nullptr) const
iterator_range< dynamic_reloc_iterator > dynamic_relocs() const
unsigned getSymbolSectionID(SymbolRef Sym) const
Error getDebugPDBInfo(const debug_directory *DebugDir, const codeview::DebugInfo *&Info, StringRef &PDBFileName) const
Get PDB information out of a codeview debug directory entry.
friend class ExportDirectoryEntryRef
symbol_iterator getRelocationSymbol(DataRefImpl Rel) const override
uint64_t getSectionAlignment(DataRefImpl Sec) const override
uint32_t getSymbolIndex(COFFSymbolRef Symbol) const
uint16_t getMachine() const
COFFSymbolRef getCOFFSymbol(const DataRefImpl &Ref) const
Expected< uint64_t > getStartAddress() const override
iterator_range< base_reloc_iterator > base_relocs() const
bool isSectionData(DataRefImpl Sec) const override
StringRef getFileFormatName() const override
bool isAnyUndefined() const
bool isFileRecord() const
const coff_aux_weak_external * getWeakExternal() const
bool isSectionDefinition() const
uint8_t getComplexType() const
uint32_t getValue() const
bool isWeakExternal() const
int32_t getSectionNumber() const
bool operator==(const DelayImportDirectoryEntryRef &Other) const
imported_symbol_iterator imported_symbol_begin() const
Error getImportAddress(int AddrIndex, uint64_t &Result) const
iterator_range< imported_symbol_iterator > imported_symbols() const
imported_symbol_iterator imported_symbol_end() const
Error getDelayImportTable(const delay_import_directory_table_entry *&Result) const
Error getName(StringRef &Result) const
bool operator==(const DynamicRelocRef &Other) const
arm64x_reloc_iterator arm64x_reloc_begin() const
void getContents(ArrayRef< uint8_t > &Ref) const
arm64x_reloc_iterator arm64x_reloc_end() const
iterator_range< arm64x_reloc_iterator > arm64x_relocs() const
bool operator==(const ExportDirectoryEntryRef &Other) const
Error getDllName(StringRef &Result) const
Error getExportRVA(uint32_t &Result) const
Error getOrdinalBase(uint32_t &Result) const
Error getOrdinal(uint32_t &Result) const
Error isForwarder(bool &Result) const
Error getForwardTo(StringRef &Result) const
Error getSymbolName(StringRef &Result) const
bool operator==(const ImportDirectoryEntryRef &Other) const
imported_symbol_iterator imported_symbol_end() const
imported_symbol_iterator imported_symbol_begin() const
Error getImportLookupTableRVA(uint32_t &Result) const
Error getImportTableEntry(const coff_import_directory_table_entry *&Result) const
imported_symbol_iterator lookup_table_end() const
iterator_range< imported_symbol_iterator > lookup_table_symbols() const
iterator_range< imported_symbol_iterator > imported_symbols() const
imported_symbol_iterator lookup_table_begin() const
Error getImportAddressTableRVA(uint32_t &Result) const
Error getName(StringRef &Result) const
bool operator==(const ImportedSymbolRef &Other) const
Error getHintNameRVA(uint32_t &Result) const
Error getOrdinal(uint16_t &Result) const
Error getSymbolName(StringRef &Result) const
Error isOrdinal(bool &Result) const
This class is the base class for all object file types.
friend class RelocationRef
static Expected< std::unique_ptr< COFFObjectFile > > createCOFFObjectFile(MemoryBufferRef Object)
section_iterator_range sections() const
Expected< uint64_t > getSymbolValue(DataRefImpl Symb) const
const uint8_t * base() const
This is a value type class that represents a single relocation in the list of relocations in the obje...
DataRefImpl getRawDataRefImpl() const
Expected< const coff_resource_dir_table & > getBaseTable()
Expected< const coff_resource_dir_table & > getEntrySubDir(const coff_resource_dir_entry &Entry)
Expected< const coff_resource_data_entry & > getEntryData(const coff_resource_dir_entry &Entry)
Error load(const COFFObjectFile *O)
Expected< ArrayRef< UTF16 > > getEntryNameString(const coff_resource_dir_entry &Entry)
Expected< StringRef > getContents(const coff_resource_data_entry &Entry)
Expected< const coff_resource_dir_entry & > getTableEntry(const coff_resource_dir_table &Table, uint32_t Index)
This is a value type class that represents a single section in the list of sections in the object fil...
DataRefImpl getRawDataRefImpl() const
This is a value type class that represents a single symbol in the list of symbols in the object file.
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ IMAGE_DYNAMIC_RELOCATION_ARM64X
@ IMAGE_FILE_MACHINE_ARM64
@ IMAGE_FILE_MACHINE_UNKNOWN
@ IMAGE_FILE_MACHINE_AMD64
@ IMAGE_FILE_MACHINE_ARM64EC
@ IMAGE_FILE_MACHINE_R4000
@ IMAGE_FILE_MACHINE_I386
@ IMAGE_FILE_MACHINE_ARM64X
@ IMAGE_FILE_MACHINE_ARMNT
@ IMAGE_SCN_CNT_UNINITIALIZED_DATA
@ IMAGE_SCN_CNT_INITIALIZED_DATA
@ IMAGE_DEBUG_TYPE_CODEVIEW
@ IMAGE_REL_ARM64_ADDR32NB
@ IMAGE_REL_AMD64_ADDR32NB
@ DELAY_IMPORT_DESCRIPTOR
@ IMAGE_DVRT_ARM64X_FIXUP_TYPE_VALUE
@ IMAGE_DVRT_ARM64X_FIXUP_TYPE_DELTA
@ IMAGE_DVRT_ARM64X_FIXUP_TYPE_ZEROFILL
@ IMAGE_WEAK_EXTERN_SEARCH_ALIAS
bool isReservedSectionNumber(int32_t SectionNumber)
static const char BigObjMagic[]
static const char PEMagic[]
@ IMAGE_SYM_DTYPE_FUNCTION
A function that returns a base type.
static Expected< const T * > getObject(MemoryBufferRef M, const void *Ptr, const uint64_t Size=sizeof(T))
content_iterator< ImportDirectoryEntryRef > import_directory_iterator
content_iterator< ImportedSymbolRef > imported_symbol_iterator
content_iterator< ExportDirectoryEntryRef > export_directory_iterator
content_iterator< Arm64XRelocRef > arm64x_reloc_iterator
content_iterator< BaseRelocRef > base_reloc_iterator
coff_tls_directory< support::little64_t > coff_tls_directory64
content_iterator< SectionRef > section_iterator
content_iterator< RelocationRef > relocation_iterator
content_iterator< BasicSymbolRef > basic_symbol_iterator
content_iterator< DelayImportDirectoryEntryRef > delay_import_directory_iterator
content_iterator< DynamicRelocRef > dynamic_reloc_iterator
This is an optimization pass for GlobalISel generic memory operations.
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
Triple::ArchType getMachineArchType(T machine)
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
uint64_t PowerOf2Ceil(uint64_t A)
Returns the power of two which is greater than or equal to the given value.
void sort(IteratorTy Start, IteratorTy End)
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
@ Ref
The access may reference the value stored in memory.
void cantFail(Error Err, const char *Msg=nullptr)
Report a fatal error if Err is a failure value.
Error errorCodeToError(std::error_code EC)
Helper for converting an std::error_code to a Error.
void consumeError(Error Err)
Consume a Error without doing anything.
support::ulittle32_t RedirectionMetadataCount
support::ulittle32_t CodeMap
support::ulittle32_t CodeRangesToEntryPointsCount
support::ulittle32_t CodeMapCount
support::ulittle32_t RedirectionMetadata
support::ulittle32_t CodeRangesToEntryPoints
support::ulittle16_t Version
support::ulittle32_t Version
support::ulittle32_t Size
support::ulittle32_t HeaderSize
support::ulittle16_t Machine
support::ulittle16_t NumberOfSections
bool isImportLibrary() const
support::ulittle16_t SizeOfOptionalHeader
support::ulittle32_t ImportAddressTableRVA
support::ulittle32_t NameRVA
support::ulittle32_t ImportLookupTableRVA
32-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY32)
64-bit load config (IMAGE_LOAD_CONFIG_DIRECTORY64)
support::ulittle16_t Type
support::ulittle32_t VirtualAddress
support::ulittle16_t NumberOfNameEntries
support::ulittle16_t NumberOfIDEntries
support::ulittle32_t PointerToRawData
char Name[COFF::NameSize]
support::ulittle32_t VirtualSize
bool hasExtendedRelocations() const
uint32_t getAlignment() const
support::ulittle32_t Characteristics
support::ulittle32_t SizeOfRawData
support::ulittle32_t VirtualAddress
support::ulittle32_t PointerToRelocations
support::ulittle16_t NumberOfRelocations
uint8_t NumberOfAuxSymbols
support::ulittle32_t RelativeVirtualAddress
support::ulittle32_t Size
support::ulittle32_t SizeOfData
support::ulittle32_t AddressOfRawData
support::ulittle32_t DelayImportAddressTable
support::ulittle32_t Name
The DOS compatible header at the front of all PE/COFF executables.
support::ulittle32_t OrdinalBase
support::ulittle32_t ExportAddressTableRVA
support::ulittle32_t NameRVA
support::ulittle32_t NumberOfNamePointers
support::ulittle32_t NamePointerRVA
support::ulittle32_t AddressTableEntries
support::ulittle32_t OrdinalTableRVA
uint32_t getHintNameRVA() const
uint16_t getOrdinal() const
The 32-bit PE header that follows the COFF header.
support::ulittle32_t NumberOfRvaAndSize
support::ulittle32_t AddressOfEntryPoint
support::ulittle32_t ImageBase
The 64-bit PE header that follows the COFF header.
support::ulittle64_t ImageBase
support::ulittle32_t NumberOfRvaAndSize
support::ulittle32_t ExportRVA