Skip to content

Commit 1baae9d

Browse files
authored
Merge pull request #147 from Decompollaborate/develop
1.20.0
2 parents 04249af + 7fb3859 commit 1baae9d

14 files changed

+204
-118
lines changed

CHANGELOG.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [1.20.0] - 2023-12-25
11+
12+
### Added
13+
14+
- Add `--name-vars-by-file` option to rename data symbols based on their offset
15+
and in their containing file.
16+
- Add `--name-vars-by-section` considers the `.text` and `.ovl`/`.reloc` sections.
17+
- For unknown `.text` symbols (that are not functions, or any kind of label)
18+
the `T_` prefix will be used.
19+
- For `.ovl`/`.reloc` symbols the `REL_` prefix will be used
20+
21+
### Changed
22+
23+
- File splits can now contain reloc sections (`.ovl` or `.reloc`).
24+
- Type-based name generation (`--name-vars-by-type`) can now be mixed with
25+
other kinds of name generations, allowing to give extra information on the
26+
symbol name.
27+
- Autogenerated symbol names will not use a suffix if said symbol is generated
28+
after another symbol or file.
29+
- Do not try to symbolize an address as a symbol plus addend if the original
30+
address is a banned address.
31+
- Recognize `volatile` type variants as aliases for the non `volatile`
32+
versions.
33+
- For example, `vs16` is recognized as a `.short`.
34+
- Use C style comments over `#` since that is more widely supperted.
35+
- For example Clang doesn't seem to support `#` comments.
36+
1037
## [1.19.0] - 2023-12-04
1138

1239
### Added
@@ -1304,6 +1331,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
13041331
- Version 1.0.0
13051332

13061333
[unreleased]: https://github.com/Decompollaborate/spimdisasm/compare/master...develop
1334+
[1.20.0]: https://github.com/Decompollaborate/spimdisasm/compare/1.19.0...1.20.0
13071335
[1.19.0]: https://github.com/Decompollaborate/spimdisasm/compare/1.18.0...1.19.0
13081336
[1.18.0]: https://github.com/Decompollaborate/spimdisasm/compare/1.17.4...1.18.0
13091337
[1.17.4]: https://github.com/Decompollaborate/spimdisasm/compare/1.17.3...1.17.4

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ If you use a `requirements.txt` file in your repository, then you can add
6868
this library with the following line:
6969

7070
```txt
71-
spimdisasm>=1.17.4,<2.0.0
71+
spimdisasm>=1.20.0,<2.0.0
7272
```
7373

7474
### Development version
@@ -87,8 +87,8 @@ In case you want to mess with the latest development version without wanting to
8787
clone the repository, then you could use the following command:
8888

8989
```bash
90-
pip uninstall spimdisasm
91-
pip install git+https://github.com/Decompollaborate/spimdisasm.git@develop
90+
python3 -m pip uninstall spimdisasm
91+
python3 -m pip install git+https://github.com/Decompollaborate/spimdisasm.git@develop
9292
```
9393

9494
NOTE: Installing the development version is not recommended unless you know what

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[project]
55
name = "spimdisasm"
66
# Version should be synced with spimdisasm/__init__.py
7-
version = "1.19.0"
7+
version = "1.20.0"
88
description = "MIPS disassembler"
99
# license = "MIT"
1010
readme = "README.md"

spimdisasm/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from __future__ import annotations
77

8-
__version_info__: tuple[int, int, int] = (1, 19, 0)
8+
__version_info__: tuple[int, int, int] = (1, 20, 0)
99
__version__ = ".".join(map(str, __version_info__))
1010
__author__ = "Decompollaborate"
1111

spimdisasm/common/ContextSymbols.py

Lines changed: 119 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ def getAllTypes(self) -> set[str]:
7979
return types
8080

