Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mips eabi64 support #270

Open
wants to merge 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ name: Python application

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
build:
Expand Down
306 changes: 295 additions & 11 deletions m2c/arch_mips.py
Original file line number Diff line number Diff line change
Expand Up @@ -1664,8 +1664,20 @@ def eval_fn(s: NodeState, a: InstrArgs) -> None:
"lwr": lambda a: handle_lwr(a),
}

@staticmethod
def default_function_abi_candidate_slots(self) -> List[AbiArgSlot]:
return [
AbiArgSlot(0, Register("f12"), Type.floatish()),
AbiArgSlot(4, Register("f13"), Type.floatish()),
AbiArgSlot(4, Register("f14"), Type.floatish()),
AbiArgSlot(12, Register("f15"), Type.floatish()),
AbiArgSlot(0, Register("a0"), Type.intptr()),
AbiArgSlot(4, Register("a1"), Type.any_reg()),
AbiArgSlot(8, Register("a2"), Type.any_reg()),
AbiArgSlot(12, Register("a3"), Type.any_reg()),
]

def function_abi(
self,
fn_sig: FunctionSignature,
likely_regs: Dict[Register, bool],
*,
Expand Down Expand Up @@ -1756,16 +1768,7 @@ def function_abi(
)

else:
candidate_slots = [
AbiArgSlot(0, Register("f12"), Type.floatish()),
AbiArgSlot(4, Register("f13"), Type.floatish()),
AbiArgSlot(4, Register("f14"), Type.floatish()),
AbiArgSlot(12, Register("f15"), Type.floatish()),
AbiArgSlot(0, Register("a0"), Type.intptr()),
AbiArgSlot(4, Register("a1"), Type.any_reg()),
AbiArgSlot(8, Register("a2"), Type.any_reg()),
AbiArgSlot(12, Register("a3"), Type.any_reg()),
]
candidate_slots = self.default_function_abi_candidate_slots()

valid_extra_regs: Set[Register] = {
slot.reg for slot in known_slots if slot.reg is not None
Expand Down Expand Up @@ -1848,3 +1851,284 @@ def function_return(expr: Expression) -> Dict[Register, Expression]:
),
Register("f1"): SecondF64Half(),
}


class MipseeArch(MipsArch):
stack_pointer_reg = Register("sp")

argument_regs = [
Register(r)
for r in [
"a0",
"a1",
"a2",
"a3",
"a4",
"a5",
"a6",
"a7",
"f12",
"f13",
"f14",
"f15",
"f16",
"f17",
"f18",
"f19",
]
]
simple_temp_regs = [
Register(r)
for r in [
"v0",
"v1",
"t4",
"t5",
"t6",
"t7",
"t8",
"t9",
"f0",
"f1",
"f2",
"f3",
"f4",
"f5",
"f6",
"f7",
"f8",
"f9",
"f10",
"f11",
"f21",
"f23",
"f25",
"f27",
"f29",
"f31",
]
]
temp_regs = (
argument_regs
+ simple_temp_regs
+ [
Register(r)
for r in [
"at",
"hi",
"lo",
"condition_bit",
]
]
)
saved_regs = [
Register(r)
for r in [
"s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
"f20",
"f22",
"f24",
"f26",
"f28",
"f30",
"ra",
"31",
"fp",
"gp",
]
]

all_regs = saved_regs + temp_regs + [stack_pointer_reg, Register("zero")]

aliased_gp_regs = {
"s8": Register("fp"),
"r0": Register("zero"),
}

o32abi_float_regs = {
"fv0": Register("f0"),
"ft14": Register("f1"),
"fv1": Register("f2"),
"ft15": Register("f3"),
"ft0": Register("f4"),
"ft1": Register("f5"),
"ft2": Register("f6"),
"ft3": Register("f7"),
"ft4": Register("f8"),
"ft5": Register("f9"),
"ft6": Register("f10"),
"ft7": Register("f11"),
"fa0": Register("f12"),
"fa1": Register("f13"),
"fa2": Register("f14"),
"fa3": Register("f15"),
"fa4": Register("f16"),
"fa5": Register("f17"),
"fa6": Register("f18"),
"fa7": Register("f19"),
"fs0": Register("f20"),
"ft8": Register("f21"),
"fs1": Register("f22"),
"ft9": Register("f23"),
"fs2": Register("f24"),
"ft10": Register("f25"),
"fs3": Register("f26"),
"ft11": Register("f27"),
"fs4": Register("f28"),
"ft12": Register("f29"),
"fs5": Register("f30"),
"ft13": Register("f31"),
}

numeric_regs = {
"0": Register("zero"),
"1": Register("at"),
"2": Register("v0"),
"3": Register("v1"),
"4": Register("a0"),
"5": Register("a1"),
"6": Register("a2"),
"7": Register("a3"),
"8": Register("a4"),
"9": Register("a5"),
"10": Register("a6"),
"11": Register("a7"),
"12": Register("t4"),
"13": Register("t5"),
"14": Register("t6"),
"15": Register("t7"),
"16": Register("s0"),
"17": Register("s1"),
"18": Register("s2"),
"19": Register("s3"),
"20": Register("s4"),
"21": Register("s5"),
"22": Register("s6"),
"23": Register("s7"),
"24": Register("t8"),
"25": Register("t9"),
"26": Register("k0"),
"27": Register("k1"),
"28": Register("gp"),
"29": Register("sp"),
"30": Register("fp"),
"31": Register("ra"),
}

