Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

relocations(mips): fixed R_MIPS_HI16 and R_MIPS_LO16 #516

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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()
Loading