Commit abc717f203

Andrew Kelley <andrew@ziglang.org>
2020-11-23 01:28:11
modernize the PIE patch for the latest master branch
This is the part of #3960 that has to be rewritten to apply to latest master branch code.
1 parent 55ab50e
lib/libc/musl/ldso/dlstart.c
@@ -0,0 +1,148 @@
+#include <stddef.h>
+#include "dynlink.h"
+#include "libc.h"
+
+#ifndef START
+#define START "_dlstart"
+#endif
+
+#define SHARED
+
+#include "crt_arch.h"
+
+#ifndef GETFUNCSYM
+#define GETFUNCSYM(fp, sym, got) do { \
+	hidden void sym(); \
+	static void (*static_func_ptr)() = sym; \
+	__asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \
+	*(fp) = static_func_ptr; } while(0)
+#endif
+
+hidden void _dlstart_c(size_t *sp, size_t *dynv)
+{
+	size_t i, aux[AUX_CNT], dyn[DYN_CNT];
+	size_t *rel, rel_size, base;
+
+	int argc = *sp;
+	char **argv = (void *)(sp+1);
+
+	for (i=argc+1; argv[i]; i++);
+	size_t *auxv = (void *)(argv+i+1);
+
+	for (i=0; i<AUX_CNT; i++) aux[i] = 0;
+	for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT)
+		aux[auxv[i]] = auxv[i+1];
+
+#if DL_FDPIC
+	struct fdpic_loadseg *segs, fakeseg;
+	size_t j;
+	if (dynv) {
+		/* crt_arch.h entry point asm is responsible for reserving
+		 * space and moving the extra fdpic arguments to the stack
+		 * vector where they are easily accessible from C. */
+		segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs;
+	} else {
+		/* If dynv is null, the entry point was started from loader
+		 * that is not fdpic-aware. We can assume normal fixed-
+		 * displacement ELF loading was performed, but when ldso was
+		 * run as a command, finding the Ehdr is a heursitic: we
+		 * have to assume Phdrs start in the first 4k of the file. */
+		base = aux[AT_BASE];
+		if (!base) base = aux[AT_PHDR] & -4096;
+		segs = &fakeseg;
+		segs[0].addr = base;
+		segs[0].p_vaddr = 0;
+		segs[0].p_memsz = -1;
+		Ehdr *eh = (void *)base;
+		Phdr *ph = (void *)(base + eh->e_phoff);
+		size_t phnum = eh->e_phnum;
+		size_t phent = eh->e_phentsize;
+		while (phnum-- && ph->p_type != PT_DYNAMIC)
+			ph = (void *)((size_t)ph + phent);
+		dynv = (void *)(base + ph->p_vaddr);
+	}
+#endif
+
+	for (i=0; i<DYN_CNT; i++) dyn[i] = 0;
+	for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT)
+		dyn[dynv[i]] = dynv[i+1];
+
+#if DL_FDPIC
+	for (i=0; i<DYN_CNT; i++) {
+		if (i==DT_RELASZ || i==DT_RELSZ) continue;
+		if (!dyn[i]) continue;
+		for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
+		dyn[i] += segs[j].addr - segs[j].p_vaddr;
+	}
+	base = 0;
+
+	const Sym *syms = (void *)dyn[DT_SYMTAB];
+
+	rel = (void *)dyn[DT_RELA];
+	rel_size = dyn[DT_RELASZ];
+	for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
+		if (!IS_RELATIVE(rel[1], syms)) continue;
+		for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
+		size_t *rel_addr = (void *)
+			(rel[0] + segs[j].addr - segs[j].p_vaddr);
+		if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) {
+			*rel_addr += segs[rel_addr[1]].addr
+				- segs[rel_addr[1]].p_vaddr
+				+ syms[R_SYM(rel[1])].st_value;
+			rel_addr[1] = dyn[DT_PLTGOT];
+		} else {
+			size_t val = syms[R_SYM(rel[1])].st_value;
+			for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++);
+			*rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val;
+		}
+	}
+#else
+	/* If the dynamic linker is invoked as a command, its load
+	 * address is not available in the aux vector. Instead, compute
+	 * the load address as the difference between &_DYNAMIC and the
+	 * virtual address in the PT_DYNAMIC program header. */
+	base = aux[AT_BASE];
+	if (!base) {
+		size_t phnum = aux[AT_PHNUM];
+		size_t phentsize = aux[AT_PHENT];
+		Phdr *ph = (void *)aux[AT_PHDR];
+		for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) {
+			if (ph->p_type == PT_DYNAMIC) {
+				base = (size_t)dynv - ph->p_vaddr;
+				break;
+			}
+		}
+	}
+
+	/* MIPS uses an ugly packed form for GOT relocations. Since we
+	 * can't make function calls yet and the code is tiny anyway,
+	 * it's simply inlined here. */
+	if (NEED_MIPS_GOT_RELOCS) {
+		size_t local_cnt = 0;
+		size_t *got = (void *)(base + dyn[DT_PLTGOT]);
+		for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO)
+			local_cnt = dynv[i+1];
+		for (i=0; i<local_cnt; i++) got[i] += base;
+	}
+
+	rel = (void *)(base+dyn[DT_REL]);
+	rel_size = dyn[DT_RELSZ];
+	for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) {
+		if (!IS_RELATIVE(rel[1], 0)) continue;
+		size_t *rel_addr = (void *)(base + rel[0]);
+		*rel_addr += base;
+	}
+
+	rel = (void *)(base+dyn[DT_RELA]);
+	rel_size = dyn[DT_RELASZ];
+	for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
+		if (!IS_RELATIVE(rel[1], 0)) continue;
+		size_t *rel_addr = (void *)(base + rel[0]);
+		*rel_addr = base + rel[2];
+	}
+#endif
+
+	stage2_func dls2;
+	GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]);
+	dls2((void *)base, sp);
+}
lib/std/os/linux/start_pie.zig
@@ -111,10 +111,10 @@ pub fn apply_relocations() void {
         var i: usize = 0;
         while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) {
             switch (dynv[i].d_tag) {
-                elf.DT_REL => rel_addr = base_addr + dynv[i].d_un.d_ptr,
-                elf.DT_RELA => rela_addr = base_addr + dynv[i].d_un.d_ptr,
-                elf.DT_RELSZ => rel_size = dynv[i].d_un.d_val,
-                elf.DT_RELASZ => rela_size = dynv[i].d_un.d_val,
+                elf.DT_REL => rel_addr = base_addr + dynv[i].d_val,
+                elf.DT_RELA => rela_addr = base_addr + dynv[i].d_val,
+                elf.DT_RELSZ => rel_size = dynv[i].d_val,
+                elf.DT_RELASZ => rela_size = dynv[i].d_val,
                 else => {},
             }
         }