8181
gAccessKinds: dict[rabbitizer.Enum, AccessTypeInfo] = {
82-
rabbitizer.AccessType.BYTE: AccessTypeInfo(1, "s8", "u8"),
83-
rabbitizer.AccessType.SHORT: AccessTypeInfo(2, "s16", "u16"),
82+
rabbitizer.AccessType.BYTE: AccessTypeInfo(1, "s8", "u8", {"vs8", "vu8"}),
83+
rabbitizer.AccessType.SHORT: AccessTypeInfo(2, "s16", "u16", {"vs16", "vu16"}),
8484
# Ignore signed WORD since it tends to not give a proper type
85-
rabbitizer.AccessType.WORD: AccessTypeInfo(4, None, "u32", {"s32"}),
86-
rabbitizer.AccessType.DOUBLEWORD: AccessTypeInfo(8, "s64", "u64"),
85+
rabbitizer.AccessType.WORD: AccessTypeInfo(4, None, "u32", {"s32", "vs32", "vu32"}),
86+
rabbitizer.AccessType.DOUBLEWORD: AccessTypeInfo(8, "s64", "u64", {"vs64", "vu64"}),
8787
rabbitizer.AccessType.FLOAT: AccessTypeInfo(4, "f32", None, {"Vec3f"}),
8888
rabbitizer.AccessType.DOUBLEFLOAT: AccessTypeInfo(8, "f64", None),
8989
}
@@ -122,8 +122,10 @@ class ContextSymbol:
122122
"This symbol was automatically generated by the disassembler"
123123

124124
isMaybeString: bool = False
125+
failedStringDecoding: bool = False
125126

126127
isMaybePascalString: bool = False
128+
failedPascalStringDecoding: bool = False
127129

128130
referenceCounter: int = 0
129131
"How much this symbol is referenced by something else"
@@ -140,6 +142,11 @@ class ContextSymbol:
140142
jumpTables: SortedDict[ContextSymbol] = dataclasses.field(default_factory=SortedDict)
141143
"For functions, the jump tables which are contained in this function"
142144

145+
parentFileName: str|None = None
146+
"Name of the file containing this symbol"
147+
inFileOffset: int|None = None
148+
"Offset relative to the start of the file"
149+
143150
overlayCategory: str|None = None
144151

145152
nameGetCallback: Callable[[ContextSymbol], str]|None = None
@@ -286,6 +293,9 @@ def isShort(self) -> bool:
286293

287294

288295
def isString(self) -> bool:
296+
if self.failedStringDecoding:
297+
return False
298+
289299
currentType = self.getTypeSpecial()
290300

291301
if self.sectionType == FileSectionType.Rodata:
@@ -312,6 +322,9 @@ def isString(self) -> bool:
312322
return False
313323

314324
def isPascalString(self) -> bool:
325+
if self.failedPascalStringDecoding:
326+
return False
327+
315328
currentType = self.getTypeSpecial()
316329

317330
if self.sectionType == FileSectionType.Rodata:
@@ -338,6 +351,9 @@ def isPascalString(self) -> bool:
338351
return False
339352

340353
def isFloat(self) -> bool:
354+
if self.vram % 4 != 0:
355+
return False
356+
341357
currentType = self.getTypeSpecial()
342358

343359
if gAccessKinds[rabbitizer.AccessType.FLOAT].typeMatchesAccess(currentType):
@@ -388,23 +404,7 @@ def isLateRodata(self) -> bool:
388404
def hasUserDeclaredSize(self) -> bool:
389405
return self.userDeclaredSize is not None
390406

391-
def getBranchLabelName(self, suffix: str) -> str:
392-
if GlobalConfig.SEQUENTIAL_LABEL_NAMES and self.parentFunction is not None:
393-
index = self.parentFunction.branchLabels.index(self.vram)
394-
if index is not None:
395-
return f".L{self.parentFunction.getName()}_{index + 1}"
396-
397-
return f".L{self.address:08X}{suffix}"
398-
399-
def getJumpTableName(self, suffix: str) -> str:
400-
if GlobalConfig.SEQUENTIAL_LABEL_NAMES and self.parentFunction is not None:
401-
index = self.parentFunction.jumpTables.index(self.vram)
402-
if index is not None:
403-
return f"jtbl_{self.parentFunction.getName()}_{index + 1}"
404-
405-
return f"jtbl_{self.address:08X}{suffix}"
406-
407-
def getDefaultName(self) -> str:
407+
def _defaultName_suffix(self) -> str:
408408
suffix = ""
409409
if self.overlayCategory is not None:
410410
suffix = "_"
@@ -413,30 +413,74 @@ def getDefaultName(self) -> str:
413413

