from .sections import Section, Symbol
from .enums import ENUM_D_TAG
from .segments import Segment
-from .relocation import RelocationTable
+from .relocation import RelocationTable, RelrRelocationTable
from ..common.exceptions import ELFError
from ..common.utils import elf_assert, struct_parse, parse_cstring_from_stream
""" Load all available relocation tables from DYNAMIC tags.
Returns a dictionary mapping found table types (REL, RELA,
- JMPREL) to RelocationTable objects.
+ RELR, JMPREL) to RelocationTable objects.
"""
result = {}
elf_assert(result['RELA'].entry_size == relentsz,
'Expected DT_RELAENT to be %s' % relentsz)
+ if list(self.iter_tags('DT_RELR')):
+ result['RELR'] = RelrRelocationTable(self.elffile,
+ self.get_table_offset('DT_RELR')[1],
+ next(self.iter_tags('DT_RELRSZ'))['d_val'],
+ next(self.iter_tags('DT_RELRENT'))['d_val'])
+
if list(self.iter_tags('DT_JMPREL')):
result['JMPREL'] = RelocationTable(self.elffile,
self.get_table_offset('DT_JMPREL')[1],
'Expected sh_entsize of %s section to be %s' % (
header['sh_type'], self.entry_size))
-class RelrRelocationSection(Section):
- """ RELR compressed relocation section. This stores relative relocations
+
+class RelrRelocationTable(object):
+ """ RELR compressed relocation table. This stores relative relocations
in a compressed format. An entry with an even value serves as an
'anchor' that defines a base address. Following this entry are one or
more bitmaps for consecutive addresses after the anchor which determine
skipped. Addends are stored at the respective addresses (as in REL
relocations).
"""
- def __init__(self, header, name, elffile):
- Section.__init__(self, header, name, elffile)
- self._offset = self['sh_offset']
- self._size = self['sh_size']
- self._relr_struct = self.elffile.structs.Elf_Relr
+
+ def __init__(self, elffile, offset, size, entrysize):
+ self._elffile = elffile
+ self._offset = offset
+ self._size = size
+ self._relr_struct = self._elffile.structs.Elf_Relr
self._entrysize = self._relr_struct.sizeof()
self._cached_relocations = None
+ elf_assert(self._entrysize == entrysize,
+ 'Expected RELR entry size to be %s, got %s' % (
+ self._entrysize, entrysize))
+
def iter_relocations(self):
""" Yield all the relocations in the section
"""
+
+ # If DT_RELRSZ is zero, offset is meaningless and could be None.
+ if self._size == 0:
+ return []
+
limit = self._offset + self._size
relr = self._offset
# The addresses of relocations in a bitmap are calculated from a base
base = None
while relr < limit:
entry = struct_parse(self._relr_struct,
- self.elffile.stream,
+ self._elffile.stream,
stream_pos=relr)
entry_offset = entry['r_offset']
if (entry_offset & 1) == 0:
# beginning of the first bitmap.
base = entry_offset
base += self._entrysize
- yield Relocation(entry, self.elffile)
+ yield Relocation(entry, self._elffile)
else:
# We're processing a bitmap.
elf_assert(base is not None, 'RELR bitmap without base address')
if (entry_offset & 1) != 0:
calc_offset = base + i * self._entrysize
yield Relocation(Container(r_offset = calc_offset),
- self.elffile)
+ self._elffile)
i += 1
# Advance 'base' past the current bitmap (8 == CHAR_BIT). There
# are 63 (or 31 for 32-bit ELFs) entries in each bitmap, and
# every bit corresponds to an ELF_addr-sized relocation.
- base += (8 * self._entrysize - 1) * self.elffile.structs.Elf_addr('').sizeof()
+ base += (8 * self._entrysize - 1) * self._elffile.structs.Elf_addr('').sizeof()
# Advance to the next entry
relr += self._entrysize
self._cached_relocations = list(self.iter_relocations())
return self._cached_relocations[n]
+
+class RelrRelocationSection(Section, RelrRelocationTable):
+ """ ELF RELR relocation section. Serves as a collection of RELR relocation entries.
+ """
+ def __init__(self, header, name, elffile):
+ Section.__init__(self, header, name, elffile)
+ RelrRelocationTable.__init__(self, self.elffile,
+ self['sh_offset'], self['sh_size'], self['sh_entsize'])
+
+
class RelocationHandler(object):
""" Handles the logic of relocations in ELF files.
"""
self.assertEqual(relr_section.num_relocations(), 100)
def test_get_relocation(self):
- """ Verify we can get a specific relocation in a RELR relocation
- section.
+ """ Verify we can get a specific RELR relocation.
"""
path = os.path.join('test', 'testfiles_for_unittests',
'lib_relro.so.elf')
self.assertEqual(reloc['r_offset'], 0x4540)
reloc = relr_section.get_relocation(n=65)
self.assertEqual(reloc['r_offset'], 0x4748)
+
+ dynamic_section = elf.get_section_by_name('.dynamic')
+ self.assertIsNotNone(dynamic_section)
+ dynamic_relr = dynamic_section.get_relocation_tables()
+ self.assertIsNotNone(dynamic_relr)
+ self.assertIsNotNone(dynamic_relr['RELR'])
+ reloc = dynamic_relr['RELR'].get_relocation(n=0)
+ self.assertEqual(reloc['r_offset'], 0x4540)
+ reloc = dynamic_relr['RELR'].get_relocation(n=65)
+ self.assertEqual(reloc['r_offset'], 0x4748)