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 | 827c8a2b077466a008a93e69546b7902361df177 (patch) | |
| tree | b8b3b39d50a8d4cd5beed2bcba9b63c245cc9fb7 /llvm/lib | |
| parent | 56be75426286b324b209a0932967b2e79ef6cee4 (diff) | |
| download | bcm5719-llvm-827c8a2b077466a008a93e69546b7902361df177.tar.gz bcm5719-llvm-827c8a2b077466a008a93e69546b7902361df177.zip  | |
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
llvm-svn: 204418
Diffstat (limited to 'llvm/lib')
| -rw-r--r-- | llvm/lib/Object/COFFObjectFile.cpp | 43 | 
1 files changed, 32 insertions, 11 deletions
diff --git a/llvm/lib/Object/COFFObjectFile.cpp b/llvm/lib/Object/COFFObjectFile.cpp index 8036ab18127..5ad8f8443f7 100644 --- a/llvm/lib/Object/COFFObjectFile.cpp +++ b/llvm/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));  }  | 

