Skip to content

Commit

Permalink
Merge pull request #130 from Decompollaborate/develop
Browse files Browse the repository at this point in the history
1.16.0
  • Loading branch information
AngheloAlf authored Jul 23, 2023
2 parents cc4d460 + 7de517e commit a1fb34e
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 11 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
[project]
name = "spimdisasm"
# Version should be synced with spimdisasm/__init__.py
version = "1.15.4"
version = "1.16.0"
description = "MIPS disassembler"
# license = "MIT"
readme = "README.md"
Expand Down
2 changes: 1 addition & 1 deletion spimdisasm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from __future__ import annotations

__version_info__ = (1, 15, 4)
__version_info__: tuple[int, int, int] = (1, 16, 0)
__version__ = ".".join(map(str, __version_info__))
__author__ = "Decompollaborate"

Expand Down
8 changes: 8 additions & 0 deletions spimdisasm/common/GlobalConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,10 @@ def AGGRESSIVE_STRING_GUESSER(self, value: bool) -> None:

COMPILER: Compiler = Compiler.IDO

DETECT_REDUNDANT_FUNCTION_END: bool = False
"""Tries to detect redundant and unreferenced functions ends and merge them together.
This option is ignored if the compiler is not set to IDO"""

ENDIAN: InputEndian = InputEndian.BIG
"""Endian for input binary files"""
ENDIAN_DATA: InputEndian|None = None
Expand Down Expand Up @@ -294,6 +298,7 @@ def addParametersToArgParse(self, parser: argparse.ArgumentParser):
backendConfig.add_argument("--custom-suffix", help="Set a custom suffix for automatically generated symbols")

backendConfig.add_argument("--compiler", help=f"Enables some tweaks for the selected compiler. Defaults to {self.COMPILER.name}", choices=compilerOptions)
backendConfig.add_argument("--detect-redundant-function-end", help=f"Tries to detect redundant and unreferenced function ends (jr $ra; nop), and merge it into the previous function. Currently it only is applied when the compiler is set to IDO. Defaults to {self.DETECT_REDUNDANT_FUNCTION_END}", action=Utils.BooleanOptionalAction)

backendConfig.add_argument("--endian", help=f"Set the endianness of input files. Defaults to {self.ENDIAN.name.lower()}", choices=["big", "little", "middle"], default=self.ENDIAN.name.lower())

Expand Down Expand Up @@ -428,6 +433,9 @@ def parseArgs(self, args: argparse.Namespace):
if args.compiler is not None:
self.COMPILER = Compiler.fromStr(args.compiler)

if args.detect_redundant_function_end is not None:
self.DETECT_REDUNDANT_FUNCTION_END = args.detect_redundant_function_end

if args.endian is not None:
self.ENDIAN = InputEndian.fromStr(args.endian)

Expand Down
5 changes: 4 additions & 1 deletion spimdisasm/mips/MipsFileBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,10 @@ def checkAndCreateFirstSymbol(self) -> None:
"Check if the very start of the file has a symbol and create it if it doesn't exist yet"

currentVram = self.getVramOffset(0)
currentVrom = self.getVromOffset(0)
if self.sectionType == common.FileSectionType.Bss:
currentVrom = None
else:
currentVrom = self.getVromOffset(0)
contextSym = self.getSymbol(currentVram, vromAddress=currentVrom, tryPlusOffset=False)
if contextSym is None:
contextSym = self.addSymbol(currentVram, sectionType=self.sectionType, isAutogenerated=True, symbolVrom=currentVrom)
Expand Down
44 changes: 36 additions & 8 deletions spimdisasm/mips/sections/MipsSectionText.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def __init__(self, context: common.Context, vromStart: int, vromEnd: int, vram:
super().__init__(context, vromStart, vromEnd, vram, filename, common.Utils.bytesToWords(array_of_bytes, vromStart, vromEnd), common.FileSectionType.Text, segmentVromStart, overlayCategory)

self.instrCat: rabbitizer.Enum = rabbitizer.InstrCategory.CPU
self.detectRedundantFunctionEnd: bool|None = None


@property
Expand All @@ -40,6 +41,14 @@ def wordListToInstructions(wordList: list[int], currentVram: int|None, instrCat:
return instrsList


def tryDetectRedundantFunctionEnd(self) -> bool:
if common.GlobalConfig.COMPILER != common.Compiler.IDO:
return False

if self.detectRedundantFunctionEnd is None:
return common.GlobalConfig.DETECT_REDUNDANT_FUNCTION_END
return self.detectRedundantFunctionEnd

def _findFunctions(self, instrsList: list[rabbitizer.Instruction]):
if len(instrsList) == 0:
return [0], [False]
Expand Down Expand Up @@ -164,10 +173,35 @@ def _findFunctions(self, instrsList: list[rabbitizer.Instruction]):
if instructionOffset + 8 == currentInstructionStart + currentFunctionSym.getSize():
functionEnded = True
else:
if not (farthestBranch > 0) and instr.isJump():
funcSymbol = self.getSymbol(currentVram + 8, vromAddress=currentVrom + 8, tryPlusOffset=False, checkGlobalSegment=False)
# If there's another function after this then the current function has ended
if funcSymbol is not None and funcSymbol.isTrustableFunction(self.instrCat == rabbitizer.InstrCategory.RSP):
if funcSymbol.vromAddress is None or currentVrom + 8 == funcSymbol.vromAddress:
functionEnded = True

if not functionEnded and not (farthestBranch > 0) and instr.isJump():
if instr.isReturn():
# Found a jr $ra and there are no branches outside of this function
functionEnded = True
if self.tryDetectRedundantFunctionEnd():
# IDO -g, -g1 and -g2 can generate a redundant and unused `jr $ra; nop`. In normal conditions this would be detected
# as its own separate empty function, which would cause issues on a decompilation project.
# In other words, we try to detect the following pattern, and the last two instructions not being a function
# already referenced or user-declared.
# jr $ra
# nop
# jr $ra
# nop
redundantPatternDetected = False
if index + 3 < nInstr:
instr1 = instrsList[index+1]
instr2 = instrsList[index+2]
instr3 = instrsList[index+3]
if funcSymbol is None and instr1.isNop() and instr2.isReturn() and instr3.isNop():
redundantPatternDetected = True
if not redundantPatternDetected:
functionEnded = True
else:
functionEnded = True
elif instr.isJumptableJump():
# Usually jumptables, ignore
pass
Expand All @@ -176,12 +210,6 @@ def _findFunctions(self, instrsList: list[rabbitizer.Instruction]):
# I don't remember the reasoning of this condition...
functionEnded = True

# If there's another function after this then the current function has ended
funcSymbol = self.getSymbol(currentVram + 8, vromAddress=currentVrom + 8, tryPlusOffset=False, checkGlobalSegment=False)
if funcSymbol is not None and funcSymbol.isTrustableFunction(self.instrCat == rabbitizer.InstrCategory.RSP):
if funcSymbol.vromAddress is None or currentVrom + 8 == funcSymbol.vromAddress:
functionEnded = True

index += 1
farthestBranch -= 4
instructionOffset += 4
Expand Down

0 comments on commit a1fb34e

Please sign in to comment.