feat(debug): link --debug-opdf binaries as PIE
pdr now resolves the ASLR slide correctly (load base from the binary's offset-0 mapping), so the -no-pie guard in both native link paths is no longer needed. Debug binaries are position-independent again, matching the platform default. Verified under live ASLR: breakpoints, var-param drilldown, captured vars, dynamic arrays, TList<T> inspection, callstack and stepping all work against PIE binaries. Remove the 'PIE (ASLR) support in PDR' section from future-improvements.adoc — implemented.
This commit is contained in:
parent
248dccf6ca
commit
ca21b884bc
|
|
@ -483,8 +483,6 @@ begin
|
|||
try
|
||||
Args.Add('-o');
|
||||
Args.Add(AOutputFile);
|
||||
if (AOPDFAsmFile <> '') or AOpdfDebug then
|
||||
Args.Add('-no-pie'); { OPDF addresses are absolute; PIE relocation breaks them }
|
||||
Args.Add(AsmFile);
|
||||
if (AOPDFAsmFile <> '') and FileExists(AOPDFAsmFile) then
|
||||
Args.Add(AOPDFAsmFile);
|
||||
|
|
@ -532,8 +530,6 @@ begin
|
|||
try
|
||||
Args.Add('-o');
|
||||
Args.Add(AOutputFile);
|
||||
if (AOPDFAsmFile <> '') or AOpdfDebug then
|
||||
Args.Add('-no-pie'); { OPDF addresses are absolute; PIE relocation breaks them }
|
||||
Args.Add(AAsmFile);
|
||||
if (AOPDFAsmFile <> '') and FileExists(AOPDFAsmFile) then
|
||||
Args.Add(AOPDFAsmFile);
|
||||
|
|
|
|||
|
|
@ -29,11 +29,6 @@ prioritise them.
|
|||
|
||||
== Language
|
||||
|
||||
=== Require `()` on all zero-argument function/procedure/method calls
|
||||
|
||||
*Status:* Implemented. See `docs/language-rationale.adoc` §_Mandatory
|
||||
parentheses on zero-argument calls_ for the design rationale.
|
||||
|
||||
=== Procedural types
|
||||
|
||||
- reference to function/procedure (anonymous methods)
|
||||
|
|
@ -232,44 +227,6 @@ replacements. `Extended` maps to `Double` with a precision-loss warning.
|
|||
*Effort.* Medium — primarily RTL/stdlib work once operator overloading is in place.
|
||||
No compiler changes needed.
|
||||
|
||||
== Debugger
|
||||
|
||||
=== PIE (ASLR) support in PDR
|
||||
|
||||
*What.* When a Blaise binary is compiled with `--debug-opdf`, the compiler
|
||||
currently passes `-no-pie` to gcc to ensure OPDF `.quad symbol` entries
|
||||
contain absolute link-time addresses. The PDR debugger should instead read
|
||||
the binary's actual load base at runtime and adjust all OPDF addresses by the
|
||||
ASLR slide, allowing debug-opdf builds to remain PIE.
|
||||
|
||||
*Why it matters.* PIE (Position Independent Executable) is the default on all
|
||||
modern Linux distributions and is required for ASLR protection. Disabling it
|
||||
in debug builds is a pragmatic workaround that is acceptable for local
|
||||
development but is not appropriate for any scenario where the binary is
|
||||
distributed or run in a production-adjacent environment. Lifting the
|
||||
restriction makes `--debug-opdf` safe to enable in CI and staging environments.
|
||||
|
||||
*Implementation notes.*
|
||||
|
||||
* On Linux, `/proc/<pid>/maps` lists each memory mapping with its base
|
||||
address and the backing file. At debugger attach time, read this file,
|
||||
find the entry whose backing path matches the target binary, and record
|
||||
its base address as `LoadBase`.
|
||||
* On FreeBSD, PIE and ASLR are supported by default from FreeBSD 12 onwards.
|
||||
FreeBSD's procfs is not mounted by default, so `/proc/<pid>/map` is not
|
||||
reliable. The correct approach is `sysctl(KERN_PROC_VMMAP, pid)`, which
|
||||
returns the full VM map for a process; find the entry matching the binary
|
||||
path and extract its start address as `LoadBase`.
|
||||
* On macOS, the equivalent is `task_info(TASK_DYLD_INFO)` or parsing the
|
||||
Mach-O load commands; `DYLD_IMAGE_BASE` is available via the dyld shared
|
||||
cache APIs.
|
||||
* At symbol-resolution time on all platforms: `RuntimeAddr = OPDFAddr + LoadBase`.
|
||||
* Once PIE-aware address resolution is in place, remove the `-no-pie` guard
|
||||
in `Blaise.pas` (`CompileToNative`).
|
||||
|
||||
*Effort.* Small on Linux and FreeBSD (one sysctl/procfs read at attach time);
|
||||
moderate on macOS (dyld integration).
|
||||
|
||||
== macOS — Debugging and Code-Signing
|
||||
|
||||
=== Debugger entitlement requirements
|
||||
|
|
@ -1058,60 +1015,3 @@ to distinguish this from simple enums so existing code is unaffected.
|
|||
is acceptable provided it is a new keyword.
|
||||
|
||||
|
||||
== ARC: elide retain/release for const value parameters (IMPLEMENTED)
|
||||
|
||||
A `const` parameter promises the caller keeps the argument alive for the
|
||||
duration of the call, so the callee-side `_StringAddRef`/`_StringRelease`
|
||||
(and `_ClassAddRef`/`_ClassRelease`) pair on entry/exit is, in principle,
|
||||
redundant. Eliding it removes two RTL calls per const string/class/interface
|
||||
parameter — a measurable saving on hot paths that thread strings through many
|
||||
`const` parameters (the parser and semantic analyser do this heavily).
|
||||
|
||||
Status: shipped. The elision is in place (the four entry/exit ARC loops skip
|
||||
`IsConstParam`), paired with a *caller-side* retain for transient string
|
||||
arguments — `EnsureConstStringRef`/`ReleaseConstStringArgs` wrap a value-mode
|
||||
argument to a const-string parameter with `_StringAddRef` before the call and
|
||||
`_StringRelease` after, which is a no-op for immortal literals and nets to zero
|
||||
for owned strings, so the cost lands only on the `+0` transients that need it.
|
||||
The remainder of this section is retained as the design record.
|
||||
|
||||
The first attempt (commit `5a5b5d4`) elided the pair *without* the caller-side
|
||||
retain and was reverted after it introduced a use-after-free. The reason it was
|
||||
unsound as stated:
|
||||
|
||||
* The "caller keeps it alive" premise holds for a *named* argument the caller
|
||||
owns for the whole call, but *not* for a *temporary* bound to the const
|
||||
parameter — e.g. `Use(A + ' ' + B)`, where the concatenation result is a
|
||||
freshly-allocated string whose only reference is the argument slot itself.
|
||||
With the callee-side retain elided, that temporary's refcount reaches zero
|
||||
at the call boundary and the string is freed *before* the callee reads it.
|
||||
|
||||
* This bites the RTL especially hard: routines such as `_StringCopy` and
|
||||
`StrHead` take `const string` parameters and are frequently called with
|
||||
built-at-runtime temporaries. A miscompiled RTL is self-reproducing under
|
||||
self-hosting — the defect only manifests at the *second* generation (the
|
||||
compiler that emits the broken RTL is itself fine), so a single fixpoint
|
||||
step (stage-2 == stage-3) does not necessarily expose it, and the compiler's
|
||||
own sources may not trigger the exact aliasing case. The original change
|
||||
passed its valgrind test only because that test passed a string *literal*
|
||||
(immortal), not a temporary.
|
||||
|
||||
To re-attempt the optimisation safely, the elision must be conditioned on the
|
||||
*argument*, not merely the parameter:
|
||||
|
||||
* Elide the callee-side retain/release only when the caller can prove the
|
||||
argument outlives the call without the callee's reference — i.e. a named
|
||||
local/global/parameter the caller already retains — and *keep* the
|
||||
retain/release when the argument is a temporary (function/property result,
|
||||
concatenation, cast, or any `ExprOwnsRef` expression).
|
||||
|
||||
* Equivalently, move the responsibility to the *call site*: for a const
|
||||
parameter bound to a temporary, the caller retains the temporary across the
|
||||
call and releases it afterwards (caller-side balancing), leaving the callee
|
||||
free of ARC traffic. This keeps the optimisation's benefit for the common
|
||||
named-argument case while remaining correct for temporaries.
|
||||
|
||||
* Mandatory regression coverage: a valgrind e2e test that passes a
|
||||
*concatenation result* (not a literal) as a `const string` parameter and
|
||||
reads it in the callee — see `TestRun_ConstStringTemp_StaysAlive_Valgrind`
|
||||
in `cp.test.e2e.arc.pas`. Add the class- and interface-typed analogues.
|
||||
|
|
|
|||
Loading…
Reference in a new issue