Skip to content

Commit

Permalink
Merge pull request #169 from Decompollaborate/develop
Browse files Browse the repository at this point in the history
1.28.0
  • Loading branch information
AngheloAlf authored Aug 9, 2024
2 parents 431f27f + e4658ec commit 2b602b8
Show file tree
Hide file tree
Showing 15 changed files with 208 additions and 37 deletions.
40 changes: 39 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.28.0] - 2024-08-09

### Added

- New `SectionText.gpRelHack` setting.
- Turning it on changes all instructions that use a `%gp_rel` reloc into macro
instructions that do not specify the relocation explicitly nor reference the
`$gp` register.
- This may even change some instruction mnemonics, like replacing `addiu` into
`la`.
- This is required by old assemblers that do not support explicit `%gp_rel`
relocations, but instead they infer the relocation to be used by checking
if the symbol was defined in the assembly file and its size fits on the
passed `-G` parameter.
- WARNING: It is the user's responsability to provide those symbol definitions
to the assembler, otherwise those instructions will be expanded into
multiple instructions and produce a shifted build.
- elfObjDisasm's readelf:
- Add `MIPS_SCOMMON` and `MIPS_SUNDEFINED` support in symtab.
- Use the section name in the ndx column instead of a plain number for
`OBJECT`s and `FUNC`s.

### Changed

- Try to detect function pointers used on tail call optimizations and try to not
confuse them with detected jumptables.
- rabbitizer 1.12.0 or above is required.

### Fixed

- Fix rodata addresses referenced _only_ by other rodata symbols on the same
file not being properly symbolized.
- elfObjDisasm's readelf:
- Fix name column not displaying the section's name.
- Fix relocation sections not displaying anything on the name columns for
relocations relative to a section instead of a symbol.

## [1.27.0] - 2024-07-10

### Added
Expand Down Expand Up @@ -1556,7 +1593,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Version 1.0.0

[unreleased]: https://github.com/Decompollaborate/spimdisasm/compare/master...develop
[1.27.0]: https://github.com/Decompollaborate/spimdisasm/compare/1.27.0...1.27.0
[1.28.0]: https://github.com/Decompollaborate/spimdisasm/compare/1.27.0...1.28.0
[1.27.0]: https://github.com/Decompollaborate/spimdisasm/compare/1.26.1...1.27.0
[1.26.1]: https://github.com/Decompollaborate/spimdisasm/compare/1.26.0...1.26.1
[1.26.0]: https://github.com/Decompollaborate/spimdisasm/compare/1.25.1...1.26.0
[1.25.1]: https://github.com/Decompollaborate/spimdisasm/compare/1.25.0...1.25.1
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ If you use a `requirements.txt` file in your repository, then you can add
this library with the following line:

```txt
spimdisasm>=1.27.0,<2.0.0
spimdisasm>=1.28.0,<2.0.0
```

### Development version
Expand Down
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.27.0"
version = "1.28.0"
description = "MIPS disassembler"
readme = "README.md"
license = {file = "LICENSE"}
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
rabbitizer>=1.10.0,<2.0.0
rabbitizer>=1.12.0,<2.0.0
4 changes: 2 additions & 2 deletions spimdisasm/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@

from __future__ import annotations

__version_info__: tuple[int, int, int] = (1, 27, 0)
__version__ = ".".join(map(str, __version_info__))# + ".dev0"
__version_info__: tuple[int, int, int] = (1, 28, 0)
__version__ = ".".join(map(str, __version_info__))# + "-dev0"
__author__ = "Decompollaborate"

from . import common as common
Expand Down
17 changes: 17 additions & 0 deletions spimdisasm/common/ContextSymbols.py
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,23 @@ def isLateRodata(self) -> bool:
# if self.referenceCounter > 1: return False # ?
return self.isJumpTable() or self.isFloat() or self.isDouble()


def notPointerByType(self) -> bool:
if self.isByte():
return True
if self.isShort():
return True
if self.isFloat():
return True
if self.isDouble():
return True
if self.isString():
return True
if self.isPascalString():
return True
return False


def hasUserDeclaredSize(self) -> bool:
return self.userDeclaredSize is not None

Expand Down
4 changes: 3 additions & 1 deletion spimdisasm/common/Relocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,13 @@ def getName(self, isSplittedSymbol: bool=False) -> str:
return f"{name} - 0x{-self.addend:X}"
return f"{name} + 0x{self.addend:X}"

def getNameWithReloc(self, isSplittedSymbol: bool=False) -> str:
def getNameWithReloc(self, *, isSplittedSymbol: bool=False, ignoredRelocs: set[RelocType]=set()) -> str:
name = self.getName(isSplittedSymbol=isSplittedSymbol)

