mirror of https://github.com/Nonannet/copapy.git
no segfault anymore
This commit is contained in:
parent
8bb75ba58b
commit
f53dd5ee51
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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.
|
|
@ -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))
|
||||||
result_func = symbol.relocations[-1].symbol
|
if symbol.relocations:
|
||||||
|
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,9 +92,8 @@ 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:
|
||||||
|
|
||||||
# address to fist byte to patch relative to the start of the symbol
|
# address to fist byte to patch relative to the start of the symbol
|
||||||
|
|
@ -94,8 +103,8 @@ class stencil_database():
|
||||||
reloc.bits,
|
reloc.bits,
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,4 +222,14 @@
|
||||||
result_float(arg1);
|
result_float(arg1);
|
||||||
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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()
|
||||||
Loading…
Reference in New Issue