MuLink and MuOVLYMGR¶
MuLink is a Shell-only MuTool in the NDK 3.2 MuTools/ drawer. It post-processes a finished executable so that selected hunks, by default every CODE hunk, are write-protected by the MMU once the program is loaded. The protection is applied at load time by MuOVLYMGR, a small loader that MuLink puts in front of the program and that uses mmu.library. The result gives AmigaOS 3.x programs a feature the OS itself lacks: code that faulty software cannot overwrite.
MuLink was added in MMULib release 0.34.1. The ReadMe describes it as a tool for "automatic self-protection of software", especially for software that must run on critical systems such as BBSs, and compares it to the post-processor ATOM.
When to use it¶
The readme is clear that MuLink is a step for finished software:
MuLink is mainly a developer tool that should be run on a file as soon as it is out of the debugging stage and runs clean.
Keep the un-MuLink'd binary for your own debugging and ship the MuLink'd one. A MuLink'd program cannot be debugged with an ordinary monitor (the readme names MonAm), because breakpoints cannot be written into write-protected code.
Synopsis¶
MuLink OVLYMGR/K,FROM=ROOT/A,TO/A,HUNKS/K,BUFSIZE/N,VERBOSE/S
| Argument | Meaning |
|---|---|
OVLYMGR |
The overlay manager (loader) linked to the front of the binary. Default MMU:MuOVLYMGR; there is little reason to change it. |
FROM (= ROOT) |
The input file. It must be a final executable: no object modules, and no overlaid programs. All debug information is stripped. |
TO |
The output executable. It must be a different file from FROM. |
HUNKS |
Which hunks to protect, as a comma-separated list (see below). Default: all CODE hunks and nothing else. |
BUFSIZE |
I/O buffer size. Default 4096; sensible values are 256 bytes to 32K. |
VERBOSE |
Prints additional debug information. |
Hunk selection¶
Each item in HUNKS is + (protect) or - (do not protect) followed by a hunk number or a class name. Hunk numbers are decimal and count from 0. Items are processed left to right, so later items override earlier ones.
| Class | Hunks selected |
|---|---|
CODE / DATA / BSS |
all code / data / BSS hunks |
CODE_C / DATA_C / BSS_C |
those hunks that load into CHIP memory |
CODE_F / DATA_F / BSS_F |
those hunks that load into FAST memory |
; the built-in default
MuLink FROM MyProg TO MyProg.mu HUNKS="+CODE,-DATA,-BSS"
; also protect data hunks, except those destined for chip memory
MuLink FROM MyProg TO MyProg.mu HUNKS="+CODE,+DATA,-BSS,-DATA_C"
The readme spells the keyword HUNK= in its own examples. The template says HUNKS/K.
Protecting DATA or BSS rarely makes sense. Some compilers put BSS space inside the DATA hunk. For the best result, have the compiler either put constant strings in a separate hunk or merge them into the CODE hunk, so that MuLink can protect them apart from writable data.
Note that the MMU cannot stop the blitter from writing to protected memory.
How the protection works at run time¶
When the MuLink'd program is loaded, LoadSeg() loads only the MuOVLYMGR hunk. MuOVLYMGR then:
- Opens mmu.library. It refuses to load the program if the library is not available. Its error strings include "This program requires the mmu.library." and "Failed to setup segment write protection.".
- Allocates memory in modules rather than per hunk. Hunks with the same memory type and protection share one module, which reduces waste when rounding to MMU page boundaries.
- Loads the hunks, rebuilds the normal BCPL segment-list linkage, so the module layout is invisible to the program, and applies protection.
- Write-protects itself after it has done its job.
It picks one of two protection modes depending on whether MuForce is running:
| Situation | Page property | Effect of a write to protected code |
|---|---|---|
| MuForce not running | MAPP_ROM |
The write is silently ignored; the code is not modified. |
| MuForce running | MAPP_WRITEPROTECTED |
The write causes a MuForce hit, which helps with debugging. |
Both properties are defined in mmu/context.h: MAPP_WRITEPROTECTED is (1<<2), MAPP_ROM is (1<<17).
Protection applies to user-mode accesses only. Supervisor-mode writes still work. A debugger that wants to set a breakpoint in MuLink'd code must therefore:
- Switch to supervisor mode.
- Write the breakpoint.
- Flush the cache line.
- Return to user mode.
Caveats¶
- Requires mmu.library, and therefore an MMU. MuLink'd programs will not run on P5 boards that use the original ppc.library, which the readme calls obsolete and unsupported.
- No self-modifying code. Programs that modify their code hunk cannot be MuLink'd.
- No overlays in the input. MuOVLYMGR cannot yet protect overlaid segments.
- No longer pure. A MuLink'd program cannot be made resident, because the loader is required to enable and disable protection. Tiny programs also waste memory because hunk starts are rounded to page boundaries.
- "Run-back" and stay-resident programs usually fail, because they modify their own code hunk to build a fake segment list.
- Tools that read executables, such as the
Hunktool named in the readme, usually cannot process the result. Some virus scanners report errors because they handle overlay files incorrectly. The readme notes the upside: viruses are unlikely to infect the file, and an infected file will most likely not run at all.
File layout (for tool writers)¶
A MuLink'd executable is an ordinary AmigaDOS load file whose root is the loader, followed by a HUNK_OVERLAY block ($3F5) that MuOVLYMGR reads itself. The loader's HUNK_HEADER deliberately does not describe an overlaid program, which keeps the overlay table small. As usual for overlaid programs, the DOS overlay magic $ABCD is in the second longword of the binary. Beyond that there is no identifier, because the loader is a custom one. For the standard overlay mechanism this builds on, see AmigaOS Hunk Overlays and Hunk Binary Format.
HUNK_HEADER loader
HUNK_CODE MuOVLYMGR
HUNK_OVERLAY $000003F5
size-1 overlay data size in longs, minus one
fileofs file offset of the main program's first HUNK_CODE
(not of its HUNK_HEADER)
ovlsize size of the loader segment in longs
loaderofs byte offset of the loader within its module
loadermodule module that holds the loader (always a protected one)
num_modules
{ module_id, memory_attrs, properties, length (longs) } * num_modules
num_hunks
{ hunk_type, hunkofs, hunksize (longs), hunkmodule } * num_hunks
HUNK_HEADER original header of the main program (ignored by the
loader, kept for easier un-linking)
HUNK_CODE ... the original program's hunks, as usual
| Field | Notes |
|---|---|
module_id |
Unique, counted from zero; currently unused by the loader. |
memory_attrs |
Flags passed to AllocMem() for the module, taken from the source HUNK_HEADER. |
properties |
MMU properties. Only MAPP_ROM is recognised; the loader turns it into MAPP_WRITEPROTECTED when MuForce is active. |
hunk_type |
HUNK_CODE, HUNK_DATA or HUNK_BSS; currently ignored. |
hunkofs |
Byte offset of the hunk inside its module. |
hunksize |
Size in longs, including memory attribute bits (currently ignored). |
MuMapRom¶
MuMapRom.debug is also in the NDK MuTools/ drawer. No guide for it is included. The MuManual ReadMe describes MuMapRom as a MuTool that "allows booting from a different kickstart release if the board is well-behaived. Be warned, this is a hack." Its ReadMe history records several changes:
- a reset-resident ROM mirror using the exec ColdCapture vector;
- a 16 MB "safety zone" around memory areas;
- CD32 lower-ROM awareness;
- A600/A1200 motherboard RAM fixes.
Release 46.7 added MuMapRom.debug as a debug build.
The binary's version string is MuMapRom 46.6 (25.07.2016) and its template is:
KICKFILE/A,PATCHFILE,RELEASECHIP/S,ROMINFAST/S,ROMINCHIP/S,KEEPDEBUGROM/S,PRINTMAPPING/S
Its messages show that it needs mmu.library V43+, utility.library V37+ and expansion.library V37+. The Kickstart image must be 256K or 512K. An optional SPatch-format patch file can be applied (PATCHFILE=AUTOMATIC is suggested when the named file cannot be opened). Beyond this, the options are not documented in the NDK.
See Also¶
Sources: NDK 3.2 R4 MuTools/MuLink.readme, MuTools/MuOVLYMGR (strings), MuTools/MuMapRom.debug (version and template strings), MuManual/ReadMe, MuManual/Include/mmu/context.h Updated: 2026-11-13