diff options
author | Rui Ueyama <ruiu@google.com> | 2014-03-21 00:44:19 +0000 |
---|---|---|
committer | Rui Ueyama <ruiu@google.com> | 2014-03-21 00:44:19 +0000 |
commit | 99995267aec69859a039670e3ba76c64f969b2bf (patch) | |
tree | 52728200aec3dfb7ab0c42e73ab4a26fc7b289f6 /lib/Object/COFFObjectFile.cpp | |
parent | fab1a40a7b6133dec43fc9de7a6a36c7c719ed30 (diff) | |
download | llvm-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
Diffstat (limited to 'lib/Object/COFFObjectFile.cpp')
-rw-r--r-- | lib/Object/COFFObjectFile.cpp | 43 |
1 files changed, 32 insertions, 11 deletions
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)); } |