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:

  1. 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.".
  2. 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.
  3. Loads the hunks, rebuilds the normal BCPL segment-list linkage, so the module layout is invisible to the program, and applies protection.
  4. 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:

  1. Switch to supervisor mode.
  2. Write the breakpoint.
  3. Flush the cache line.
  4. 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 Hunk tool 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