Archive for April, 2009
Although you probably want to create programs anew, and I’m with you there, knowing how to disassemble code is really important today with such an old system.
Much of the wisdom and the “knowing of things” is lost to time, it’s amazing how much gets discarded. The only real record is in the actual code itself, but you have to decode and decipher to regain that lost wisdom. Even with the most complete documentation library, many things are not still clear and having a good old working example goes miles to filling in those little what the hey’s.
Disassembly is the practice of decoding binary file images and producing a sourcefile. You could do this by hand, reading byte for byte and looking up the meaning of the byte as interpreted at the particular location in the code and translating that to the proper assembly syntax, and of course that would take “deep time” as the cosmologists would say.
A quicker way is to use a disassembler.
These come in all flavors, from the mundane to the sublime. I think I used to have a beta of the ORCA disassembler but that’s long gone, all I have left is the DISASM.data listing from it. I looked around the Internet and the only thing I could find was a Windows based disassembler for the 65816 called D816.
Now, D816 don’t know anything about Apple firmware, software and the like. It’s a generic 65816 disassembler knowing only the microprocessor opcodes and modes but we’re getting ahead of ourselves a bit here.
Let’s backup a notch and deal with the file some more.
The file you want to disassemble will be a ProDOS 8 binary file or relocatable OMF type. Determining which is which will be vital to successful disassembly.
A ProDOS8 binary is filetype BIN($06) but relocatables can be of several filetypes:
GS/OS or ProDOS 16 application S16($B3)
Shell application EXE($B5)
Permanent initialization PIF($B6)
Temporary initialization TIF($B7)
New desk accessory NDA($B8)
Classic desk accessory CDA($B9)
Tool set files TOL($BA)
Apple IIgs device drivers DVR($BB)
Generic loadfile LDF($BC)
GS/OS file system translator FST($BD)
If you want to disassemble a ProDOS8 BIN($06) file then you can go straight to the disassembler, but if you want to do a relocatable filetype (most likely) you need to do some pre decoding, or de-OMFing.
Oh yeah, OMF stands for Object Module Format which is basically how relocatable code it’s still done today, only the specifics have changed, the principle remains the same. All computer code must run at a specific location, it’s ORG. In short, code needs to be relocatable when a robot such as the Toolboxes Memory Manager is in control. It relentlessly works to dole out and keep track of blocks of memory in the IIgs usually at the next most convenient location. It also compacts memory (move things around to create larger available spaces).
Because it chooses where a program will be initially loaded, the code needs to be installed at and re-written for that location.
Because it moves blocks of code around, the code in them has to be re-written to operate correctly at their new location.
That’s why a relocation scheme is necessary, in the case of the AppleIIgs that’s OMF2.
Many of these filetypes can be stripped of OMF segmentation by using the MAKEBIN utility in APW as long as you change the filetype to EXE($B5). If they are multi-segment or ExpressLoad type however, this trick will not work and MAKEBIN will let you know. One thing about MAKEBIN is that it will ORG the code at $2000 instead of the normal disassembler ORG of $0. Remember this difference for later on.
In tough cases what you need to do is a little hex editing of the file to remove and expand the necessary parts of the code. Many applications use just a few segment types while a few can use the entire list. You need to learn how to read OMF, it’s not that bad but you will need a reference with the OMF segments and headers described. I know this documentation exists in the GS/OS Reference Manual and the APW Reference Manual. It may also appear elsewhere.
Figure#3.1 shows two HexEdit windows where the left one contains a straight OMF2 file and the right one contains an ExpressLoad OMF type of file. The most noticeable difference is that the ExpressLoad header is bigger… it even has the word ExpressLoad in it’s header. De-OMFing either is done the same, it’s just that the header is different, the segment codes however are exactly the same.
I have highlighted the headers in blue for clarity this is Photoshop magic, although HexEdit can do this, it looks better when dolled up in Photoshop for web publication.
We’ll do the easier of the two by doing the OMF2 file on the left, CB.PRELAUNCH. After loading this file into HexEdit I open up a TextEdit window and make some zeroes… several lines of 32 zeroes each this corresponds to each line having 16 bytes ($10). These will be used for type $F1 (DS) segments. See Figure#3.2.
Now that I am setup for decoding OMF lets take a look at exactly what we are up against. Figure#3.3 shows CB.PRELAUNCH with all important regions color coded. Blue is the header and trailing zeroes, Green is LCONST segment headers, Orange is DS segment headers, Purple is the relocation dictionary and yellow is static code bytes (what we are after here). I picked this file because it is simple and also because it will fit on one screen, most programs are a bit bigger than this one.
The key skill involved with this in my opinion is “pattern recognition”, much like as is dramatized in the movie “A Beautiful Mind”. Just remember to never interact with those imaginary people!
The first 64($40) bytes are the header, it has a lot of 00 and 20′s (spaces) all that information means something but for our purposes only one bit is of interest. 8 bytes in there is the pattern “7C 02 00 00″. This is the finished length of the file contained, make a note of this. If you are new to the IIgs, numbers are stored in memory in reverse order what is really being represented is a 4 byte value (long) “00 00 02 7C” or just plain “27C” ignoring the leading zeroes. That’s a number represented in hexidecimal and after a quick tap on the calculator the file will be 636 decimal bytes long. You could of course do this conversion in your head if you were painfully smart. Personaly, I need my calculator set to programmer.
After the header there is another pattern “F2 A2 01 00 00″… a five byte pattern. This is an LCONST($F2) segment header. Once again make note of the last four bytes, they are the length of bytes to follow that contain static program code. Here we go… Select the first 69($45) bytes which is the header and this segment header and delete them!
Now, index in $1A2 bytes and you will find another pattern: “F1 9A 00 00 00″ immediately followed by another pattern “F2 40 00 00 00″. This is a DS segment header followed by another LCONST segment header. The DS header says to insert $9A(154) zeroes at that point in the code. Go to the TextEdit window with the zeroes and highlight $9A of them, hit
Now we’re nearly there, see… I told you it would not be real hard. The last thing to do because we are all out of construction segments is to highlight and remove the relocation dictionary and trailing spaces Figure#3.6. On most code, that’s all there is to it except for their being more DS followed by LCONST headers in the code, do them one by one in sequence and you will not have any problems.
INTERSEG headers can appear when the program is broken down into multiple load segments where each segment has it’s own relocation dictionary, you will come across INTERSEG headers and special relocation headers which have to be dealt with differently. Read up about these segments and it will all become clear. Now you have a properly constructed binary image of the file ORGed at $0… perfect! Save this away to disk as CBPRE.BIN and get ready to stick it in the disassembler.
The next chapter will be a continuation of this chapter but it will actually deal with authentic disassembly, the meat and potatoes of the process, until then try this out a bit and get a feel for relocatable architecture.
As a side note here, if you have the ORCA disassembler then you really don’t need to do any of this stuff because ORCA knows how to read OMF along with a bunch of other stuff and does all this cutting and pasting for you automatically. I just though it would be good background on what’s really happening when you load a relocatable file by telling you this at the end of this section rather than before where you might tend to skip over this vital information.
Next Post: Chapter 3 (cont.): Actual disassembly
I know we’re talking assembly language here and something has come to light and needs to be disseminated to the Apple IIgs user base post haste. Back in 1990 when So What Software closed it’s doors, we were unaware of GS/OS version 6 because it was not out yet. It appears to make our flagship software product “Call Box” crash!!! After a bit of digging, disassembling and help from key old timers such as Dave Lyons I have found the problem, which in reality is a big one, but fixable. It all has to do with Memory Manager master pointer records and tools and the way I abuse them in that software. I quickly made a patch which will allow Call Box version 2.0 to operate under GS/OS version 6.xx.
Seeing that this is a discourse on assembly language and toolbox programming I have posted the sourcecode and macros for the patch so that you can get some APW time right off the bat with pre-debugged source. Just some simple copying, pasting, assembling and linking.
I realize that you can count the number of 65816 programmers on one hand these days so I have included the compiled patch as well. This image also includes the file BASIC.LAUNCHER which Apple cleverly removed from the 6.0.X release of the System Disk. This file is necessary for launching Call Box BASIC programs from the Call Box Launching Shell.
GEN ON LIST ON SYMBOL ON ABSADDR ON MCOPY fixcb.mac KEEP fixcb ORG $2000 ;------------------------------------------------ ; This patch is for Call Box Version 2.0 only!!!! ; ; This patch fixes the Master Pointer Block Bug ; found when operating CB 2.0 under GS/OS V6.XX ; ; This patch is quite fragile and is intended as ; a temporary fix until the new version 3.0 is ; released later in 2009. ; ; By William Stephens 04.10.2009 ;------------------------------------------------ PatchLocation gequ $84 ;V2.0 specific PatchValue gequ $CC ;New value, original is 0600 PatchValue1 gequ $13 ;VERY HARDWIRED *** DANGER *** FileLength gequ $602A ;V2.0 specific OpenBuf gequ $1C00 ;4 page DOS buffer HexOut gequ $FDDA ;Print a hex byte C gequ $43 ;ASCII "C" B gequ $42 ;ASCII "B" Indexer gequ $F8 ;Zero page indexer Begin START OBJ $2000 sec xce sep #$30 longa off longi off ;-- Make the full pathname ---------------------- _P8:Get_Prefix GetPrefixPrm tax lda #0 bcs errnxt lda #PathBuf sta Indexer lda #>Pathbuf sta Indexer+1 ldy PathLen lda #C sta (Indexer),y iny lda #B sta (Indexer),y iny sty PathLen ;-- Fix the file access bits -------------------- _P8:Get_File_Info FilePrm tax lda #1 bcs error lda #35 ;Set to __BWR sta FileAccess lda #7 sta FilePrm _P8:Set_File_Info FilePrm tax lda #2 errnxt bcs error ;-- Open the file ------------------------------- _P8:Open OpenPrm tax lda #3 bcs error ;-- Pass the reference number ------------------- lda Orefnum sta Crefnum sta Rrefnum sta SMrefnum ;-- Read the file into the buffer --------------- _P8:Read ReadPrm tax lda #4 bcs error ;-- Do the patch -------------------------------- lda #Image sta Indexer lda #>Image sta Indexer+1 ldy #PatchLocation lda #PatchValue sta (Indexer),y iny lda #PatchValue1 sta (Indexer),y ;-- Reposition to the start of file ------------- _P8:Set_Mark SetMarkPrm txa lda #5 bcs error ;-- Write the file back to itself --------------- _P8:Write ReadPrm tax lda #6 bcs error ;-- Close the file ------------------------------ _P8:Close ClosePrm ;-- Fix the file access bits -------------------- lda #33 ;Set to __B_R sta FileAccess _P8:Set_File_Info FilePrm tax lda #7 bcs error ;-- Patching finished --------------------------- rts ;-- Error handler ------------------------------- error jsr HexOut ;Display command#/error# txa jsr HexOut rts ;-- Parameter tables and data ------------------- SetMarkPrm dc i1'2' SMrefnum dc i1'0' dc i3'0' FilePrm dc i1'10' dc i'PathLen' FileAccess dc i1'0' dc i1'0' dc i'0' dc i1'0' dc i'0' dc i'0' dc i'0' dc i'0' dc i'0' OpenPrm dc i1'3' dc i'PathLen' dc i'OpenBuf' Orefnum dc i1'0' ClosePrm dc i1'1' Crefnum dc i1'0' GetPrefixPrm dc i1'1' dc i'PathLen' ReadPrm dc i1'4' Rrefnum dc i1'0' dc i'Image' dc i'FileLength' dc i'0' PathLen dc i1'0' PathBuf ds 63 Image ds FileLength END
MACRO &lab _P8:Get_Prefix ¶ms &lab jsr $BF00 dc i1"$C7" dc i2"¶ms" MEND MACRO &lab _P8:Get_File_Info ¶ms &lab jsr $BF00 dc i1"$C4" dc i2"¶ms" MEND MACRO &lab _P8:Set_File_Info ¶ms &lab jsr $BF00 dc i1"$C3" dc i2"¶ms" MEND MACRO &lab _P8:Open ¶ms &lab jsr $BF00 dc i1"$C8" dc i2"¶ms" MEND MACRO &lab _P8:Read ¶ms &lab jsr $BF00 dc i1"$CA" dc i2"¶ms" MEND MACRO &lab _P8:Set_Mark ¶ms &lab jsr $BF00 dc i1"$CE" dc i2"¶ms" MEND MACRO &lab _P8:Write ¶ms &lab jsr $BF00 dc i1"$CB" dc i2"¶ms" MEND MACRO &lab _P8:Close ¶ms &lab jsr $BF00 dc i1"$CC" dc i2"¶ms" MEND
Once you have this assembled and linked as a P8 binary file named “FIXCB”, put it in the directory with the file CB (the Call Box BASIC engine) and type BRUN FIXCB. Also, put the file BASIC.LAUNCHER in you root directory.
That should fix up your Call Box installation for now.
Call Box version 2.0 is freely downloadable from this site, simply visit The Call Box TPS page. There you will find the 2.0 installation set, Programmers association disks and the all important manual.
Chapter 3 will be posted soon…
Using an emulation development enviroment for the Apple IIgs presents some unique problems when dealing with files.
First things first, you’ll want a transfer disk to get things from the Mac to the IIgs emulator and back again. This can be simply done by going to Applications/Utilities/Disk Uility on you Mac and click “New Image”. Make the “Save as” and “Volume name” the same thing as in this example “transfer”. Use a volume size of 100Meg.. nice round figure. Volume Format should be Mac OS Extended (journaled). Encryption: none, Partitions: single partition and Image format: read/write disk image. Once these settings are made click “Create” and a transfer.dmg will be created in the location you specified by setting the “Save as”. If that image got mounted somehow, unmount it.
You’re done with this phase so close down Disk Utility and open up your emulator, mount your GSOS, start it up and mount the transfer.dmg you just created. GSOS will complain that it can not read the disk and it want’s to format it. Select HFS and Format the disk. It will now appear as a 3.5″ disk on the GSOS desktop even though it’s 100meg.
You can now drag and drop files to it or from it in either GSOS or OSX as long as only one of the OS’s have it mounted and any given time. Having both GSOS and OSX mount the dmg at the same time causes havoc!
Source to TextMate, TextMate to Source
TextMate is the main text editor used in this configuration and a few simple things need to be addressed. On the GS/OS side of things we are using APW/ORCA for the generation of binaries and executables used by the Apple IIgs.
The first transfer (Source to TextMate) is pretty simple, From the AppleIIgs, mount the transfer disk and drag and drop the sourcefile(s) into it, drag the disk to the AppleIIgs trash to eject (unmount) the disk. From the Mac, mount the transfer disk and drag and drop the sourcefile to your working directory. That’s about it, you can now open this file with TextMate and edit away.
The second transfer (TextMate to Source) is a little more complicated. The default Line ending in TextMate is a line feed (LF – $0A), APW/ORCA on the other hand uses carriage returns (CR – $0D). If you attempt to open up a line feed version with the APW Editor it thinks it’s a single long string of characters and will fail. In TextMate, select “TextMate/Preferences/Advanced” and in this dialog you will see a selector for “Line Endings”. Set this selector to “CR (Mac OS Classic)”. This will solve this little problem. To make sure this is happening you can open up the file in HexEdit, look for the $0A or $0D at the end of text lines. If you find $0A then you can search for $0A and replace with $0D globally to fix the difference.
In the Mac, mount the transfer disk and drag and drop the source file in it, then unmount the transfer disk then from the AppleIIgs, mount the transfer disk and drag and drop the file to the APW sourcecode folder. At this point you would think your all done but this is not the case. This file is not a filetype $B0(SRC), auxtype $0003(ASM65816) identified file and APW will not recognize it. You need to change the filetype and auxtype on the file before it’s official. I use the File Utility in Call Box to accomplish this, there are other file utilities and byte zappers that can do this as well, that’s up to you.
A simpler but much slower method is to copy the source in TextMate (select all) and with Sweet16 up and running the APW Editor, with a new blank document named the same as the sourcefile, you can use the File/Paste function of Sweet16 to write the file into the blank document. Once the APW Editor saves this file, the type and subtype will be the correct kinds and you will not have to worry about the line feeds and carriage returns.
You can also use the Sweet16 paste command to great advantage with Applesoft code. Copy the Applesoft code you have in TextMate and have the emulator up and running. Goto Applesoft BASIC environment (once again I use the Call Box Launchung Shell for this purpose). From the ProDOS8 command line type “NEW” and then use the Sweet16 paste command to write the Applesoft into the interpreter. Once done, “SAVE” the file and that’s it!
Going the other way however is not as easy. Applesoft is a tokenized language where all it’s commands are not the text of the command but are instead single byte values (the tokens) not to mention the linked list bytes. A straight binary copy as I have been discussing so far will result in a whacky, mostly unreadable file in TextMate. This is because you would be looking at the encoded version that only Applesoft interpreters can read. Sweet16 has a command that can overcome this conundrum. It’s the “Capture Text Screen” command in the File menu. What you do is LIST the file on the screen, Capture the text and then paster into TextMate. This is easier to say than it is in practice.
What gets pasted into TextMate is the characters that make up the screen display of the IIgs including all the trailing spaces and whatnot, a rectangle of characters. You need to carefully use the LIST command to limit what’s displayed because even modest Applesoft programs are more than the screen height and scroll by if LISTed without limits. In textMate you will need to remove all those trailing spaces but TextMate is good at things like that.
Next post – Chapter 3: Disassembly