This commit is contained in:
Nicolas 2025-10-07 22:56:04 +02:00
parent 23be1b1cae
commit 59f3b162de
11 changed files with 157 additions and 42 deletions

3
inspect.sh Normal file
View File

@ -0,0 +1,3 @@
#!/bin/bash
objdump -D -b binary -m i386:x86-64 --adjust-vma=0x1000 bin/test_code.bin

View File

@ -354,7 +354,6 @@ def compile_to_instruction_list(node_list: Iterable[Node], sdb: stencil_database
for variable in variable_list:
lengths = sdb.var_size['dummy_' + variable.dtype]
print('variable_mem_layout', variable.dtype, lengths)
object_list.append((variable, offset, lengths))
offset += (lengths + 3) // 4 * 4
@ -455,6 +454,8 @@ class Target():
dw = binw.data_writer(self.sdb.byteorder)
dw.write_com(binw.Command.RUN_PROG)
dw.write_int(0)
#for s in self._variables:
# add_read_command(dw, self._variables, s)
dw.write_com(binw.Command.END_PROG)
assert coparun(dw.get_data()) > 0

View File

@ -2,24 +2,26 @@ from enum import Enum
from typing import Literal
import struct
ByteOrder = Literal['little', 'big']
Command = Enum('Command', [('ALLOCATE_DATA', 1), ('COPY_DATA', 2),
('ALLOCATE_CODE', 3), ('COPY_CODE', 4),
('PATCH_FUNC', 5), ('PATCH_OBJECT', 6),
('RUN_PROG', 64), ('READ_DATA', 65),
('END_PROG', 256), ('FREE_MEMORY', 257)])
COMMAND_SIZE = 4
class data_writer():
def __init__(self, byteorder: Literal['little', 'big']):
def __init__(self, byteorder: ByteOrder):
self._data: list[tuple[str, bytes, int]] = list()
self.byteorder: Literal['little', 'big'] = byteorder
self.byteorder: ByteOrder = byteorder
def write_int(self, value: int, num_bytes: int = 4, signed: bool = False) -> None:
self._data.append((f"INT {value}", value.to_bytes(length=num_bytes, byteorder=self.byteorder, signed=signed), 0))
def write_com(self, value: Enum, num_bytes: int = 4) -> None:
self._data.append((value.name, value.value.to_bytes(length=num_bytes, byteorder=self.byteorder, signed=False), 1))
def write_com(self, value: Command) -> None:
self._data.append((value.name, value.value.to_bytes(length=COMMAND_SIZE, byteorder=self.byteorder, signed=False), 1))
def write_byte(self, value: int) -> None:
self._data.append((f"BYTE {value}", bytes([value]), 0))
@ -52,3 +54,30 @@ class data_writer():
def to_file(self, path: str) -> None:
with open(path, 'wb') as f:
f.write(self.get_data())
class data_reader():
def __init__(self, data: bytes | bytearray, byteorder: ByteOrder):
self._data = data
self._index: int = 0
self.byteorder: ByteOrder = byteorder
def read_int(self, num_bytes: int = 4, signed: bool = False) -> int:
ret = int.from_bytes(self._data[self._index:self._index + num_bytes], byteorder=self.byteorder, signed=signed)
self._index += num_bytes
return ret
def read_com(self) -> Command:
com_value = int.from_bytes(self._data[self._index:self._index + COMMAND_SIZE], byteorder=self.byteorder)
ret = Command(com_value)
self._index += COMMAND_SIZE
return ret
def read_byte(self) -> int:
ret = self._data[self._index]
self._index += 1
return ret
def read_bytes(self, num_bytes: int) -> bytes:
ret = self._data[self._index:self._index + num_bytes]
self._index += num_bytes
return ret

View File

@ -9,7 +9,7 @@ def get_function_start() -> str:
return """
int function_start(){
result_int(0); // dummy call instruction before marker gets striped
asm volatile (".long 0xF27ECAFE");
asm volatile (".long 0x0F1F4400E2");
return 1;
}
"""
@ -19,7 +19,7 @@ def get_function_end() -> str:
return """
int function_end(){
result_int(0);
asm volatile (".long 0xF17ECAFE");
asm volatile (".long 0x0F1F4400E1");
return 1;
}
"""
@ -28,9 +28,9 @@ def get_function_end() -> str:
def get_op_code(op: str, type1: str, type2: str, type_out: str) -> str:
return f"""
void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{
asm volatile (".long 0xF17ECAFE");
asm volatile (".long 0x0F1F4400E1");
result_{type_out}_{type2}(arg1 {op_signs[op]} arg2, arg2);
asm volatile (".long 0xF27ECAFE");
asm volatile (".long 0x0F1F4400E2");
}}
"""
@ -38,9 +38,9 @@ def get_op_code(op: str, type1: str, type2: str, type_out: str) -> str:
def get_op_code_float(op: str, type1: str, type2: str) -> str:
return f"""
void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{
asm volatile (".long 0xF17ECAFE");
asm volatile (".long 0x0F1F4400E1");
result_float_{type2}((float)arg1 {op_signs[op]} arg2, arg2);
asm volatile (".long 0xF27ECAFE");
asm volatile (".long 0x0F1F4400E2");
}}
"""
@ -48,9 +48,9 @@ def get_op_code_float(op: str, type1: str, type2: str) -> str:
def get_op_code_int(op: str, type1: str, type2: str) -> str:
return f"""
void {op}_{type1}_{type2}({type1} arg1, {type2} arg2) {{
asm volatile (".long 0xF17ECAFE");
asm volatile (".long 0x0F1F4400E1");
result_int_{type2}((int)(arg1 {op_signs[op]} arg2), arg2);
asm volatile (".long 0xF27ECAFE");
asm volatile (".long 0x0F1F4400E2");
}}
"""
@ -70,9 +70,9 @@ def get_result_stubs2(type1: str, type2: str) -> str:
def get_read_reg0_code(type1: str, type2: str, type_out: str) -> str:
return f"""
void read_{type_out}_reg0_{type1}_{type2}({type1} arg1, {type2} arg2) {{
asm volatile (".long 0xF17ECAFE");
asm volatile (".long 0x0F1F4400E1");
result_{type_out}_{type2}(dummy_{type_out}, arg2);
asm volatile (".long 0xF27ECAFE");
asm volatile (".long 0x0F1F4400E2");
}}
"""
@ -80,9 +80,9 @@ def get_read_reg0_code(type1: str, type2: str, type_out: str) -> str:
def get_read_reg1_code(type1: str, type2: str, type_out: str) -> str:
return f"""
void read_{type_out}_reg1_{type1}_{type2}({type1} arg1, {type2} arg2) {{
asm volatile (".long 0xF17ECAFE");
asm volatile (".long 0x0F1F4400E1");
result_{type1}_{type_out}(arg1, dummy_{type_out});
asm volatile (".long 0xF27ECAFE");
asm volatile (".long 0x0F1F4400E2");
}}
"""
@ -90,10 +90,10 @@ def get_read_reg1_code(type1: str, type2: str, type_out: str) -> str:
def get_write_code(type1: str) -> str:
return f"""
void write_{type1}({type1} arg1) {{
asm volatile (".long 0xF17ECAFE");
asm volatile (".long 0x0F1F4400E1");
dummy_{type1} = arg1;
result_{type1}(arg1);
asm volatile (".long 0xF27ECAFE");
asm volatile (".long 0x0F1F4400E2");
}}
"""

View File

@ -5,11 +5,12 @@ from enum import Enum
ByteOrder = Literal['little', 'big']
START_MARKER = 0xF17ECAFE
END_MARKER = 0xF27ECAFE
MARKER_LENGTH = 4
START_MARKER = 0x0F1F4400E1 # Nop on x86-64
END_MARKER = 0x0F1F4400E2 # Nop on x86-64
MARKER_LENGTH = 5
LENGTH_CALL_INSTRUCTION = 5 # x86_64
# on x86_64: call or jmp instruction when tail call optimized
LENGTH_CALL_INSTRUCTION = 5
RelocationType = Enum('RelocationType', [('RELOC_RELATIVE_32', 0)])

View File

@ -45,9 +45,9 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
parse_commands(file_buff);
int ret = parse_commands(file_buff);
free_memory();
return EXIT_SUCCESS;
return ret < 0;
}

