mirror of
https://github.com/alfishe/amiga-bootcamp.git
synced 2026-06-12 16:16:28 +00:00
173 lines
5.3 KiB
Markdown
173 lines
5.3 KiB
Markdown
|
|
[← Home](../README.md) · [Linking & Libraries](README.md)
|
||
|
|
|
||
|
|
# AmigaLib Static Linking
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
AmigaOS programs are linked against a set of **static libraries** that provide startup code, C runtime stubs, and glue for OS entry points. The linker resolves all external symbols at link time and produces a self-contained HUNK-format executable.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Key Static Libraries (NDK39 / SAS/C)
|
||
|
|
|
||
|
|
| Library | Purpose |
|
||
|
|
|---|---|
|
||
|
|
| `amiga.lib` | OS stub functions — `OpenLibrary`, `AllocMem`, etc. for non-inline linking |
|
||
|
|
| `sc.lib` / `c.lib` | SAS/C runtime: `printf`, `malloc`, `strlen`, standard I/O |
|
||
|
|
| `auto.lib` | Auto-open libraries (`DOSBase`, `SysBase` acquisition) |
|
||
|
|
| `debug.lib` | `kprintf`, `dprintf` serial debugging stubs |
|
||
|
|
| `m.lib` | Math library (software floating point) |
|
||
|
|
| `scm68020.lib` | SAS/C math for 68020 (co-processor stubs) |
|
||
|
|
|
||
|
|
For GCC:
|
||
|
|
| Library | Purpose |
|
||
|
|
|---|---|
|
||
|
|
| `libnix` | C runtime for `m68k-amigaos-gcc` — replaces `sc.lib` |
|
||
|
|
| `libamiga` | OS glue for GCC (NDK-based) |
|
||
|
|
| `libm` | Soft-float math |
|
||
|
|
| `libgcc` | GCC internal helpers (division, etc.) |
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Startup Object: `c.o` / `_start`
|
||
|
|
|
||
|
|
Every AmigaOS C program begins execution at the **first word of segment 0** — not at `main()`. The startup object `c.o` (SAS/C) or `crt0.o` (GCC/libnix) is always linked first and provides:
|
||
|
|
|
||
|
|
```asm
|
||
|
|
;; SAS/C c.o skeleton (simplified)
|
||
|
|
_start:
|
||
|
|
MOVE.L 4.W, A6 ; SysBase from absolute location $4
|
||
|
|
MOVE.L A0, _CommandStr ; raw CLI argument string (from dos.library)
|
||
|
|
MOVE.L A1, _WBenchMsg ; WBStartup message (if WB launch, else NULL)
|
||
|
|
JSR __main ; C runtime init → eventually calls main()
|
||
|
|
; D0 = exit code from main()
|
||
|
|
MOVE.L D0, _rc ; save return code
|
||
|
|
JSR __exit ; C runtime cleanup
|
||
|
|
RTS ; return to dos.library
|
||
|
|
```
|
||
|
|
|
||
|
|
### What `__main` Does
|
||
|
|
|
||
|
|
1. Opens `DOSBase` via `OpenLibrary("dos.library", 0)` using SysBase in A6
|
||
|
|
2. Sets up `stdin`/`stdout`/`stderr` file handles (wraps `dos.library` I/O)
|
||
|
|
3. Allocates C heap (if any static `malloc`/`new` usage)
|
||
|
|
4. Initializes `errno`, `_timezone`, `__ProgramName`
|
||
|
|
5. Calls any registered `__constructor` functions (C++ static init)
|
||
|
|
6. Calls `main(argc, argv)` — argument string is parsed from `_CommandStr`
|
||
|
|
7. Calls `exit(return_code)` → runs `atexit()` handlers → `CloseLibrary(DOSBase)`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## WBStartup Glue
|
||
|
|
|
||
|
|
When launched from Workbench (double-click), `A0 = NULL`, `A1 = WBStartup msg ptr`. The startup code must:
|
||
|
|
|
||
|
|
```c
|
||
|
|
/* standard WB detection in __main / startup */
|
||
|
|
if (_WBenchMsg) {
|
||
|
|
/* We are a WB launch. argc=0, argv=NULL passed to main() */
|
||
|
|
/* Must not return until cleanup */
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
On exit from a WB-launched program:
|
||
|
|
```c
|
||
|
|
Forbid(); /* prevent task switching during cleanup */
|
||
|
|
ReplyMsg((struct Message *)_WBenchMsg); /* unblock Workbench */
|
||
|
|
/* now safe to RTS / remove task */
|
||
|
|
```
|
||
|
|
|
||
|
|
This pattern is critical: **failing to `ReplyMsg` a WB launch will hang Workbench**.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Stack Cookie
|
||
|
|
|
||
|
|
SAS/C startup checks for a stack size cookie in the executable:
|
||
|
|
|
||
|
|
```c
|
||
|
|
/* In your source — sets minimum stack to 8 KB */
|
||
|
|
LONG __stack = 8192;
|
||
|
|
```
|
||
|
|
|
||
|
|
The linker includes this symbol at a known offset; the OS shell reads it and allocates at least that much stack before launching. IDA Pro will often highlight `_stack` as a data symbol.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## CTRL-C Checking
|
||
|
|
|
||
|
|
SAS/C runtime polls for CTRL-C via `CheckSignal(SIGBREAKF_CTRL_C)` inside `printf`, `fgets`, and other stdio functions. Programs that do long computation loops should call:
|
||
|
|
|
||
|
|
```c
|
||
|
|
if (SetSignal(0, 0) & SIGBREAKF_CTRL_C)
|
||
|
|
cleanup_and_exit();
|
||
|
|
```
|
||
|
|
|
||
|
|
Or use `SAS/C`'s `__chkabort()` hook.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Typical Link Command (SAS/C)
|
||
|
|
|
||
|
|
```
|
||
|
|
slink FROM lib/c.o myobj.o LIB lib/sc.lib lib/amiga.lib TO myprogram
|
||
|
|
```
|
||
|
|
|
||
|
|
Order matters:
|
||
|
|
1. `lib/c.o` — **must be first** (entry point at start of segment 0)
|
||
|
|
2. Object files (`myobj.o`, ...)
|
||
|
|
3. `sc.lib` — C runtime (resolves `printf`, etc.)
|
||
|
|
4. `amiga.lib` — OS stubs (resolves any non-inlined OS calls)
|
||
|
|
|
||
|
|
### Typical GCC Link (bebbo)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
m68k-amigaos-gcc -o myprogram myobj.o -lamiga -lnix -lgcc \
|
||
|
|
-Wl,-Map,myprogram.map
|
||
|
|
```
|
||
|
|
|
||
|
|
Linker script places `crt0.o` automatically via `-lnix` startup group.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Library Archive Format
|
||
|
|
|
||
|
|
Static libraries (`.lib`) are HUNK_LIB archives — sequences of embedded HUNK_UNIT object files with a HUNK_INDEX for fast symbol lookup:
|
||
|
|
|
||
|
|
```
|
||
|
|
HUNK_LIB
|
||
|
|
[HUNK_UNIT: AllocMem.o]
|
||
|
|
HUNK_CODE
|
||
|
|
HUNK_EXT (export: _AllocMem)
|
||
|
|
HUNK_END
|
||
|
|
[HUNK_UNIT: FreeMem.o]
|
||
|
|
...
|
||
|
|
HUNK_INDEX
|
||
|
|
[symbol table: _AllocMem → unit 0, _FreeMem → unit 1, ...]
|
||
|
|
```
|
||
|
|
|
||
|
|
The linker only pulls in units whose exported symbols are referenced — unused code from libraries is **not** linked into the executable (link-time dead-stripping).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## Segment Layout in Final Executable
|
||
|
|
|
||
|
|
With a typical 3-object, 2-lib link:
|
||
|
|
|
||
|
|
```
|
||
|
|
Segment 0 (code): c.o startup + all CODE sections merged
|
||
|
|
Segment 1 (data): all DATA sections merged
|
||
|
|
Segment 2 (BSS): all BSS sections (zero-filled)
|
||
|
|
```
|
||
|
|
|
||
|
|
Most linkers merge same-type sections by default. `slink` supports explicit placement control via `CHIP` / `FAST` keywords.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## References
|
||
|
|
|
||
|
|
- NDK39: `lib/` — `amiga.lib`, `auto.lib`, `debug.lib`, `c.o`
|
||
|
|
- SAS/C 6.x Programmer's Reference Manual — linking chapter
|
||
|
|
- libnix source: https://github.com/bebbo/libnix
|
||
|
|
- *Amiga ROM Kernel Reference Manual: Libraries* — process startup appendix
|