no segfault anymore

This commit is contained in:
Nicolas 2025-09-30 23:11:14 +02:00
parent 8bb75ba58b
commit f53dd5ee51
14 changed files with 114 additions and 39 deletions

9
.gitignore vendored
View File

@ -1,13 +1,16 @@
backend/index/* /backend/index/*
__pycache__ __pycache__
*.code-workspace *.code-workspace
*.egg.info *.egg.info
/src/*.egg-info/* /src/*.egg-info/*
/dist/* /dist/*
.vscode .vscode
.venv
.mypy_cache .mypy_cache
.pytest_cache .pytest_cache
tests/autogenerated_*.py /tests/autogenerated_*.py
*test*.o *test*.o
/src/copapy/obj/ops*.o
test.copapy test.copapy
token.txt
/src/copapy/obj/*.o
runmem2

View File

@ -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 -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 -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 gcc -c src/copapy/stencils.c -O3 -o src/copapy/obj/stencils_x86_64_O3.o
ls -l src/copapy/obj/*.o

View File

@ -7,7 +7,7 @@ authors = [
description = "Copy-Patch Compiler" description = "Copy-Patch Compiler"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"
license = "MIT" license = "GPL-3.0-only"
classifiers = [ classifiers = [
"Programming Language :: Python :: 3", "Programming Language :: Python :: 3",
"Operating System :: OS Independent", "Operating System :: OS Independent",

View File

@ -338,20 +338,30 @@ def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_w
print('object_addr_lookp: ', object_addr_lookp) 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: for result_net, node in extended_output_ops:
assert node.name in sdb.function_definitions, f"- Warning: {node.name} prototype not found" assert node.name in sdb.function_definitions, f"- Warning: {node.name} prototype not found"
data = sdb.get_func_data(node.name) data = sdb.get_func_data(node.name)
data_list.append(data) 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): for patch in sdb.get_patch_positions(node.name):
assert result_net, f"Relocation found but no net defined for operation {node.name}" assert result_net, f"Relocation found but no net defined for operation {node.name}"
object_addr = object_addr_lookp[result_net] object_addr = object_addr_lookp[result_net]
print('patch: ', patch, offset + patch.addr) patch_value = object_addr + patch.addend - (offset + patch.addr)
patch_list.append((patch.type.value, offset + patch.addr, object_addr)) print('patch: ', patch, object_addr, patch_value)
patch_list.append((patch.type.value, offset + patch.addr, patch_value))
offset += len(data) 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 # allocate program data
dw.write_com(binw.Command.ALLOCATE_CODE) dw.write_com(binw.Command.ALLOCATE_CODE)
dw.write_int(offset) 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_com(binw.Command.PATCH_OBJECT)
dw.write_int(patch_addr) dw.write_int(patch_addr)
dw.write_int(patch_type) dw.write_int(patch_type)
dw.write_int(object_addr) dw.write_int(object_addr, signed=True)
# set entry point # set entry point
dw.write_com(binw.Command.SET_ENTR_POINT) dw.write_com(binw.Command.SET_ENTR_POINT)

View File

@ -4,6 +4,22 @@ from typing import Generator
op_signs = {'add': '+', 'sub': '-', 'mul': '*', 'div': '/'} 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): def get_op_code(op: str, type1: str, type2: str, type_out: str):
return f""" return f"""
void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{ void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{
@ -95,5 +111,7 @@ if __name__ == "__main__":
for t1 in types: for t1 in types:
code += get_write_code(t1) code += get_write_code(t1)
code += get_function_start() + get_function_end()
with open('src/copapy/stencils.c', 'w') as f: with open('src/copapy/stencils.c', 'w') as f:
f.write(code) f.write(code)

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -3,11 +3,13 @@ import pelfy
from typing import Generator, Literal from typing import Generator, Literal
from enum import Enum from enum import Enum
ByteOrder = Literal['little', 'big']
start_marker = 0xF17ECAFE START_MARKER = 0xF17ECAFE
end_marker = 0xF27ECAFE 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)]) RelocationType = Enum('RelocationType', [('RELOC_RELATIVE_32', 0)])
@ -22,37 +24,45 @@ class patch_entry:
type: RelocationType type: RelocationType
addr: int addr: int
addend: int
def translate_relocation(relocation_addr: int, reloc_type: str, bits: int, r_addend: int) -> patch_entry: 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'): if reloc_type in ('R_AMD64_PLT32', 'R_AMD64_PC32'):
# S + A - P # S + A - P
patch_offset = relocation_addr - r_addend patch_offset = relocation_addr
return patch_entry(RelocationType.RELOC_RELATIVE_32, patch_offset) return patch_entry(RelocationType.RELOC_RELATIVE_32, patch_offset, r_addend)
else: else:
raise Exception(f"Unknown: {reloc_type}") raise Exception(f"Unknown: {reloc_type}")
def get_ret_function_def(symbol: pelfy.elf_symbol): def get_ret_function_def(symbol: pelfy.elf_symbol) -> str:
#print('*', symbol.name, symbol.section) #print('*', symbol.name, len(symbol.relocations))
if symbol.relocations:
result_func = symbol.relocations[-1].symbol result_func = symbol.relocations[-1].symbol
assert result_func.name.startswith('result_') assert result_func.name.startswith('result_')
return result_func.name[7:] 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)""" """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 # 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 # Find last end marker
end_index = data.rfind(end_marker.to_bytes(4, byteorder), start_index) 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
assert start_index > -1 and end_index > -1, f"Marker not found"
return data[start_index + 4:end_index - LENGTH_CALL_INSTRUCTION]
return start_index, end_index
class stencil_database(): class stencil_database():
@ -82,8 +92,7 @@ class stencil_database():
"""Return patch positions """Return patch positions
""" """
symbol = self.elf.symbols[symbol_name] symbol = self.elf.symbols[symbol_name]
start_index = symbol.data.find(start_marker.to_bytes(4, symbol.file.byteorder)) start_index, end_index = get_stencil_position(symbol.data, symbol.file.byteorder)
end_index = symbol.data.rfind(end_marker.to_bytes(4, symbol.file.byteorder), start_index)
for reloc in symbol.relocations: for reloc in symbol.relocations:
@ -95,7 +104,7 @@ class stencil_database():
reloc.fields['r_addend']) reloc.fields['r_addend'])
# Exclude the call to the result_x function # Exclude the call to the result_x function
if patch.addr < end_index - start_index - LENGTH_CALL_INSTRUCTION: if patch.addr < end_index - start_index:
yield patch yield patch

View File

@ -223,3 +223,13 @@
asm volatile (".long 0xF27ECAFE"); asm volatile (".long 0xF27ECAFE");
} }
void function_start(){
result_int(0);
asm volatile (".long 0xF27ECAFE");
}
void function_end(){
result_int(0);
asm volatile (".long 0xF17ECAFE");
}

View File

@ -71,6 +71,7 @@ int parse_commands(uint8_t *bytes){
int data_offs; int data_offs;
uint32_t size; uint32_t size;
int err_flag = 0; int err_flag = 0;
uint32_t rel_entr_point;
while(!err_flag){ while(!err_flag){
command = *(uint32_t*)bytes; command = *(uint32_t*)bytes;
@ -78,8 +79,8 @@ int parse_commands(uint8_t *bytes){
switch(command) { switch(command) {
case ALLOCATE_DATA: case ALLOCATE_DATA:
size = *(uint32_t*)bytes; bytes += 4; size = *(uint32_t*)bytes; bytes += 4;
printf("ALLOCATE_DATA size=%i\n", size);
data_memory = get_data_memory(size); data_memory = get_data_memory(size);
printf("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)data_memory);
break; break;
case COPY_DATA: case COPY_DATA:
@ -91,9 +92,9 @@ int parse_commands(uint8_t *bytes){
case ALLOCATE_CODE: case ALLOCATE_CODE:
size = *(uint32_t*)bytes; bytes += 4; size = *(uint32_t*)bytes; bytes += 4;
printf("ALLOCATE_CODE size=%i\n", size);
executable_memory = get_executable_memory(size); executable_memory = get_executable_memory(size);
executable_memory_len = 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); //printf("# d %i c %i off %i\n", data_memory, executable_memory, data_offs);
break; break;
@ -117,19 +118,19 @@ int parse_commands(uint8_t *bytes){
offs = *(uint32_t*)bytes; bytes += 4; offs = *(uint32_t*)bytes; bytes += 4;
reloc_type = *(uint32_t*)bytes; bytes += 4; reloc_type = *(uint32_t*)bytes; bytes += 4;
value = *(int32_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); 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) { if (abs(data_offs) > 0x7FFFFFFF) {
perror("code and data memory to far apart"); perror("code and data memory to far apart");
return EXIT_FAILURE; 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); //printf("> %i\n", data_offs);
break; break;
case SET_ENTR_POINT: 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); printf("SET_ENTR_POINT rel_entr_point=%i\n", rel_entr_point);
entr_point = (int (*)())(executable_memory + rel_entr_point); entr_point = (int (*)())(executable_memory + rel_entr_point);
break; break;

8
test.sh Normal file
View File

@ -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

View File

@ -1,9 +1,26 @@
from copapy import stencil_database 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') sdb = stencil_database('src/copapy/obj/stencils_x86_64_O3.o')
print('----') print('----')
#print(sdb.function_definitions) #print(sdb.function_definitions)
for sym_name in sdb.function_definitions.keys(): for sym_name in sdb.function_definitions.keys():
print('\n-', sym_name) print('\n-', sym_name)
print(list(sdb.get_patch_positions(sym_name))) 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()