@@ -122,14 +122,14 @@ pub fn apply_relocations() void {
 
     // Perform the relocations
     if (rel_addr != 0) {
-        const rel = @bytesToSlice(elf.Rel, @intToPtr([*]u8, rel_addr)[0..rel_size]);
+        const rel = std.mem.bytesAsSlice(elf.Rel, @intToPtr([*]u8, rel_addr)[0..rel_size]);
         for (rel) |r| {
             if (r.r_type() != ARCH_RELATIVE_RELOC) continue;
             @intToPtr(*usize, base_addr + r.r_offset).* += base_addr;
         }
     }
     if (rela_addr != 0) {
-        const rela = @bytesToSlice(elf.Rela, @intToPtr([*]u8, rela_addr)[0..rela_size]);
+        const rela = std.mem.bytesAsSlice(elf.Rela, @intToPtr([*]u8, rela_addr)[0..rela_size]);
         for (rela) |r| {
             if (r.r_type() != ARCH_RELATIVE_RELOC) continue;
             @intToPtr(*usize, base_addr + r.r_offset).* += base_addr + @bitCast(usize, r.r_addend);
lib/std/build.zig
@@ -1286,6 +1286,9 @@ pub const LibExeObjStep = struct {
     /// Position Independent Code
     force_pic: ?bool = null,
 
+    /// Position Independent Executable
+    pie: ?bool = null,
+
     subsystem: ?builtin.SubSystem = null,
 
     const LinkObject = union(enum) {
@@ -2307,6 +2310,14 @@ pub const LibExeObjStep = struct {
             }
         }
 
+        if (self.pie) |pie| {
+            if (pie) {
+                try zig_args.append("-fPIE");
+            } else {
+                try zig_args.append("-fno-PIE");
+            }
+        }
+
         if (self.subsystem) |subsystem| {
             try zig_args.append("--subsystem");
             try zig_args.append(switch (subsystem) {
lib/std/dynamic_library.zig
@@ -63,7 +63,7 @@ const RDebug = extern struct {
 extern var _DYNAMIC: [128]elf.Dyn;
 
 comptime {
-    if (builtin.os == .linux) {
+    if (std.Target.current.os.tag == .linux) {
         asm (
             \\ .weak _DYNAMIC
             \\ .hidden _DYNAMIC
src/link/Elf.zig
@@ -1425,7 +1425,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
         try argv.append("-shared");
     }
 
-    if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
+    if (self.base.options.pie and self.base.options.output_mode == .Exe) {
         try argv.append("-pie");
     }
 
@@ -1444,7 +1444,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
                     break :o "crtbegin_static.o";
                 }
             } else if (self.base.options.link_mode == .Static) {
-                break :o "crt1.o";
+                if (self.base.options.pie) {
+                    break :o "rcrt1.o";
+                } else {
+                    break :o "crt1.o";
+                }
             } else {
                 break :o "Scrt1.o";
             }
src/stage1/all_types.hpp
@@ -2177,6 +2177,7 @@ struct CodeGen {
     bool is_test_build;
     bool is_single_threaded;
     bool have_pic;
+    bool have_pie;
     bool link_mode_dynamic;
     bool dll_export_fns;
     bool have_stack_probing;
src/stage1/codegen.cpp
@@ -9043,6 +9043,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
     buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
     buf_appendf(contents, "pub const valgrind_support = false;\n");
     buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic));
+    buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));
     buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));
     buf_appendf(contents, "pub const code_model = CodeModel.default;\n");
 
@@ -9170,6 +9171,14 @@ static void init(CodeGen *g) {
         reloc_mode = LLVMRelocStatic;
     }
 
+    if (g->have_pic) {
+        ZigLLVMSetModulePICLevel(g->module);
+    }
+
+    if (g->have_pie) {
+        ZigLLVMSetModulePIELevel(g->module);
+    }
+
     const char *target_specific_cpu_args = "";
     const char *target_specific_features = "";
 
src/stage1/stage1.cpp
@@ -89,6 +89,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
     g->link_mode_dynamic = stage1->link_mode_dynamic;
     g->dll_export_fns = stage1->dll_export_fns;
     g->have_pic = stage1->pic;
+    g->have_pie = stage1->pie;
     g->have_stack_probing = stage1->enable_stack_probing;
     g->is_single_threaded = stage1->is_single_threaded;
     g->valgrind_enabled = stage1->valgrind_enabled;
src/stage1/stage1.h
@@ -177,6 +177,7 @@ struct ZigStage1 {
     enum ErrColor err_color;
 
     bool pic;
+    bool pie;
     bool link_libc;
     bool link_libcpp;
     bool strip;
src/clang_options_data.zig
@@ -2460,7 +2460,14 @@ sepd1("exported_symbols_list"),
     .pd2 = false,
     .psl = false,
 },
-flagpd1("fPIE"),
+.{
+    .name = "fPIE",
+    .syntax = .flag,
+    .zig_equivalent = .pie,
+    .pd1 = true,
+    .pd2 = false,
+    .psl = false,
+},
 flagpd1("fno-access-control"),
 flagpd1("faddrsig"),
 flagpd1("faggressive-function-elimination"),
@@ -2775,7 +2782,14 @@ flagpd1("fnext-runtime"),
     .pd2 = false,
     .psl = false,
 },
-flagpd1("fno-PIE"),
+.{
+    .name = "fno-PIE",
+    .syntax = .flag,
+    .zig_equivalent = .no_pie,
+    .pd1 = true,
+    .pd2 = false,
+    .psl = false,
+},
 flagpd1("fno-no-access-control"),
 flagpd1("fno-addrsig"),
 flagpd1("fno-aggressive-function-elimination"),
src/Compilation.zig
@@ -343,6 +343,10 @@ pub const InitOptions = struct {
     link_libc: bool = false,
     link_libcpp: bool = false,
     want_pic: ?bool = null,
+    /// This means that if the output mode is an executable it will be a
+    /// Position Independent Executable. If the output mode is not an
+    /// executable this field is ignored.
+    want_pie: ?bool = null,
     want_sanitize_c: ?bool = null,
     want_stack_check: ?bool = null,
     want_valgrind: ?bool = null,
@@ -527,17 +531,30 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             options.libc_installation,
         );
 
+        const must_pie = target_util.requiresPIE(options.target);
+        const pie = if (options.want_pie) |explicit| pie: {
+            if (!explicit and must_pie) {
+                return error.TargetRequiresPIE;
+            }
+            break :pie explicit;
+        } else must_pie;
+
         const must_pic: bool = b: {
             if (target_util.requiresPIC(options.target, link_libc))
                 break :b true;
             break :b link_mode == .Dynamic;
         };
         const pic = if (options.want_pic) |explicit| pic: {
-            if (!explicit and must_pic) {
-                return error.TargetRequiresPIC;
+            if (!explicit) {
+                if (must_pic) {
+                    return error.TargetRequiresPIC;
+                }
+                if (pie) {
+                    return error.PIERequiresPIC;
+                }
             }
             break :pic explicit;
-        } else must_pic;
+        } else pie or must_pic;
 
         // Make a decision on whether to use Clang for translate-c and compiling C files.
         const use_clang = if (options.use_clang) |explicit| explicit else blk: {
@@ -618,6 +635,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
         cache.hash.add(options.target.abi);
         cache.hash.add(ofmt);
         cache.hash.add(pic);
+        cache.hash.add(pie);
         cache.hash.add(stack_check);
         cache.hash.add(link_mode);
         cache.hash.add(options.function_sections);
@@ -814,6 +832,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             .version = options.version,
             .libc_installation = libc_dirs.libc_installation,
             .pic = pic,
+            .pie = pie,
             .valgrind = valgrind,
             .stack_check = stack_check,
             .single_threaded = single_threaded,
@@ -898,7 +917,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             try comp.addBuildingGLibCJobs();
         }
         if (comp.wantBuildMuslFromSource()) {
-            try comp.work_queue.ensureUnusedCapacity(5);
+            try comp.work_queue.ensureUnusedCapacity(6);
             if (target_util.libc_needs_crti_crtn(comp.getTarget())) {
                 comp.work_queue.writeAssumeCapacity(&[_]Job{
                     .{ .musl_crt_file = .crti_o },
@@ -908,6 +927,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
             comp.work_queue.writeAssumeCapacity(&[_]Job{
                 .{ .musl_crt_file = .crt1_o },
                 .{ .musl_crt_file = .scrt1_o },
+                .{ .musl_crt_file = .rcrt1_o },
                 .{ .musl_crt_file = .libc_a },
             });
         }
@@ -2473,6 +2493,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
         \\pub const have_error_return_tracing = {};
         \\pub const valgrind_support = {};
         \\pub const position_independent_code = {};
+        \\pub const position_independent_executable = {};
         \\pub const strip_debug_info = {};
         \\pub const code_model = CodeModel.{};
         \\
@@ -2484,6 +2505,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
         comp.bin_file.options.error_return_tracing,
         comp.bin_file.options.valgrind,
         comp.bin_file.options.pic,
+        comp.bin_file.options.pie,
         comp.bin_file.options.strip,
         @tagName(comp.bin_file.options.machine_code_model),
     });
@@ -2587,6 +2609,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
         .want_stack_check = false,
         .want_valgrind = false,
         .want_pic = comp.bin_file.options.pic,
+        .want_pie = comp.bin_file.options.pie,
         .emit_h = null,
         .strip = comp.bin_file.options.strip,
         .is_native_os = comp.bin_file.options.is_native_os,
@@ -2795,6 +2818,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
         .subsystem = subsystem,
         .err_color = @enumToInt(comp.color),
         .pic = comp.bin_file.options.pic,
+        .pie = comp.bin_file.options.pie,
         .link_libc = comp.bin_file.options.link_libc,
         .link_libcpp = comp.bin_file.options.link_libcpp,
         .strip = comp.bin_file.options.strip,
@@ -2950,6 +2974,7 @@ pub fn build_crt_file(
         .want_stack_check = false,
         .want_valgrind = false,
         .want_pic = comp.bin_file.options.pic,
+        .want_pie = comp.bin_file.options.pie,
         .emit_h = null,
         .strip = comp.bin_file.options.strip,
         .is_native_os = comp.bin_file.options.is_native_os,
src/libcxx.zig
@@ -171,6 +171,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
         .want_stack_check = false,
         .want_valgrind = false,
         .want_pic = comp.bin_file.options.pic,
+        .want_pie = comp.bin_file.options.pie,
         .emit_h = null,
         .strip = comp.bin_file.options.strip,
         .is_native_os = comp.bin_file.options.is_native_os,
@@ -288,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
         .want_stack_check = false,
         .want_valgrind = false,
         .want_pic = comp.bin_file.options.pic,
+        .want_pie = comp.bin_file.options.pie,
         .emit_h = null,
         .strip = comp.bin_file.options.strip,
         .is_native_os = comp.bin_file.options.is_native_os,
src/libunwind.zig
@@ -104,6 +104,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
         .want_stack_check = false,
         .want_valgrind = false,
         .want_pic = comp.bin_file.options.pic,
+        .want_pie = comp.bin_file.options.pie,
         .emit_h = null,
         .strip = comp.bin_file.options.strip,
         .is_native_os = comp.bin_file.options.is_native_os,
src/link.zig
@@ -71,6 +71,7 @@ pub const Options = struct {
     bind_global_refs_locally: bool,
     is_native_os: bool,
     pic: bool,
+    pie: bool,
     valgrind: bool,
     stack_check: bool,
     single_threaded: bool,
src/main.zig
@@ -270,6 +270,8 @@ const usage_build_generic =
     \\  --main-pkg-path           Set the directory of the root package
     \\  -fPIC                     Force-enable Position Independent Code
     \\  -fno-PIC                  Force-disable Position Independent Code
+    \\  -fPIE                     Force-enable Position Independent Executable
+    \\  -fno-PIE                  Force-disable Position Independent Executable
     \\  -fstack-check             Enable stack probing in unsafe builds
     \\  -fno-stack-check          Disable stack probing in safe builds
     \\  -fsanitize-c              Enable C undefined behavior detection in unsafe builds
@@ -457,6 +459,7 @@ fn buildOutputType(
     var want_native_include_dirs = false;
     var enable_cache: ?bool = null;
     var want_pic: ?bool = null;
+    var want_pie: ?bool = null;
     var want_sanitize_c: ?bool = null;
     var want_stack_check: ?bool = null;
     var want_valgrind: ?bool = null;
@@ -795,6 +798,10 @@ fn buildOutputType(
                         want_pic = true;
                     } else if (mem.eql(u8, arg, "-fno-PIC")) {
                         want_pic = false;
+                    } else if (mem.eql(u8, arg, "-fPIE")) {
+                        want_pie = true;
+                    } else if (mem.eql(u8, arg, "-fno-PIE")) {
+                        want_pie = false;
                     } else if (mem.eql(u8, arg, "-fstack-check")) {
                         want_stack_check = true;
                     } else if (mem.eql(u8, arg, "-fno-stack-check")) {
@@ -1006,6 +1013,8 @@ fn buildOutputType(
                     },
                     .pic => want_pic = true,
                     .no_pic => want_pic = false,
+                    .pie => want_pie = true,
+                    .no_pie => want_pie = false,
                     .nostdlib => ensure_libc_on_non_freestanding = false,
                     .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false,
                     .shared => {
@@ -1640,6 +1649,7 @@ fn buildOutputType(
         .link_libc = link_libc,
         .link_libcpp = link_libcpp,
         .want_pic = want_pic,
+        .want_pie = want_pie,
         .want_sanitize_c = want_sanitize_c,
         .want_stack_check = want_stack_check,
         .want_valgrind = want_valgrind,
@@ -2773,6 +2783,8 @@ pub const ClangArgIterator = struct {
         driver_punt,
         pic,
         no_pic,
+        pie,
+        no_pie,
         nostdlib,
         nostdlib_cpp,
         shared,
src/musl.zig
@@ -12,6 +12,7 @@ pub const CRTFile = enum {
     crti_o,
     crtn_o,
     crt1_o,
+    rcrt1_o,
     scrt1_o,
     libc_a,
 };
@@ -68,6 +69,23 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
                 },
             });
         },
+        .rcrt1_o => {
+            var args = std.ArrayList([]const u8).init(arena);
+            try add_cc_args(comp, arena, &args, false);
+            try args.appendSlice(&[_][]const u8{
+                "-fPIC",
+                "-fno-stack-protector",
+                "-DCRT",
+            });
+            return comp.build_crt_file("rcrt1", .Obj, &[1]Compilation.CSourceFile{
+                .{
+                    .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
+                        "libc", "musl", "crt", "rcrt1.c",
+                    }),
+                    .extra_flags = args.items,
+                },
+            });
+        },
         .scrt1_o => {
             var args = std.ArrayList([]const u8).init(arena);
             try add_cc_args(comp, arena, &args, false);
src/stage1.zig
@@ -108,6 +108,7 @@ pub const Module = extern struct {
     subsystem: TargetSubsystem,
     err_color: ErrColor,
     pic: bool,
+    pie: bool,
     link_libc: bool,
     link_libcpp: bool,
     strip: bool,
tools/update_clang_options.zig
@@ -54,6 +54,14 @@ const known_options = [_]KnownOpt{
         .name = "fno-PIC",
         .ident = "no_pic",
     },
+    .{
+        .name = "fPIE",
+        .ident = "pie",
+    },
+    .{
+        .name = "fno-PIE",
+        .ident = "no_pie",
+    },
     .{
         .name = "nolibc",
         .ident = "nostdlib",