View File

@ -49,10 +49,10 @@ int parse_commands(uint8_t *bytes) {
uint32_t reloc_type;
uint32_t offs;
uint32_t size;
int err_flag = 0;
int end_flag = 0;
uint32_t rel_entr_point;
while(!err_flag) {
while(!end_flag) {
command = *(uint32_t*)bytes;
bytes += 4;
switch(command) {
@ -61,7 +61,7 @@ int parse_commands(uint8_t *bytes) {
data_memory = allocate_data_memory(size);
data_memory_len = size;
printf("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)data_memory);
if (!update_data_offs()) return EXIT_FAILURE;
if (!update_data_offs()) end_flag = -4;
break;
case COPY_DATA:
@ -77,7 +77,7 @@ int parse_commands(uint8_t *bytes) {
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);
if (!update_data_offs()) return EXIT_FAILURE;
if (!update_data_offs()) end_flag = -4;
break;
case COPY_CODE:
@ -126,20 +126,19 @@ int parse_commands(uint8_t *bytes) {
break;
case FREE_MEMORY:
size = *(uint32_t*)bytes; bytes += 4;
free_memory();
break;
case END_PROG:
printf("END_PROG\n");
err_flag = 1;
end_flag = 1;
break;
default:
printf("Unknown command\n");
return EXIT_FAILURE;
end_flag = -1;
break;
}
}
return EXIT_SUCCESS;
return end_flag;
}

View File

@ -13,11 +13,21 @@ def test_ast_generation():
#r1 = i1 + i3
#r2 = i3 * i2
#c1 = const(4)
#i1 = c1 * 2
#r1 = i1 + 7
#r2 = i1 + 9
#out = [Write(r1), Write(r2)]
c1 = const(4)
i1 = c1 * 2
r1 = i1 + 7
r2 = i1 + 9
out = [Write(r1), Write(r2)]
c2 = const(2)
#i1 = c1 * 2
#r1 = i1 + 7 + (c2 + 7 * 9)
#r2 = i1 + 9
#out = [Write(r1), Write(r2)]
r1 = c1 * 5 + 8 + c2 * 3
out = [Write(r1)]
print(out)
print('-- get_edges:')

View File

@ -48,10 +48,12 @@ def test_compile():
c1 = const(4)
c2 = const(2)
i1 = c1 * 2
r1 = i1 + 7 + (c2 + 7 * 9)
r2 = i1 + 9
out = [Write(r1), Write(r2)]
#i1 = c1 * 2
#r1 = i1 + 7 + (c2 + 7 * 9)
#r2 = i1 + 9
#out = [Write(r1), Write(r2)]
r1 = c1 * 5 + 8 + c2 * 3
out = [Write(r1)]
il, _ = copapy.compile_to_instruction_list(out, copapy.generic_sdb)

View File

@ -23,7 +23,7 @@ def test_compile():
tg.compile(ret)
#time.sleep(5)
print('* run and copy ...')
#tg.run()
tg.run()
#print('* finished')
ret_ref = function(4, 2)

70
tools/extract_code.py Normal file
View File

@ -0,0 +1,70 @@
from copapy.binwrite import data_reader, Command, ByteOrder
from copapy.stencil_db import RelocationType
input_file = "bin/test.copapy"
output_file = "bin/test_code.bin"
data_section_offset = 0x2000
byteorder: ByteOrder = 'little'
with open(input_file, mode='rb') as f:
dr = data_reader(f.read(), byteorder)
buffer_index: int = 0
end_flag: int = 0
program_data: bytearray = bytearray([])
while(end_flag == 0):
com = dr.read_com()
if com == Command.ALLOCATE_DATA:
size = dr.read_int()
print(f"ALLOCATE_DATA size={size}")
elif com == Command.ALLOCATE_CODE:
size = dr.read_int()
program_data = bytearray(size)
print(f"ALLOCATE_CODE size={size}")
elif com == Command.COPY_DATA:
offs = dr.read_int()
size = dr.read_int()
datab = dr.read_bytes(size)
print(f"COPY_DATA offs={offs} size={size} data={' '.join(hex(d) for d in datab)}")
elif com == Command.COPY_CODE:
offs = dr.read_int()
size = dr.read_int()
datab = dr.read_bytes(size)
program_data[offs:offs + size] = datab
print(f"COPY_CODE offs={offs} size={size} data={' '.join(hex(d) for d in datab[:5])}...")
elif com == Command.PATCH_FUNC:
offs = dr.read_int()
reloc_type = dr.read_int()
value = dr.read_int(signed=True)
print(f"PATCH_FUNC patch_offs={offs} reloc_type={reloc_type} value={value}")
elif com == Command.PATCH_OBJECT:
offs = dr.read_int()
reloc_type = dr.read_int()
value = dr.read_int(signed=True)
assert reloc_type == RelocationType.RELOC_RELATIVE_32.value
program_data[offs:offs + 4] = (value + data_section_offset).to_bytes(4, byteorder, signed=True)
print(f"PATCH_OBJECT patch_offs={offs} reloc_type={reloc_type} value={value}")
elif com == Command.RUN_PROG:
rel_entr_point = dr.read_int()
print(f"RUN_PROG rel_entr_point={rel_entr_point}")
elif com == Command.READ_DATA:
offs = dr.read_int()
size = dr.read_int()
print(f"READ_DATA offs={offs} size={size}")
elif com == Command.FREE_MEMORY:
print("READ_DATA")
elif com == Command.END_PROG:
print("END_PROG")
end_flag = 1
else:
assert False, f"Unknown command: {com}"
with open(output_file, mode='wb') as f:
f.write(program_data)
print('OK')