mirror of
https://github.com/zeldaret/tp
synced 2026-08-21 22:41:04 -04:00
detect more floats/doubles, including from relocations
This commit is contained in:
@@ -27,9 +27,11 @@ def analyze(context: Context,
|
||||
cache_path = Path(f"build/generate/analyze_cache_{module_id}.dump")
|
||||
if cache and cache_path.exists():
|
||||
with cache_path.open('rb') as input:
|
||||
return pickle.load(input)
|
||||
access, highLink = pickle.load(input)
|
||||
return access, highLink
|
||||
|
||||
accesses = dict()
|
||||
highLink = dict()
|
||||
for section in sections:
|
||||
for start, stop in section.code_segments:
|
||||
size = stop - start
|
||||
@@ -40,10 +42,10 @@ def analyze(context: Context,
|
||||
pass
|
||||
|
||||
accesses.update(collector.accesses)
|
||||
|
||||
highLink.update(collector.highLink)
|
||||
if cache:
|
||||
util._create_dirs_for_file(cache_path)
|
||||
with cache_path.open('wb') as output:
|
||||
pickle.dump(accesses, output)
|
||||
pickle.dump((accesses,highLink,), output)
|
||||
|
||||
return accesses
|
||||
return accesses, highLink
|
||||
|
||||
@@ -141,7 +141,7 @@ class ArbitraryData(Symbol):
|
||||
if self.data:
|
||||
assert self.size == len(self.data)
|
||||
if self.alignment > 0:
|
||||
await builder.write_nonewline(f" __attribute__((aligned({self.alignment})))")
|
||||
await builder.write_nonewline(f" ALIGN_DECL({self.alignment})")
|
||||
|
||||
await builder.write(f" = {{")
|
||||
await self.export_u8_data(builder, self.data)
|
||||
@@ -154,7 +154,7 @@ class ArbitraryData(Symbol):
|
||||
await builder.write("};")
|
||||
else:
|
||||
if self.alignment > 0:
|
||||
await builder.write_nonewline(f" __attribute__((aligned({self.alignment})))")
|
||||
await builder.write_nonewline(f" ALIGN_DECL({self.alignment})")
|
||||
|
||||
await builder.write(";")
|
||||
|
||||
@@ -167,11 +167,12 @@ class ArbitraryData(Symbol):
|
||||
await self.export_declaration_body(exporter, builder)
|
||||
|
||||
if self._section == ".rodata":
|
||||
await builder.write_nonewline("SECTION_DEAD ")
|
||||
await builder.write_nonewline("void* const ")
|
||||
await builder.write_nonewline(f"cg_{self.addr:08X} = (void*)(")
|
||||
await builder.write_nonewline(self.cpp_reference(None, self.addr))
|
||||
await builder.write(f");")
|
||||
await builder.write(f"COMPILER_STRIP_GATE({self.addr:08X}, {self.cpp_reference(None, self.addr)});")
|
||||
#await builder.write_nonewline("SECTION_DEAD ")
|
||||
#await builder.write_nonewline("void* const ")
|
||||
#await builder.write_nonewline(f"cg_{self.addr:08X} = (void*)(")
|
||||
#await builder.write_nonewline(self.cpp_reference(None, self.addr))
|
||||
#await builder.write(f");")
|
||||
|
||||
if self.requires_force_active:
|
||||
await builder.write(f"#pragma pop")
|
||||
|
||||
@@ -50,6 +50,10 @@ loadStoreInsns = {
|
||||
PPC_INS_STDU,
|
||||
}
|
||||
|
||||
cs = Cs(CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN)
|
||||
cs.detail = True
|
||||
cs.imm_unsigned = False
|
||||
|
||||
# Returns true if the instruction is a load or store with the given register as a base
|
||||
def is_load_store_reg_offset(insn, reg):
|
||||
return insn.id in loadStoreInsns and (reg == None or insn.operands[1].mem.base == reg)
|
||||
@@ -246,10 +250,6 @@ class Disassembler:
|
||||
"""Disassemble code segments with support for merging loads that are split"""
|
||||
|
||||
def __init__(self, sections):
|
||||
self.cs = Cs(CS_ARCH_PPC, CS_MODE_32 | CS_MODE_BIG_ENDIAN)
|
||||
self.cs.detail = True
|
||||
self.cs.imm_unsigned = False
|
||||
|
||||
self.lisInsns = {}
|
||||
self.splitDataLoads = {}
|
||||
self.linkedInsns = {}
|
||||
@@ -257,6 +257,7 @@ class Disassembler:
|
||||
self.r2AddrInsns = {}
|
||||
self.registers = {}
|
||||
self.registerLoads = {}
|
||||
self.highLink = {}
|
||||
self.sections = sections
|
||||
|
||||
self.r13_addr = 0x80458580
|
||||
@@ -299,6 +300,7 @@ class Disassembler:
|
||||
self.r2AddrInsns = {}
|
||||
self.registers = {}
|
||||
self.registerLoads = {}
|
||||
self.highLink = {}
|
||||
|
||||
self.r13_addr = 0x80458580
|
||||
self.r2_addr = 0x80459A00
|
||||
@@ -309,7 +311,7 @@ class Disassembler:
|
||||
instructions = []
|
||||
offset = 0
|
||||
while offset < size:
|
||||
decoded_insns = list(self.cs.disasm(data[offset:], addr + offset))
|
||||
decoded_insns = list(cs.disasm(data[offset:], addr + offset))
|
||||
if len(decoded_insns) == 0:
|
||||
instructions.append((addr + offset, None, data[offset:][:4]))
|
||||
offset += 4
|
||||
@@ -344,7 +346,7 @@ class Disassembler:
|
||||
instructions = []
|
||||
offset = 0
|
||||
while offset < size:
|
||||
decoded_insns = list(self.cs.disasm(data[offset:], addr + offset))
|
||||
decoded_insns = list(cs.disasm(data[offset:], addr + offset))
|
||||
if len(decoded_insns) == 0:
|
||||
instructions.append((addr + offset, None, data[offset:][:4]))
|
||||
offset += 4
|
||||
@@ -369,7 +371,7 @@ class Disassembler:
|
||||
instructions = []
|
||||
offset = 0
|
||||
while offset < size:
|
||||
decoded_insns = list(self.cs.disasm(data[offset:], addr + offset))
|
||||
decoded_insns = list(cs.disasm(data[offset:], addr + offset))
|
||||
if len(decoded_insns) == 0:
|
||||
instructions.append((addr + offset, None, data[offset:][:4]))
|
||||
offset += 4
|
||||
@@ -424,6 +426,7 @@ class Disassembler:
|
||||
|
||||
value = combine_split_load_value(hiLoadInsn, insn)
|
||||
self.linkedInsns[hiLoadInsn.address] = insn
|
||||
self.highLink[insn.address] = hiLoadInsn.address
|
||||
self.splitDataLoads[hiLoadInsn.address] = value
|
||||
self.splitDataLoads[insn.address] = value
|
||||
self.lisInsns.pop(insn.operands[1].reg, None)
|
||||
@@ -471,6 +474,9 @@ class FloatLoadAccess(Access):
|
||||
class DoubleLoadAccess(Access):
|
||||
"""Double-float access"""
|
||||
|
||||
DOUBLE_INST = { PPC_INS_LFD, PPC_INS_LFDU, PPC_INS_STFD, PPC_INS_STFDU }
|
||||
FLOAT_INST = { PPC_INS_LFS, PPC_INS_LFSU, PPC_INS_STFS, PPC_INS_STFSU }
|
||||
|
||||
class AccessCollector(Disassembler):
|
||||
"""
|
||||
Search through assembly code and collect access to possible labels.
|
||||
@@ -489,14 +495,10 @@ class AccessCollector(Disassembler):
|
||||
if not self.is_label_candidate(value):
|
||||
return
|
||||
|
||||
if insn.address == 0x80143294:
|
||||
print(f"{insn.address:08X}")
|
||||
assert False
|
||||
|
||||
assert not insn.address in self.accesses
|
||||
if insn.id in { PPC_INS_LFD, PPC_INS_LFDU }:
|
||||
if insn.id in DOUBLE_INST:
|
||||
self.accesses[insn.address] = DoubleLoadAccess(insn.address, value)
|
||||
elif insn.id in { PPC_INS_LFS, PPC_INS_LFSU }:
|
||||
elif insn.id in FLOAT_INST:
|
||||
self.accesses[insn.address] = FloatLoadAccess(insn.address, value)
|
||||
else:
|
||||
self.accesses[insn.address] = Access(insn.address, value)
|
||||
@@ -512,20 +514,6 @@ class AccessCollector(Disassembler):
|
||||
r2_addr = self.r2AddrInsns[insn.address]
|
||||
r13_addr = self.r13AddrInsns[insn.address]
|
||||
|
||||
"""
|
||||
if address == 0x80143294:
|
||||
print(insn.address in self.splitDataLoads)
|
||||
print(is_load_store_reg_offset(insn, None))
|
||||
if insn.address in self.splitDataLoads:
|
||||
value = self.splitDataLoads[address]
|
||||
rA = insn.reg_name(insn.operands[0].reg)
|
||||
rB = insn.reg_name(insn.operands[1].mem.base)
|
||||
print(f"{value:08X} {rA} {rB}")
|
||||
print(f"{insn.mnemonic} {insn.op_str}")
|
||||
sys.exit(1)
|
||||
"""
|
||||
|
||||
|
||||
if insn.id in {PPC_INS_B, PPC_INS_BL, PPC_INS_BC, PPC_INS_BDZ, PPC_INS_BDNZ}:
|
||||
for op in insn.operands:
|
||||
if op.type == PPC_OP_IMM:
|
||||
@@ -556,6 +544,3 @@ class AccessCollector(Disassembler):
|
||||
elif insn.address in self.splitDataLoads and is_load_store_reg_offset(insn, None):
|
||||
value = self.splitDataLoads[insn.address]
|
||||
self.add_load_access(insn, value)
|
||||
#elif insn.address in self.registerLoads and is_load_store_reg_offset(insn, None):
|
||||
# value = self.registerLoads[insn.address]
|
||||
# self.add_load_access(insn, value)
|
||||
@@ -241,9 +241,15 @@ def value_initialized_symbol(section: Section,
|
||||
pass
|
||||
else:
|
||||
values = Integer.u32_from(data)
|
||||
padding_values = Integer.u32_from(padding_data)
|
||||
float_values = FloatingPoint.f32_from(data)
|
||||
if values[0] != 0:
|
||||
return [Integer.create_u32(identifier, symbol.addr, data, values, padding_data, padding_values)]
|
||||
f32 = float_values[0][1]
|
||||
if util.is_nice_float32(f32) or f32 in util.float32_exact:
|
||||
padding_values = FloatingPoint.f32_from(padding_data)
|
||||
return [FloatingPoint.create_f32(identifier, symbol.addr, float_values, padding_values)]
|
||||
else:
|
||||
padding_values = Integer.u32_from(padding_data)
|
||||
return [Integer.create_u32(identifier, symbol.addr, data, values, padding_data, padding_values)]
|
||||
|
||||
if symbol.size == 2 and len(padding_data) % 2 == 0:
|
||||
if identifier.name and "$" in identifier.name:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import librel
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from collections import defaultdict
|
||||
from typing import Dict, List
|
||||
@@ -5,7 +7,7 @@ from pathlib import Path
|
||||
from intervaltree import Interval, IntervalTree
|
||||
|
||||
from .context import Context
|
||||
from .disassemble import Access, BranchAccess
|
||||
from .disassemble import Access, BranchAccess, FloatLoadAccess, DoubleLoadAccess
|
||||
from .data import *
|
||||
|
||||
from . import util
|
||||
@@ -15,6 +17,7 @@ from . import sort_translation_units
|
||||
from . import generate_symbols
|
||||
from . import generate_functions
|
||||
from . import settings
|
||||
from . import disassemble
|
||||
|
||||
|
||||
def insert_access_as_symbol(context: Context,
|
||||
@@ -23,14 +26,17 @@ def insert_access_as_symbol(context: Context,
|
||||
map_sections: Dict[str, linker_map.Section],
|
||||
map_addrs: Dict[str, Dict[int, linker_map.Symbol]],
|
||||
ait: Dict[str, IntervalTree],
|
||||
relocations,
|
||||
access: Access) -> bool:
|
||||
"""Insert new symbol from the access data"""
|
||||
|
||||
# determine what sections the access addr are in
|
||||
in_sections = [x for x in sections if access.addr in x]
|
||||
if len(in_sections) == 0:
|
||||
return False
|
||||
if len(in_sections) != 1:
|
||||
context.warning("multiple section for symbol at 0x%08X" %
|
||||
(addr & 0xFFFFFFFF))
|
||||
(access.addr & 0xFFFFFFFF))
|
||||
context.warning([(x.name, x.start, x.end) for x in sections])
|
||||
context.warning([x.name for x in in_sections])
|
||||
return False
|
||||
@@ -42,6 +48,12 @@ def insert_access_as_symbol(context: Context,
|
||||
map_addrs[section.name][relative_addr].access = access
|
||||
return False
|
||||
|
||||
#if map_sections[section.name].index in relocations:
|
||||
# for relocation in relocations[map_sections[section.name].index]:
|
||||
# if relocation.replace_addr == relative_addr:
|
||||
# relocation.access = access
|
||||
# return False
|
||||
|
||||
overlap = ait[section.name].at(relative_addr)
|
||||
if len(overlap) > 0:
|
||||
overlap_symbol = list(overlap)[0].data
|
||||
@@ -203,7 +215,7 @@ def search(context: Context,
|
||||
base_folder=(module_id == 0))
|
||||
|
||||
# Find accesses/symbols by analyzing the code
|
||||
accesses = binary.analyze(
|
||||
accesses, highLink = binary.analyze(
|
||||
context,
|
||||
module_id,
|
||||
sections,
|
||||
@@ -221,22 +233,9 @@ def search(context: Context,
|
||||
sorted_accesses = list(accesses.items())
|
||||
sorted_accesses.sort(key=lambda x: x[0])
|
||||
for relative_addr, access in sorted_accesses:
|
||||
is_relocation_symbol = False
|
||||
"""
|
||||
for relocs in relocations.values():
|
||||
if relative_addr in relocs:
|
||||
relocs[relative_addr].access = access
|
||||
is_relocation_symbol = True
|
||||
break
|
||||
"""
|
||||
|
||||
# if the access is a relocatable symbol skip
|
||||
if is_relocation_symbol:
|
||||
continue
|
||||
|
||||
# add access as symbol, the check if the address is already a symbol is done inside 'insert_access_as_symbol'
|
||||
insert_access_as_symbol(context, module_id, sections,
|
||||
map_sections, map_addrs, ait_sections, access)
|
||||
map_sections, map_addrs, ait_sections, relocations, access)
|
||||
|
||||
# add entrypoint to the right section. the entrypoint is required as it is not included in the linker map.
|
||||
if module_id == 0:
|
||||
@@ -246,7 +245,7 @@ def search(context: Context,
|
||||
|
||||
branch_access = BranchAccess(at=0x00000000, addr=settings.ENTRY_POINT)
|
||||
insert_access_as_symbol(
|
||||
context, module_id, sections, map_sections, map_addrs, ait_sections, branch_access)
|
||||
context, module_id, sections, map_sections, map_addrs, ait_sections, relocations, branch_access)
|
||||
break
|
||||
|
||||
# insert relocation that are not already symbol from the linker map
|
||||
@@ -271,13 +270,40 @@ def search(context: Context,
|
||||
overlap_symbol = list(overlap)[0].data
|
||||
if overlap_symbol.name == "@stringBase0":
|
||||
continue
|
||||
|
||||
|
||||
access = None
|
||||
if r.parent.data and r.parent.executable_flag and module_id == 372:
|
||||
inst_addr = r.parent.addr + r.offset
|
||||
if r.type == librel.R_PPC_ADDR16_LO:
|
||||
inst_addr -= 2
|
||||
elif r.type == librel.R_PPC_ADDR16_HI:
|
||||
inst_addr -= 2
|
||||
elif r.type == librel.R_PPC_ADDR16_HA:
|
||||
inst_addr -= 2
|
||||
if inst_addr in highLink:
|
||||
high_inst_data = r.parent.data[highLink[inst_addr] - r.parent.addr:][:4]
|
||||
high_insts = list(disassemble.cs.disasm(high_inst_data, highLink[inst_addr]))
|
||||
|
||||
inst_data = r.parent.data[inst_addr - r.parent.addr:][:4]
|
||||
insts = list(disassemble.cs.disasm(inst_data, inst_addr))
|
||||
|
||||
if len(insts) == 1 and len(high_insts) == 1:
|
||||
high_inst = high_insts[0]
|
||||
inst = insts[0]
|
||||
if high_inst.id == disassemble.PPC_INS_LIS:
|
||||
if inst.id in disassemble.FLOAT_INST:
|
||||
access = FloatLoadAccess(r.offset, section.addr + addr)
|
||||
elif inst.id in disassemble.DOUBLE_INST:
|
||||
access = DoubleLoadAccess(r.offset, section.addr + addr)
|
||||
|
||||
if not addr in table[section.name]:
|
||||
symbol = linker_map.Symbol(addr, 0, 0, None, None, None)
|
||||
symbol.source = f"relocation/{section.name}/{r.addend:08X}"
|
||||
symbol.access = r.access
|
||||
symbol.access = access
|
||||
table[section.name][addr] = symbol
|
||||
map_sections[section.name].symbols.append(symbol)
|
||||
elif access:
|
||||
table[section.name][addr].access = access
|
||||
else:
|
||||
context.error(f"{section.name} not in module {module_id}")
|
||||
|
||||
@@ -287,14 +313,6 @@ def search(context: Context,
|
||||
tree_order = defaultdict(lambda: defaultdict(list))
|
||||
for section in map_sections.values():
|
||||
|
||||
"""
|
||||
# .rel will be compiled with some standard libraries, but the linker map for the rel does not included what library these function come from.
|
||||
for symbol in section.symbols:
|
||||
if module_id != 0:
|
||||
if symbol.obj == "global_destructor_chain.o":
|
||||
symbol.lib = "Runtime.PPCEABI.H.a"
|
||||
"""
|
||||
|
||||
# calculate the size of symbols and determine where symbols without a library and object file should be located.
|
||||
infer_location_from_other_symbols(section, section.symbols)
|
||||
calculate_symbol_sizes(section, section.symbols)
|
||||
|
||||
+3
-3
@@ -40,17 +40,17 @@ def rel():
|
||||
|
||||
@rel.command(name="info")
|
||||
@click.option('--debug/--no-debug')
|
||||
@click.option('--header', '-h', 'dump_header', is_flag=True, default=False)
|
||||
@click.option('--header', '-t', 'dump_header', is_flag=True, default=False)
|
||||
@click.option('--sections', '-s', 'dump_sections', is_flag=True, default=False)
|
||||
@click.option('--data', '-d', 'dump_data', is_flag=True, default=False)
|
||||
@click.option('--relocations', '-r', 'dump_relocation', is_flag=True, default=False)
|
||||
@click.option('--imp', '-i', 'dump_imp', is_flag=True, default=False)
|
||||
@click.argument("rel_path", metavar='<REL>', nargs=-1)
|
||||
@click.argument("rel_path", metavar='<REL>', nargs=1, type=click.Path(exists=True,file_okay=True,dir_okay=False))
|
||||
def rel_info(debug, rel_path, dump_header, dump_sections, dump_data, dump_relocation, dump_imp):
|
||||
if debug:
|
||||
LOG.setLevel(logging.DEBUG)
|
||||
|
||||
path = Path(rel_path[0])
|
||||
path = Path(rel_path)
|
||||
if not path.exists():
|
||||
LOG.error(f"File not found: '{path}'")
|
||||
sys.exit(1)
|
||||
|
||||
Reference in New Issue
Block a user