Skip to content

Commit

Permalink
Fix R_MIPS_HI16 and R_MIPS_LO16 (#516)
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielBotnik authored Oct 2, 2024
1 parent e45626c commit d6530d3
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 2 deletions.
40 changes: 38 additions & 2 deletions cle/backends/elf/relocation/mips.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@

from __future__ import annotations

from ctypes import c_int16

from archinfo import Endness

from .generic import (
GenericAbsoluteAddendReloc,
GenericAbsoluteReloc,
Expand Down Expand Up @@ -52,11 +56,37 @@ class R_MIPS_TLS_DTPREL32(GenericTLSDoffsetReloc):


class R_MIPS_HI16(GenericAbsoluteReloc):

def find_matching_lo16_relocation(self):
current_hi16_index = self.owner.relocs.index(self)
return next(
reloc
for reloc in self.owner.relocs[current_hi16_index:]
if (self.symbol == reloc.symbol and type(reloc) is R_MIPS_LO16)
)

def relocate(self):
if not self.resolved:
return False

self.owner.memory.pack_word(self.dest_addr, self.value >> 16, size=2)
# Relocating R_MIPS_HI16 requires to know the value placed at the following R_MIPS_LO16 relocation
matching_lo16_reloc_dest_addr = self.find_matching_lo16_relocation().dest_addr

dest_addr = self.dest_addr
if self.arch.memory_endness == Endness.BE:
dest_addr += 2
matching_lo16_reloc_dest_addr += 2

matching_lo16_reloc_target_bytes = c_int16(
self.owner.memory.unpack_word(matching_lo16_reloc_dest_addr, size=2)
).value

target_value = (self.value + matching_lo16_reloc_target_bytes) - (
(self.value + matching_lo16_reloc_target_bytes) & 0xFFFF
)
target_value = (target_value >> 16) + self.owner.memory.unpack_word(dest_addr, size=2)

self.owner.memory.pack_word(dest_addr, target_value, size=2)
return True


Expand All @@ -65,7 +95,13 @@ def relocate(self):
if not self.resolved:
return False

self.owner.memory.pack_word(self.dest_addr, self.value & 0xFFFF, size=2)
dest_addr = self.dest_addr
if self.arch.memory_endness == Endness.BE:
dest_addr += 2

target_value = (self.value + self.owner.memory.unpack_word(dest_addr, size=2)) & 0xFFFF

self.owner.memory.pack_word(dest_addr, target_value, size=2)
return True


Expand Down
35 changes: 35 additions & 0 deletions tests/test_mips_relocations.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# pylint: disable=missing-class-docstring
from __future__ import annotations

import binascii
import os
import unittest

import cle

TEST_FILE = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
os.path.join("..", "..", "binaries", "tests"),
os.path.join("mips", "mips-hilo.o"),
)


class TestMipsRellocations(unittest.TestCase):

@staticmethod
def test_mips_hilo16():
# 0x21000: R_MIPS_HI16 3c080002 lui $t0, 2
# 0x21004: R_MIPS_HI16 3c090002 lui $t1, 2
# 0x21008: R_MIPS_LO16 21081004 addi $t0, $t0, 4100
# 0x2100c: R_MIPS_LO16 2108102c addi $t0, $t0, 4140
# 0x21010: R_MIPS_HI16 3c080003 lui $t0, 3
# 0x21014: R_MIPS_HI16 3c090004 lui $t1, 4
# 0x21018: R_MIPS_LO16 2108101c addi $t0, $t0, 4124
EXPECTED_RESULT = b"3c0800023c090002210810042108102c3c0800033c0900042108101c"

ld = cle.Loader(TEST_FILE, auto_load_libs=False, main_opts={"base_addr": 0x21000})
assert EXPECTED_RESULT == binascii.hexlify(ld.memory.load(0x21000, 0x1C))


if __name__ == "__main__":
unittest.main()

0 comments on commit d6530d3

Please sign in to comment.