From 99995267aec69859a039670e3ba76c64f969b2bf Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Fri, 21 Mar 2014 00:44:19 +0000 Subject: 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 --- include/llvm/Object/COFF.h | 7 ++++ lib/Object/COFFObjectFile.cpp | 43 +++++++++++++++------ .../tools/llvm-objdump/Inputs/many-relocs.obj-i386 | Bin 0 -> 305 bytes test/tools/llvm-objdump/coff-many-relocs.test | 14 +++++++ 4 files changed, 53 insertions(+), 11 deletions(-) create mode 100644 test/tools/llvm-objdump/Inputs/many-relocs.obj-i386 create mode 100644 test/tools/llvm-objdump/coff-many-relocs.test diff --git a/include/llvm/Object/COFF.h b/include/llvm/Object/COFF.h index 31b7d6ea17..c2e7d52b91 100644 --- a/include/llvm/Object/COFF.h +++ b/include/llvm/Object/COFF.h @@ -250,6 +250,13 @@ struct coff_section { support::ulittle16_t NumberOfRelocations; support::ulittle16_t NumberOfLinenumbers; 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 { diff --git a/lib/Object/COFFObjectFile.cpp b/lib/Object/COFFObjectFile.cpp index 8036ab1812..5ad8f8443f 100644 --- a/lib/Object/COFFObjectFile.cpp +++ b/lib/Object/COFFObjectFile.cpp @@ -367,25 +367,46 @@ error_code COFFObjectFile::sectionContainsSymbol(DataRefImpl SecRef, relocation_iterator COFFObjectFile::section_rel_begin(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); DataRefImpl Ret; - if (Sec->NumberOfRelocations == 0) + if (Sec->NumberOfRelocations == 0) { Ret.p = 0; - else - Ret.p = reinterpret_cast(base() + Sec->PointerToRelocations); - + } else { + auto begin = reinterpret_cast( + base() + Sec->PointerToRelocations); + if (Sec->hasExtendedRelocations()) { + // Skip the first relocation entry repurposed to store the number of + // relocations. + begin++; + } + Ret.p = reinterpret_cast(begin); + } 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( + base + Sec->PointerToRelocations); + return FirstReloc->VirtualAddress; + } + return Sec->NumberOfRelocations; +} + relocation_iterator COFFObjectFile::section_rel_end(DataRefImpl Ref) const { const coff_section *Sec = toSec(Ref); DataRefImpl Ret; - if (Sec->NumberOfRelocations == 0) + if (Sec->NumberOfRelocations == 0) { Ret.p = 0; - else - Ret.p = reinterpret_cast( - reinterpret_cast( - base() + Sec->PointerToRelocations) - + Sec->NumberOfRelocations); - + } else { + auto begin = reinterpret_cast( + base() + Sec->PointerToRelocations); + uint32_t NumReloc = getNumberOfRelocations(Sec, base()); + Ret.p = reinterpret_cast(begin + NumReloc); + } return relocation_iterator(RelocationRef(Ret, this)); } diff --git a/test/tools/llvm-objdump/Inputs/many-relocs.obj-i386 b/test/tools/llvm-objdump/Inputs/many-relocs.obj-i386 new file mode 100644 index 0000000000..c13e235658 Binary files /dev/null and b/test/tools/llvm-objdump/Inputs/many-relocs.obj-i386 differ diff --git a/test/tools/llvm-objdump/coff-many-relocs.test b/test/tools/llvm-objdump/coff-many-relocs.test new file mode 100644 index 0000000000..d6d0d608b3 --- /dev/null +++ b/test/tools/llvm-objdump/coff-many-relocs.test @@ -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 -- cgit v1.2.3