diff --git a/src/pelfy/_main.py b/src/pelfy/_main.py index e7db9a7..98e106d 100644 --- a/src/pelfy/_main.py +++ b/src/pelfy/_main.py @@ -27,51 +27,12 @@ def open_elf_file(file_path: str) -> 'elf_file': return elf_file(f.read()) -def _decode_thumb_branch_imm(field: int, bits: int) -> int: - """ - Decode Thumb-2 wide branch immediate. - bits: 22 (R_ARM_THM_PC22) or 24 (R_ARM_THM_JUMP24) - """ - - h1 = (field >> 16) & 0xFFFF - h2 = field & 0xFFFF - - S = (h1 >> 10) & 1 - imm10 = h1 & 0x03FF - J1 = (h2 >> 13) & 1 - J2 = (h2 >> 11) & 1 - imm11 = h2 & 0x07FF - - # Decode J1/J2 → I1/I2 - I1 = (~(J1 ^ S)) & 1 - I2 = (~(J2 ^ S)) & 1 - - if bits == 24: - imm = ( - (S << 23) | - (I1 << 22) | - (I2 << 21) | - (imm10 << 11) | - (imm11 << 0) - ) - sign_bit = 23 - else: - assert bits == 22 - imm = ( - (S << 21) | - (I1 << 20) | - (I2 << 19) | - (imm10 << 9) | - (imm11 << 0) - ) - sign_bit = 21 - - # Sign extend - if imm & (1 << sign_bit): - imm |= ~((1 << (sign_bit + 1)) - 1) - - # Thumb branch offsets are halfword aligned - return imm << 1 +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(): @@ -592,9 +553,33 @@ class elf_file: imm24 |= ~0xFFFFFF return imm24 << 2 if name == 'R_ARM_THM_PC22': - return _decode_thumb_branch_imm(field, 22) + # 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'): - return _decode_thumb_branch_imm(field, 24) + # 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 diff --git a/tests/test_arm_addend.py b/tests/test_arm_addend.py index 4365315..c77e986 100644 --- a/tests/test_arm_addend.py +++ b/tests/test_arm_addend.py @@ -1,7 +1,8 @@ import pelfy._main as _main import os -def test_arm_addend_extraction(): + +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) @@ -59,7 +60,3 @@ def test_arm_addend_extraction(): 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})" - - print(found, f"Missing or incorrect addend for {ref_type} offset=0x{ref_offset:X} symbol={ref_symbol} (value={addend}, expected {ref_addend})") - - assert False \ No newline at end of file diff --git a/tests/test_thumb_addend.py b/tests/test_thumb_addend.py index 99edd36..a31f276 100644 --- a/tests/test_thumb_addend.py +++ b/tests/test_thumb_addend.py @@ -1,7 +1,8 @@ import pelfy._main as _main import os -def test_thumb_addend_extraction(): + +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) @@ -13,46 +14,46 @@ def test_thumb_addend_extraction(): 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 = [ + reference: list[tuple[str, 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, 0, 'auxsub_get_42'), - ('R_ARM_THM_CALL', 0xA, 0, 'result_int'), - ('R_ARM_THM_JUMP24', 0xA, 0, 'result_float_int'), - ('R_ARM_THM_JUMP24', 0xC, 0, 'result_float_float'), - ('R_ARM_THM_JUMP24', 0xA, 0, 'result_int_int'), - ('R_ARM_THM_JUMP24', 0xC, 0, 'result_int_float'), - ('R_ARM_THM_CALL', 0xA, 0, 'aux_get_42'), - ('R_ARM_THM_JUMP24', 0x12, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x2, 0, 'aux_get_42'), - ('R_ARM_THM_JUMP24', 0xA, 0, 'result_float'), - ('R_ARM_THM_JUMP24', 0x2, 0, 'result_int'), - ('R_ARM_THM_JUMP24', 0x4, 0, 'result_float'), - ('R_ARM_THM_JUMP24', 0x28, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x2C, 0, 'sqrtf'), - ('R_ARM_THM_JUMP24', 0x20, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x24, 0, 'sqrtf'), - ('R_ARM_THM_CALL', 0xA, 0, 'expf'), - ('R_ARM_THM_JUMP24', 0x12, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x2, 0, 'expf'), - ('R_ARM_THM_JUMP24', 0xA, 0, 'result_float'), - ('R_ARM_THM_CALL', 0xA, 0, 'logf'), - ('R_ARM_THM_JUMP24', 0x12, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x2, 0, 'logf'), - ('R_ARM_THM_JUMP24', 0xA, 0, 'result_float'), - ('R_ARM_THM_CALL', 0xA, 0, 'sinf'), - ('R_ARM_THM_JUMP24', 0x12, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x2, 0, 'sinf'), - ('R_ARM_THM_JUMP24', 0xA, 0, 'result_float'), - ('R_ARM_THM_CALL', 0xA, 0, 'cosf'), - ('R_ARM_THM_JUMP24', 0x12, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x2, 0, 'cosf'), - ('R_ARM_THM_JUMP24', 0xA, 0, 'result_float'), - ('R_ARM_THM_CALL', 0xA, 0, 'tanf'), - ('R_ARM_THM_JUMP24', 0x12, 0, 'result_float'), - ('R_ARM_THM_CALL', 0x2, 0, 'tanf'), + ('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: