Author
|
Topic: SNES Disassembler? (Read 779 times)
|
DaMarsMan
Guest
|
|
« on: December 23, 2007, 04:15:57 pm » |
|
I'm recoding Glory of Heracles from scratch due to it's nasty bugs. I'm looking for a disassembler that can disassembler a whole bank in code format with labels. I tried tracer and a couple others but I'm not too happy with the results. Anybody have any suggestions?
By the way, the reason I'm looking for this is because my code was so nasty and disorganized on the last version. I had little custom hacks inserted everywhere.
|
|
|
|
byuu
Guest
|
|
« Reply #1 on: December 24, 2007, 09:23:23 am » |
|
I'm recoding Glory of Heracles from scratch due to it's nasty bugs. ... the whole game? That would indeed be a first. I'm looking for a disassembler that can disassembler a whole bank in code format with labels. Try and disassemble the db's in this code: lda $7e2000 pha plp db $a9,$00,$6b,$ea It could be either lda #$6b00 : nop, or lda #$00 : rtl : nop. And this is why you can't have a generic disassembler for the SNES. Variable instruction lengths. This is why few have even tried. But if you're looking for the best overall disassembler, you might try ISDA by Louis Bontes, if you can find it. It tries a lot harder to predict changes to P, but of course no disassembler can be perfect. Really, the only good way to do this would be to have a debugger that logged what addresses contained what opcodes. Also export a lot of symbolic information like where the code usually jumps to, sort of a profiler if you will. Follow up with a disassembly that also attempts micro-emulation of code blocks for the stuff you couldn't trigger through normal gameplay. Although it is possible to have the same code do two different things by changing P, in reality I've never seen it done, so it shouldn't be a problem. Of course, no such tools exist, so you'd have a lot of fun making something like that. Overall, I think your goal is technically possible, but way, way more trouble than it's worth. Still, if you do decide to give it a shot, I wish you the best of luck!
|
|
|
|
DaMarsMan
Guest
|
|
« Reply #2 on: December 24, 2007, 11:00:47 am » |
|
Heh well I should of said rehack instead of recode. I get what your saying and I have definitely seen the problem before. Is there anything that can take a squelched trace and put it into code format and the right order?
|
|
|
|
ecst
Guest
|
|
« Reply #3 on: December 24, 2007, 12:34:33 pm » |
|
And this is why you can't have a generic disassembler for the SNES. Variable instruction lengths. This is why few have even tried. But if you're looking for the best overall disassembler, you might try ISDA by Louis Bontes, if you can find it. It tries a lot harder to predict changes to P, but of course no disassembler can be perfect. While this is indeed the greatest obstacle for disassemblers trying to primarily incrementally disassemble a given contiguous block of (presumed) code (e. g., a subroutine), which is in most cases what is desired, it is not so much of (but, however, still is) a problem with disassemblers following a control flow analysis based approach, which I would recommend here, since a whole bank is certain to contain non-asm data, which the first kind of disassemblers will not be able to distinguish from code. Of course, the success of this approach depends entirely upon the game code abstaining from certain "ugly" things, like untraceable stack manipulation, executing non-trivial modifiable code from RAM, relevant interaction with interrupts, or, as in your example, byuu, loading the status register from an address with unpredictable content. As SNES games were standardly coded directly in asm, there is no limit on the possible level of ugliness. For some of these things, depending on the level of ugliness, game-specific workarounds might enable the disassembler to handle the situation. Last but not least, the disassembler will sooner or later encounter indirect jumps/calls (there are many forms of them, not just JMP (a,x), JMP (a), or JSR (a,x), but also hand-crafted ones via stack "manipulation"), which either require external information (debugger trace), human interaction, or a very intelligent/fast theorem prover to decide upon possible jump/call targets. In practise, though I have not looked at too many ROMs, this approach (without even further sophistication I am currently experimenting with) seems to be at least somewhat feasible, with the code of many games abstaining from the most ugliest things. I managed to completely disassemble Lufia II, for which I originally started this project: You can see some result at http://uxul.org/lufia2_E, though I would be surprised if this were of use to anybody (aside from the usage map, it is just a bunch of asm with meaningless label names). Wondering if what I have written so far could also be useful for this game (I take it you are referring to the third game in the series), I tried and managed without much game-specific adjustments to disassemble roughly 80 kb of asm code, including most of the first bank (see http://uxul.org/heracles_usage.bmp (Warning, 1,5 mb! For much smaller PNG version see below) - white dots represent asm bytes, banks are separated by blue lines). If you are interested in this approach, let me hear, so that we can pursuit further.
|
|
« Last Edit: December 24, 2007, 05:19:39 pm by ecst »
|
|
|
|
creaothceann
Guest
|
|
« Reply #4 on: December 24, 2007, 05:06:09 pm » |
|
heracles_usage.bmp
Could've used PNG, and reduced the size down to 2.5 KB. :huh: </offtopic>
|
|
|
|
ecst
Guest
|
|
« Reply #5 on: December 24, 2007, 05:17:58 pm » |
|
Yeah, you're right. I usually create those usage images on the fly for use only by myself, and there size doesn't matter. Anyway, here's the PNG version (9,6 kb): http://uxul.org/heracles_usage.png
|
|
« Last Edit: December 24, 2007, 05:24:41 pm by ecst »
|
|
|
|
DaMarsMan
Guest
|
|
« Reply #6 on: December 24, 2007, 06:32:43 pm » |
|
I may not need to whole rom but only bank 2. 028000-02FFFF is where most the code for the text box and menus seem to be. PM me with your AIM screen name or some other way and maybe we could work a little bit on it together. I already have the complete translation but I'm looking to rework the whole hacking job.
|
|
|
|
DaMarsMan
Guest
|
|
« Reply #7 on: December 28, 2007, 11:41:15 am » |
|
With the help of a ecst, we've got the whole rom recompiling. I moved bank 02 to a new region. Now I have one large chunk of code to work with. The only problem is I don't know where to set break points now. Does anyone know if there is an xkas function that can output the PC to the console? That way when I add code before or after, it'll show where I need to set the breakpoint.
|
|
|
|
Kejardon
Guest
|
|
« Reply #8 on: December 28, 2007, 04:10:37 pm » |
|
It says in the xkas help file. <_< IIRC, you can use: print 'Current PC offset: ',pc
|
|
|
|
DaMarsMan
Guest
|
|
« Reply #9 on: December 28, 2007, 04:24:34 pm » |
|
Okay thanks... I feel like a noob. The xkas readme is missing a lot so I guess I assumed what I wanted wasn't there.
|
|
|
|
Gemini
Guest
|
|
« Reply #10 on: December 31, 2007, 11:20:06 am » |
|
I'm recoding Glory of Heracles from scratch due to it's nasty bugs. I'm looking for a disassembler that can disassembler a whole bank in code format with labels. Do you think this output is good enough? It's part of my Snes porting SDK (65816 plug-in for IDA), and it's still on WIP, but works with most of the instructions. On this matter, there is a question I'd like to ask byuu and all the other Snes experts: what it actually RTI for? I know it stands for "ReTurn from Interrupt", but WHERE does it return? It's not like that was a subroutine, so I really don't know how to treat that kind of instruction. Also, is BRK only used to break the console? Thanks!
|
|
|
|
DaMarsMan
Guest
|
|
« Reply #11 on: December 31, 2007, 11:38:11 am » |
|
The one that ecst made looks like this.... SUBROUTINE_04C1: ; $02C234 PHY PHB LDA.b #$7E PHA PLB LDA $13E9 CMP.b #$A0 BCC LABEL_09ED CMP.b #$D0 BCS LABEL_09EB SEC SBC.b #$50 PHA LDA.b #$2F BNE LABEL_09EC LABEL_09EB: ; $02C24D SEC SBC.b #$60 PHA LDA.b #$2E LABEL_09EC: ; $02C253 STA $13E9 JSR SUBROUTINE_04C2 PLA STA $13E9 LABEL_09ED: ; $02C25D STA ($D2) LDY.b #$01 LDA.b #$20 ORA $13DE STA ($D2),y LDA $138F BEQ LABEL_09EE LDY $1248 LDA $13E9 STA $111C,y LDA.b #$20 ORA $13DE STA $11B2,y REP #$20 SEC LDA $D2 SBC.w #$8000 LSR A STA $19 SEP #$20 CLC LDA $19 ADC.b #$00 STA $1054,y LDA $1A ADC.b #$78 STA $10B8,y INY STY $1248 LABEL_09EE: ; $02C29E PLB REP #$20 INC $D2 INC $D2 SEP #$20 PLY RTS
SUBROUTINE_04C2: ; $02C2A9 LDA $D3 PHA LDA $D2 PHA SEC LDA $D2 SBC.b #$2A STA $D2 BCS LABEL_09EF DEC $D3 LABEL_09EF: ; $02C2BA LDY.b #$00 LDA $13E9 ORA $13DE STA ($D2),y INY LDA.b #$20 ORA $13DE STA ($D2),y PLA STA $D2 PLA STA $D3 RTS
|
|
|
|
Kejardon
Guest
|
|
« Reply #12 on: December 31, 2007, 01:30:50 pm » |
|
On this matter, there is a question I'd like to ask byuu and all the other Snes experts: what it actually RTI for? I know it stands for "ReTurn from Interrupt", but WHERE does it return? It's not like that was a subroutine, so I really don't know how to treat that kind of instruction. Also, is BRK only used to break the console? Thanks!
When an interrupt hits, the game finishes whatever instruction it's on and immediately goes to the interrupt vector (FFEE for IRQ, or FFEA for NMI). You can sort of think of it as a JSL (Interrupt Vector) : PHP, and the RTI is a PLP : RTL. BRK and COP are like interrupts triggered by opcodes, and with their own vectors, but I've never seen them used so I'm not too sure about them.
|
|
|
|
tomaitheous
Guest
|
|
« Reply #13 on: December 31, 2007, 06:52:14 pm » |
|
The BRK return address is +2 bytes incremented from the BRK opcode location, with the BRK only being one byte opcode. It's used as a software interrupt. For the BRK interrupt routine, the programmer can get the address from the stack, grab that one byte after the BRK opcode as an operand.
|
|
|
|
|