diff --git a/.gitignore b/.gitignore index c5541f6..781a906 100644 --- a/.gitignore +++ b/.gitignore @@ -1,13 +1,16 @@ -backend/index/* +/backend/index/* __pycache__ *.code-workspace *.egg.info /src/*.egg-info/* /dist/* .vscode +.venv .mypy_cache .pytest_cache -tests/autogenerated_*.py +/tests/autogenerated_*.py *test*.o -/src/copapy/obj/ops*.o -test.copapy \ No newline at end of file +test.copapy +token.txt +/src/copapy/obj/*.o +runmem2 diff --git a/build_ops_obj.sh b/build.sh similarity index 93% rename from build_ops_obj.sh rename to build.sh index 3b4c79d..a7ad068 100644 --- a/build_ops_obj.sh +++ b/build.sh @@ -7,4 +7,3 @@ gcc -c src/copapy/stencils.c -o src/copapy/obj/stencils_x86_64.o gcc -c src/copapy/stencils.c -O1 -o src/copapy/obj/stencils_x86_64_O1.o gcc -c src/copapy/stencils.c -O2 -o src/copapy/obj/stencils_x86_64_O2.o gcc -c src/copapy/stencils.c -O3 -o src/copapy/obj/stencils_x86_64_O3.o -ls -l src/copapy/obj/*.o diff --git a/pyproject.toml b/pyproject.toml index da58c50..f8ee4b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ authors = [ description = "Copy-Patch Compiler" readme = "README.md" requires-python = ">=3.10" -license = "MIT" +license = "GPL-3.0-only" classifiers = [ "Programming Language :: Python :: 3", "Operating System :: OS Independent", diff --git a/src/copapy/__init__.py b/src/copapy/__init__.py index 924e678..1e283ba 100644 --- a/src/copapy/__init__.py +++ b/src/copapy/__init__.py @@ -338,20 +338,30 @@ def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_w print('object_addr_lookp: ', object_addr_lookp) + data = sdb.get_func_data('function_start') + data_list.append(data) + offset += len(data) + 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)) + print(f"* {node.name} ({offset}) " + ' '.join(f'{d:02X}' for d in data)) for patch in sdb.get_patch_positions(node.name): assert result_net, f"Relocation found but no net defined for operation {node.name}" object_addr = object_addr_lookp[result_net] - print('patch: ', patch, offset + patch.addr) - patch_list.append((patch.type.value, offset + patch.addr, object_addr)) + patch_value = object_addr + patch.addend - (offset + patch.addr) + print('patch: ', patch, object_addr, patch_value) + patch_list.append((patch.type.value, offset + patch.addr, patch_value)) offset += len(data) + data = sdb.get_func_data('function_end') + data_list.append(data) + offset += len(data) + print('function_end', offset, data) + # allocate program data dw.write_com(binw.Command.ALLOCATE_CODE) dw.write_int(offset) @@ -367,7 +377,7 @@ def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_w dw.write_com(binw.Command.PATCH_OBJECT) dw.write_int(patch_addr) dw.write_int(patch_type) - dw.write_int(object_addr) + dw.write_int(object_addr, signed=True) # set entry point dw.write_com(binw.Command.SET_ENTR_POINT) diff --git a/src/copapy/generate_stencils.py b/src/copapy/generate_stencils.py index 6d3c237..bfa78fe 100644 --- a/src/copapy/generate_stencils.py +++ b/src/copapy/generate_stencils.py @@ -4,6 +4,22 @@ from typing import Generator op_signs = {'add': '+', 'sub': '-', 'mul': '*', 'div': '/'} +def get_function_start(): + return """ + void function_start(){ + result_int(0); + asm volatile (".long 0xF27ECAFE"); + } + """ + +def get_function_end(): + return """ + void function_end(){ + result_int(0); + asm volatile (".long 0xF17ECAFE"); + } + """ + def get_op_code(op: str, type1: str, type2: str, type_out: str): return f""" void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{ @@ -95,5 +111,7 @@ if __name__ == "__main__": for t1 in types: code += get_write_code(t1) + code += get_function_start() + get_function_end() + with open('src/copapy/stencils.c', 'w') as f: f.write(code) diff --git a/src/copapy/obj/stencils_x86_64.o b/src/copapy/obj/stencils_x86_64.o index 0af302f..d328f5c 100644 Binary files a/src/copapy/obj/stencils_x86_64.o and b/src/copapy/obj/stencils_x86_64.o differ diff --git a/src/copapy/obj/stencils_x86_64_O1.o b/src/copapy/obj/stencils_x86_64_O1.o index df5c0cc..8838584 100644 Binary files a/src/copapy/obj/stencils_x86_64_O1.o and b/src/copapy/obj/stencils_x86_64_O1.o differ diff --git a/src/copapy/obj/stencils_x86_64_O2.o b/src/copapy/obj/stencils_x86_64_O2.o index 5a06a56..3f6a64b 100644 Binary files a/src/copapy/obj/stencils_x86_64_O2.o and b/src/copapy/obj/stencils_x86_64_O2.o differ diff --git a/src/copapy/obj/stencils_x86_64_O3.o b/src/copapy/obj/stencils_x86_64_O3.o index 5a06a56..3f6a64b 100644 Binary files a/src/copapy/obj/stencils_x86_64_O3.o and b/src/copapy/obj/stencils_x86_64_O3.o differ diff --git a/src/copapy/stencil_db.py b/src/copapy/stencil_db.py index e64249b..44b2f8d 100644 --- a/src/copapy/stencil_db.py +++ b/src/copapy/stencil_db.py @@ -3,11 +3,13 @@ import pelfy from typing import Generator, Literal from enum import Enum +ByteOrder = Literal['little', 'big'] -start_marker = 0xF17ECAFE -end_marker = 0xF27ECAFE +START_MARKER = 0xF17ECAFE +END_MARKER = 0xF27ECAFE +MARKER_LENGTH = 4 -LENGTH_CALL_INSTRUCTION = 4 # x86_64 +LENGTH_CALL_INSTRUCTION = 5 # x86_64 RelocationType = Enum('RelocationType', [('RELOC_RELATIVE_32', 0)]) @@ -22,37 +24,45 @@ class patch_entry: type: RelocationType addr: int + addend: 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) + patch_offset = relocation_addr + return patch_entry(RelocationType.RELOC_RELATIVE_32, patch_offset, r_addend) 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 +def get_ret_function_def(symbol: pelfy.elf_symbol) -> str: + #print('*', symbol.name, len(symbol.relocations)) + if symbol.relocations: + result_func = symbol.relocations[-1].symbol - assert result_func.name.startswith('result_') - return result_func.name[7:] + assert result_func.name.startswith('result_') + return result_func.name[7:] + else: + return 'void' -def strip_symbol(data: bytes, byteorder: Literal['little', 'big']) -> bytes: +def strip_symbol(data: bytes, byteorder: ByteOrder) -> bytes: """Return data between start and end marker and removing last instruction (call)""" + start_index, end_index = get_stencil_position(data, byteorder) + return data[start_index:end_index] + +def get_stencil_position(data: bytes, byteorder: ByteOrder) -> tuple[int, int]: # Find first start marker - start_index = data.find(start_marker.to_bytes(4, byteorder)) + marker_index = data.find(START_MARKER.to_bytes(MARKER_LENGTH, byteorder)) + start_index = 0 if marker_index < 0 else marker_index + MARKER_LENGTH # Find last end marker - end_index = data.rfind(end_marker.to_bytes(4, byteorder), start_index) - - assert start_index > -1 and end_index > -1, f"Marker not found" - return data[start_index + 4:end_index - LENGTH_CALL_INSTRUCTION] + end_index = data.rfind(END_MARKER.to_bytes(MARKER_LENGTH, byteorder)) + end_index = len(data) if end_index < 0 else end_index - LENGTH_CALL_INSTRUCTION + return start_index, end_index class stencil_database(): @@ -82,9 +92,8 @@ class stencil_database(): """Return patch positions """ symbol = self.elf.symbols[symbol_name] - start_index = symbol.data.find(start_marker.to_bytes(4, symbol.file.byteorder)) - end_index = symbol.data.rfind(end_marker.to_bytes(4, symbol.file.byteorder), start_index) - + start_index, end_index = get_stencil_position(symbol.data, symbol.file.byteorder) + for reloc in symbol.relocations: # address to fist byte to patch relative to the start of the symbol @@ -94,8 +103,8 @@ class stencil_database(): reloc.bits, reloc.fields['r_addend']) - # Exclude the call to the result_x function - if patch.addr < end_index - start_index - LENGTH_CALL_INSTRUCTION: + # Exclude the call to the result_x function + if patch.addr < end_index - start_index: yield patch diff --git a/src/copapy/stencils.c b/src/copapy/stencils.c index ae52294..6dcd207 100644 --- a/src/copapy/stencils.c +++ b/src/copapy/stencils.c @@ -222,4 +222,14 @@ result_float(arg1); asm volatile (".long 0xF27ECAFE"); } + + void function_start(){ + result_int(0); + asm volatile (".long 0xF27ECAFE"); + } + + void function_end(){ + result_int(0); + asm volatile (".long 0xF17ECAFE"); + } \ No newline at end of file diff --git a/src/runner/runmem2.c b/src/runner/runmem2.c index 2513371..de1398b 100644 --- a/src/runner/runmem2.c +++ b/src/runner/runmem2.c @@ -71,6 +71,7 @@ int parse_commands(uint8_t *bytes){ int data_offs; uint32_t size; int err_flag = 0; + uint32_t rel_entr_point; while(!err_flag){ command = *(uint32_t*)bytes; @@ -78,8 +79,8 @@ int parse_commands(uint8_t *bytes){ switch(command) { case ALLOCATE_DATA: size = *(uint32_t*)bytes; bytes += 4; - printf("ALLOCATE_DATA size=%i\n", size); data_memory = get_data_memory(size); + printf("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)data_memory); break; case COPY_DATA: @@ -91,9 +92,9 @@ int parse_commands(uint8_t *bytes){ case ALLOCATE_CODE: size = *(uint32_t*)bytes; bytes += 4; - printf("ALLOCATE_CODE size=%i\n", size); executable_memory = get_executable_memory(size); executable_memory_len = size; + printf("ALLOCATE_CODE size=%i mem_addr=%p\n", size, (void*)executable_memory); //printf("# d %i c %i off %i\n", data_memory, executable_memory, data_offs); break; @@ -117,19 +118,19 @@ int parse_commands(uint8_t *bytes){ offs = *(uint32_t*)bytes; bytes += 4; reloc_type = *(uint32_t*)bytes; bytes += 4; value = *(int32_t*)bytes; bytes += 4; - printf("PATCH_OBJECT patch_offs=%i reloc_type=%i value=%i\n", - offs, reloc_type, value); data_offs = (int32_t)(data_memory - executable_memory); + //printf("PATCH_OBJECT patch_offs=%i reloc_type=%i value=%i data_offs=%i\n", + // offs, reloc_type, value, data_offs); if (abs(data_offs) > 0x7FFFFFFF) { perror("code and data memory to far apart"); return EXIT_FAILURE; } - patch(executable_memory + offs, reloc_type, value + (int32_t)data_offs); + patch(executable_memory + offs, reloc_type, value + data_offs); //printf("> %i\n", data_offs); break; case SET_ENTR_POINT: - uint32_t rel_entr_point = *(uint32_t*)bytes; bytes += 4; + rel_entr_point = *(uint32_t*)bytes; bytes += 4; printf("SET_ENTR_POINT rel_entr_point=%i\n", rel_entr_point); entr_point = (int (*)())(executable_memory + rel_entr_point); break; diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..feb7f06 --- /dev/null +++ b/test.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -e +echo "Compile..." +python tests/test_compile.py +echo "Run..." +echo "-----------------------------------" +gcc -Wall -Wextra -Wconversion -Wsign-conversion -Wshadow -Wstrict-overflow -Werror -g src/runner/runmem2.c -o runmem2 +./runmem2 test.copapy \ No newline at end of file diff --git a/tests/test_stencil.db.py b/tests/test_stencil.db.py index abdcb7e..a5bfe7a 100644 --- a/tests/test_stencil.db.py +++ b/tests/test_stencil.db.py @@ -1,9 +1,26 @@ from copapy import stencil_database +from copapy import stencil_db -if __name__ == "__main__": +def test_list_symbols(): sdb = stencil_database('src/copapy/obj/stencils_x86_64_O3.o') print('----') #print(sdb.function_definitions) for sym_name in sdb.function_definitions.keys(): print('\n-', sym_name) - print(list(sdb.get_patch_positions(sym_name))) \ No newline at end of file + print(list(sdb.get_patch_positions(sym_name))) + + +def test_start_end_function(): + sdb = stencil_database('src/copapy/obj/stencils_x86_64_O3.o') + for sym_name in sdb.function_definitions.keys(): + data = sdb.elf.symbols[sym_name].data + print('-', sym_name, stencil_db.get_stencil_position(data, sdb.elf.byteorder), len(data)) + + start, end = stencil_db.get_stencil_position(data, sdb.elf.byteorder) + + assert start>= 0 and end >= start and end <= len(data) + + +if __name__ == "__main__": + test_list_symbols() + test_start_end_function() \ No newline at end of file