mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-06 21:27:23 +00:00
Object/COFF: Support large relocation table.
NumberOfRelocations field in COFF section table is only 16-bit wide. If an object has more than 65535 relocations, the number of relocations is stored to VirtualAddress field in the first relocation field, and a special flag (IMAGE_SCN_LNK_NRELOC_OVFL) is set to Characteristics field. In test we cheated a bit. I made up a test file so that it has IMAGE_SCN_LNK_NRELOC_OVFL flag but the number of relocations is much smaller than 65535. This is to avoid checking in a large test file just to test a file with many relocations. Differential Revision: http://llvm-reviews.chandlerc.com/D3139 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@204418 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -250,6 +250,13 @@ struct coff_section {
|
|||||||
support::ulittle16_t NumberOfRelocations;
|
support::ulittle16_t NumberOfRelocations;
|
||||||
support::ulittle16_t NumberOfLinenumbers;
|
support::ulittle16_t NumberOfLinenumbers;
|
||||||
support::ulittle32_t Characteristics;
|
support::ulittle32_t Characteristics;
|
||||||
|
|
||||||
|
// Returns true if the actual number of relocations is stored in
|
||||||
|
// VirtualAddress field of the first relocation table entry.
|
||||||
|
bool hasExtendedRelocations() const {
|
||||||
|
return Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL &&
|
||||||
|
NumberOfRelocations == UINT16_MAX;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct coff_relocation {
|
struct coff_relocation {
|
||||||
|
@@ -367,25 +367,46 @@ error_code COFFObjectFile::sectionContainsSymbol(DataRefImpl SecRef,
|
|||||||
relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
|
relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const {
|
||||||
const coff_section *Sec = toSec(Ref);
|
const coff_section *Sec = toSec(Ref);
|
||||||
DataRefImpl Ret;
|
DataRefImpl Ret;
|
||||||
if (Sec->NumberOfRelocations == 0)
|
if (Sec->NumberOfRelocations == 0) {
|
||||||
Ret.p = 0;
|
Ret.p = 0;
|
||||||
else
|
} else {
|
||||||
Ret.p = reinterpret_cast<uintptr_t>(base() + Sec->PointerToRelocations);
|
auto begin = reinterpret_cast<const coff_relocation*>(
|
||||||
|
base() + Sec->PointerToRelocations);
|
||||||
|
if (Sec->hasExtendedRelocations()) {
|
||||||
|
// Skip the first relocation entry repurposed to store the number of
|
||||||
|
// relocations.
|
||||||
|
begin++;
|
||||||
|
}
|
||||||
|
Ret.p = reinterpret_cast<uintptr_t>(begin);
|
||||||
|
}
|
||||||
return relocation_iterator(RelocationRef(Ret, this));
|
return relocation_iterator(RelocationRef(Ret, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uint32_t getNumberOfRelocations(const coff_section *Sec,
|
||||||
|
const uint8_t *base) {
|
||||||
|
// The field for the number of relocations in COFF section table is only
|
||||||
|
// 16-bit wide. If a section has more than 65535 relocations, 0xFFFF is set to
|
||||||
|
// NumberOfRelocations field, and the actual relocation count is stored in the
|
||||||
|
// VirtualAddress field in the first relocation entry.
|
||||||
|
if (Sec->hasExtendedRelocations()) {
|
||||||
|
auto *FirstReloc = reinterpret_cast<const coff_relocation*>(
|
||||||
|
base + Sec->PointerToRelocations);
|
||||||
|
return FirstReloc->VirtualAddress;
|
||||||
|
}
|
||||||
|
return Sec->NumberOfRelocations;
|
||||||
|
}
|
||||||
|
|
||||||
relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
|
relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const {
|
||||||
const coff_section *Sec = toSec(Ref);
|
const coff_section *Sec = toSec(Ref);
|
||||||
DataRefImpl Ret;
|
DataRefImpl Ret;
|
||||||
if (Sec->NumberOfRelocations == 0)
|
if (Sec->NumberOfRelocations == 0) {
|
||||||
Ret.p = 0;
|
Ret.p = 0;
|
||||||
else
|
} else {
|
||||||
Ret.p = reinterpret_cast<uintptr_t>(
|
auto begin = reinterpret_cast<const coff_relocation*>(
|
||||||
reinterpret_cast<const coff_relocation*>(
|
base() + Sec->PointerToRelocations);
|
||||||
base() + Sec->PointerToRelocations)
|
uint32_t NumReloc = getNumberOfRelocations(Sec, base());
|
||||||
+ Sec->NumberOfRelocations);
|
Ret.p = reinterpret_cast<uintptr_t>(begin + NumReloc);
|
||||||
|
}
|
||||||
return relocation_iterator(RelocationRef(Ret, this));
|
return relocation_iterator(RelocationRef(Ret, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BIN
test/tools/llvm-objdump/Inputs/many-relocs.obj-i386
Normal file
BIN
test/tools/llvm-objdump/Inputs/many-relocs.obj-i386
Normal file
Binary file not shown.
14
test/tools/llvm-objdump/coff-many-relocs.test
Normal file
14
test/tools/llvm-objdump/coff-many-relocs.test
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
// Test that llvm-objdump can handle IMAGE_SCN_LNK_NRELOC_OVFL.
|
||||||
|
// RUN: llvm-objdump -r %p/Inputs/many-relocs.obj-i386 | FileCheck %s
|
||||||
|
|
||||||
|
CHECK: RELOCATION RECORDS FOR [.text]:
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_DIR16 foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_REL16 foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_DIR32 foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_DIR32NB foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_SEG12 foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_SECTION foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_SECREL foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_TOKEN foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_SECREL7 foo
|
||||||
|
CHECK-NEXT: IMAGE_REL_I386_REL32 foo
|
Reference in New Issue
Block a user