tp/tools/libdol2asm/tools.py

116 lines
3.5 KiB
Python

from intervaltree import Interval, IntervalTree
from .data import *
from . import util
def calculate_function_alignments(context, libraries):
# gather all functions
function_list = []
for lib in libraries:
for tu in lib.translation_units.values():
for sec in tu.sections.values():
function_list.extend([symbol for symbol in sec.symbols if isinstance(symbol, Function)])
# sort functions
function_list.sort(key=lambda x: x.addr)
# find function alignment
for curr, next in util.mapOverlap(function_list, 2):
if not curr or not next:
continue
assert isinstance(curr, Function)
assert isinstance(next, Function)
curr_end = curr.addr + curr.size
next_start = next.addr
if curr_end == next_start:
continue
for x in [32,16,8]:
if (curr_end + x - 1) & ~(x - 1) == next_start:
next.alignment = x
context.debug(f"[function] {next.addr:08X} {next.identifier.name} aligned with {next.alignment} bytes")
curr.padding = 0
break
def caluclate_symbol_data_alignment(context, section):
for curr, next in util.mapOverlap(section.symbols, 2):
if not curr or not next:
continue
if isinstance(curr, Function):
continue
curr_end = curr.relative_addr + curr.size
next_start = next.relative_addr
if curr_end == next_start:
continue
for x in [64,32,16]:
if x > section.alignment:
continue
if (curr_end + x - 1) & ~(x - 1) == next_start:
next.alignment = x
context.debug(f"[symbol] {next.identifier.name}: {next.addr:08X} ({next.relative_addr:06X}) aligned with {x} bytes")
break
def merge_symbol_from_group(context, section, group):
if len(group) == 1:
return None
if isinstance(group[0], ArbitraryData):
struct = Structure.create(section, group)
struct.set_mlts(group[0]._module,group[0]._library,group[0]._translation_unit,group[0]._section)
return [struct]
context.error(group[0])
context.error(group[0].section.id)
context.error(group)
assert False
def merge_section_symbols(context, section, add_list, remove_list):
group = []
symbols = []
def merge_group():
assert group
new_symbols = merge_symbol_from_group(context, section, group)
if new_symbols != None:
add_list.update(set(new_symbols))
remove_list.update(set(group) - add_list)
symbols.extend(new_symbols)
else:
symbols.extend(group)
for old_symbol in section.symbols:
is_unaligned = type(old_symbol).__name__ == "ArbitraryData" and old_symbol.addr % 4 != 0
if is_unaligned:
assert group
group.append(old_symbol)
else:
if group:
merge_group()
else:
symbols.extend(group)
group = [old_symbol]
if group:
merge_group()
section.symbols = symbols
def merge_symbols(context, libraries):
remove_list = set()
add_list = set()
for lib in libraries:
for tu in lib.translation_units.values():
for section in tu.sections.values():
merge_section_symbols(context, section, add_list, remove_list)
return add_list, remove_list