commit cb8e08d7d89c0ce544883b60d2d04a5c883df51e
parent 8b8960344ffcc9a12161a218fece7e8bf2beaf8b
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Sat, 6 Jun 2026 04:41:35 -0700
Fix -no-pie overriding explicit PIE
Diffstat:
6 files changed, 49 insertions(+), 11 deletions(-)
diff --git a/doc/plan/TODO.md b/doc/plan/TODO.md
@@ -5,17 +5,6 @@ fixed, remove it instead of checking it off or keeping a closed entry.
Add new deferred fixes below as they are discovered.
-## `-no-pie` does not produce a non-PIE (ET_EXEC) executable
-
-`-no-pie` sets `o->target.pic = KIT_PIC_NONE` (`driver/cmd/cc.c:1185`) but does
-not clear `o->pie`, which is what feeds the linker's e_type decision
-(`driver/cmd/cc.c:2494`). So `kit cc -no-pie -static foo.c -o exe` still emits an
-ET_DYN (static-PIE) image — `readelf`/`file` report "shared object", and the
-program loads at an ASLR base, so captured code addresses don't match link-time
-addresses without computing the load slide. `-no-pie` should clear `o->pie` (and
-ideally `-static` without `-pie` should default to non-PIE). Found while making a
-backtrace demo's addresses line up with `kit addr2line`.
-
## ASan host build: some fatal diagnostics SEGV during `compiler_panic` recovery
While reproducing the former x64 inline-asm fatal on the ASan host build, the
diff --git a/driver/cmd/build.c b/driver/cmd/build.c
@@ -798,6 +798,7 @@ static int build_parse(int argc, char** argv, BuildOptions* o) {
}
if (driver_streq(a, "-no-pie")) {
o->target.pic = KIT_PIC_NONE;
+ o->pie = 0;
continue;
}
diff --git a/driver/cmd/cc.c b/driver/cmd/cc.c
@@ -1184,6 +1184,7 @@ static int cc_parse(int argc, char** argv, CcOptions* o) {
}
if (driver_streq(a, "-no-pie")) {
o->target.pic = KIT_PIC_NONE;
+ o->pie = 0;
continue;
}
if (driver_streq(a, "-Bstatic")) {
diff --git a/driver/cmd/ld.c b/driver/cmd/ld.c
@@ -1018,6 +1018,7 @@ static int ld_parse(int argc, char** argv, LdOptions* o) {
}
if (driver_streq(a, "-no-pie")) {
o->target.pic = KIT_PIC_NONE;
+ o->pie = 0;
o->pic_explicit = 1;
continue;
}
diff --git a/test/buildcmds/run.sh b/test/buildcmds/run.sh
@@ -169,6 +169,17 @@ contains be-neg-shared-diag "$work/be-neg-shared.err" "shared"
run_ok be-default-name "$KIT" build-exe -lc -Iinc hello.c helper.c
assert_file_exists be-default-name-file a.out
+# -no-pie must cancel an earlier -pie for build-exe's link state.
+printf 'void _start(void) { for (;;) {} }\n' > no_pie_start.c
+run_ok be-no-pie "$KIT" build-exe -target x86_64-linux -nostdlib \
+ -pie -no-pie no_pie_start.c -o no-pie-exe
+e_type=$(od -An -tx1 -j 16 -N 2 no-pie-exe | tr -d ' \n')
+if [ "$e_type" = "0200" ]; then ok be-no-pie-et-exec; else
+ printf 'e_type bytes=%s want=0200\n' "$e_type" \
+ > "$work/be-no-pie-et-exec.diag"
+ not_ok be-no-pie-et-exec "$work/be-no-pie-et-exec.diag"
+fi
+
# --group scoping is observable through the program's exit code: the bare TU
# sees -DRET=0 (global), the grouped TU overrides it to a non-zero value.
printf '#ifndef RET\n#define RET 7\n#endif\nint ret_val(void){return RET;}\n' > rv.c
diff --git a/test/driver/run.sh b/test/driver/run.sh
@@ -465,6 +465,41 @@ else
"$work/ld-static-pie-setup.diag"
fi
+# ---- ld -no-pie cancels an earlier -pie and emits ET_EXEC ----
+if "$KIT" ld -pie -no-pie -nostdlib "$work/ld-static-pie.o" \
+ -o "$work/ld-no-pie" > "$work/ld-no-pie.out" \
+ 2> "$work/ld-no-pie.err"; then
+ e_type=$(od -An -tx1 -j 16 -N 2 "$work/ld-no-pie" | tr -d ' \n')
+ if [ "$e_type" = "0200" ]; then
+ ok "ld-no-pie-cancels-pie"
+ else
+ printf 'e_type bytes=%s want=0200\n' "$e_type" \
+ > "$work/ld-no-pie.diag"
+ not_ok "ld-no-pie-cancels-pie" "$work/ld-no-pie.diag"
+ fi
+else
+ not_ok "ld-no-pie-cancels-pie" "$work/ld-no-pie.err"
+fi
+
+# ---- -no-pie cancels an earlier -pie and emits ET_EXEC ----
+cat > "$work/cc-no-pie.c" <<'SRC'
+void _start(void) { for (;;) {} }
+SRC
+if "$KIT" cc -target x86_64-linux -nostdlib -pie -no-pie \
+ "$work/cc-no-pie.c" -o "$work/cc-no-pie" \
+ > "$work/cc-no-pie.out" 2> "$work/cc-no-pie.err"; then
+ e_type=$(od -An -tx1 -j 16 -N 2 "$work/cc-no-pie" | tr -d ' \n')
+ if [ "$e_type" = "0200" ]; then
+ ok "cc-no-pie-cancels-pie"
+ else
+ printf 'e_type bytes=%s want=0200\n' "$e_type" \
+ > "$work/cc-no-pie.diag"
+ not_ok "cc-no-pie-cancels-pie" "$work/cc-no-pie.diag"
+ fi
+else
+ not_ok "cc-no-pie-cancels-pie" "$work/cc-no-pie.err"
+fi
+
# ---- objdump -x aggregate (sections + symbol table) ----
if "$KIT" objdump -x "$work/main.o" \
> "$work/objdump-x.out" 2> "$work/objdump-x.err" &&