diff --git a/src/copapy/__init__.py b/src/copapy/__init__.py index d8bce93..a02f29a 100644 --- a/src/copapy/__init__.py +++ b/src/copapy/__init__.py @@ -1,8 +1,6 @@ import re import pkgutil -from tkinter import Variable -from typing import Generator, Iterable, Any, Literal, TypeVar -import pelfy +from typing import Generator, Iterable, Any from . import binwrite as binw from .stencil_db import stencil_database @@ -361,14 +359,39 @@ def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_w # write auxiliary_functions # TODO - # write program - for net, node in extended_output_ops: + # Prepare program data and relocations + object_addr_lookp = {net: out_offs for net, out_offs, _ in object_list} + data_list: list[bytes] = [] + patch_list: list[tuple[int, int, int]] = [] + offset = 0 # offset in generated code chunk + + print('object_addr_lookp: ', object_addr_lookp) + + for result_net, node in extended_output_ops: assert node.name in sdb.function_definitions, f"- Warning: {node.name} prototype not found" data = sdb.get_func_data(node.name) + data_list.append(data) print('*', node.name, ' '.join(f'{d:02X}' for d in data)) - for reloc_offset, lengths, bits, reloc_type in sdb.get_relocs(node.name): - #if not relocation.symbol.name.startswith('result_'): - print(relocation) + + for patch in sdb.get_patch_positions(node.name): + assert result_net, f"Relocation found but no result net defined for operation {node.name}" + print('patch: ', patch) + object_addr = object_addr_lookp[result_net] + patch_list.append((patch.type.value, offset + patch.addr, object_addr)) + + offset += len(data) + + # write program data + dw.write_com(binw.Command.ALLOCATE_CODE) + dw.write_int(offset) + dw.write_bytes(b''.join(data_list)) + + # write relocations + for patch_type, patch_addr, object_addr in patch_list: + dw.write_com(binw.Command.PATCH_OBJECT) + dw.write_int(patch_addr) + dw.write_int(patch_type) + dw.write_int(object_addr) print('-----') diff --git a/src/copapy/binwrite.py b/src/copapy/binwrite.py index 34ec547..708c17f 100644 --- a/src/copapy/binwrite.py +++ b/src/copapy/binwrite.py @@ -3,28 +3,19 @@ from pelfy import elf_symbol from typing import Literal import struct + Command = Enum('Command', [('ALLOCATE_DATA', 1), ('COPY_DATA', 2), ('ALLOCATE_CODE', 3), ('COPY_CODE', 4), - ('RELOCATE_FUNC', 5), ('RELOCATE_OBJECT', 6), + ('PATCH_FUNC', 5), ('PATCH_OBJECT', 6), ('SET_ENTR_POINT', 64), ('END_PROG', 255)]) -RelocationType = Enum('RelocationType', [('RELOC_RELATIVE_32', 0)]) - -def translate_relocation(new_sym_addr: int, new_patch_addr: int, reloc_type: str, r_addend: int) -> tuple[int, int]: - if reloc_type in ('R_AMD64_PLT32', 'R_AMD64_PC32'): - # S + A - P - value = new_sym_addr + r_addend - new_patch_addr - return RelocationType.RELOC_RELATIVE_32.value, value - else: - raise Exception(f"Unknown: {reloc_type}") - def get_variable_data(symbols: list[elf_symbol]) -> tuple[list[tuple[elf_symbol, int, int]], int]: object_list: list[tuple[elf_symbol, int, int]] = [] out_offs = 0 for sym in symbols: assert sym.info == 'STT_OBJECT' - lengths = sym.fields['st_size'] + lengths = sym.fields['st_size'], object_list.append((sym, out_offs, lengths)) out_offs += (lengths + 3) // 4 * 4 return object_list, out_offs @@ -114,6 +105,6 @@ def get_c_consts() -> str: ret: list[str] = [] for c in Command: ret.append (f"#define {c.name} {c.value}") - for c in RelocationType: + for c in PatchType: ret.append(f"#define {c.name} {c.value}") return '\n'.join(ret) \ No newline at end of file diff --git a/src/copapy/stencil_db.py b/src/copapy/stencil_db.py index 2fe2853..e64249b 100644 --- a/src/copapy/stencil_db.py +++ b/src/copapy/stencil_db.py @@ -1,8 +1,7 @@ -from ast import Tuple -from os import name -from tkinter import NO +from dataclasses import dataclass import pelfy from typing import Generator, Literal +from enum import Enum start_marker = 0xF17ECAFE @@ -10,6 +9,30 @@ end_marker = 0xF27ECAFE LENGTH_CALL_INSTRUCTION = 4 # x86_64 +RelocationType = Enum('RelocationType', [('RELOC_RELATIVE_32', 0)]) + +@dataclass +class patch_entry: + """ + A class for representing a relocation entry + + Attributes: + addr (int): address of first byte to patch relative to the start of the symbol + type (RelocationType): relocation type""" + + type: RelocationType + addr: int + + +def translate_relocation(relocation_addr: int, reloc_type: str, bits: int, r_addend: int) -> patch_entry: + if reloc_type in ('R_AMD64_PLT32', 'R_AMD64_PC32'): + # S + A - P + patch_offset = relocation_addr - r_addend + return patch_entry(RelocationType.RELOC_RELATIVE_32, patch_offset) + else: + raise Exception(f"Unknown: {reloc_type}") + + def get_ret_function_def(symbol: pelfy.elf_symbol): #print('*', symbol.name, symbol.section) result_func = symbol.relocations[-1].symbol @@ -55,13 +78,8 @@ class stencil_database(): self.elf.symbols[name].data - def get_relocs(self, symbol_name: str) -> Generator[tuple[int, int, str], None, None]: - """Return relocation offset relative to striped symbol start. - Yields tuples of (reloc_offset, symbol_lenght, bits, reloc_type) - 1. reloc_offset: Offset of the relocation relative to the start of the stripped symbol data. - 2. Length of the striped symbol. - 3. Bits to patch - 4. reloc_type: Type of the relocation as a string. + def get_patch_positions(self, symbol_name: str) -> Generator[patch_entry, None, None]: + """Return patch positions """ symbol = self.elf.symbols[symbol_name] start_index = symbol.data.find(start_marker.to_bytes(4, symbol.file.byteorder)) @@ -69,10 +87,16 @@ class stencil_database(): for reloc in symbol.relocations: - reloc_offset = reloc.fields['r_offset'] - symbol.fields['st_value'] - start_index + # address to fist byte to patch relative to the start of the symbol + patch = translate_relocation( + reloc.fields['r_offset'] - symbol.fields['st_value'] - start_index, + reloc.type, + reloc.bits, + reloc.fields['r_addend']) - if reloc_offset < end_index - start_index - LENGTH_CALL_INSTRUCTION: - yield (reloc_offset, reloc.bits, reloc.type) + # Exclude the call to the result_x function + if patch.addr < end_index - start_index - LENGTH_CALL_INSTRUCTION: + yield patch def get_func_data(self, name: str) -> bytes: diff --git a/src/runner/runmem2.c b/src/runner/runmem2.c index 2db48b5..2513371 100644 --- a/src/runner/runmem2.c +++ b/src/runner/runmem2.c @@ -11,12 +11,12 @@ #define COPY_DATA 2 #define ALLOCATE_CODE 3 #define COPY_CODE 4 -#define RELOCATE_FUNC 5 -#define RELOCATE_OBJECT 6 +#define PATCH_FUNC 5 +#define PATCH_OBJECT 6 #define SET_ENTR_POINT 64 #define END_PROG 255 -#define RELOC_RELATIVE_32 0 +#define PATCH_RELATIVE_32 0 uint8_t *data_memory; uint8_t *executable_memory; @@ -53,8 +53,8 @@ void patch_mem_32(uint8_t *patch_addr, int32_t value){ *val_ptr = value; } -int relocate(uint8_t *patch_addr, uint32_t reloc_type, int32_t value){ - if (reloc_type == RELOC_RELATIVE_32){ +int patch(uint8_t *patch_addr, uint32_t reloc_type, int32_t value){ + if (reloc_type == PATCH_RELATIVE_32){ patch_mem_32(patch_addr, value); }else{ printf("Not implemented"); @@ -104,27 +104,27 @@ int parse_commands(uint8_t *bytes){ memcpy(executable_memory + offs, bytes, size); bytes += size; break; - case RELOCATE_FUNC: + case PATCH_FUNC: offs = *(uint32_t*)bytes; bytes += 4; reloc_type = *(uint32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4; - printf("RELOCATE_FUNC patch_offs=%i reloc_type=%i value=%i\n", + printf("PATCH_FUNC patch_offs=%i reloc_type=%i value=%i\n", offs, reloc_type, value); - relocate(executable_memory + offs, reloc_type, value); + patch(executable_memory + offs, reloc_type, value); break; - case RELOCATE_OBJECT: + case PATCH_OBJECT: offs = *(uint32_t*)bytes; bytes += 4; reloc_type = *(uint32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4; - printf("RELOCATE_OBJECT patch_offs=%i reloc_type=%i value=%i\n", + printf("PATCH_OBJECT patch_offs=%i reloc_type=%i value=%i\n", offs, reloc_type, value); data_offs = (int32_t)(data_memory - executable_memory); if (abs(data_offs) > 0x7FFFFFFF) { perror("code and data memory to far apart"); return EXIT_FAILURE; } - relocate(executable_memory + offs, reloc_type, value + (int32_t)data_offs); + patch(executable_memory + offs, reloc_type, value + (int32_t)data_offs); //printf("> %i\n", data_offs); break; diff --git a/tests/test_compile.py b/tests/test_compile.py index f822f53..8bc8f07 100644 --- a/tests/test_compile.py +++ b/tests/test_compile.py @@ -1,11 +1,5 @@ -#from diss_helper import dmprint -import pelfy -#from IPython.display import Markdown - -from typing import Literal -from copapy import Op, Write, const +from copapy import Write, const import copapy as rc -from copapy.binwrite import data_writer, Command, RelocationType, get_variable_data, get_function_data, translate_relocation def test_compile(): c1 = const(1.11) diff --git a/tests/test_stencil.db.py b/tests/test_stencil.db.py index cc0af9b..abdcb7e 100644 --- a/tests/test_stencil.db.py +++ b/tests/test_stencil.db.py @@ -5,5 +5,5 @@ if __name__ == "__main__": print('----') #print(sdb.function_definitions) for sym_name in sdb.function_definitions.keys(): - print('-', sym_name) - print(list(sdb.get_relocs(sym_name))) \ No newline at end of file + print('\n-', sym_name) + print(list(sdb.get_patch_positions(sym_name))) \ No newline at end of file