mirror of https://github.com/Nonannet/copapy.git
python module is working. no return values yet.
This commit is contained in:
parent
672a67837f
commit
6625da1a47
|
|
@ -14,3 +14,5 @@ test.copapy
|
||||||
token.txt
|
token.txt
|
||||||
/src/copapy/obj/*.o
|
/src/copapy/obj/*.o
|
||||||
runmem2
|
runmem2
|
||||||
|
src/*.so
|
||||||
|
bin/*
|
||||||
|
|
|
||||||
2
build.sh
2
build.sh
|
|
@ -9,5 +9,5 @@ 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
|
||||||
|
|
||||||
mkdir bin -p
|
mkdir bin -p
|
||||||
gcc -Wall -Wextra -Wconversion -Wsign-conversion -Wshadow -Wstrict-overflow -Werror -g src/coparun/coparun.c src/coparun/runmem.c -o bin/coparun
|
gcc -Wall -Wextra -Wconversion -Wsign-conversion -Wshadow -Wstrict-overflow -Werror -g src/coparun/runmem.c src/coparun/coparun.c -o bin/coparun
|
||||||
#x86_64-w64-mingw32-gcc -Wall -Wextra -Wconversion -Wsign-conversion -Wshadow -Wstrict-overflow -Werror src/runner/runmem2.c -Wall -O3 -o bin/runmem2.exe
|
#x86_64-w64-mingw32-gcc -Wall -Wextra -Wconversion -Wsign-conversion -Wshadow -Wstrict-overflow -Werror src/runner/runmem2.c -Wall -O3 -o bin/runmem2.exe
|
||||||
|
|
@ -30,9 +30,6 @@ where = ["src"]
|
||||||
[tool.setuptools.package-data]
|
[tool.setuptools.package-data]
|
||||||
copapy = ["*.o"]
|
copapy = ["*.o"]
|
||||||
|
|
||||||
[tool.setuptools.ext_modules]
|
|
||||||
coparun = { sources = ["src/coparun/coparun_module.c"] }
|
|
||||||
|
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
dev = [
|
dev = [
|
||||||
"flake8",
|
"flake8",
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
from setuptools import setup, Extension
|
||||||
|
|
||||||
|
ext = Extension(
|
||||||
|
"coparun_module",
|
||||||
|
sources=[
|
||||||
|
"src/coparun/coparun_module.c",
|
||||||
|
"src/coparun/runmem.c"
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
setup(
|
||||||
|
ext_modules=[ext],
|
||||||
|
)
|
||||||
|
|
@ -163,9 +163,11 @@ def stable_toposort(edges: Iterable[tuple[Node, Node]]) -> list[Node]:
|
||||||
pos = 0
|
pos = 0
|
||||||
for u, v in edges:
|
for u, v in edges:
|
||||||
if u not in order:
|
if u not in order:
|
||||||
order[u] = pos; pos += 1
|
order[u] = pos
|
||||||
|
pos += 1
|
||||||
if v not in order:
|
if v not in order:
|
||||||
order[v] = pos; pos += 1
|
order[v] = pos
|
||||||
|
pos += 1
|
||||||
adj[u].append(v)
|
adj[u].append(v)
|
||||||
indeg[v] += 1
|
indeg[v] += 1
|
||||||
indeg.setdefault(u, 0)
|
indeg.setdefault(u, 0)
|
||||||
|
|
@ -306,7 +308,6 @@ def compile_to_instruction_list(end_nodes: Iterable[Node] | Node) -> binw.data_w
|
||||||
|
|
||||||
# Get all nets associated with heap memory
|
# Get all nets associated with heap memory
|
||||||
variable_list = get_nets([[const_net_list]], extended_output_ops)
|
variable_list = get_nets([[const_net_list]], extended_output_ops)
|
||||||
assert(len(set(variable_list)) == len(variable_list)), 'Duplicates!'
|
|
||||||
|
|
||||||
dw = binw.data_writer(sdb.byteorder)
|
dw = binw.data_writer(sdb.byteorder)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ Command = Enum('Command', [('ALLOCATE_DATA', 1), ('COPY_DATA', 2),
|
||||||
('ALLOCATE_CODE', 3), ('COPY_CODE', 4),
|
('ALLOCATE_CODE', 3), ('COPY_CODE', 4),
|
||||||
('PATCH_FUNC', 5), ('PATCH_OBJECT', 6),
|
('PATCH_FUNC', 5), ('PATCH_OBJECT', 6),
|
||||||
('SET_ENTR_POINT', 64), ('READ_DATA', 65),
|
('SET_ENTR_POINT', 64), ('READ_DATA', 65),
|
||||||
('END_PROG', 255)])
|
('END_PROG', 256), ('FREE_MEMORY', 257)])
|
||||||
|
|
||||||
|
|
||||||
class data_writer():
|
class data_writer():
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "runmem.h"
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
if (argc != 2) {
|
||||||
|
fprintf(stderr, "Usage: %s <binary_file>\n", argv[0]);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open the file
|
||||||
|
int fd = open(argv[1], O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("open");
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get file size
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fd, &st) < 0) {
|
||||||
|
perror("fstat");
|
||||||
|
close(fd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (st.st_size == 0) {
|
||||||
|
fprintf(stderr, "Error: File is empty\n");
|
||||||
|
close(fd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//uint8_t *file_buff = get_data_memory((uint32_t)st.st_size);
|
||||||
|
uint8_t *file_buff = (uint8_t*)malloc((size_t)st.st_size);
|
||||||
|
|
||||||
|
// Read file into allocated memory
|
||||||
|
if (read(fd, file_buff, (long unsigned int)st.st_size) != st.st_size) {
|
||||||
|
perror("read");
|
||||||
|
close(fd);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
|
||||||
|
parse_commands(file_buff);
|
||||||
|
|
||||||
|
free_memory();
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -1,31 +1,46 @@
|
||||||
#define PY_SSIZE_T_CLEAN
|
#define PY_SSIZE_T_CLEAN
|
||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
|
#include "runmem.h"
|
||||||
|
|
||||||
// A simple C function exposed to Python
|
/*
|
||||||
static PyObject* my_function(PyObject* self, PyObject* args) {
|
* coparun(PyObject *self, PyObject *args)
|
||||||
int a, b;
|
* Accepts a Python `bytes` (or objects supporting the buffer protocol).
|
||||||
if (!PyArg_ParseTuple(args, "ii", &a, &b)) {
|
* We use the "y#" format in PyArg_ParseTuple which returns a pointer to
|
||||||
return NULL; // Error if arguments aren't two integers
|
* the internal bytes buffer and its length (Py_ssize_t). For safety and
|
||||||
}
|
* performance we pass that pointer directly to parse_commands which expects
|
||||||
return PyLong_FromLong(a + b); // Return sum as Python integer
|
* a uint8_t* buffer. If parse_commands needs the length, consider
|
||||||
|
* extending its API to accept a length parameter.
|
||||||
|
*/
|
||||||
|
static PyObject* coparun(PyObject* self, PyObject* args) {
|
||||||
|
const char *buf;
|
||||||
|
Py_ssize_t buf_len;
|
||||||
|
int result;
|
||||||
|
|
||||||
|
if (!PyArg_ParseTuple(args, "y#", &buf, &buf_len)) {
|
||||||
|
return NULL; /* TypeError set by PyArg_ParseTuple */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If parse_commands may run for a long time, release the GIL. */
|
||||||
|
Py_BEGIN_ALLOW_THREADS
|
||||||
|
result = parse_commands((uint8_t*)buf);
|
||||||
|
Py_END_ALLOW_THREADS
|
||||||
|
|
||||||
|
return PyLong_FromLong(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method definitions
|
|
||||||
static PyMethodDef MyMethods[] = {
|
static PyMethodDef MyMethods[] = {
|
||||||
{"add", my_function, METH_VARARGS, "Adds two numbers"},
|
{"coparun", coparun, METH_VARARGS, "Pass raw command data to coparun"},
|
||||||
{NULL, NULL, 0, NULL} // Sentinel
|
{NULL, NULL, 0, NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Module definition
|
static struct PyModuleDef coparun_module = {
|
||||||
static struct PyModuleDef my_module = {
|
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"my_module", // Module name
|
"coparun_module", // Module name
|
||||||
NULL, // Documentation
|
NULL, // Documentation
|
||||||
-1, // Size of per-interpreter state (-1 for global)
|
-1, // Size of per-interpreter state (-1 for global)
|
||||||
MyMethods
|
MyMethods
|
||||||
};
|
};
|
||||||
|
|
||||||
// Module initialization function
|
PyMODINIT_FUNC PyInit_coparun_module(void) {
|
||||||
PyMODINIT_FUNC PyInit_my_module(void) {
|
return PyModule_Create(&coparun_module);
|
||||||
return PyModule_Create(&my_module);
|
|
||||||
}
|
}
|
||||||
|
|
@ -6,23 +6,14 @@
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include "runmem.h"
|
||||||
|
|
||||||
#define ALLOCATE_DATA 1
|
/* Definitions for globals declared extern in runmem.h */
|
||||||
#define COPY_DATA 2
|
uint8_t *data_memory = NULL;
|
||||||
#define ALLOCATE_CODE 3
|
uint32_t data_memory_len = 0;
|
||||||
#define COPY_CODE 4
|
uint8_t *executable_memory = NULL;
|
||||||
#define PATCH_FUNC 5
|
uint32_t executable_memory_len = 0;
|
||||||
#define PATCH_OBJECT 6
|
entry_point_t entr_point = NULL;
|
||||||
#define SET_ENTR_POINT 64
|
|
||||||
#define READ_DATA 65
|
|
||||||
#define END_PROG 255
|
|
||||||
|
|
||||||
#define PATCH_RELATIVE_32 0
|
|
||||||
|
|
||||||
uint8_t *data_memory;
|
|
||||||
uint8_t *executable_memory;
|
|
||||||
uint32_t executable_memory_len;
|
|
||||||
int (*entr_point)();
|
|
||||||
|
|
||||||
uint8_t *get_executable_memory(uint32_t num_bytes){
|
uint8_t *get_executable_memory(uint32_t num_bytes){
|
||||||
// Allocate executable memory
|
// Allocate executable memory
|
||||||
|
|
@ -64,6 +55,13 @@ int patch(uint8_t *patch_addr, uint32_t reloc_type, int32_t value){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void free_memory(){
|
||||||
|
if (executable_memory_len) munmap(executable_memory, executable_memory_len);
|
||||||
|
if (data_memory_len) munmap(data_memory, data_memory_len);
|
||||||
|
data_memory_len = 0;
|
||||||
|
executable_memory_len = 0;
|
||||||
|
}
|
||||||
|
|
||||||
int parse_commands(uint8_t *bytes){
|
int parse_commands(uint8_t *bytes){
|
||||||
int32_t value;
|
int32_t value;
|
||||||
uint32_t command;
|
uint32_t command;
|
||||||
|
|
@ -78,9 +76,15 @@ int parse_commands(uint8_t *bytes){
|
||||||
command = *(uint32_t*)bytes;
|
command = *(uint32_t*)bytes;
|
||||||
bytes += 4;
|
bytes += 4;
|
||||||
switch(command) {
|
switch(command) {
|
||||||
|
case FREE_MEMORY:
|
||||||
|
size = *(uint32_t*)bytes; bytes += 4;
|
||||||
|
free_memory();
|
||||||
|
break;
|
||||||
|
|
||||||
case ALLOCATE_DATA:
|
case ALLOCATE_DATA:
|
||||||
size = *(uint32_t*)bytes; bytes += 4;
|
size = *(uint32_t*)bytes; bytes += 4;
|
||||||
data_memory = get_data_memory(size);
|
data_memory = get_data_memory(size);
|
||||||
|
data_memory_len = size;
|
||||||
printf("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)data_memory);
|
printf("ALLOCATE_DATA size=%i mem_addr=%p\n", size, (void*)data_memory);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -163,47 +167,3 @@ int parse_commands(uint8_t *bytes){
|
||||||
}
|
}
|
||||||
return err_flag;
|
return err_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
|
||||||
if (argc != 2) {
|
|
||||||
fprintf(stderr, "Usage: %s <binary_file>\n", argv[0]);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the file
|
|
||||||
int fd = open(argv[1], O_RDONLY);
|
|
||||||
if (fd < 0) {
|
|
||||||
perror("open");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get file size
|
|
||||||
struct stat st;
|
|
||||||
if (fstat(fd, &st) < 0) {
|
|
||||||
perror("fstat");
|
|
||||||
close(fd);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (st.st_size == 0) {
|
|
||||||
fprintf(stderr, "Error: File is empty\n");
|
|
||||||
close(fd);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
//uint8_t *file_buff = get_data_memory((uint32_t)st.st_size);
|
|
||||||
uint8_t *file_buff = (uint8_t*)malloc((size_t)st.st_size);
|
|
||||||
|
|
||||||
// Read file into allocated memory
|
|
||||||
if (read(fd, file_buff, (long unsigned int)st.st_size) != st.st_size) {
|
|
||||||
perror("read");
|
|
||||||
close(fd);
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
parse_commands(file_buff);
|
|
||||||
|
|
||||||
munmap(executable_memory, executable_memory_len);
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef RUNMEM_H
|
||||||
|
#define RUNMEM_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* Command opcodes used by the parser */
|
||||||
|
#define ALLOCATE_DATA 1
|
||||||
|
#define COPY_DATA 2
|
||||||
|
#define ALLOCATE_CODE 3
|
||||||
|
#define COPY_CODE 4
|
||||||
|
#define PATCH_FUNC 5
|
||||||
|
#define PATCH_OBJECT 6
|
||||||
|
#define SET_ENTR_POINT 64
|
||||||
|
#define READ_DATA 65
|
||||||
|
#define END_PROG 256
|
||||||
|
#define FREE_MEMORY 257
|
||||||
|
|
||||||
|
/* Relocation types */
|
||||||
|
#define PATCH_RELATIVE_32 0
|
||||||
|
|
||||||
|
/* Memory blobs accessible by other translation units */
|
||||||
|
extern uint8_t *data_memory;
|
||||||
|
extern uint32_t data_memory_len;
|
||||||
|
extern uint8_t *executable_memory;
|
||||||
|
extern uint32_t executable_memory_len;
|
||||||
|
|
||||||
|
/* Entry point type and variable */
|
||||||
|
typedef int (*entry_point_t)(void);
|
||||||
|
extern entry_point_t entr_point;
|
||||||
|
|
||||||
|
|
||||||
|
/* Command parser: takes a pointer to the command stream and returns
|
||||||
|
an error flag (0 on success according to current code) */
|
||||||
|
int parse_commands(uint8_t *bytes);
|
||||||
|
|
||||||
|
/* Free program and data memory */
|
||||||
|
void free_memory();
|
||||||
|
|
||||||
|
#endif /* RUNMEM_H */
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
from copapy import Write, const, Node
|
from copapy import Write, const
|
||||||
import copapy as rc
|
import copapy as rc
|
||||||
from typing import Iterable, Generator
|
|
||||||
|
|
||||||
|
|
||||||
def test_ast_generation():
|
def test_ast_generation():
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ from copapy import Write, const
|
||||||
import copapy
|
import copapy
|
||||||
import subprocess
|
import subprocess
|
||||||
import struct
|
import struct
|
||||||
from copapy import binwrite as binw
|
from copapy import binwrite
|
||||||
|
|
||||||
|
|
||||||
def run_command(command: list[str], encoding: str = 'utf8') -> str:
|
def run_command(command: list[str], encoding: str = 'utf8') -> str:
|
||||||
|
|
@ -60,12 +60,12 @@ def test_compile():
|
||||||
copapy.read_variable(il, r1)
|
copapy.read_variable(il, r1)
|
||||||
copapy.read_variable(il, r2)
|
copapy.read_variable(il, r2)
|
||||||
|
|
||||||
il.write_com(binw.Command.READ_DATA)
|
il.write_com(binwrite.Command.READ_DATA)
|
||||||
il.write_int(0)
|
il.write_int(0)
|
||||||
il.write_int(36)
|
il.write_int(36)
|
||||||
|
|
||||||
# run program command
|
# run program command
|
||||||
il.write_com(binw.Command.END_PROG)
|
il.write_com(binwrite.Command.END_PROG)
|
||||||
|
|
||||||
print('* Data to runner:')
|
print('* Data to runner:')
|
||||||
il.print()
|
il.print()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
from coparun_module import coparun
|
||||||
|
from copapy import Write, const
|
||||||
|
import copapy
|
||||||
|
from copapy import binwrite
|
||||||
|
|
||||||
|
|
||||||
|
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)]
|
||||||
|
|
||||||
|
il = copapy.compile_to_instruction_list(out)
|
||||||
|
|
||||||
|
copapy.read_variable(il, r1)
|
||||||
|
copapy.read_variable(il, r2)
|
||||||
|
|
||||||
|
il.write_com(binwrite.Command.READ_DATA)
|
||||||
|
il.write_int(0)
|
||||||
|
il.write_int(36)
|
||||||
|
|
||||||
|
# run program command
|
||||||
|
il.write_com(binwrite.Command.END_PROG)
|
||||||
|
|
||||||
|
#print('* Data to runner:')
|
||||||
|
#il.print()
|
||||||
|
|
||||||
|
print('+ run coparun')
|
||||||
|
result = coparun(il.get_data())
|
||||||
|
|
||||||
|
assert result == 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
test_compile()
|
||||||
Loading…
Reference in New Issue