dol2asm OK

This commit is contained in:
Julgodis
2021-03-28 22:49:05 +02:00
parent 88eb837a9c
commit d244b7cb0d
60106 changed files with 4755966 additions and 1107376 deletions
@@ -0,0 +1,4 @@
from .base import *
from .asm import *
from .ret import *
+135
View File
@@ -0,0 +1,135 @@
import struct
from dataclasses import dataclass, field
from typing import List, Set, Dict
from pathlib import Path
from ...builder import AsyncBuilder
from ...disassemble import AccessCollector
from ... import util
from ..base import *
from ..symbol import *
from .base import *
"""
@dataclass(eq=False)
class Block(ArbitraryData):
sda_hack_references: Set[int] = field(default=None, repr=False)
def _get_internal_references(self, context, symbol_table):
collector = AccessCollector([])
for x in collector.execute_generator(self.addr, self.data, self.size):
pass
sda_hack_symbols = [symbol_table[self._module, x]
for x in collector.sda_hack_references]
self.sda_hack_references = set([
(x._module, x.addr)
for x in sda_hack_symbols
if x
])
symbols = [
symbol_table[self._module, x.addr]
for x in collector.accesses.values()
]
return set([(x._module, x.addr) for x in symbols if x])
"""
@dataclass
class Block():
identifier: Identifier
addr: int
size: int
@property
def start(self):
return self.addr
@property
def end(self):
return self.addr + self.size
def asm_reference(self, addr):
if addr != self.addr:
return None
return self.identifier.label
from .. import static_analyze
@dataclass(eq=False)
class ASMFunction(Function):
blocks: List[Block] = field(default_factory=list, repr=False)
include_path: Path = None
asm: bool = True
data: bytearray = None
def gather_references(self, context, valid_range):
addrs = static_analyze.function(self.data, self.addr, self.size)
function_range = AddressRange(self.start, self.end)
self.references = [
addr
for addr in addrs.values()
if addr in valid_range and not addr in function_range
]
async def export_function_body(self, exporter, builder: AsyncBuilder):
await builder.write(f" {{")
await builder.write(f"\tnofralloc")
await builder.write(f"#include \"{self.include_path}\"")
await builder.write(f"}}")
async def export_declaration(self, exporter, builder: AsyncBuilder):
assert self.padding == 0
await builder.write("#pragma push")
await builder.write("#pragma optimization_level 0")
await builder.write("#pragma optimizewithasm off")
if self.alignment:
await builder.write(f"#pragma function_align {self.alignment}")
await self.export_function_header(exporter, builder, forward=False, specialize_templates=self.has_template)
await self.export_function_body(exporter, builder)
await builder.write("#pragma pop")
await builder.write("")
@staticmethod
def create(section, group):
first = group[0]
last = group[-1]
start = first.start
end = last.end
blocks = []
for symbol in group:
#block = Block(
# Identifier("lbl", symbol.addr, None),
# symbol.addr, symbol.size,
# data=section.data_for_symbol(symbol))
block = Block(
Identifier("lbl", symbol.addr, None),
symbol.addr, symbol.size,
)
blocks.append(block)
# Calculate additional padding from zeros at the end of the function
data = section.get_data(start, end)
end_padding = 0
last_data = list(util.chunks(data, 4))
for x in last_data[::-1]:
if struct.unpack('>I', x)[0] != 0:
break
end_padding += 4
if end_padding > 0:
data = data[:-end_padding]
end -= end_padding
return ASMFunction(
Identifier("func", start, first.name),
addr=start,
size=end - start,
padding=last.padding + end_padding,
alignment=0,
blocks=blocks,
source=first.source,
data=data)
+190
View File
@@ -0,0 +1,190 @@
import libdemangle
from dataclasses import dataclass, field
from typing import List
from ...builder import AsyncBuilder
from ... import util
from ...types import *
from ..symbol import *
special_func_no_return = set([
"ct",
"dt"
])
@dataclass(eq=False)
class Function(Symbol):
return_type: Type = None
argument_types: List[Type] = field(default_factory=list)
func_name: libdemangle.QualifiedName = None
special_func_name: str = None
func_is_const: bool = False
template_index: int = -1
asm: bool = False
@property
def label(self):
return self.identifier.label
def function_name(self,
original: bool = False,
full_qualified_name: bool = True,
without_template: bool = False,
specialize_templates: bool = False):
if not self.func_name or original:
return self.identifier.label
name = self.func_name
if self.special_func_name and self.has_class and specialize_templates:
# fix up the constructor and destructor if the function is template specialized
special_name = None
if self.special_func_name == "ct":
special_name = name.second_last.to_str(specialize_templates=specialize_templates,
without_template=without_template)
if self.special_func_name == "dt":
special_name = "~" + name.second_last.to_str(specialize_templates=specialize_templates,
without_template=without_template)
if special_name:
name = NamedType(
self.func_name.names[:-1] + [ClassName(special_name, [])])
if full_qualified_name:
return name.to_str(specialize_templates=specialize_templates,
without_template=without_template)
else:
return name.last.to_str(specialize_templates=specialize_templates,
without_template=without_template)
def is_demangled(self):
return self.func_name != None
def valid_reference(self, addr):
return addr % 4 == 0
def cpp_reference(self, accessor, addr):
if addr == self.addr:
return self.label
else:
offset = addr - self.addr
return f"(((char*){self.label})+0x{offset:X})"
def relocation_symbols(self, context, symbol_table, section):
symbols = section.relocations_in_range(symbol_table, self.start, self.end)
return symbols
def types(self):
return set()
@property
def has_class(self):
return self.func_name and self.func_name.has_class
@property
def has_template(self):
return self.func_name and self.func_name.has_template
async def export_function_header(self, exporter,
builder: AsyncBuilder,
forward: bool,
original: bool = False,
full_qualified_name: bool = True,
specialize_templates: bool = False,
without_template: bool = False,
comment_arguments: bool = False,
template_args: List[str] = None):
# prints internal references for the function
if False:
if not forward:
refs = self.internal_references(exporter.context, exporter.gst)
await builder.write(f"/* internal references (count {len(refs)})")
for ref in refs:
await builder.write(f"// {ref.addr:08X} {ref.label}")
declspec = "extern \"C\" "
if not original and self.is_demangled():
declspec = ""
if self._section == ".init":
declspec = "SECTION_INIT "
await builder.write_nonewline(f"{declspec}")
if self.asm and not forward:
await builder.write_nonewline(f"asm ")
if full_qualified_name and not self.has_class:
# this symbol is only referenced by other symbol in the same translation unit
if self.is_static:
await builder.write_nonewline(f"static ")
if not self.special_func_name in special_func_no_return or original:
return_type = self.return_type
if not self.return_type:
return_type = VOID
await builder.write_nonewline(f"{return_type.type(specialize_templates,without_template)} ")
await builder.write_nonewline(f"{self.function_name(original, full_qualified_name, without_template, specialize_templates)}")
arg_type = ""
if not original and self.is_demangled():
if forward:
arg_type = ", ".join([x.type(specialize_templates,without_template) for x in self.argument_types])
else:
arg_type = ", ".join([x.decl(f"param_{i}",specialize_templates,without_template) for i, x in zip(
range(len(self.argument_types)), self.argument_types)])
if template_args:
args = ", ".join(template_args)
await builder.write_nonewline(f"<{args}>")
if comment_arguments:
arg_type = f"/* {arg_type} */"
await builder.write_nonewline(f"({arg_type})")
if not original and self.has_class and self.func_is_const:
await builder.write_nonewline(f" const")
async def export_forward_references(self, exporter,
builder: AsyncBuilder,
c_export: bool = False,
full_qualified_name: bool = True,
template_args: List[str] = None):
if not template_args:
template_args = []
if c_export:
# export unmangled name
await self.export_function_header(exporter, builder, forward=True, original=True)
await builder.write(f";")
return
if full_qualified_name:
if self.is_demangled():
# forward references are not written for class functions
if not self.has_class:
await self.export_function_header(exporter, builder, forward=True, full_qualified_name=True, specialize_templates=True)
await builder.write(f";")
else:
# export the function as a class method
await self.export_function_header(exporter, builder, forward=True, full_qualified_name=False, template_args=template_args)
await builder.write(f";")
async def export_function_body(self, exporter, builder: AsyncBuilder):
assert False
async def export_declaration(self, exporter, builder: AsyncBuilder):
assert self.padding == 0
if self.alignment:
await builder.write("#pragma push")
await builder.write(f"#pragma function_align {self.alignment}")
await self.export_function_header(exporter, builder, forward=False, specialize_templates=self.has_template)
await self.export_function_body(exporter, builder)
if self.alignment:
await builder.write("#pragma pop")
await builder.write("")
+21
View File
@@ -0,0 +1,21 @@
from dataclasses import dataclass, field
from ...builder import AsyncBuilder
from .base import *
@dataclass(eq=False)
class ReturnFunction(Function):
return_value: str = None
def export_return_value(self):
return self.return_value
async def export_function_body(self, exporter, builder: AsyncBuilder):
return_value = self.export_return_value()
await builder.write(f" {{")
if return_value:
await builder.write(f"\treturn {return_value};")
else:
await builder.write(f"\t/* empty function */")
await builder.write(f"}}")