percentRel = self.relocType.getPercentRel()
if percentRel is not None:
if self.relocType in ignoredRelocs:
return f"({name})"
return f"{percentRel}({name})"

wordRel = self.relocType.getWordRel()
Expand Down
8 changes: 5 additions & 3 deletions spimdisasm/elf32/Elf32Constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -346,9 +346,11 @@ class Elf32SectionHeaderNumber(enum.Enum):
UNDEF = 0
ABS = 0xFFF1
COMMON = 0xFFF2
MIPS_ACOMMON = 0xFF00
MIPS_TEXT = 0xFF01
MIPS_DATA = 0xFF02
MIPS_ACOMMON = 0xFF00 # Allocated common symbols.
MIPS_TEXT = 0xFF01 # Allocated test symbols.
MIPS_DATA = 0xFF02 # Allocated data symbols.
MIPS_SCOMMON = 0xFF03 # Small common symbols.
MIPS_SUNDEFINED = 0xFF04 # Small undefined symbols.

@staticmethod
def fromValue(value: int) -> Elf32SectionHeaderNumber|None:
Expand Down
23 changes: 21 additions & 2 deletions spimdisasm/elf32/Elf32File.py
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ def _readelf_symbol_table(self, symbolTable: Elf32Syms, stringTable: Elf32String

print(f"Symbol table '{symbolTableName}' contains {len(symbolTable.symbols)} entries:")

print(f" {'Num':>5}: {'Value':>8} {'Size':>5} {'Type':7} {'Bind':6} {'Vis':9} {'Ndx':>12} {'Name'}")
print(f" {'Num':>5}: {'Value':>8} {'Size':>5} {'Type':7} {'Bind':6} {'Vis':9} {'Ndx':>15} {'Name'}")

for i, sym in enumerate(symbolTable.symbols):
entryType = Elf32SymbolTableType(sym.stType)
Expand All @@ -562,11 +562,23 @@ def _readelf_symbol_table(self, symbolTable: Elf32Syms, stringTable: Elf32String
shndx = Elf32SectionHeaderNumber.fromValue(sym.shndx)
if shndx is not None:
ndx = shndx.name
elif entryType in { Elf32SymbolTableType.OBJECT, Elf32SymbolTableType.FUNC }:
# spimdisasm-extension: instead of a number we use the section name if available
section = self.sectionHeaders[sym.shndx]
if section is not None:
ndx = self.shstrtab[section.name]

symName = ""
if stringTable is not None:
symName = stringTable[sym.name]
print(f" {i:>5}: {sym.value:08X} {sym.size:>5X} {entryType.name:7} {bind:6} {visibility:9} {ndx:>12} {symName}")
if symName == "":
# GNU readelf uses the section's name as the name column for sections instead of the symbol's name.
if entryType == Elf32SymbolTableType.SECTION:
section = self.sectionHeaders[sym.shndx]
if section is not None:
symName = self.shstrtab[section.name]

print(f" {i:>5}: {sym.value:08X} {sym.size:>5X} {entryType.name:7} {bind:6} {visibility:9} {ndx:>15} {symName}")

print()

Expand Down Expand Up @@ -601,6 +613,13 @@ def readelf_relocs(self) -> None:
symValue = f"{sym.value:08X}"
if self.strtab is not None:
symName = self.strtab[sym.name]
if symName == "":
# Some relocations are an offset to a section on the current object instead of to a symtab symbol.
# TODO: what is the proper way to check this?
section = self.sectionHeaders[sym.shndx]
if section is not None:
symName = self.shstrtab[section.name]

print(f" {rel.offset:08X} {rel.info:08X} {relType:<12} {symValue:>9} {symName}")

print()
Expand Down
6 changes: 6 additions & 0 deletions spimdisasm/elf32/Elf32SectionHeaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ def __getitem__(self, key: int) -> Elf32SectionHeaderEntry | None:
return self.mipsText
if key == Elf32SectionHeaderNumber.MIPS_DATA.value:
return self.mipsData
if key == Elf32SectionHeaderNumber.MIPS_SCOMMON.value:
common.Utils.eprint("Warning: Elf32SectionHeaderNumber.MIPS_SCOMMON not implemented\n")
return None
if key == Elf32SectionHeaderNumber.MIPS_SUNDEFINED.value:
common.Utils.eprint("Warning: Elf32SectionHeaderNumber.MIPS_SUNDEFINED not implemented\n")
return None
if key > len(self.sections):
return None
return self.sections[key]
Expand Down
1 change: 0 additions & 1 deletion spimdisasm/mips/sections/MipsSectionData.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ def analyze(self) -> None:
localOffset = 0
for w in self.words:
currentVram = self.getVramOffset(localOffset)
currentVrom = self.getVromOffset(localOffset)

if self.popPointerInDataReference(currentVram) is not None and localOffset not in localOffsetsWithSymbols:
contextSym = self._addOwnedSymbol(localOffset)
Expand Down
40 changes: 35 additions & 5 deletions spimdisasm/mips/sections/MipsSectionRodata.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,11 @@ def _analyze_processJumptable(self, localOffset: int, w: int, contextSym: common
def analyze(self) -> None:
lastVramSymbol: common.ContextSymbol = self._checkAndCreateFirstSymbol()

symbolList: list[tuple[int, int]] = []
symbolList: list[tuple[int, common.ContextSymbol]] = []
localOffset = 0
localOffsetsWithSymbols: set[int] = set()

needsFurtherAnalyzis = False

jumpTableSym: common.ContextSymbol|None = None
firstJumptableWord = -1
Expand All @@ -97,17 +100,43 @@ def analyze(self) -> None:
self.checkWordIsASymbolReference(w)

if contextSym is not None:
self.symbolsVRams.add(currentVram)
symbolList.append((localOffset, currentVram))
symbolList.append((localOffset, contextSym))
localOffsetsWithSymbols.add(localOffset)

self._createAutoPadFromSymbol(localOffset, contextSym)

elif jumpTableSym is None and self.popPointerInDataReference(currentVram) is not None:
contextSym = self._addOwnedSymbol(localOffset)
symbolList.append((localOffset, contextSym))
localOffsetsWithSymbols.add(localOffset)

if not lastVramSymbol.notPointerByType():
if self.checkWordIsASymbolReference(w):
if w < currentVram and self.containsVram(w):
# References a data symbol from this section and it is behind this current symbol
needsFurtherAnalyzis = True

localOffset += 4

if needsFurtherAnalyzis:
localOffset = 0
for w in self.words:
currentVram = self.getVramOffset(localOffset)

if self.popPointerInDataReference(currentVram) is not None and localOffset not in localOffsetsWithSymbols:
contextSym = self._addOwnedSymbol(localOffset)
symbolList.append((localOffset, contextSym))
localOffsetsWithSymbols.add(localOffset)

localOffset += 4

# Since we appended new symbols, this list is not sorted anymore
symbolList.sort()

previousSymbolWasLateRodata = False
previousSymbolExtraPadding = 0

for i, (offset, vram) in enumerate(symbolList):
for i, (offset, contextSym) in enumerate(symbolList):
if i + 1 == len(symbolList):
words = self.words[offset//4:]
else:
Expand All @@ -116,12 +145,13 @@ def analyze(self) -> None:

vrom = self.getVromOffset(offset)
vromEnd = vrom + len(words)*4
sym = symbols.SymbolRodata(self.context, vrom, vromEnd, offset + self.inFileOffset, vram, words, self.segmentVromStart, self.overlayCategory)
sym = symbols.SymbolRodata(self.context, vrom, vromEnd, offset + self.inFileOffset, contextSym.vram, words, self.segmentVromStart, self.overlayCategory)
sym.parent = self
sym.setCommentOffset(self.commentOffset)
sym.stringEncoding = self.stringEncoding
sym.analyze()
self.symbolList.append(sym)
self.symbolsVRams.add(contextSym.vram)

# File boundaries detection
if sym.inFileOffset % 16 == 0:
Expand Down
3 changes: 3 additions & 0 deletions spimdisasm/mips/sections/MipsSectionText.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ def __init__(self, context: common.Context, vromStart: int, vromEnd: int, vram:

self.instrCat: rabbitizer.Enum = rabbitizer.InstrCategory.CPU
self.detectRedundantFunctionEnd: bool|None = None
self.gpRelHack: bool = False
"""Get rid of `%gp_rel` and `$gp` since old assemblers don't support `%gp_rel`."""

self.enableStringGuessing = False

Expand Down Expand Up @@ -319,6 +321,7 @@ def analyze(self) -> None:
func.hasUnimplementedIntrs = hasUnimplementedIntrs
func.parent = self
func.isRsp = self.instrCat == rabbitizer.InstrCategory.RSP
func.gpRelHack = self.gpRelHack
func.analyze()
self.symbolList.append(func)

Expand Down
Loading

0 comments on commit 2b602b8

Please sign in to comment.