feat(system): source linux page_size from AT_PAGESZ (#336)#343
Merged
Conversation
page_size() on linux hardcoded 4096, wrong on aarch64 kernels running 16 KiB or 64 KiB pages. Capture AT_PAGESZ from the auxiliary vector once at startup into a shared OS-layer global (_pagesz) and have each arch's page_size() read it, falling back to 4096 only when the auxv genuinely lacks it. The entrypoint publishes the value via capture_pagesz() right after _envp, and (under --pie) after _rt_relocate has applied the relocations, so it is ordinary post-relocation code that may touch globals. std.runtime.linux.reloc keeps its own private pre-relocation read of AT_PAGESZ for the RELRO mprotect, since that runs before any global is safe to reference; the OS layer is the single consumer-facing page-size source of truth. Closes #336
page_size() fell back to 4096 when the captured _pagesz was 0. AT_PAGESZ is mandatory on linux, so a 0 at call time means the auxv lacked it (broken or nonstandard environment) or a caller ran before _rt_init published — and on a large-page kernel the fallback would hand that early caller 4096 while later callers see 16K, an inconsistency worse than either constant. Panic naming the invariant rather than fabricating a value; no in-tree caller runs before the startup capture, so the normal path is unaffected.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #336.
What
std.system.os.linux.{aarch64,riscv64,x86_64}.page_size()hardcodedret 4096, wrong on aarch64 kernels configured for 16 KiB or 64 KiB pages. This sources the page size fromAT_PAGESZin the auxiliary vector instead.src/system/os/linux/shared.mach): add_pagesz(the runtime page size,0= unavailable),pagesz_from_auxv(envp)(walks envp to its NULL terminator, then scans the auxv forAT_PAGESZ), andcapture_pagesz()(publishes the walk result into_pagesz, reading the already-set_envp).page_size(): readshared._pagesz, falling back to4096only when the auxv genuinely lackedAT_PAGESZ. All three linux arches converge on the one source.src/runtime/linux/*): each_rt_initcallsos.capture_pagesz()right afteros._envp = _rt_envp.Capture / ordering design
_rt_initruns, in order: (--pieonly)reloc._rt_relocate(...), thenos._envp = _rt_envp, thenos.capture_pagesz(). So the capture happens after relocation and after_envpis set — it is ordinary post-relocation code that may freely touch globals.std.runtime.linux.relockeeps its own private pre-relocation read ofAT_PAGESZ(for the RELROmprotect): that pass runs before any global is safe to reference and is deliberately position-independent, so it cannot consume the OS-layer global. The two reads serve different constraints at different times; the OS layer is the single consumer-facing page-size source of truth, which is what #336 asked for.Verification
mach build .andmach test .— 571 passed, 0 failed.test/riscv64/verify.sh(repo smoke test) — passes under qemu-riscv64.AT_PAGESZand assertsos.page_size() == AT_PAGESZ,shared._pagesz != 0(capture ran), andshared._pagesz == page_size()— exits 0 on x86_64 native, riscv64/qemu, aarch64/qemu, both default and--piebuilds. (This qemu-user build presents a fixed 4 KiB page and cannot override it, so a live 16 KiB/64 KiB run is not reproducible locally; the probe proves the value is auxv-sourced rather than a literal.)🤖 Generated with Claude Code