aliased_regs = {**o32abi_float_regs, **aliased_gp_regs, **numeric_regs}

def default_function_abi_candidate_slots(self) -> List[AbiArgSlot]:
return [
AbiArgSlot(0, Register("f12"), Type.floatish()),
AbiArgSlot(4, Register("f13"), Type.floatish()),
AbiArgSlot(8, Register("f14"), Type.floatish()),
AbiArgSlot(12, Register("f15"), Type.floatish()),
AbiArgSlot(16, Register("f16"), Type.floatish()),
AbiArgSlot(20, Register("f17"), Type.floatish()),
AbiArgSlot(24, Register("f18"), Type.floatish()),
AbiArgSlot(28, Register("f19"), Type.floatish()),
AbiArgSlot(0, Register("a0"), Type.intptr()),
AbiArgSlot(4, Register("a1"), Type.any_reg()),
AbiArgSlot(8, Register("a2"), Type.any_reg()),
AbiArgSlot(12, Register("a3"), Type.any_reg()),
AbiArgSlot(16, Register("a4"), Type.any_reg()),
AbiArgSlot(20, Register("a5"), Type.any_reg()),
AbiArgSlot(24, Register("a6"), Type.any_reg()),
AbiArgSlot(28, Register("a7"), Type.any_reg()),
]

def function_abi(
self,
fn_sig: FunctionSignature,
likely_regs: Dict[Register, bool],
*,
for_call: bool,
) -> Abi:
# $rX & $fX regs can be interspersed in function args, unlike in the MIPS O32 ABI
intptr_regs = [r for r in self.argument_regs if r.register_name[0] != "f"]
float_regs = [r for r in self.argument_regs if r.register_name[0] == "f"]

known_slots: List[AbiArgSlot] = []
candidate_slots: List[AbiArgSlot] = []
if fn_sig.params_known:
for ind, param in enumerate(fn_sig.params):
# TODO: Support passing parameters on the stack
param_type = param.type.decay()
reg: Optional[Register]
try:
if param_type.is_float():
reg = float_regs.pop(0)
else:
reg = intptr_regs.pop(0)
except IndexError:
# Stack variable
reg = None
known_slots.append(
AbiArgSlot(
offset=4 * ind, reg=reg, name=param.name, type=param_type
)
)
if fn_sig.is_variadic:
# TODO: Find a better value to use for `offset`?
for reg in intptr_regs:
candidate_slots.append(
AbiArgSlot(
offset=4 * len(known_slots), reg=reg, type=Type.intptr()
)
)
for reg in float_regs:
candidate_slots.append(
AbiArgSlot(
offset=4 * len(known_slots), reg=reg, type=Type.floatish()
)
)

else:
candidate_slots = self.default_function_abi_candidate_slots()

possible_slots: List[AbiArgSlot] = []
valid_extra_regs: Set[Register] = {
slot.reg for slot in known_slots if slot.reg is not None
}

for slot in candidate_slots:
if slot.reg is None or slot.reg not in likely_regs:
continue

# Don't pass this register if lower numbered ones are undefined.
if slot == candidate_slots[0]:
# For varargs, a subset of regs may be used. Don't check
# earlier registers for the first member of that subset.
pass
else:
# Only r3-r10/f1-f13 can be used for arguments
regname = slot.reg.register_name
prev_reg = Register(f"{regname[0]}{int(regname[1:])-1}")
if prev_reg in self.argument_regs and prev_reg not in valid_extra_regs:
continue

valid_extra_regs.add(slot.reg)

# Skip registers that are untouched from the initial parameter
# list. This is sometimes wrong (can give both false positives
# and negatives), but having a heuristic here is unavoidable
# without access to function signatures, or when dealing with
# varargs functions. Decompiling multiple functions at once
# would help.
# TODO: don't do this in the middle of the argument list
if not likely_regs[slot.reg]:
continue

possible_slots.append(slot)

return Abi(
arg_slots=known_slots,
possible_slots=possible_slots,
)
9 changes: 6 additions & 3 deletions m2c/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
narrow_func_call_outputs,
)
from .types import TypePool
from .arch_mips import MipsArch
from .arch_mips import MipsArch, MipseeArch
from .arch_ppc import PpcArch


Expand Down Expand Up @@ -66,7 +66,10 @@ def print_exception_as_comment(
def run(options: Options) -> int:
arch: Arch
if options.target.arch == Target.ArchEnum.MIPS:
arch = MipsArch()
if options.target.platform == Target.PlatformEnum.MIPSEE:
arch = MipseeArch()
else:
arch = MipsArch()
elif options.target.arch == Target.ArchEnum.PPC:
arch = PpcArch()
else:
Expand Down Expand Up @@ -469,7 +472,7 @@ def parse_flags(flags: List[str]) -> Options:
type=Target.parse,
default="mips-ido-c",
help="Target architecture, compiler, and language triple. "
"Supported triples: mips-ido-c, mips-gcc-c, mipsel-gcc-c, ppc-mwcc-c++, ppc-mwcc-c. "
"Supported triples: mips-ido-c, mips-gcc-c, mipsel-gcc-c, mipsee-gcc-c, mipsee-gcc-c++, ppc-mwcc-c++, ppc-mwcc-c. "
"Default is mips-ido-c, `ppc` is an alias for ppc-mwcc-c++. ",
)
group.add_argument(
Expand Down
Loading
Loading