docs(freebsd): correct stale paths and refactor state in design doc
The RTL-unification work relocated the RTL units into the compiler tree and
replaced the per-host blaise_rtl.a archive with in-process source compilation;
the runtime now ships its own _start (commit 626ee4c9). Update the FreeBSD
backend design doc to match current reality:
- runtime/src/main/pascal/* -> compiler/src/main/pascal/* (unit relocation).
- blaise_thread.pas/blaise_mem.pas -> runtime.thread.pas/runtime.mem.pas; the
setjmp .s file is now inline-asm runtime.setjmp.pas (all .s migrated).
- Startup section: runtime owns _start; the linker no longer scans host CRT
objects (Scrt1.o/crti.o/crtn.o).
- Toolchain section: FindRTLArchive/blaise_rtl.a is gone; EnsureRTLObjects
source-builds the RTL; the internal linker honours --target (Step 1).
- Step 4 syscall trampoline reframed as inline-asm Pascal (no .s files),
mirroring the shipped Linux runtime.syscall.linux leaf.
- Step 5 reframed: end-state (no per-target .a) has landed, so it is a unit-list
change in EnsureRTLObjects, not an archive change.
- Mark Steps 1 and 2 done with NOTE admonitions; fix the Step 2 class name
(TPlatformLayoutFreeBSDX86_64) and pin it to FreeBSD 14.x; fix a Step 9 ->
Step 8 cross-reference (there is no Step 9).
This commit is contained in:
parent
a7ded4c228
commit
7af27a7db1
|
|
@ -88,7 +88,7 @@ entire FreeBSD work surface.
|
|||
|
||||
=== The runtime reaches the kernel through glibc
|
||||
|
||||
`runtime/src/main/pascal/rtl.platform.posix.pas` is *pure Pascal* but is not
|
||||
`compiler/src/main/pascal/rtl.platform.posix.pas` is *pure Pascal* but is not
|
||||
syscall-direct: every primitive is an `external name` binding to a libc
|
||||
symbol — `open`, `read`, `write`, `lseek`, `close`, `fstat`, `stat`,
|
||||
`mkdir`, `clock_gettime`, `fork`, `execvp`, `waitpid`, `nanosleep`,
|
||||
|
|
@ -113,32 +113,43 @@ Consequences for FreeBSD:
|
|||
=== The entry/startup model assumes glibc
|
||||
|
||||
`blaise.codegen.native.x86_64.pas` (`EmitProgram`) emits an exported
|
||||
`main(argc, argv)` and relies on the CRT's `_start` →
|
||||
`__libc_start_main(main, ...)` to drive it. The internal linker
|
||||
(`LinkViaInternalLinker` in `blaise.codegen.native.driver.pas`) links:
|
||||
`main(argc, argv)`. The runtime now ships its *own* `_start` (the
|
||||
`runtime.start` RTL unit, since master commit 626ee4c9) which reads
|
||||
`argc`/`argv` off the stack and calls `__libc_start_main(main, ...)`; the
|
||||
internal linker (`LinkViaInternalLinker` in `blaise.codegen.native.driver.pas`)
|
||||
no longer scans for the host CRT objects (`Scrt1.o`, `crti.o`, `crtn.o`). It
|
||||
links:
|
||||
|
||||
* the host CRT objects discovered by `FindCrtObjects` in `uToolchain.pas`
|
||||
(`Scrt1.o`, `crti.o`, `crtbeginS.o`, `crtendS.o`, `crtn.o`), searched
|
||||
under `/usr/lib/x86_64-linux-gnu`, `/usr/lib/gcc/...`;
|
||||
* the program object and `blaise_rtl.a`;
|
||||
* in dynamic mode, against `libc.so.6` via the interpreter
|
||||
* the program object and the source-built RTL objects (including
|
||||
`runtime.start`, which provides `_start`);
|
||||
* in the default dynamic mode, against `libc.so.6` via the interpreter
|
||||
`/lib64/ld-linux-x86-64.so.2` (both strings hard-coded in
|
||||
`TLinker.BuildDynamic`).
|
||||
`TLinker.BuildDynamic`) — so `__libc_start_main` is still resolved from
|
||||
glibc on the Linux target.
|
||||
|
||||
`__libc_start_main`, `Scrt1.o`, `libc.so.6`, and the glibc loader path are
|
||||
glibc-specific. None exist on FreeBSD, whose libc startup convention,
|
||||
CRT objects (`crt1.o`), and run-time linker (`/libexec/ld-elf.so.1`)
|
||||
differ.
|
||||
`__libc_start_main`, `libc.so.6`, and the glibc loader path are glibc-specific.
|
||||
None exist on FreeBSD, whose run-time linker (`/libexec/ld-elf.so.1`) and libc
|
||||
differ. Because the runtime already owns `_start` and the linker already has a
|
||||
static `ET_EXEC` / `_start` path (Strategy B), FreeBSD needs only a FreeBSD
|
||||
`_start` variant that calls `main` directly and exits via syscall — the
|
||||
link-time-swap seam is present (Step 3).
|
||||
|
||||
=== Toolchain discovery is Linux-pathed
|
||||
|
||||
`uToolchain.pas`:
|
||||
`uToolchain.pas` and the driver:
|
||||
|
||||
* `FindCrtObjects` searches Linux library directories only.
|
||||
* `FindRTLArchive`/`ResolveToolchain` locate one `blaise_rtl.a` — built for
|
||||
the host. A FreeBSD binary needs a FreeBSD-built `blaise_rtl.a`.
|
||||
* `TLinker` is always constructed via `LinuxX86_64Target()`; the driver
|
||||
never selects a FreeBSD `TLinkTarget`.
|
||||
* The RTL is no longer a pre-built per-host archive. `EnsureRTLObjects`
|
||||
(`blaise.codegen.driver.pas`) compiles the embedded RTL source
|
||||
(`compiler/src/main/pascal/runtime.*`, `rtl.platform.*`) in-process and links
|
||||
the resulting `.o` files; the legacy `FindRTLArchive`/`blaise_rtl.a` path is
|
||||
gone. The RTL unit list it compiles is Linux-specific (it names
|
||||
`rtl.platform.layout.linux`); a FreeBSD program must compile the FreeBSD
|
||||
adapter set instead (Step 5).
|
||||
* The internal linker now honours `--target` (Step 1): it builds the resolved
|
||||
toolkit's `TLinkTarget` rather than always `LinuxX86_64Target()`. What
|
||||
remains Linux-specific is the driver's unconditional `FindCrtObjects` /
|
||||
dynamic-libc link line (Step 6 selects the static, CRT-free path for FreeBSD).
|
||||
|
||||
[#syscall-strategy]
|
||||
== The central decision: how does the FreeBSD binary reach the kernel?
|
||||
|
|
@ -180,11 +191,11 @@ with a FreeBSD syscall stub layer. Produce a *static* `ET_EXEC`
|
|||
!===
|
||||
! libc symbol(s) ! Why a raw-syscall replacement is non-trivial
|
||||
|
||||
! `pthread_create/join/mutex_*` (`blaise_thread.pas`)
|
||||
! `pthread_create/join/mutex_*` (`runtime.thread.pas`)
|
||||
! Threading. Reimplementing on raw `thr_new`/`_umtx_op` FreeBSD syscalls is
|
||||
real work, not a thin stub.
|
||||
|
||||
! `mmap/munmap/mremap` (`blaise_mem.pas`)
|
||||
! `mmap/munmap/mremap` (`runtime.mem.pas`)
|
||||
! The memory manager. `mmap`/`munmap` map to syscalls cleanly, but FreeBSD
|
||||
has no `mremap`; the allocator's in-place-grow path needs a fallback.
|
||||
|
||||
|
|
@ -196,9 +207,10 @@ with a FreeBSD syscall stub layer. Produce a *static* `ET_EXEC`
|
|||
! Timezone-aware date math. No syscall equivalent; needs a pure-Pascal
|
||||
tz/calendar implementation or shipping the rules.
|
||||
|
||||
! `setjmp`/`longjmp` (`_blaise_longjmp`, `blaise_setjmp_x86_64.s`)
|
||||
! Exception unwinding. Already hand-written assembly — portable, but must be
|
||||
verified for the FreeBSD stack/`jmp_buf` layout.
|
||||
! `setjmp`/`longjmp` (`_blaise_longjmp`, `runtime.setjmp.pas`)
|
||||
! Exception unwinding. Hand-written inline assembly (the former
|
||||
`blaise_setjmp_x86_64.s`, since migrated into `runtime.setjmp.pas`) — portable,
|
||||
but must be verified for the FreeBSD stack/`jmp_buf` layout.
|
||||
|
||||
! `atexit`
|
||||
! Finalisation. Replaceable with our own registry plus an `exit`-time flush.
|
||||
|
|
@ -315,6 +327,10 @@ no dynamic-link / sysroot work on this path.
|
|||
|
||||
=== Step 1 — FreeBSD link target + toolkit skeleton
|
||||
|
||||
NOTE: Done. The FreeBSD toolkit is registered and the internal linker honours
|
||||
`--target freebsd-x86_64` (stamps `EI_OSABI = 9`); test
|
||||
`TLinkerE2ETests.TestLink_FreeBSDTarget_StampsOSABI`.
|
||||
|
||||
* Add `TFreeBSDX86_64Toolkit` and register it. Its `MakeLinkTarget` returns a
|
||||
FreeBSD `TLinkTarget` with `OSABI := ELFOSABI_FREEBSD`,
|
||||
`EMachine := EM_X86_64`, and the FreeBSD load base / page size
|
||||
|
|
@ -327,12 +343,27 @@ no dynamic-link / sysroot work on this path.
|
|||
|
||||
=== Step 2 — FreeBSD `TPlatformLayout` adapter
|
||||
|
||||
* Add `TLayoutFreeBSDX86_64`: the FreeBSD `struct stat` field offsets (note
|
||||
FreeBSD 12+ widened `ino_t`/`dev_t`; pin to a target major version),
|
||||
`struct tm` layout, and the FreeBSD `O_*` / `S_IFDIR` / `CLOCK_REALTIME` /
|
||||
`WNOHANG` / `SEEK_*` constant values.
|
||||
NOTE: Done. `TPlatformLayoutFreeBSDX86_64` in
|
||||
`compiler/src/main/pascal/rtl.platform.layout.freebsd.pas`, pinned to FreeBSD
|
||||
14.x amd64 (also valid for 13.x — the `ino_t`/`dev_t` widening landed in
|
||||
FreeBSD 12 and has been stable since). `struct stat` offsets `st_mode` = 24,
|
||||
`st_mtim.tv_sec` = 64, `st_size` = 112, `sizeof` = 224 (all differing from
|
||||
Linux); `O_CREAT`/`O_TRUNC`/`O_APPEND` = `$200`/`$400`/`$008` (differing); the
|
||||
remaining `S_*`/`SEEK_*`/`CLOCK_REALTIME`/`WNOHANG` share Linux's values. The
|
||||
unit is a standalone sibling of `rtl.platform.layout.linux` — nothing in the
|
||||
default Linux build graph `uses` it, so it is composed only when the FreeBSD
|
||||
RTL is built (Step 5). Test `cp.test.platformlayout.freebsd` asserts every
|
||||
constant and validates the `struct stat` accessors by planting sentinels at the
|
||||
FreeBSD offsets (catching an offset typo on the Linux host, ahead of the
|
||||
emulation lane).
|
||||
|
||||
* Add `TPlatformLayoutFreeBSDX86_64`: the FreeBSD `struct stat` field offsets
|
||||
(note FreeBSD 12+ widened `ino_t`/`dev_t`; pin to a target major version),
|
||||
and the FreeBSD `O_*` / `S_IFDIR` / `CLOCK_REALTIME` /
|
||||
`WNOHANG` / `SEEK_*` constant values. (`struct tm` is not abstracted — its
|
||||
used fields share an identical layout on Linux/FreeBSD amd64.)
|
||||
* *Verify:* a FreeBSD `fstat`-based `FileExists`/`FileAge`/`DirectoryExists`
|
||||
returns correct results under emulation (Step 9) — static checks cannot
|
||||
returns correct results under emulation (Step 8) — static checks cannot
|
||||
catch a wrong struct offset.
|
||||
|
||||
=== Step 3 — Freestanding `_start` entry stub
|
||||
|
|
@ -347,8 +378,10 @@ no dynamic-link / sysroot work on this path.
|
|||
|
||||
=== Step 4 — FreeBSD syscall leaf (the libc-replacement work)
|
||||
|
||||
* Provide a FreeBSD syscall trampoline (a small `.s` stub like
|
||||
`blaise_setjmp_x86_64.s`, or compiler-emitted): number in `%rax`, args in
|
||||
* Provide a FreeBSD syscall trampoline as inline-assembly Pascal stubs (the RTL
|
||||
is now pure Pascal with `asm … end` bodies — there are no `.s` files; this
|
||||
mirrors the Linux direct-syscall leaf `runtime.syscall.linux.pas` already
|
||||
shipped under `--static`): number in `%rax`, args in
|
||||
`rdi/rsi/rdx/r10/r8/r9`, `syscall`, then branch on the *carry flag* to
|
||||
translate FreeBSD's CF-error convention into the errno-style negative return
|
||||
the existing Pascal call sites (`if Fd < 0 ...`) expect.
|
||||
|
|
@ -368,24 +401,24 @@ no dynamic-link / sysroot work on this path.
|
|||
|
||||
* The compiler must link a FreeBSD-built RTL (the FreeBSD `TPlatformLayout` and
|
||||
kernel-stub) into a `--target freebsd-x86_64` program, not the host RTL.
|
||||
* *Transitional* (matches today's archive model): build a FreeBSD
|
||||
`blaise_rtl-freebsd-x86_64.a` (RTL compiled with `--target freebsd-x86_64`,
|
||||
composing the FreeBSD adapter set) and have `FindRTLArchive` select the
|
||||
archive matching the *target*, not the host.
|
||||
* *End-state* (per the RTL-unification track in
|
||||
`docs/native-target-architecture.adoc`): no per-target `.a` — the compiler
|
||||
compiles the embedded RTL source for `freebsd-x86_64` in-process and links it.
|
||||
Implement whichever is current when this step is reached; the FreeBSD adapter
|
||||
set is the same either way.
|
||||
* The RTL-unification track (`docs/native-target-architecture.adoc`) has already
|
||||
landed its end-state: there is no per-target `.a`. `EnsureRTLObjects`
|
||||
compiles the embedded RTL source in-process and links the `.o` files. So this
|
||||
step is a *unit-list* change, not an archive change: `EnsureRTLObjects` must
|
||||
select the FreeBSD adapter set (`rtl.platform.layout.freebsd` in place of
|
||||
`…layout.linux`, plus the FreeBSD kernel-stub / `runtime.start.static.freebsd`
|
||||
in place of their Linux counterparts) when the target is `freebsd-x86_64`,
|
||||
driven off `AOpts.Target` rather than the hard-coded `RTL_UNITS` list.
|
||||
* *Verify:* a `--target freebsd-x86_64` program links the FreeBSD layout +
|
||||
syscall-stub and contains no Linux/libc RTL code.
|
||||
|
||||
=== Step 6 — Drive target selection through the linker
|
||||
|
||||
* `LinkViaInternalLinker` currently always builds `LinuxX86_64Target` and
|
||||
calls `FindCrtObjects` unconditionally. Drive it from the resolved toolkit:
|
||||
select the FreeBSD `TLinkTarget`, and for the Strategy-B static path skip
|
||||
CRT discovery and dynamic mode entirely (static `_start`, no interp).
|
||||
* `LinkViaInternalLinker` already builds the resolved toolkit's `TLinkTarget`
|
||||
(Step 1), but the driver still drives the Linux dynamic-libc link line. For
|
||||
the Strategy-B static path, when the target is `freebsd-x86_64` skip dynamic
|
||||
mode entirely (static `ET_EXEC`, freestanding `_start`, no interp, no libc
|
||||
`NEEDED`).
|
||||
* *Verify:* `--target freebsd-x86_64` end-to-end emits a FreeBSD `ET_EXEC` on
|
||||
a Linux host with no external tools invoked.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue