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 re
import pkgutil import pkgutil
from tkinter import Variable from typing import Generator, Iterable, Any
from typing import Generator, Iterable, Any, Literal, TypeVar
import pelfy
from . import binwrite as binw from . import binwrite as binw
from .stencil_db import stencil_database 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 # write auxiliary_functions
# TODO # TODO
# write program # Prepare program data and relocations
for net, node in extended_output_ops: 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" 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)
print('*', node.name, ' '.join(f'{d:02X}' for d in 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_'): for patch in sdb.get_patch_positions(node.name):
print(relocation) 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('-----') print('-----')

View File

@ -3,28 +3,19 @@ from pelfy import elf_symbol
from typing import Literal from typing import Literal
import struct import struct
Command = Enum('Command', [('ALLOCATE_DATA', 1), ('COPY_DATA', 2), Command = Enum('Command', [('ALLOCATE_DATA', 1), ('COPY_DATA', 2),
('ALLOCATE_CODE', 3), ('COPY_CODE', 4), ('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)]) ('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]: def get_variable_data(symbols: list[elf_symbol]) -> tuple[list[tuple[elf_symbol, int, int]], int]:
object_list: list[tuple[elf_symbol, int, int]] = [] object_list: list[tuple[elf_symbol, int, int]] = []
out_offs = 0 out_offs = 0
for sym in symbols: for sym in symbols:
assert sym.info == 'STT_OBJECT' assert sym.info == 'STT_OBJECT'
lengths = sym.fields['st_size'] lengths = sym.fields['st_size'],
object_list.append((sym, out_offs, lengths)) object_list.append((sym, out_offs, lengths))
out_offs += (lengths + 3) // 4 * 4 out_offs += (lengths + 3) // 4 * 4
return object_list, out_offs return object_list, out_offs
@ -114,6 +105,6 @@ def get_c_consts() -> str:
ret: list[str] = [] ret: list[str] = []
for c in Command: for c in Command:
ret.append (f"#define {c.name} {c.value}") ret.append (f"#define {c.name} {c.value}")
for c in RelocationType: for c in PatchType:
ret.append(f"#define {c.name} {c.value}") ret.append(f"#define {c.name} {c.value}")
return '\n'.join(ret) return '\n'.join(ret)

View File

@ -1,8 +1,7 @@
from ast import Tuple from dataclasses import dataclass
from os import name
from tkinter import NO
import pelfy import pelfy
from typing import Generator, Literal from typing import Generator, Literal
from enum import Enum
start_marker = 0xF17ECAFE start_marker = 0xF17ECAFE
@ -10,6 +9,30 @@ end_marker = 0xF27ECAFE
LENGTH_CALL_INSTRUCTION = 4 # x86_64 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): def get_ret_function_def(symbol: pelfy.elf_symbol):
#print('*', symbol.name, symbol.section) #print('*', symbol.name, symbol.section)
result_func = symbol.relocations[-1].symbol result_func = symbol.relocations[-1].symbol
@ -55,13 +78,8 @@ class stencil_database():
self.elf.symbols[name].data self.elf.symbols[name].data
def get_relocs(self, symbol_name: str) -> Generator[tuple[int, int, str], None, None]: def get_patch_positions(self, symbol_name: str) -> Generator[patch_entry, None, None]:
"""Return relocation offset relative to striped symbol start. """Return patch positions
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.
""" """
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 = symbol.data.find(start_marker.to_bytes(4, symbol.file.byteorder))
@ -69,10 +87,16 @@ class stencil_database():
for reloc in symbol.relocations: 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: # Exclude the call to the result_x function
yield (reloc_offset, reloc.bits, reloc.type) if patch.addr < end_index - start_index - LENGTH_CALL_INSTRUCTION:
yield patch
def get_func_data(self, name: str) -> bytes: def get_func_data(self, name: str) -> bytes:

View File

@ -11,12 +11,12 @@
#define COPY_DATA 2 #define COPY_DATA 2
#define ALLOCATE_CODE 3 #define ALLOCATE_CODE 3
#define COPY_CODE 4 #define COPY_CODE 4
#define RELOCATE_FUNC 5 #define PATCH_FUNC 5
#define RELOCATE_OBJECT 6 #define PATCH_OBJECT 6
#define SET_ENTR_POINT 64 #define SET_ENTR_POINT 64
#define END_PROG 255 #define END_PROG 255
#define RELOC_RELATIVE_32 0 #define PATCH_RELATIVE_32 0
uint8_t *data_memory; uint8_t *data_memory;
uint8_t *executable_memory; uint8_t *executable_memory;
@ -53,8 +53,8 @@ void patch_mem_32(uint8_t *patch_addr, int32_t value){
*val_ptr = value; *val_ptr = value;
} }
int relocate(uint8_t *patch_addr, uint32_t reloc_type, int32_t value){ int patch(uint8_t *patch_addr, uint32_t reloc_type, int32_t value){
if (reloc_type == RELOC_RELATIVE_32){ if (reloc_type == PATCH_RELATIVE_32){
patch_mem_32(patch_addr, value); patch_mem_32(patch_addr, value);
}else{ }else{
printf("Not implemented"); printf("Not implemented");
@ -104,27 +104,27 @@ int parse_commands(uint8_t *bytes){
memcpy(executable_memory + offs, bytes, size); bytes += size; memcpy(executable_memory + offs, bytes, size); bytes += size;
break; break;
case RELOCATE_FUNC: case PATCH_FUNC:
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("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); offs, reloc_type, value);
relocate(executable_memory + offs, reloc_type, value); patch(executable_memory + offs, reloc_type, value);
break; break;
case RELOCATE_OBJECT: case PATCH_OBJECT:
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("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); offs, reloc_type, value);
data_offs = (int32_t)(data_memory - executable_memory); data_offs = (int32_t)(data_memory - executable_memory);
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;
} }
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); //printf("> %i\n", data_offs);
break; break;

View File

@ -1,11 +1,5 @@
#from diss_helper import dmprint from copapy import Write, const
import pelfy
#from IPython.display import Markdown
from typing import Literal
from copapy import Op, Write, const
import copapy as rc import copapy as rc
from copapy.binwrite import data_writer, Command, RelocationType, get_variable_data, get_function_data, translate_relocation
def test_compile(): def test_compile():
c1 = const(1.11) c1 = const(1.11)

View File

@ -5,5 +5,5 @@ if __name__ == "__main__":
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('-', sym_name) print('\n-', sym_name)
print(list(sdb.get_relocs(sym_name))) print(list(sdb.get_patch_positions(sym_name)))