414414
if GlobalConfig.CUSTOM_SUFFIX:
415415
suffix += GlobalConfig.CUSTOM_SUFFIX
416+
return suffix
416417

417-
currentType = self.getTypeSpecial()
418+
def _defaultName_uniqueIdentifier(self, symType: SymbolSpecialType|str|None) -> str:
419+
if GlobalConfig.SEQUENTIAL_LABEL_NAMES and self.parentFunction is not None:
420+
if symType in {SymbolSpecialType.branchlabel, SymbolSpecialType.jumptablelabel}:
421+
index = self.parentFunction.branchLabels.index(self.vram)
422+
if index is not None:
423+
return f"{self.parentFunction.getName()}_{index + 1}"
424+
elif symType == SymbolSpecialType.jumptable:
425+
index = self.parentFunction.jumpTables.index(self.vram)
426+
if index is not None:
427+
return f"{self.parentFunction.getName()}_{index + 1}"
428+
429+
if GlobalConfig.AUTOGENERATED_NAMES_BASED_ON_FILE_NAME:
430+
if self.parentFileName is not None and self.inFileOffset is not None:
431+
sectionName = self.sectionType.toStr().replace(".", "_")
432+
return f"{self.parentFileName}{sectionName}_{self.inFileOffset:06X}"
433+
434+
suffix = self._defaultName_suffix()
435+
436+
# Stringify the address
437+
if GlobalConfig.LEGACY_SYM_ADDR_ZERO_PADDING:
438+
return f"{self.address:06X}{suffix}"
439+
return f"{self.address:08X}{suffix}"
418440

419-
if currentType is not None:
420-
if currentType == SymbolSpecialType.function:
421-
return f"func_{self.address:08X}{suffix}"
422-
if currentType in {SymbolSpecialType.branchlabel, SymbolSpecialType.jumptablelabel}:
423-
return self.getBranchLabelName(suffix)
424-
if currentType == SymbolSpecialType.jumptable:
425-
return self.getJumpTableName(suffix)
441+
def _defaultName_sectionPrefix(self, symType: SymbolSpecialType|str|None) -> str:
442+
# Functions, labels and jumptables don't get a section prefix because most of the time they are in their respective sections
443+
if symType in {SymbolSpecialType.function, SymbolSpecialType.branchlabel, SymbolSpecialType.jumptablelabel, SymbolSpecialType.jumptable}:
444+
return ""
426445

446+
# Determine the section type prefix
427447
if GlobalConfig.AUTOGENERATED_NAMES_BASED_ON_SECTION_TYPE:
428448
if self.sectionType == FileSectionType.Rodata:
429-
if GlobalConfig.LEGACY_SYM_ADDR_ZERO_PADDING:
430-
return f"RO_{self.address:06X}{suffix}"
431-
return f"RO_{self.address:08X}{suffix}"
432-
if self.sectionType == FileSectionType.Bss:
433-
if GlobalConfig.LEGACY_SYM_ADDR_ZERO_PADDING:
434-
return f"B_{self.address:06X}{suffix}"
435-
return f"B_{self.address:08X}{suffix}"
449+
return "RO_"
450+
elif self.sectionType == FileSectionType.Bss:
451+
return "B_"
452+
elif self.sectionType == FileSectionType.Text:
453+
return "T_"
454+
elif self.sectionType == FileSectionType.Reloc:
455+
return "REL_"
456+
return "D_"
457+
458+
def _defaultName_typePrefix(self, symType: SymbolSpecialType|str|None) -> str:
459+
if symType == SymbolSpecialType.function:
460+
return f"func_"
461+
if symType in {SymbolSpecialType.branchlabel, SymbolSpecialType.jumptablelabel}:
462+
return f".L"
463+
if symType == SymbolSpecialType.jumptable:
464+
return f"jtbl_"
465+
466+
if GlobalConfig.AUTOGENERATED_NAMES_BASED_ON_DATA_TYPE:
467+
if self.isFloat():
468+
return f"FLT_"
469+
elif self.isDouble():
470+
return f"DBL_"
471+
elif self.isString():
472+
return f"STR_"
473+
elif self.isPascalString():
474+
return f"PSTR_"
475+
return ""
436476

