disassembler.library¶
disassembler.library is a small system library from the MMULib project (Thomas Richter, THOR-Software). It turns 680x0 machine code into Motorola-syntax assembler text. The NDK 3.2 ships the library binary in MuTools/ (disassembler.library 40.9 (24.1.2021)) and its developer files in MuManual/ (autodoc, C and assembler includes, FD file and BMAP, all at include revision 40.2).
MuForce and MuGuardianAngel use it for their DISPC/DISRANGE options. The library is just as useful in your own monitors, crash reporters and debug output.
According to its autodoc, the library:
- knows every MC68K processor from the 68000 to the 68060, including FPU and MMU instructions;
- is MMU aware. If mmu.library is available, it will not read invalid or unavailable memory or I/O space, provided the MMU table is set up correctly. It also works without mmu.library, but then it cannot validate its accesses;
- is interrupt and supervisor callable, provided your output procedure is too.
Library interface¶
| Item | Value |
|---|---|
| Library name | "disassembler.library" (DISASSEMBLER_NAME; assembler macro DISASSEMBLERNAME) |
| Base variable | DisassemblerBase |
| Base structure | struct DisassemblerBase { struct Library dllib_Library; /* private */ }; |
| Headers | libraries/disassembler.h / .i, clib/disassembler_protos.h, pragmas/disassembler_pragmas.h, proto/disassembler.h, lvo/disassembler_lvo.i |
| FD bias | 66 (the FD notes "6 slots reserved here" before the public functions) |
| Function | LVO | Registers | Prototype |
|---|---|---|---|
Disassemble |
−66 ($42) |
A0 |
APTR Disassemble(struct DisData *ds); |
FindStartPosition |
−72 ($48) |
A0, D0, D1 |
APTR FindStartPosition(APTR startpc, UWORD min, UWORD max); |
struct DisData¶
struct DisData {
APTR ds_From; /* base to start disassembly from (must be even) */
APTR ds_UpTo; /* where to stop it (exclusive) */
APTR ds_PC; /* the disassembler prints a "*" here */
void *ds_PutProc; /* output routine; void * to avoid casts */
APTR ds_UserData; /* passed to the PutProc in a1 and a3 */
APTR ds_UserBase; /* passed to the PutProc in a4 */
UWORD ds_Truncate; /* limit width of the output, 0 = no limit */
UWORD ds_reserved; /* must be zero */
};
| Field | Meaning |
|---|---|
ds_From |
First address to disassemble. Must be even. |
ds_UpTo |
Exclusive end of the region. |
ds_PC |
An address to mark with * in the output, typically the program counter of a fault. |
ds_PutProc |
Character output routine (see below). |
ds_UserData |
Loaded into A1 and A3 for the first call of ds_PutProc. |
ds_UserBase |
Loaded into A4 before each call. For near-data C code, set it to the linker's data base (_LinkerDB). |
ds_Truncate |
Maximum line length; longer lines are cut. 0 disables truncation. |
ds_reserved |
Must be 0 for future extensions. |
The PutProc¶
ds_PutProc is called once per output character, in the style of exec RawDoFmt():
| Register | Contents |
|---|---|
D0 |
The character. Lines end with a single LF (0x0A). |
A1, A3 |
ds_UserData on the first call; afterwards, whatever A3 the routine returned last time. |
A4 |
ds_UserBase. |
The routine may return an updated A3, which is passed in A1 and A3 on the next call. That makes the classic "store byte and advance pointer" routine possible:
; PutProc that appends to a buffer: a3 = current write pointer
PutChar:
move.b d0,(a3)+
rts
If Disassemble() is called from an interrupt or in supervisor mode, the PutProc must be safe there as well.
Disassemble()¶
APTR Disassemble(struct DisData *ds); /* A0 */
Disassemble() disassembles the memory from ds_From up to ds_UpTo and sends the text through ds_PutProc, marking ds_PC with an asterisk. It returns the address where the disassembly stopped. Pass that value back as ds_From to continue at the right place.
FindStartPosition()¶
APTR FindStartPosition(APTR startpc, UWORD min, UWORD max); /* A0, D0, D1 */
68k instructions have variable length, so you cannot simply start disassembling n bytes before an address. FindStartPosition() examines the code in front of startpc and returns an address between startpc - max and startpc - min (with min < max, both positive distances). Disassembly started there includes the instruction at startpc and shows as few illegal instructions as possible. If no suitable address is found, startpc itself is returned.
startpc should be an address known to hold a valid instruction. The autodoc's recipe for disassembling "around" an address:
- Call
FindStartPosition()with that address. - Disassemble from the result for about
max * 2bytes.
MuForce's DISPC output is a disassembly of this kind: DISRANGE (default 32) sets the approximate number of bytes disassembled before and after the fault.
Example: disassemble around an address¶
#include <exec/types.h>
#include <libraries/disassembler.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/disassembler.h>
struct Library *DisassemblerBase;
/* SAS/C style register arguments; adapt for your compiler. */
static void __asm __saveds PutProc(register __d0 UBYTE c,
register __a3 UBYTE *buf)
{
/* Simplest possible sink: print each character with dos.library.
Not interrupt-safe; use a buffer (see the asm example) if you
need to call Disassemble() from an exception or interrupt. */
FPutC(Output(), c);
}
void DumpCode(APTR pc)
{
struct DisData dd;
APTR start;
if (DisassemblerBase = OpenLibrary(DISASSEMBLER_NAME, 40)) {
start = FindStartPosition(pc, 16, 32);
dd.ds_From = start;
dd.ds_UpTo = (UBYTE *)pc + 32;
dd.ds_PC = pc;
dd.ds_PutProc = (void *)PutProc;
dd.ds_UserData = NULL;
dd.ds_UserBase = NULL; /* or the near-data base pointer */
dd.ds_Truncate = 79;
dd.ds_reserved = 0;
Disassemble(&dd);
Flush(Output());
CloseLibrary(DisassemblerBase);
}
}
The output format matches the disassembly lines in MuForce reports:
01044770 : 31c0 0000 move.w d0,$0.w
01044774 : *4eae ff7c jsr -$84(a6)
01044778 : 2014 move.l (a4),d0
Fixes recorded in the MuManual ReadMe¶
The ReadMe history lists these fixes. Older copies of the library disassemble the affected instructions wrongly:
| Fixed issue |
|---|
| 64-bit arithmetic instructions disassembled incorrectly |
lea (offset.L,pc) offset wrong by two bytes |
fmovem.x <dynamiclist>,memory disassembled incorrectly |
| Issues fixed by Christian Sauer in 40.5; garbled output for floating-point constants |
Licensing¶
The header carries the THOR-Software notice: no commercial use, reassembly or modification without written permission, and including the library in commercial software requires written permission and a small fee.
See Also¶
Sources: NDK 3.2 R4 MuManual/Autodocs/disassembler.doc, MuManual/Include/libraries/disassembler.h, MuManual/Include/libraries/disassembler.i, MuManual/Include/clib/disassembler_protos.h, MuManual/Include/pragmas/disassembler_pragmas.h, MuManual/Include/lvo/disassembler_lvo.i, MuManual/fd/disassembler_lib.fd, MuManual/BMAPs/Disassembler_lib.bmap, MuTools/disassembler.library (version string), MuTools/MuForce.guide, MuManual/ReadMe Updated: 2026-11-13