From 639a7b2d8d17fe5df22d760dd1b30a8d5be4f809 Mon Sep 17 00:00:00 2001 From: Dexrn ZacAttack Date: Thu, 20 Nov 2025 01:30:02 -0800 Subject: [PATCH 1/2] feat: mangler script (experimental) --- tools/mangle.py | 152 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 tools/mangle.py diff --git a/tools/mangle.py b/tools/mangle.py new file mode 100644 index 00000000..8dc3e6da --- /dev/null +++ b/tools/mangle.py @@ -0,0 +1,152 @@ +import argparse +import os +import sys +import subprocess +from anytree import Node, RenderTree, Resolver + +# @author Dexrn ZacAttack +# my least favorite language + +# https://www.geeksforgeeks.org/python/command-line-arguments-in-python/#using-argparse-module +parser = argparse.ArgumentParser(description = "Allows you to mangle symbols with our modified toolchain") +parser.add_argument("-d", "--decl", help = "Mangle a function declaration") +parser.add_argument("-g", "--gvar", help = "Mangle a global variable declaration") # bruh global is reserved in python +parser.add_argument("-i", "--imports", nargs='+', type=str, help = "Import a file") +parser.add_argument("-fwd", "--forwards", nargs='+', type=str, help = "Forward classes") +args = parser.parse_args() + +if len(sys.argv) == 1: + parser.print_help(sys.stderr) + sys.exit(1) + +sd = os.path.dirname(os.path.abspath(__file__)) +d = 'mangler' +f = os.path.join(sd, d, 'temp.cpp') +o = os.path.join(sd, d, 'a.out') +dt = "int" +dv = "0" +res = Resolver('name', relax=True) +clist = Node("Classes") + +os.makedirs(d, exist_ok=True) + + +with open(f, 'w') as t: + t.write("// Autogenerated by mangle.py\n") + t.write("#include \n\n") + if args.imports: + for i in args.imports: + if i == "string": + continue; + + t.write(f"#include <{i}>\n") + + t.write(f"#define DEFAULT_TYPE {dt}\n") + + if args.forwards: + for fwd in args.forwards: + p = fwd.split("::") + parent = clist + for cl in p: + t.write(f"class {cl} {{\n") + t.write("public:\n") + ex = next((c for c in parent.children if c.name == cl), None) + if ex: + node = ex + else: + node = Node(cl, line=t.tell(), parent=parent) + parent = node + + for cl in p: + t.write("\n};") + +if args.decl: + with open(f, 'a') as t: + p = args.decl[:args.decl.find("(")].split("::") + n = p[-1] + cls = p[:-1] + parent = clist + found = [] + for cl in cls: + ex = next((c for c in parent.children if c.name == cl), None) + if ex: + found.append(ex) + parent = ex + else: + break + + parent = clist + + for cl in cls: + if cl in [f.name for f in found]: + t.seek(found[[f.name for f in found].index(cl)].line) + + + if cl not in [f.name for f in found]: + t.write(f"class {cl} {{\n") + ex = next((c for c in parent.children if c.name == cl), None) + if ex: + node = ex + else: + node = Node(cl, line=t.tell(), parent=parent) + parent = node + + t.write("__attribute__((used))\n") + t.write(f" {"DEFAULT_TYPE " if p[-2] != n else ""}{n}{args.decl[args.decl.find('('):]} {{}}") + + for cl in cls: + if cl not in [f.name for f in found]: + t.write("\n};") +elif args.gvar: + with open(f, 'a') as t: + p = args.gvar.split("::") + n = p[-1] + cls = p[:-1] + parent = clist + found = [] + for cl in cls: + ex = next((c for c in parent.children if c.name == cl), None) + if ex: + found.append(ex) + parent = ex + else: + break + + parent = clist + + for cl in cls: + if cl in [f.name for f in found]: + t.seek(found[[f.name for f in found].index(cl)].line) + + + if cl not in [f.name for f in found]: + t.write(f"class {cl} {{\n") + ex = next((c for c in parent.children if c.name == cl), None) + if ex: + node = ex + else: + node = Node(cl, line=t.tell(), parent=parent) + parent = node + + t.write(f"static DEFAULT_TYPE {n};") + + for cl in cls: + if cl not in [f.name for f in found]: + t.write("\n};") + + t.write("\n__attribute__((used))\n") + t.write(f"DEFAULT_TYPE {args.gvar} = {dv};") + +c = subprocess.run([os.path.join(sd, "../toolchain/clang-4.0.1/bin/clang++"), "-stdlib=libc++", "-O3", "-g2", "-std=c++1z", "-fno-rtti", "-fno-exceptions", "-fno-strict-aliasing", "-c", "-Wno-return-type", f, "-o", o], + capture_output=True, text=True) + +if (c.stderr): + print(c.stderr) + +n = subprocess.run(["nm", o], + capture_output=True, text=True) + +print(n.stdout) +if (n.stderr): + print(n.stderr) + From 9164bf9a0755c9d87b1f1c3ca9dfa28857b12928 Mon Sep 17 00:00:00 2001 From: Dexrn ZacAttack Date: Thu, 20 Nov 2025 02:34:04 -0800 Subject: [PATCH 2/2] feat: add include paths and allow for static --- tools/mangle.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tools/mangle.py b/tools/mangle.py index 8dc3e6da..973b9f71 100644 --- a/tools/mangle.py +++ b/tools/mangle.py @@ -13,6 +13,7 @@ parser.add_argument("-g", "--gvar", help = "Mangle a global variable declaration") # bruh global is reserved in python parser.add_argument("-i", "--imports", nargs='+', type=str, help = "Import a file") parser.add_argument("-fwd", "--forwards", nargs='+', type=str, help = "Forward classes") +parser.add_argument("-s", "--static", type=bool, help = "Mark a declaration as static") args = parser.parse_args() if len(sys.argv) == 1: @@ -92,7 +93,11 @@ parent = node t.write("__attribute__((used))\n") - t.write(f" {"DEFAULT_TYPE " if p[-2] != n else ""}{n}{args.decl[args.decl.find('('):]} {{}}") + if args.static: + t.write(f" {"static DEFAULT_TYPE " if p[-2] != n else ""}{n}{args.decl[args.decl.find('('):]} {{}}") + else: + t.write(f" {"DEFAULT_TYPE " if p[-2] != n else ""}{n}{args.decl[args.decl.find('('):]} {{}}") + for cl in cls: if cl not in [f.name for f in found]: @@ -137,7 +142,7 @@ t.write("\n__attribute__((used))\n") t.write(f"DEFAULT_TYPE {args.gvar} = {dv};") -c = subprocess.run([os.path.join(sd, "../toolchain/clang-4.0.1/bin/clang++"), "-stdlib=libc++", "-O3", "-g2", "-std=c++1z", "-fno-rtti", "-fno-exceptions", "-fno-strict-aliasing", "-c", "-Wno-return-type", f, "-o", o], +c = subprocess.run([os.path.join(sd, "../toolchain/clang-4.0.1/bin/clang++"), f"-I{os.path.join(sd, '../src')}", f"-I{os.path.join(sd, '../src/Minecraft.World')}", f"-I{os.path.join(sd, '../src/4JLibraries_Source')}", f"-I{os.path.join(sd, '../src/Minecraft.Client')}", f"-I{os.path.join(sd, '../src/PlatformLibraries_Source')}", f"-I{os.path.join(sd, '../lib/nnheaders/include')}", "-stdlib=libc++", "-O3", "-g2", "-std=c++1z", "-fno-rtti", "-fno-exceptions", "-fno-strict-aliasing", "-c", "-Wno-return-type", f, "-o", o], capture_output=True, text=True) if (c.stderr):