mirror of https://github.com/zeldaret/tp.git
284 lines
10 KiB
Python
284 lines
10 KiB
Python
|
|
from dataclasses import dataclass, field
|
|
|
|
from .. import util
|
|
from ..builder import AsyncBuilder
|
|
from ..types import *
|
|
from .identifier import *
|
|
|
|
@dataclass(frozen=True)
|
|
class AddressRange:
|
|
start: int
|
|
end: int
|
|
|
|
def __contains__(self, value):
|
|
return value >= self.start and value < self.end
|
|
|
|
@dataclass
|
|
class ReferenceCount:
|
|
total: int = 0
|
|
static: int = 0
|
|
extern: int = 0
|
|
rel: int = 0
|
|
|
|
def add_reference(self, referencee, referencer, count):
|
|
self.total += count
|
|
if referencer:
|
|
if referencee._module != referencer._module:
|
|
self.rel += count
|
|
elif (referencee._library == referencer._library and
|
|
referencee._translation_unit == referencer._translation_unit):
|
|
self.static += count
|
|
else:
|
|
self.extern += count
|
|
else:
|
|
self.extern += count
|
|
|
|
def make_static(self):
|
|
self.total = 1
|
|
self.static = 1
|
|
self.extern = 0
|
|
self.rel = 0
|
|
|
|
|
|
@dataclass(eq=False)
|
|
class Symbol:
|
|
identifier: Identifier
|
|
addr: int
|
|
size: int
|
|
padding: int = 0
|
|
alignment: int = 0
|
|
reference_count: ReferenceCount = field(default_factory=ReferenceCount)
|
|
implicit_reference_count: ReferenceCount = field(default_factory=ReferenceCount)
|
|
sda_hack_reference_count: ReferenceCount = field(
|
|
default_factory=ReferenceCount)
|
|
require_forward_reference: bool = False
|
|
data_type: Type = None
|
|
source: str = None
|
|
force_section: str = None
|
|
_module: str = None
|
|
_library: str = None
|
|
_translation_unit: str = None
|
|
_section: str = None
|
|
alignment: int = 0
|
|
relative_addr: int = -1
|
|
template_index: int = -1
|
|
|
|
demangled_name: NamedType = None
|
|
references: Set[int] = field(default_factory=set)
|
|
implicit_references: Set[int] = field(default_factory=set)
|
|
is_reachable: bool = False
|
|
|
|
def __hash__(self):
|
|
return hash(self.addr)
|
|
|
|
def __eq__(self, other):
|
|
if not hasattr(self, 'addr'):
|
|
return True
|
|
return self.addr == other.addr and self.size == other.size
|
|
|
|
@property
|
|
def start(self):
|
|
return self.addr
|
|
|
|
@property
|
|
def end(self):
|
|
return self.addr + self.size
|
|
|
|
@property
|
|
def offset(self):
|
|
return self.addr - self.section.addr
|
|
|
|
@property
|
|
def label(self):
|
|
return self.identifier.label
|
|
|
|
@property
|
|
def is_static(self):
|
|
return False
|
|
|
|
@property
|
|
def has_body(self):
|
|
return True
|
|
|
|
@property
|
|
def has_class(self):
|
|
return self.demangled_name and self.demangled_name.has_class
|
|
|
|
@property
|
|
def has_template(self):
|
|
return self.demangled_name and self.demangled_name.has_template
|
|
|
|
@property
|
|
def uses_class_template(self):
|
|
return self.demangled_name and self.demangled_name.has_template
|
|
|
|
@property
|
|
def is_demangled(self):
|
|
return self.demangled_name != None
|
|
|
|
@property
|
|
def requires_force_active(self):
|
|
return False
|
|
|
|
def add_reference(self, referencer, count=1):
|
|
self.reference_count.add_reference(self, referencer, count)
|
|
|
|
def add_implicit_reference(self, referencer, count=1):
|
|
self.implicit_reference_count.add_reference(self, referencer, count)
|
|
|
|
def add_sda_hack(self, referencer, count=1):
|
|
self.sda_hack_reference_count.add_reference(self, referencer, count)
|
|
|
|
def valid_reference(self, addr):
|
|
return addr == self.addr
|
|
|
|
def cpp_reference(self, accessor, addr):
|
|
if addr != self.addr:
|
|
raise Dol2ZelException(
|
|
f"invalid reference addr 0x{addr:08X} for {type(self).__name__}\n{self}")
|
|
return f"&{self.identifier.label}"
|
|
|
|
def cpp_load(self, accessor, addr):
|
|
if addr != self.addr:
|
|
raise Dol2ZelException(
|
|
f"invalid reference addr 0x{addr:08X} for {type(self).__name__}\n{self}")
|
|
return f"{self.identifier.label}"
|
|
|
|
def asm_reference(self, addr):
|
|
if addr != self.addr:
|
|
return None
|
|
return self.identifier.label
|
|
|
|
def gather_references(self, context, valid_range):
|
|
pass
|
|
|
|
def get_reference_information(self, context, symbol_table):
|
|
pass
|
|
|
|
def types(self):
|
|
return set()
|
|
|
|
def set_mlts(self, module: int, library: str, translation_unit: str, section: str):
|
|
self._module = module
|
|
self._library = library
|
|
self._translation_unit = translation_unit
|
|
self._section = section
|
|
|
|
async def export_section_header(self, builder: AsyncBuilder):
|
|
if self._section == ".extab":
|
|
await builder.write("#pragma section \"extab_\"")
|
|
if self._section == ".extabindex":
|
|
await builder.write("#pragma section \"extabindex_\"")
|
|
elif self._section == ".ctors":
|
|
if self.identifier.label == "__init_cpp_exceptions_reference":
|
|
#await builder.write("#pragma section \".ctors$10\"")
|
|
#await builder.write_nonewline("__declspec(section \".ctors$10\") ")
|
|
await builder.write_nonewline("SECTION_CTORS10 ")
|
|
elif self.identifier.label == "_ctors":
|
|
#await builder.write("#pragma section \".ctors$15\"")
|
|
#await builder.write_nonewline("__declspec(section \".ctors$15\") ")
|
|
await builder.write_nonewline("SECTION_CTORS15 ")
|
|
elif self._section == ".dtors":
|
|
if self.identifier.label == "__destroy_global_chain_reference":
|
|
#await builder.write("#pragma section \".dtors$10\"")
|
|
#await builder.write_nonewline("__declspec(section \".dtors$10\") ")
|
|
await builder.write_nonewline("SECTION_DTORS10 ")
|
|
elif self.identifier.label == "__fini_cpp_exceptions_reference":
|
|
#await builder.write("#pragma section \".dtors$15\"")
|
|
#await builder.write_nonewline("__declspec(section \".dtors$15\") ")
|
|
await builder.write_nonewline("SECTION_DTORS15 ")
|
|
elif self.identifier.label == "__dtors_null_terminator":
|
|
#await builder.write("#pragma section \".dtors$15\"")
|
|
#await builder.write_nonewline("__declspec(section \".dtors$15\") ")
|
|
await builder.write_nonewline("SECTION_DTORS15 ")
|
|
elif self.identifier.label == "_dtors":
|
|
await builder.write_nonewline("SECTION_DTORS10 ")
|
|
elif self.force_section:
|
|
if self.force_section == '.bss':
|
|
await builder.write_nonewline("SECTION_BSS ")
|
|
else:
|
|
assert False
|
|
else:
|
|
await builder.write_nonewline("extern \"C\" ")
|
|
|
|
async def export_section(self, builder: AsyncBuilder):
|
|
section = ""
|
|
|
|
if self._section == ".data":
|
|
section = "SECTION_DATA "
|
|
elif self._section == ".sdata":
|
|
section = "SECTION_SDATA "
|
|
elif self._section == ".sdata2":
|
|
section = "SECTION_SDATA2 "
|
|
# elif self._section == ".bss":
|
|
# section = "SECTION_BSS "
|
|
# elif self._section == ".sbss":
|
|
# section = "SECTION_SBSS "
|
|
elif self._section == ".sbss2":
|
|
section = "SECTION_SBSS2 "
|
|
elif self._section == ".init":
|
|
section = "SECTION_INIT "
|
|
elif self._section == ".rodata":
|
|
section = "SECTION_RODATA "
|
|
elif self._section == ".extab":
|
|
await builder.write_nonewline("SECTION_EXTAB ")
|
|
elif self._section == ".extabindex":
|
|
await builder.write_nonewline("SECTION_EXTABINDEX ")
|
|
elif self._section == ".ctors":
|
|
if self.identifier.label == "__init_cpp_exceptions_reference":
|
|
#section = "__declspec(section \".ctors$10\") "
|
|
section = "SECTION_CTORS10 "
|
|
elif self.identifier.label == "_ctors":
|
|
#section = "__declspec(section \".ctors$15\") "
|
|
section = "SECTION_CTORS15 "
|
|
elif self._section == ".dtors":
|
|
if self.identifier.label == "__destroy_global_chain_reference":
|
|
#section = "__declspec(section \".dtors$10\") "
|
|
section = "SECTION_DTORS10 "
|
|
elif self.identifier.label == "__fini_cpp_exceptions_reference":
|
|
#section = "__declspec(section \".dtors$15\") "
|
|
section = "SECTION_DTORS15 "
|
|
elif self.identifier.label == "__dtors_null_terminator":
|
|
#section = "__declspec(section \".dtors$15\") "
|
|
section = "SECTION_DTORS15 "
|
|
elif self.identifier.label == "_dtors":
|
|
section = "SECTION_DTORS10 "
|
|
await builder.write_nonewline(section)
|
|
|
|
async def export_extern(self, builder: AsyncBuilder):
|
|
await builder.write_nonewline(f"extern ")
|
|
|
|
async def export_static(self, builder: AsyncBuilder):
|
|
await builder.write_nonewline(f"static ")
|
|
|
|
async def export_force_active(self, builder: AsyncBuilder):
|
|
await builder.write_nonewline(f"__declspec(forceactive) ")
|
|
|
|
async def export_readonly(self, builder: AsyncBuilder):
|
|
if self._section == ".rodata":
|
|
await builder.write_nonewline(f"const ")
|
|
elif self._section == ".extab":
|
|
await builder.write_nonewline(f"const ")
|
|
elif self._section == ".extabindex":
|
|
await builder.write_nonewline(f"const ")
|
|
elif self._section == ".ctors":
|
|
await builder.write_nonewline(f"const ")
|
|
elif self._section == ".dtors":
|
|
await builder.write_nonewline(f"const ")
|
|
|
|
async def export_declaration_head(self, builder: AsyncBuilder):
|
|
assert False
|
|
|
|
async def export_declaration_body(self, builder: AsyncBuilder):
|
|
assert False
|
|
|
|
async def export_declaration(self, exporter, builder: AsyncBuilder):
|
|
await self.export_declaration_head(exporter, builder)
|
|
await self.export_declaration_body(exporter, builder)
|
|
|
|
async def export_u8_data(self, builder: AsyncBuilder, data: bytearray):
|
|
for chunk in util.chunks(data, 16):
|
|
line = ", ".join([f"0x{x:02X}" for x in chunk])
|
|
await builder.write(f"\t{line},")
|