437-
if GlobalConfig.LEGACY_SYM_ADDR_ZERO_PADDING:
438-
return f"D_{self.address:06X}{suffix}"
439-
return f"D_{self.address:08X}{suffix}"
477+
def getDefaultName(self) -> str:
478+
currentType = self.getTypeSpecial()
479+
480+
uniqueIdentifier = self._defaultName_uniqueIdentifier(currentType)
481+
sectionPrefix = self._defaultName_sectionPrefix(currentType)
482+
typePrefix = self._defaultName_typePrefix(currentType)
483+
return f"{sectionPrefix}{typePrefix}{uniqueIdentifier}"
440484

441485
def getName(self) -> str:
442486
if self.nameGetCallback is not None:
@@ -501,7 +545,7 @@ def setSizeIfUnset(self, size: int) -> bool:
501545
return True
502546
return False
503547

504-
def getTypeSpecial(self) -> str|SymbolSpecialType|None:
548+
def getTypeSpecial(self) -> SymbolSpecialType|str|None:
505549
if self.userDeclaredType is not None:
506550
return self.userDeclaredType
507551
return self.autodetectedType
@@ -520,13 +564,13 @@ def getType(self) -> str:
520564
return currentType.toStr()
521565
return currentType
522566

523-
def setTypeSpecial(self, newType: str|SymbolSpecialType|None, isAutogenerated: bool):
567+
def setTypeSpecial(self, newType: SymbolSpecialType|str|None, isAutogenerated: bool):
524568
if isAutogenerated:
525569
self.autodetectedType = newType
526570
else:
527571
self.userDeclaredType = newType
528572

529-
def setTypeIfUnset(self, newType: str|SymbolSpecialType|None, isAutogenerated: bool) -> bool:
573+
def setTypeIfUnset(self, newType: SymbolSpecialType|str|None, isAutogenerated: bool) -> bool:
530574
if self.hasNoType():
531575
self.setTypeSpecial(newType, isAutogenerated=isAutogenerated)
532576
return True
@@ -556,12 +600,12 @@ def getLabelMacro(self, isInMiddleLabel: bool=False) -> str|None:
556600
label = ""
557601
if GlobalConfig.ASM_COMMENT:
558602
if self.isStatic():
559-
label += f"# static variable{GlobalConfig.LINE_ENDS}"
603+
label += f"/* static variable */{GlobalConfig.LINE_ENDS}"
560604
if self.isAutogeneratedPad():
561605
mainSymbolInfo = ""
562606
if self.autoCreatedPadMainSymbol is not None:
563607
mainSymbolInfo = f" (generated by the size of {self.autoCreatedPadMainSymbol.getName()})"
564-
label += f"# Automatically generated and unreferenced pad{mainSymbolInfo}{GlobalConfig.LINE_ENDS}"
608+
label += f"/* Automatically generated and unreferenced pad{mainSymbolInfo} */{GlobalConfig.LINE_ENDS}"
565609

566610
currentType = self.getTypeSpecial()
567611
if currentType == SymbolSpecialType.jumptablelabel:
@@ -583,16 +627,16 @@ def getReferenceeSymbols(self) -> str:
583627
return ""
584628

585629
if len(self.referenceFunctions):
586-
output = "# Functions referencing this symbol:"
630+
output = "/* Functions referencing this symbol:"
587631
for sym in self.referenceFunctions:
588632
output += f" {sym.getName()}"
589-
return f"{output}{GlobalConfig.LINE_ENDS}"
633+
return f"{output} */{GlobalConfig.LINE_ENDS}"
590634

