summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRui Ueyama <ruiu@google.com>2014-03-21 00:44:19 +0000
committerRui Ueyama <ruiu@google.com>2014-03-21 00:44:19 +0000
commit99995267aec69859a039670e3ba76c64f969b2bf (patch)
tree52728200aec3dfb7ab0c42e73ab4a26fc7b289f6
parentfab1a40a7b6133dec43fc9de7a6a36c7c719ed30 (diff)
downloadllvm-99995267aec69859a039670e3ba76c64f969b2bf.tar.gz
llvm-99995267aec69859a039670e3ba76c64f969b2bf.tar.bz2
llvm-99995267aec69859a039670e3ba76c64f969b2bf.tar.xz
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
-rw-r--r--include/llvm/Object/COFF.h7
-rw-r--r--lib/Object/COFFObjectFile.cpp43
-rw-r--r--test/tools/llvm-objdump/Inputs/many-relocs.obj-i386bin0 -> 305 bytes
-rw-r--r--test/tools/llvm-objdump/coff-many-relocs.test14
4 files changed, 53 insertions, 11 deletions
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<uintptr_t>(base() + Sec->PointerToRelocations);
-
+ } else {
+ 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));
}
+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 {
const coff_section *Sec = toSec(Ref);
DataRefImpl Ret;
- if (Sec->NumberOfRelocations == 0)
+ if (Sec->NumberOfRelocations == 0) {
Ret.p = 0;
- else
- Ret.p = reinterpret_cast<uintptr_t>(
- reinterpret_cast<const coff_relocation*>(
- base() + Sec->PointerToRelocations)
- + Sec->NumberOfRelocations);
-
+ } else {
+ auto begin = reinterpret_cast<const coff_relocation*>(
+ base() + Sec->PointerToRelocations);
+ uint32_t NumReloc = getNumberOfRelocations(Sec, base());
+ Ret.p = reinterpret_cast<uintptr_t>(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
--- /dev/null
+++ b/test/tools/llvm-objdump/Inputs/many-relocs.obj-i386
Binary files 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