| |||
Views: 88,486,538 |
Main | FAQ | Uploader | IRC chat | Radio | Memberlist | Active users | Latest posts | Calendar | Stats | Online users | Search | 04-26-24 09:31 AM |
|
Guest: Register | Login |
0 users currently in ROM Hacking | 2 guests | 2 bots |
Main - ROM Hacking - I've come accross a few interesting 6502 ASM things... | New thread | New reply |
Jigglysaint |
| ||
Red Paragoomba Level: 20 Posts: 28/62 EXP: 38539 Next: 3900 Since: 04-04-07 Last post: 4617 days Last view: 2354 days |
So I've been hacking the Guardian Legend...again, and I've noticed a few odd things that seem to not make any sense. The first is that for a specific spot in the rom, the pointers that lead to data all lead to the last byte of the previous code. So basically the pointers lead to an RTS, but the data the pointer is getting is one byte to the right of it.
The second oddity is that there are pointers that are defined, but the code that defines them runs right into the list without an RTS to signify the end of the code. Say for example that we have the code, followed by a JSR xx xx, but then I see a $47 $C0 followed by the pointer list. I've seen this happen with the Z80, but not with the 6502. In fact, $47 is considered future expansion. So does anbody know what's going on with this? |
Sliver X |
| ||
Paragoomba Level: 21 Posts: 62/66 EXP: 42453 Next: 7490 Since: 02-26-07 From: WV Last post: 5488 days Last view: 5344 days |
Posted by Jigglysaint Sure it's not doing something like an LDA, X? What's the status of X and Y when a pointer is read? Is either #$01?
Most likely $47 and $C0 are some kind of data, not opcodes. FCEUXD's code/data logger would easily show which it is without debugging. ____________________ Arc-Nova.org: More Chiptunes Than Your Mother Can Handle |
NetSplit |
| ||
Level: 32 Posts: 115/178 EXP: 188030 Next: 18412 Since: 02-26-07 Last post: 2217 days Last view: 2142 days |
Assuming the pointers point to code, they are likely being pushed to the stack and then used with an RTS. RTS works by pulling the top two bytes from the stack and jumping to that address plus one. I used to know a bit about the reasoning for that sort of setup, but I've since forgotten. The RTS method is an important method for jumping to the proper routine; for example, if you have several weapons and need to get to the code for the right one, putting the address minus one on the stack and doing RTS is an effective method for getting there.
I don't know what to tell you about the other thing. In the event that you haven't simply read the code wrong, it's certainly possible to do JSRs that don't need to be returned from. It's possible that the game wants the address, in which case you could do a JSR and a couple of PLA instructions, followed by adding 1 to the pair if need be. One would need to examine the code, primarily after the JSR, to understand what it's doing. |
smkdan |
| ||
Ninji Level: 36 Posts: 151/238 EXP: 288647 Next: 19463 Since: 05-26-07 Last post: 4062 days Last view: 4011 days |
I know SMW does this a fair bit and that metroid disassembly on RHDN does this too.
By placing pointer table right after the JSL/JSR, the routine that is being 'called' can pull the return address off the stack, add 1 and treat it as a pointer to the jump table which in this case is indexed by the value in A. This may be relevant considering you said that there's a pointer list after the JSR in the game. |
Trax |
| ||
Yellow Stalfos Level: 71 Posts: 490/1145 EXP: 3035781 Next: 131333 Since: 07-06-07 From: Québec Last post: 3627 days Last view: 2879 days |
Exactly. I've seen that a few times, it's possible that a JSR doesn't come back to where it was called, because the routine it points to pulls a byte from the stack two times and jumps to the address using the two bytes. But there's no way you can tell until you know the ROM well. There are even blocks of code that end with BNE or BEQ...
The first oddity looks like an indirect address fetch. It could be that, just next of the RTS, there's some data table, and the offset variable is known to be always more than 0. It's made this way sometimes when the variable values are not zero-based... |
Jigglysaint |
| ||
Red Paragoomba Level: 20 Posts: 29/62 EXP: 38539 Next: 3900 Since: 04-04-07 Last post: 4617 days Last view: 2354 days |
Ahh that would explain it then. It's pretty much a creative use of the RTS to exploit it's function. I've seen JSR's before, followed by a list of pointers. The two bytes inbetween are most likely a pointer to the first in the list, which in this case is the "No Use" option. So in this case, the JSR must actually work as a JMP, but the RTS is the pointer in which to return. Basically a way to make an indirect JMP, but to save space. This case does not need to use an X or Y value, nor does it need to access a large array of pointers. Both examples are actually directly connected, as the pointers in the list lead to the RTS. |
optomon |
| ||
Leever Level: 33 Posts: 108/198 EXP: 220473 Next: 8706 Since: 03-05-07 From: Vancouver, WA Last post: 2457 days Last view: 2045 days |
I'll admit, I still don't understand the logic of a lot of coding techniques I've come across in games or why they work the way they do. I just know what they do. I couldn't tell you how a stack works or even what a stack is. Is this pretty much how everyone does stuff? |
Trax |
| ||
Yellow Stalfos Level: 71 Posts: 499/1145 EXP: 3035781 Next: 131333 Since: 07-06-07 From: Québec Last post: 3627 days Last view: 2879 days |
Everyone must start at the very beginning, anyways. But doing everything in the black doesn't help. When you don't know how something works, you can hardly make changes to it without breaking everything. So the exact uderstanding comes handy when you want to actually hack the code and modify the game's behavior...
A stack is exactly what it's called. Like a stack of plates. But instead of plates, it's bytes. You push values on the top, and take back the values later. It's a system of the type "first in, last out". When you add a plate on the stack, you must put it on top, you can't "slide" it in between other plates. And when you want to take a plate from the stack, you have to take the one on the top... |
optomon |
| ||
Leever Level: 33 Posts: 109/198 EXP: 220473 Next: 8706 Since: 03-05-07 From: Vancouver, WA Last post: 2457 days Last view: 2045 days |
The plate analogy is good, but it doesn't tell me exactly what it is. Is it just a register (or something) used to temporarily store bytes when you need them? So if an RTS is sneaking the original location of the address right after the JSR location from the stack... would a single PHA or PLA before the RTS corrupt the return address that would be pulled from the stack?
EDIT: While we're on the subject of Guardian Legend, what are you doing to the game exactly Jigglysaint? If anyone's interested in a Guardian Legend hack it is definitely me. |
Kawa |
| ||
CHIKKN NI A BAAZZKIT!!! 80's Cheerilee is best pony Level: 138 Posts: 1193/5344 EXP: 30944726 Next: 718255 Since: 02-20-07 From: The Netherlands Last post: 4498 days Last view: 2633 days |
Stack's usually a part of regular memory. Often enough it starts at the highest possible address and works down. There's usually a matching register (marked SP for Stack Pointer) that determines how deep the stack currently goes.
I prefer the stack of papers analogy, but plates work too. ____________________ Wife make lunch - Shampoo Opera - give it a spin Spare some of your free time? <GreyMaria> I walked around the Lake so many goddamn times that my sex drive was brutally murdered Kawa rocks — byuu |
Jigglysaint |
| ||
Red Paragoomba Level: 20 Posts: 30/62 EXP: 38539 Next: 3900 Since: 04-04-07 Last post: 4617 days Last view: 2354 days |
Posted by optomon Well truth be told I did create a hack a while ago, but I never got around to finishing it. The overall labyrnth is done, and all items are obtainable, but other room interiors were not added. That's a shame because I wanted to do some creative things with the interiors. Currently I am checking to see how things are coded so I can made some changes to things like weapons and corridor seals. So far I made the Saber weapon spin arround instead of stay straight(except in corridors), and I've discovered how the game handles the 4th seal. The only problem is there is little to no space to add new code, and even so, the passwords would not be able to hold any additional information, such as new upgrades. Seriously though, if anybody is interested in making a TGL hack, contact me because I've got almost all the data, save that for the Corridors. |
Hamtaro126 |
| ||
Cheep-cheep Level: 33 Posts: 88/194 EXP: 212837 Next: 16342 Since: 05-02-07 From: Shelton, WA Last post: 2472 days Last view: 2315 days |
Posted by smkdan Super Mario Brothers 1 does this too, It has already been disassembled by Doppleganger of NESDEV forums. And it is in Romhacking.Net under the documents section with the name SMBDIS. ____________________ Mah boi, romhacking is what all true warriors strive for! I wonder what's for dinner? |
Trax |
| ||
Yellow Stalfos Level: 71 Posts: 507/1145 EXP: 3035781 Next: 131333 Since: 07-06-07 From: Québec Last post: 3627 days Last view: 2879 days |
The stack is userful for functions embedding. It's a way the program "remembers" what it was doing when another function is called. Like Kawa said, it's a part of memory. On the NES, it goes from 0x1FF down to 0x100 (correct me if I'm wrong). Suppose you have functions A B C. In pseudo-pseudo-code, it would go like that:
- Execute A. - Halfway in A, I must do B, so I need to remember my current position in the program, so I can come back later. - Push current position to the stack. - Execute B. - Halfway in B, I must do C, so I push my position on the stack again. - Execute C. - When C exits, pull back the last position and go on. - Pull and continue with B function. - When B exits, pull back again. - Go on with A. - Etc... In plain language, here's how JSR works: - Add 3 to the program counter - Push the least significant byte of the current PC (Program Counter) on the stack - Push the most significant byte of the current PC (Program Counter) on the stack - Jump to the address stated by the operand. Example: E212: 20 34FC JSR $FC34- Push the value E2 on the stack - Push the value 15 on the stack - Jump to $FC34 And how RTS works: - Pull value from stack and set it as the most significant byte of the PC - Pull value from stack and set it as the least significant byte of the PC - Go on with the resulting PC When the $FC34 function hits a RTS, the PC is set to $E215 and the program goes on... |
Main - ROM Hacking - I've come accross a few interesting 6502 ASM things... | New thread | New reply |
© 2005-2023 Acmlm, blackhole89, Xkeeper et al. |
MySQL - queries: 87, rows: 120/120, time: 0.018 seconds. |