stecin_db and binwrite updated

This commit is contained in:
Nicolas Kruse 2025-09-21 23:08:30 +02:00
parent d4bc56f1db
commit 0ec9007033
6 changed files with 86 additions and 54 deletions

View File

@ -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('-----')

View File

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

View File

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

View File

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

View File

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

View File

@ -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)))
print('\n-', sym_name)
print(list(sdb.get_patch_positions(sym_name)))