From 22b7fb87de17467adf7f779c5f06c13cd606fdaf Mon Sep 17 00:00:00 2001 From: angie Date: Wed, 19 Jul 2023 16:11:40 -0400 Subject: [PATCH 1/3] Fix bss sections not creating an starting symbol if it was not being referenced --- pyproject.toml | 2 +- spimdisasm/__init__.py | 4 ++-- spimdisasm/mips/MipsFileBase.py | 5 ++++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 28d9efa6..c9476acc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ [project] name = "spimdisasm" # Version should be synced with spimdisasm/__init__.py -version = "1.15.4" +version = "1.15.5.dev0" description = "MIPS disassembler" # license = "MIT" readme = "README.md" diff --git a/spimdisasm/__init__.py b/spimdisasm/__init__.py index 1420c730..2256143e 100644 --- a/spimdisasm/__init__.py +++ b/spimdisasm/__init__.py @@ -5,8 +5,8 @@ from __future__ import annotations -__version_info__ = (1, 15, 4) -__version__ = ".".join(map(str, __version_info__)) +__version_info__ = (1, 15, 5) +__version__ = ".".join(map(str, __version_info__)) + ".dev0" __author__ = "Decompollaborate" from . import common as common diff --git a/spimdisasm/mips/MipsFileBase.py b/spimdisasm/mips/MipsFileBase.py index 2ea83c86..27d5e012 100644 --- a/spimdisasm/mips/MipsFileBase.py +++ b/spimdisasm/mips/MipsFileBase.py @@ -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) From 243394bb597cbf2e6b6c9eb9db997f719cdbfa7b Mon Sep 17 00:00:00 2001 From: angie Date: Sun, 23 Jul 2023 14:08:22 -0400 Subject: [PATCH 2/3] DETECT_REDUNDANT_FUNCTION_END --- spimdisasm/common/GlobalConfig.py | 8 ++++ spimdisasm/mips/sections/MipsSectionText.py | 44 +++++++++++++++++---- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/spimdisasm/common/GlobalConfig.py b/spimdisasm/common/GlobalConfig.py index 0a7762f2..e1c35029 100644 --- a/spimdisasm/common/GlobalConfig.py +++ b/spimdisasm/common/GlobalConfig.py @@ -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 @@ -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()) @@ -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) diff --git a/spimdisasm/mips/sections/MipsSectionText.py b/spimdisasm/mips/sections/MipsSectionText.py index 3bd0a568..454acfdd 100644 --- a/spimdisasm/mips/sections/MipsSectionText.py +++ b/spimdisasm/mips/sections/MipsSectionText.py @@ -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 @@ -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] @@ -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 @@ -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 From 7de517e8d064757538a06066bebf921f09641ae1 Mon Sep 17 00:00:00 2001 From: angie Date: Sun, 23 Jul 2023 14:47:16 -0400 Subject: [PATCH 3/3] version bump --- pyproject.toml | 2 +- spimdisasm/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index c9476acc..e417026e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ [project] name = "spimdisasm" # Version should be synced with spimdisasm/__init__.py -version = "1.15.5.dev0" +version = "1.16.0" description = "MIPS disassembler" # license = "MIT" readme = "README.md" diff --git a/spimdisasm/__init__.py b/spimdisasm/__init__.py index 2256143e..95fd64c6 100644 --- a/spimdisasm/__init__.py +++ b/spimdisasm/__init__.py @@ -5,8 +5,8 @@ from __future__ import annotations -__version_info__ = (1, 15, 5) -__version__ = ".".join(map(str, __version_info__)) + ".dev0" +__version_info__: tuple[int, int, int] = (1, 16, 0) +__version__ = ".".join(map(str, __version_info__)) __author__ = "Decompollaborate" from . import common as common