detect more floats/doubles, including from relocations

This commit is contained in:
Julgodis
2021-04-07 09:16:47 +02:00
parent ed1ee30dd2
commit dca1d2a1c0
1645 changed files with 69992 additions and 69984 deletions
+6 -4
View File
@@ -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
+8 -7
View File
@@ -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")
+15 -30
View File
@@ -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)
+8 -2
View File
@@ -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:
+46 -28
View File
@@ -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
View File
@@ -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)