591635
if len(self.referenceSymbols):
592-
output = "# Symbols referencing this symbol:"
636+
output = "/* Symbols referencing this symbol:"
593637
for sym in self.referenceSymbols:
594638
output += f" {sym.getName()}"
595-
return f"{output}{GlobalConfig.LINE_ENDS}"
639+
return f"{output} */{GlobalConfig.LINE_ENDS}"
596640
return ""
597641

598642

@@ -608,15 +652,20 @@ def getCsvHeader() -> str:
608652
output += "autodetectedSize,"
609653
output += "getSize,getVrom,sectionType,"
610654

611-
output += "isDefined,isUserDeclared,isAutogenerated,isMaybeString,isMaybePascalString,"
612-
output += "referenceCounter,overlayCategory,unknownSegment,"
655+
output += "isDefined,isUserDeclared,isAutogenerated,"
656+
output += "isMaybeString,failedStringDecoding,isMaybePascalString,failedPascalStringDecoding,"
657+
output += "referenceCounter,"
658+
output += "parentFunction,"
659+
output += "parentFileName,"
660+
output += "inFileOffset,"
661+
output += "overlayCategory,unknownSegment,"
613662
output += "isGot,isGotGlobal,isGotLocal,gotIndex,accessedAsGpRel,"
614663
output += "firstLoAccess,isAutogeneratedPad,autoCreatedPadMainSymbol,isElfNotype,"
615664
output += "isAutocreatedSymFromOtherSizedSym,isMips1Double"
616665
return output
617666

618667
def toCsv(self) -> str:
619-
output = f"0x{self.address:06X},{self.name},{self.getName()},{self.getNameEnd()},"
668+
output = f"0x{self.address:08X},{self.name},{self.getName()},{self.getNameEnd()},"
620669

621670
output += f"{self.userDeclaredType},{self.autodetectedType},{self.getType()},"
622671

@@ -633,9 +682,26 @@ def toCsv(self) -> str:
633682
output += "None,"
634683
else:
635684
output += f"0x{self.autodetectedSize:X},"
685+
636686
output += f"0x{self.getSize():X},0x{self.getVrom():X},{self.sectionType.toStr()},"
637-
output += f"{self.isDefined},{self.isUserDeclared},{self.isAutogenerated},{self.isMaybeString},{self.isMaybePascalString},"
638-
output += f"{self.referenceCounter},{self.overlayCategory},{self.unknownSegment},"
687+
output += f"{self.isDefined},{self.isUserDeclared},{self.isAutogenerated},"
688+
output += f"{self.isMaybeString},{self.failedStringDecoding},{self.isMaybePascalString},{self.failedPascalStringDecoding},"
689+
output += f"{self.referenceCounter},"
690+
691+
if self.parentFunction is not None:
692+
output += f"{self.parentFunction.getName()},"
693+
else:
694+
output += f"None,"
695+
if self.parentFileName is not None:
696+
output += f"{self.parentFileName},"
697+
else:
698+
output += f"None,"
699+
if self.inFileOffset is not None:
700+
output += f"{self.inFileOffset},"
701+
else:
702+
output += f"None,"
703+
704+
output += f"{self.overlayCategory},{self.unknownSegment},"
639705
output += f"{self.isGot},{self.isGotGlobal},{self.isGotLocal},{self.gotIndex},{self.accessedAsGpRel},"
640706
autoCreatedPadMainSymbolName = ""
641707
if self.autoCreatedPadMainSymbol is not None:

spimdisasm/common/FileSectionType.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ def toSectionName(self) -> str:
8080
".rodata": FileSectionType.Rodata,
8181
".rdata": FileSectionType.Rodata,
8282
".bss": FileSectionType.Bss,
83+
".ovl": FileSectionType.Reloc,
8384
".reloc": FileSectionType.Reloc,
8485
".end": FileSectionType.End,
8586
".dummy": FileSectionType.Dummy,

0 commit comments

Comments
 (0)