mirror of https://github.com/Nonannet/pelfy.git
commit
b9f9032872
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "pelfy"
|
||||
version = "1.0.7"
|
||||
version = "1.0.8"
|
||||
authors = [
|
||||
{ name="Nicolas Kruse", email="nicolas.kruse@nonan.net" },
|
||||
]
|
||||
|
|
|
|||
|
|
@ -390,38 +390,42 @@ relocation_table_types = {
|
|||
},
|
||||
"EM_ARM": {
|
||||
0: ("R_ARM_NONE", 0, ""),
|
||||
1: ("R_ARM_PC24", 24, "S - P + A"),
|
||||
2: ("R_ARM_ABS32", 32, "S + A"),
|
||||
3: ("R_ARM_REL32", 32, "S - P + A"),
|
||||
4: ("R_ARM_PC13", 13, "S - P + A"),
|
||||
1: ("R_ARM_PC24", 24, "((S + A) | T) - P"),
|
||||
2: ("R_ARM_ABS32", 32, "(S + A) | T"),
|
||||
3: ("R_ARM_REL32", 32, "((S + A) | T) - P"),
|
||||
4: ("R_ARM_LDR_PC_G0", 12, "S + A - P"),
|
||||
5: ("R_ARM_ABS16", 16, "S + A"),
|
||||
6: ("R_ARM_ABS12", 12, "S + A"),
|
||||
7: ("R_ARM_THM_ABS5", 5, "S + A"),
|
||||
8: ("R_ARM_ABS8", 8, "S + A"),
|
||||
9: ("R_ARM_SBREL32", 32, "S - B + A"),
|
||||
10: ("R_ARM_THM_PC22", 22, "S - P + A"),
|
||||
11: ("R_ARM_THM_PC8", 8, "S - P + A"),
|
||||
12: ("Reserved", 0, ""),
|
||||
13: ("R_ARM_SWI24", 24, "S + A"),
|
||||
9: ("R_ARM_SBREL32", 32, "((S + A) | T) - B(S)"),
|
||||
10: ("R_ARM_THM_CALL", 22, "((S + A) | T) - P"),
|
||||
11: ("R_ARM_THM_PC8", 8, "S + A - Pa"),
|
||||
12: ("R_ARM_BREL_ADJ", 0, "ChangeIn[B(S)] + A"),
|
||||
13: ("R_ARM_TLS_DESC", 0, ""),
|
||||
14: ("R_ARM_THM_SWI8", 8, "S + A"),
|
||||
15: ("R_ARM_XPC25", 25, ""),
|
||||
16: ("R_ARM_THM_XPC22", 22, ""),
|
||||
28: ("R_ARM_CALL", 24, "((S + A) - P) >> 2"),
|
||||
29: ("R_ARM_JUMP24", 24, "((S + A) - P) >> 2"),
|
||||
30: ("R_ARM_TLS_DESC", 0, ""),
|
||||
32: ("R_ARM_ALU_PCREL_7_0", 7, "(S - P + A) & 0x000000FF"),
|
||||
33: ("R_ARM_ALU_PCREL_15_8", 15, "(S - P + A) & 0x0000FF00"),
|
||||
34: ("R_ARM_ALU_PCREL_23_15", 23, "(S - P + A) & 0x00FF0000"),
|
||||
35: ("R_ARM_LDR_SBREL_11_0", 11, "(S - B + A) & 0x00000FFF"),
|
||||
36: ("R_ARM_ALU_SBREL_19_12", 19, "(S - B + A) & 0x000FF000"),
|
||||
37: ("R_ARM_ALU_SBREL_27_20", 27, "(S - B + A) & 0x0FF00000"),
|
||||
38: ("R_ARM_RELABS32", 32, "S + A or S - P + A"),
|
||||
39: ("R_ARM_ROSEGREL32", 32, "S - E + A"),
|
||||
17: ("R_ARM_TLS_DTPMOD32", 0, "Module[S]"),
|
||||
18: ("R_ARM_TLS_DTPOFF32", 0, "S + A - TLS"),
|
||||
19: ("R_ARM_TLS_TPOFF32", 0, "S + A - tp"),
|
||||
20: ("R_ARM_COPY", 0, ""),
|
||||
21: ("R_ARM_GLOB_DAT", 0, "(S + A) | T"),
|
||||
22: ("R_ARM_JUMP_SLOT", 0, "(S + A) | T"),
|
||||
23: ("R_ARM_RELATIVE", 0, "B(S) + A"),
|
||||
24: ("R_ARM_GOTOFF32", 0, "((S + A) | T) - GOT_ORG"),
|
||||
25: ("R_ARM_BASE_PREL", 0, "B(S) + A - P"),
|
||||
26: ("R_ARM_GOT_BREL", 0, "GOT(S) + A - GOT_ORG"),
|
||||
27: ("R_ARM_PLT32", 0, "((S + A) | T) - P"),
|
||||
28: ("R_ARM_CALL", 24, "((S + A) | T) - P"),
|
||||
29: ("R_ARM_JUMP24", 24, "((S + A) | T) - P"),
|
||||
30: ("R_ARM_THM_JUMP24", 24, "((S + A) | T) - P"),
|
||||
40: ("R_ARM_V4BX", 0, ""),
|
||||
41: ("R_ARM_STKCHK", 0, ""),
|
||||
42: ("R_ARM_THM_STKCHK", 0, ""),
|
||||
43: ("R_ARM_MOVW_ABS_NC", 16, "S + A"),
|
||||
44: ("R_ARM_MOVT_ABS", 16, "S + A")
|
||||
42: ("R_ARM_PREL31", 31, "((S + A) | T) - P"),
|
||||
43: ("R_ARM_MOVW_ABS_NC", 16, "(S + A) | T"),
|
||||
44: ("R_ARM_MOVT_ABS", 16, "S + A"),
|
||||
47: ("R_ARM_THM_MOVW_ABS_NC", 16, "(S + A) | T"),
|
||||
48: ("R_ARM_THM_MOVT_ABS", 16, "S + A"),
|
||||
},
|
||||
"EM_AARCH64": {
|
||||
0: ("R_AARCH64_NONE", 0, ""),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Typical usage example:
|
|||
from . import _fields_data as fdat
|
||||
from . import _output_formatter
|
||||
from typing import TypeVar, Literal, Iterable, Generic, Iterator, Generator, Optional, Union
|
||||
import warnings
|
||||
|
||||
_T = TypeVar('_T')
|
||||
|
||||
|
|
@ -26,6 +27,14 @@ def open_elf_file(file_path: str) -> 'elf_file':
|
|||
return elf_file(f.read())
|
||||
|
||||
|
||||
def _sign_extend(value: int, bits: int) -> int:
|
||||
"""Sign-extend a value with given bit width to 32 bits."""
|
||||
sign_bit = 1 << (bits - 1)
|
||||
if value & sign_bit:
|
||||
return value - (1 << bits)
|
||||
return value
|
||||
|
||||
|
||||
class elf_symbol():
|
||||
"""A class for representing data of an ELF symbol
|
||||
|
||||
|
|
@ -42,6 +51,7 @@ class elf_symbol():
|
|||
offset_in_section: Position of first symbol byte
|
||||
relative to section start
|
||||
offset_in_file: Position of first symbol byte in object file
|
||||
size: size of symbol in bytes
|
||||
fields: All symbol header fields as dict
|
||||
"""
|
||||
|
||||
|
|
@ -71,19 +81,17 @@ class elf_symbol():
|
|||
self.thumb_mode = bool((file.architecture == 'EM_ARM') & fields['st_value'] & 1)
|
||||
self.offset_in_section = fields['st_value'] & ~int(self.thumb_mode)
|
||||
self.offset_in_file = self.section['sh_offset'] + self.offset_in_section if self.section else 0
|
||||
self.size = self.fields['st_size']
|
||||
|
||||
@property
|
||||
def data(self) -> bytes:
|
||||
"""Returns the binary data the symbol is pointing to.
|
||||
The offset in the ELF file is calculated by:
|
||||
sections[symbol.st_shndx].sh_offset + symbol.st_value
|
||||
"""
|
||||
assert self.section, 'This symbol is not associated to a data section'
|
||||
if self.section.type == 'SHT_NOBITS':
|
||||
return b'\x00' * self['st_size']
|
||||
else:
|
||||
offset = self.section['sh_offset'] + self['st_value']
|
||||
return self.file.read_bytes(offset, self['st_size'])
|
||||
return self.file.read_bytes(self.offset_in_file, self['st_size'])
|
||||
|
||||
@property
|
||||
def data_hex(self) -> str:
|
||||
|
|
@ -102,7 +110,7 @@ class elf_symbol():
|
|||
assert self.section and self.section.type == 'SHT_PROGBITS'
|
||||
for reloc in self.file.get_relocations():
|
||||
if reloc.target_section == self.section:
|
||||
offset = reloc['r_offset'] - self['st_value']
|
||||
offset = reloc['r_offset'] - self.offset_in_section
|
||||
if 0 <= offset < self['st_size']:
|
||||
ret.append(reloc)
|
||||
return relocation_list(ret)
|
||||
|
|
@ -528,7 +536,7 @@ class elf_file:
|
|||
if reloc_types and 'A' in reloc_types[relocation_type][2]:
|
||||
name = reloc_types[relocation_type][0]
|
||||
sh = self.sections[reloc_section['sh_info']]
|
||||
field = self.read_int(r_offset + sh['sh_offset'], 4, True)
|
||||
field = self.read_int(r_offset + sh['sh_offset'], 4, False)
|
||||
if name in ('R_386_PC32', 'R_386_32', 'R_X86_64_PC32', 'R_X86_64_PLT32', 'R_ARM_REL32', 'R_ARM_ABS32'):
|
||||
return field
|
||||
if name == 'R_ARM_MOVW_ABS_NC':
|
||||
|
|
@ -544,11 +552,45 @@ class elf_file:
|
|||
if imm24 & 0x800000:
|
||||
imm24 |= ~0xFFFFFF
|
||||
return imm24 << 2
|
||||
if '_THM_' in name:
|
||||
print('Warning: Thumb relocation addend extraction is not implemented')
|
||||
return 0
|
||||
if name == 'R_ARM_THM_PC22':
|
||||
# BL Encoding T2
|
||||
h1 = field & 0xFFFF
|
||||
h2 = (field >> 16) & 0xFFFF
|
||||
s = (h1 >> 10) & 0x1 # Bit 10 of h1
|
||||
imm10H = h1 & 0x3FF # Bits 9..0 of h1
|
||||
j1 = (h2 >> 13) & 0x1 # Bit 13 of h2
|
||||
j2 = (h2 >> 11) & 0x1 # Bit 11 of h2
|
||||
imm10L = (h2 >> 1) & 0x3FF # Bits 10..1 of h2
|
||||
i1 = ~(j1 ^ s) & 0x1
|
||||
i2 = ~(j2 ^ s) & 0x1
|
||||
imm22 = (s << 21) | (i1 << 20) | (i2 << 19) | (imm10H << 9) | imm10L
|
||||
imm32 = _sign_extend(imm22 << 1, 23) # Shift left by 1, then sign-extend 23 bits
|
||||
return imm32
|
||||
if name in ('R_ARM_THM_JUMP24', 'R_ARM_THM_CALL'):
|
||||
# B.W Encoding T4
|
||||
h1 = field & 0xFFFF
|
||||
h2 = (field >> 16) & 0xFFFF
|
||||
s = (h1 >> 10) & 0x1 # Bit 10 of h1
|
||||
imm10 = h1 & 0x3FF # Bits 9..0 of h1
|
||||
j1 = (h2 >> 13) & 0x1 # Bit 13 of h2
|
||||
j2 = (h2 >> 11) & 0x1 # Bit 11 of h2
|
||||
imm11 = h2 & 0x7FF # Bits 10..0 of h2
|
||||
i1 = ~(j1 ^ s) & 0x1
|
||||
i2 = ~(j2 ^ s) & 0x1
|
||||
imm24 = (s << 23) | (i1 << 22) | (i2 << 21) | (imm10 << 11) | imm11
|
||||
imm32 = _sign_extend(imm24 << 1, 25) # Shift left by 1, then sign-extend 25 bits
|
||||
return imm32
|
||||
if name == 'R_ARM_THM_MOVW_ABS_NC' or name == 'R_ARM_THM_MOVT_ABS':
|
||||
i = (field >> 10) & 1
|
||||
imm4 = field & 0xF
|
||||
imm3 = (field >> 28) & 0x7
|
||||
imm8 = (field >> 16) & 0xFF
|
||||
imm16 = imm8 | (imm3 << 8) | (i << 11) | (imm4 << 12)
|
||||
if name == 'R_ARM_THM_MOVT_ABS':
|
||||
return imm16 << 16
|
||||
return imm16
|
||||
if '_MIPS_' in name:
|
||||
print('Warning: MIPS relocations addend extraction is not implemented')
|
||||
warnings.warn('Warning: MIPS relocations addend extraction is not implemented', stacklevel=2)
|
||||
return 0
|
||||
raise NotImplementedError(f"Relocation addend extraction for {name} is not implemented")
|
||||
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
|
@ -0,0 +1,62 @@
|
|||
import pelfy._main as _main
|
||||
import os
|
||||
|
||||
|
||||
def test_arm_addend_extraction() -> None:
|
||||
# Path to the test object file
|
||||
obj_path = os.path.join('tests', 'obj', 'stencils_armv7_O3.o')
|
||||
elf = _main.open_elf_file(obj_path)
|
||||
|
||||
# Collect all ARM relocations
|
||||
reloc_addends: list[tuple[str, int, int, str]] = []
|
||||
for reloc in elf.get_relocations():
|
||||
if reloc.type.startswith('R_ARM'):
|
||||
reloc_addends.append((reloc.type, reloc['r_offset'], reloc['r_addend'], reloc.symbol.name))
|
||||
|
||||
# Reference values from stencils_armv7_O3.asm (addend = 0 for V4BX, -8 for JUMP24/CALL)
|
||||
reference = [
|
||||
('R_ARM_V4BX', 0xB4, 0, ''),
|
||||
('R_ARM_V4BX', 0xC0, 0, ''),
|
||||
('R_ARM_V4BX', 0xD0, 0, ''),
|
||||
('R_ARM_V4BX', 0x114, 0, ''),
|
||||
('R_ARM_V4BX', 0x144, 0, ''),
|
||||
('R_ARM_V4BX', 0x148, 0, ''),
|
||||
('R_ARM_JUMP24', 0x124, -8, '__aeabi_idiv0'),
|
||||
('R_ARM_JUMP24', 0x14, -8, 'auxsub_get_42'),
|
||||
('R_ARM_CALL', 0x10, -8, 'result_int'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_float_int'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_float_float'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_int_int'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_int_float'),
|
||||
('R_ARM_CALL', 0xC, -8, 'aux_get_42'),
|
||||
('R_ARM_JUMP24', 0x14, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0x4, -8, 'aux_get_42'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_float'),
|
||||
('R_ARM_JUMP24', 0x4, -8, 'result_int'),
|
||||
('R_ARM_JUMP24', 0x4, -8, 'result_float'),
|
||||
('R_ARM_JUMP24', 0x2C, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0x30, -8, 'sqrtf'),
|
||||
('R_ARM_JUMP24', 0x24, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0x28, -8, 'sqrtf'),
|
||||
('R_ARM_CALL', 0xC, -8, 'expf'),
|
||||
('R_ARM_JUMP24', 0x14, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0x4, -8, 'expf'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0xC, -8, 'logf'),
|
||||
('R_ARM_JUMP24', 0x14, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0x4, -8, 'logf'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0xC, -8, 'sinf'),
|
||||
('R_ARM_JUMP24', 0x14, -8, 'result_float'),
|
||||
('R_ARM_CALL', 0x4, -8, 'sinf'),
|
||||
('R_ARM_JUMP24', 0xC, -8, 'result_float'),
|
||||
]
|
||||
# For each reference, check that at least one matching relocation has the expected addend
|
||||
for ref_type, ref_offset, ref_addend, ref_symbol in reference:
|
||||
found = False
|
||||
addend = None
|
||||
for typ, offset, addend, symbol in reloc_addends:
|
||||
if typ == ref_type and offset == ref_offset and symbol == ref_symbol and addend == ref_addend:
|
||||
found = True
|
||||
break
|
||||
assert found, f"Missing or incorrect addend for {ref_type} offset=0x{ref_offset:X} symbol={ref_symbol} (value={addend}, expected {ref_addend})"
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
import pelfy._main as _main
|
||||
import os
|
||||
from typing import Union
|
||||
|
||||
|
||||
def test_thumb_addend_extraction() -> None:
|
||||
# Path to the test object file
|
||||
obj_path = os.path.join('tests', 'obj', 'stencils_armv7thumb_O3_THM_MOVW.o')
|
||||
elf = _main.open_elf_file(obj_path)
|
||||
|
||||
# Collect all relocations of interest
|
||||
reloc_addends: list[tuple[str, int, int, str]] = []
|
||||
for reloc in elf.get_relocations():
|
||||
if reloc.type.startswith('R_ARM_THM'):
|
||||
reloc_addends.append((reloc.type, reloc['r_offset'], reloc['r_addend'], reloc.symbol.name))
|
||||
|
||||
# Reference values from the .asm file (addend = 0 for all Thumb relocations)
|
||||
reference: list[tuple[str, Union[int, None], int, str]] = [
|
||||
('R_ARM_THM_MOVW_ABS_NC', None, 0, 'dummy_int'),
|
||||
('R_ARM_THM_MOVT_ABS', None, 0, 'dummy_int'),
|
||||
('R_ARM_THM_MOVW_ABS_NC', None, 0, 'dummy_float'),
|
||||
('R_ARM_THM_MOVT_ABS', None, 0, 'dummy_float'),
|
||||
('R_ARM_THM_JUMP24', 0x14, -4, 'auxsub_get_42'),
|
||||
('R_ARM_THM_CALL', 0xA, -4, 'result_int'),
|
||||
('R_ARM_THM_JUMP24', 0xA, -4, 'result_float_int'),
|
||||
('R_ARM_THM_JUMP24', 0xC, -4, 'result_float_float'),
|
||||
('R_ARM_THM_JUMP24', 0xA, -4, 'result_int_int'),
|
||||
('R_ARM_THM_JUMP24', 0xC, -4, 'result_int_float'),
|
||||
('R_ARM_THM_CALL', 0xA, -4, 'aux_get_42'),
|
||||
('R_ARM_THM_JUMP24', 0x12, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x2, -4, 'aux_get_42'),
|
||||
('R_ARM_THM_JUMP24', 0xA, -4, 'result_float'),
|
||||
('R_ARM_THM_JUMP24', 0x2, -4, 'result_int'),
|
||||
('R_ARM_THM_JUMP24', 0x4, -4, 'result_float'),
|
||||
('R_ARM_THM_JUMP24', 0x28, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x2C, -4, 'sqrtf'),
|
||||
('R_ARM_THM_JUMP24', 0x20, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x24, -4, 'sqrtf'),
|
||||
('R_ARM_THM_CALL', 0xA, -4, 'expf'),
|
||||
('R_ARM_THM_JUMP24', 0x12, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x2, -4, 'expf'),
|
||||
('R_ARM_THM_JUMP24', 0xA, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0xA, -4, 'logf'),
|
||||
('R_ARM_THM_JUMP24', 0x12, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x2, -4, 'logf'),
|
||||
('R_ARM_THM_JUMP24', 0xA, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0xA, -4, 'sinf'),
|
||||
('R_ARM_THM_JUMP24', 0x12, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x2, -4, 'sinf'),
|
||||
('R_ARM_THM_JUMP24', 0xA, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0xA, -4, 'cosf'),
|
||||
('R_ARM_THM_JUMP24', 0x12, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x2, -4, 'cosf'),
|
||||
('R_ARM_THM_JUMP24', 0xA, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0xA, -4, 'tanf'),
|
||||
('R_ARM_THM_JUMP24', 0x12, -4, 'result_float'),
|
||||
('R_ARM_THM_CALL', 0x2, -4, 'tanf'),
|
||||
]
|
||||
# For each reference, check that at least one matching relocation has the expected addend
|
||||
for ref_type, _, ref_addend, ref_symbol in reference:
|
||||
found = False
|
||||
addend = 0
|
||||
for typ, offset, addend, symbol in reloc_addends:
|
||||
if typ == ref_type and symbol == ref_symbol and addend == ref_addend:
|
||||
found = True
|
||||
break
|
||||
assert found, f"Missing or incorrect addend for {ref_type} {ref_symbol} (value={addend:X}, expected {ref_addend})"
|
||||
Loading…
Reference in New Issue