authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-22 17:30:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-22 17:30:34-07:00
logc7170e4a5480581db5f30913eebd9ad4f7cd121e
treefba79b8f4241c94f886e7708d18081e8fc0e31fe
parent98d5bfbd4d21e99363a0a68ef5a0d0104c302ecb
parentabc717f203060f7ab16d36f2afe681d838b46801

Support PIE (Position Independent Executables)

Closes #4503 Revives #3960 Merges branch 'pie' into master

23 files changed, 485 insertions(+), 34 deletions(-)

lib/libc/musl/ldso/dlstart.c created+148
......@@ -0,0 +1,148 @@
1#include <stddef.h>
2#include "dynlink.h"
3#include "libc.h"
4
5#ifndef START
6#define START "_dlstart"
7#endif
8
9#define SHARED
10
11#include "crt_arch.h"
12
13#ifndef GETFUNCSYM
14#define GETFUNCSYM(fp, sym, got) do { \
15 hidden void sym(); \
16 static void (*static_func_ptr)() = sym; \
17 __asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \
18 *(fp) = static_func_ptr; } while(0)
19#endif
20
21hidden void _dlstart_c(size_t *sp, size_t *dynv)
22{
23 size_t i, aux[AUX_CNT], dyn[DYN_CNT];
24 size_t *rel, rel_size, base;
25
26 int argc = *sp;
27 char **argv = (void *)(sp+1);
28
29 for (i=argc+1; argv[i]; i++);
30 size_t *auxv = (void *)(argv+i+1);
31
32 for (i=0; i<AUX_CNT; i++) aux[i] = 0;
33 for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT)
34 aux[auxv[i]] = auxv[i+1];
35
36#if DL_FDPIC
37 struct fdpic_loadseg *segs, fakeseg;
38 size_t j;
39 if (dynv) {
40 /* crt_arch.h entry point asm is responsible for reserving
41 * space and moving the extra fdpic arguments to the stack
42 * vector where they are easily accessible from C. */
43 segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs;
44 } else {
45 /* If dynv is null, the entry point was started from loader
46 * that is not fdpic-aware. We can assume normal fixed-
47 * displacement ELF loading was performed, but when ldso was
48 * run as a command, finding the Ehdr is a heursitic: we
49 * have to assume Phdrs start in the first 4k of the file. */
50 base = aux[AT_BASE];
51 if (!base) base = aux[AT_PHDR] & -4096;
52 segs = &fakeseg;
53 segs[0].addr = base;
54 segs[0].p_vaddr = 0;
55 segs[0].p_memsz = -1;
56 Ehdr *eh = (void *)base;
57 Phdr *ph = (void *)(base + eh->e_phoff);
58 size_t phnum = eh->e_phnum;
59 size_t phent = eh->e_phentsize;
60 while (phnum-- && ph->p_type != PT_DYNAMIC)
61 ph = (void *)((size_t)ph + phent);
62 dynv = (void *)(base + ph->p_vaddr);
63 }
64#endif
65
66 for (i=0; i<DYN_CNT; i++) dyn[i] = 0;
67 for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT)
68 dyn[dynv[i]] = dynv[i+1];
69
70#if DL_FDPIC
71 for (i=0; i<DYN_CNT; i++) {
72 if (i==DT_RELASZ || i==DT_RELSZ) continue;
73 if (!dyn[i]) continue;
74 for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
75 dyn[i] += segs[j].addr - segs[j].p_vaddr;
76 }
77 base = 0;
78
79 const Sym *syms = (void *)dyn[DT_SYMTAB];
80
81 rel = (void *)dyn[DT_RELA];
82 rel_size = dyn[DT_RELASZ];
83 for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
84 if (!IS_RELATIVE(rel[1], syms)) continue;
85 for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
86 size_t *rel_addr = (void *)
87 (rel[0] + segs[j].addr - segs[j].p_vaddr);
88 if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) {
89 *rel_addr += segs[rel_addr[1]].addr
90 - segs[rel_addr[1]].p_vaddr
91 + syms[R_SYM(rel[1])].st_value;
92 rel_addr[1] = dyn[DT_PLTGOT];
93 } else {
94 size_t val = syms[R_SYM(rel[1])].st_value;
95 for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++);
96 *rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val;
97 }
98 }
99#else
100 /* If the dynamic linker is invoked as a command, its load
101 * address is not available in the aux vector. Instead, compute
102 * the load address as the difference between &_DYNAMIC and the
103 * virtual address in the PT_DYNAMIC program header. */
104 base = aux[AT_BASE];
105 if (!base) {
106 size_t phnum = aux[AT_PHNUM];
107 size_t phentsize = aux[AT_PHENT];
108 Phdr *ph = (void *)aux[AT_PHDR];
109 for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) {
110 if (ph->p_type == PT_DYNAMIC) {
111 base = (size_t)dynv - ph->p_vaddr;
112 break;
113 }
114 }
115 }
116
117 /* MIPS uses an ugly packed form for GOT relocations. Since we
118 * can't make function calls yet and the code is tiny anyway,
119 * it's simply inlined here. */
120 if (NEED_MIPS_GOT_RELOCS) {
121 size_t local_cnt = 0;
122 size_t *got = (void *)(base + dyn[DT_PLTGOT]);
123 for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO)
124 local_cnt = dynv[i+1];
125 for (i=0; i<local_cnt; i++) got[i] += base;
126 }
127
128 rel = (void *)(base+dyn[DT_REL]);
129 rel_size = dyn[DT_RELSZ];
130 for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) {
131 if (!IS_RELATIVE(rel[1], 0)) continue;
132 size_t *rel_addr = (void *)(base + rel[0]);
133 *rel_addr += base;
134 }
135
136 rel = (void *)(base+dyn[DT_RELA]);
137 rel_size = dyn[DT_RELASZ];
138 for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
139 if (!IS_RELATIVE(rel[1], 0)) continue;
140 size_t *rel_addr = (void *)(base + rel[0]);
141 *rel_addr = base + rel[2];
142 }
143#endif
144
145 stage2_func dls2;
146 GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]);
147 dls2((void *)base, sp);
148}
lib/std/build.zig+11
......@@ -1286,6 +1286,9 @@ pub const LibExeObjStep = struct {
12861286 /// Position Independent Code
12871287 force_pic: ?bool = null,
12881288
1289 /// Position Independent Executable
1290 pie: ?bool = null,
1291
12891292 subsystem: ?builtin.SubSystem = null,
12901293
12911294 const LinkObject = union(enum) {
......@@ -2307,6 +2310,14 @@ pub const LibExeObjStep = struct {
23072310 }
23082311 }
23092312
2313 if (self.pie) |pie| {
2314 if (pie) {
2315 try zig_args.append("-fPIE");
2316 } else {
2317 try zig_args.append("-fno-PIE");
2318 }
2319 }
2320
23102321 if (self.subsystem) |subsystem| {
23112322 try zig_args.append("--subsystem");
23122323 try zig_args.append(switch (subsystem) {
lib/std/dynamic_library.zig+26-26
......@@ -59,48 +59,48 @@ const RDebug = extern struct {
5959 r_ldbase: usize,
6060};
6161
62fn elf_get_va_offset(phdrs: []elf.Phdr) !usize {
63 for (phdrs) |*phdr| {
64 if (phdr.p_type == elf.PT_LOAD) {
65 return @ptrToInt(phdr) - phdr.p_vaddr;
66 }
62// TODO: This should be weak (#1917)
63extern var _DYNAMIC: [128]elf.Dyn;
64
65comptime {
66 if (std.Target.current.os.tag == .linux) {
67 asm (
68 \\ .weak _DYNAMIC
69 \\ .hidden _DYNAMIC
70 );
6771 }
68 return error.InvalidExe;
6972}
7073
7174pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
72 const va_offset = try elf_get_va_offset(phdrs);
73
74 const dyn_table = init: {
75 for (phdrs) |*phdr| {
76 if (phdr.p_type == elf.PT_DYNAMIC) {
77 const ptr = @intToPtr([*]elf.Dyn, va_offset + phdr.p_vaddr);
78 break :init ptr[0 .. phdr.p_memsz / @sizeOf(elf.Dyn)];
79 }
80 }
75 if (@ptrToInt(&_DYNAMIC[0]) == 0) {
8176 // No PT_DYNAMIC means this is either a statically-linked program or a
8277 // badly corrupted one
8378 return LinkMap.Iterator{ .current = null };
84 };
79 }
8580
8681 const link_map_ptr = init: {
87 for (dyn_table) |*dyn| {
88 switch (dyn.d_tag) {
82 var i: usize = 0;
83 while (_DYNAMIC[i].d_tag != elf.DT_NULL) : (i += 1) {
84 switch (_DYNAMIC[i].d_tag) {
8985 elf.DT_DEBUG => {
90 const r_debug = @intToPtr(*RDebug, dyn.d_val);
91 if (r_debug.r_version != 1) return error.InvalidExe;
92 break :init r_debug.r_map;
86 const ptr = @intToPtr(?*RDebug, _DYNAMIC[i].d_val);
87 if (ptr) |r_debug| {
88 if (r_debug.r_version != 1) return error.InvalidExe;
89 break :init r_debug.r_map;
90 }
9391 },
9492 elf.DT_PLTGOT => {
95 const got_table = @intToPtr([*]usize, dyn.d_val);
96 // The address to the link_map structure is stored in the
97 // second slot
98 break :init @intToPtr(?*LinkMap, got_table[1]);
93 const ptr = @intToPtr(?[*]usize, _DYNAMIC[i].d_val);
94 if (ptr) |got_table| {
95 // The address to the link_map structure is stored in
96 // the second slot
97 break :init @intToPtr(?*LinkMap, got_table[1]);
98 }
9999 },
100100 else => {},
101101 }
102102 }
103 return error.InvalidExe;
103 return LinkMap.Iterator{ .current = null };
104104 };
105105
106106 return LinkMap.Iterator{ .current = link_map_ptr };
lib/std/elf.zig+38
......@@ -719,20 +719,48 @@ pub const Elf64_Syminfo = extern struct {
719719pub const Elf32_Rel = extern struct {
720720 r_offset: Elf32_Addr,
721721 r_info: Elf32_Word,
722
723 pub inline fn r_sym(self: @This()) u24 {
724 return @truncate(u24, self.r_info >> 8);
725 }
726 pub inline fn r_type(self: @This()) u8 {
727 return @truncate(u8, self.r_info & 0xff);
728 }
722729};
723730pub const Elf64_Rel = extern struct {
724731 r_offset: Elf64_Addr,
725732 r_info: Elf64_Xword,
733
734 pub inline fn r_sym(self: @This()) u32 {
735 return @truncate(u32, self.r_info >> 32);
736 }
737 pub inline fn r_type(self: @This()) u32 {
738 return @truncate(u32, self.r_info & 0xffffffff);
739 }
726740};
727741pub const Elf32_Rela = extern struct {
728742 r_offset: Elf32_Addr,
729743 r_info: Elf32_Word,
730744 r_addend: Elf32_Sword,
745
746 pub inline fn r_sym(self: @This()) u24 {
747 return @truncate(u24, self.r_info >> 8);
748 }
749 pub inline fn r_type(self: @This()) u8 {
750 return @truncate(u8, self.r_info & 0xff);
751 }
731752};
732753pub const Elf64_Rela = extern struct {
733754 r_offset: Elf64_Addr,
734755 r_info: Elf64_Xword,
735756 r_addend: Elf64_Sxword,
757
758 pub inline fn r_sym(self: @This()) u32 {
759 return @truncate(u32, self.r_info >> 32);
760 }
761 pub inline fn r_type(self: @This()) u32 {
762 return @truncate(u32, self.r_info & 0xffffffff);
763 }
736764};
737765pub const Elf32_Dyn = extern struct {
738766 d_tag: Elf32_Sword,
......@@ -917,6 +945,16 @@ pub const Dyn = switch (@sizeOf(usize)) {
917945 8 => Elf64_Dyn,
918946 else => @compileError("expected pointer size of 32 or 64"),
919947};
948pub const Rel = switch (@sizeOf(usize)) {
949 4 => Elf32_Rel,
950 8 => Elf64_Rel,
951 else => @compileError("expected pointer size of 32 or 64"),
952};
953pub const Rela = switch (@sizeOf(usize)) {
954 4 => Elf32_Rela,
955 8 => Elf64_Rela,
956 else => @compileError("expected pointer size of 32 or 64"),
957};
920958pub const Shdr = switch (@sizeOf(usize)) {
921959 4 => Elf32_Shdr,
922960 8 => Elf64_Shdr,
lib/std/os/linux/start_pie.zig created+138
......@@ -0,0 +1,138 @@
1const std = @import("std");
2const elf = std.elf;
3const builtin = @import("builtin");
4const assert = std.debug.assert;
5
6const R_AMD64_RELATIVE = 8;
7const R_386_RELATIVE = 8;
8const R_ARM_RELATIVE = 23;
9const R_AARCH64_RELATIVE = 1027;
10const R_RISCV_RELATIVE = 3;
11
12const ARCH_RELATIVE_RELOC = switch (builtin.arch) {
13 .i386 => R_386_RELATIVE,
14 .x86_64 => R_AMD64_RELATIVE,
15 .arm => R_ARM_RELATIVE,
16 .aarch64 => R_AARCH64_RELATIVE,
17 .riscv64 => R_RISCV_RELATIVE,
18 else => @compileError("unsupported architecture"),
19};
20
21// Just a convoluted (but necessary) way to obtain the address of the _DYNAMIC[]
22// vector as PC-relative so that we can use it before any relocation is applied
23fn getDynamicSymbol() [*]elf.Dyn {
24 const addr = switch (builtin.arch) {
25 .i386 => asm volatile (
26 \\ .weak _DYNAMIC
27 \\ .hidden _DYNAMIC
28 \\ call 1f
29 \\ 1: pop %[ret]
30 \\ lea _DYNAMIC-1b(%[ret]), %[ret]
31 : [ret] "=r" (-> usize)
32 ),
33 .x86_64 => asm volatile (
34 \\ .weak _DYNAMIC
35 \\ .hidden _DYNAMIC
36 \\ lea _DYNAMIC(%%rip), %[ret]
37 : [ret] "=r" (-> usize)
38 ),
39 // Work around the limited offset range of `ldr`
40 .arm => asm volatile (
41 \\ .weak _DYNAMIC
42 \\ .hidden _DYNAMIC
43 \\ ldr %[ret], 1f
44 \\ add %[ret], pc
45 \\ b 2f
46 \\ 1: .word _DYNAMIC-1b
47 \\ 2:
48 : [ret] "=r" (-> usize)
49 ),
50 // A simple `adr` is not enough as it has a limited offset range
51 .aarch64 => asm volatile (
52 \\ .weak _DYNAMIC
53 \\ .hidden _DYNAMIC
54 \\ adrp %[ret], _DYNAMIC
55 \\ add %[ret], %[ret], #:lo12:_DYNAMIC
56 : [ret] "=r" (-> usize)
57 ),
58 .riscv64 => asm volatile (
59 \\ lla %[ret], _DYNAMIC
60 : [ret] "=r" (-> usize)
61 ),
62 else => @compileError("???"),
63 };
64 if (addr == 0) unreachable;
65 return @intToPtr([*]elf.Dyn, addr);
66}
67
68pub fn apply_relocations() void {
69 @setRuntimeSafety(false);
70
71 const dynv = getDynamicSymbol();
72 const auxv = std.os.linux.elf_aux_maybe.?;
73 var at_phent: usize = undefined;
74 var at_phnum: usize = undefined;
75 var at_phdr: usize = undefined;
76 var at_hwcap: usize = undefined;
77
78 {
79 var i: usize = 0;
80 while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) {
81 switch (auxv[i].a_type) {
82 elf.AT_PHENT => at_phent = auxv[i].a_un.a_val,
83 elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val,
84 elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val,
85 else => continue,
86 }
87 }
88 }
89
90 // Sanity check
91 assert(at_phent == @sizeOf(elf.Phdr));
92
93 // Search the TLS section
94 const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum];
95
96 const base_addr = blk: {
97 for (phdrs) |*phdr| {
98 if (phdr.p_type == elf.PT_DYNAMIC) {
99 break :blk @ptrToInt(&dynv[0]) - phdr.p_vaddr;
100 }
101 }
102 unreachable;
103 };
104
105 var rel_addr: usize = 0;
106 var rela_addr: usize = 0;
107 var rel_size: usize = 0;
108 var rela_size: usize = 0;
109
110 {
111 var i: usize = 0;
112 while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) {
113 switch (dynv[i].d_tag) {
114 elf.DT_REL => rel_addr = base_addr + dynv[i].d_val,
115 elf.DT_RELA => rela_addr = base_addr + dynv[i].d_val,
116 elf.DT_RELSZ => rel_size = dynv[i].d_val,
117 elf.DT_RELASZ => rela_size = dynv[i].d_val,
118 else => {},
119 }
120 }
121 }
122
123 // Perform the relocations
124 if (rel_addr != 0) {
125 const rel = std.mem.bytesAsSlice(elf.Rel, @intToPtr([*]u8, rel_addr)[0..rel_size]);
126 for (rel) |r| {
127 if (r.r_type() != ARCH_RELATIVE_RELOC) continue;
128 @intToPtr(*usize, base_addr + r.r_offset).* += base_addr;
129 }
130 }
131 if (rela_addr != 0) {
132 const rela = std.mem.bytesAsSlice(elf.Rela, @intToPtr([*]u8, rela_addr)[0..rela_size]);
133 for (rela) |r| {
134 if (r.r_type() != ARCH_RELATIVE_RELOC) continue;
135 @intToPtr(*usize, base_addr + r.r_offset).* += base_addr + @bitCast(usize, r.r_addend);
136 }
137 }
138}
lib/std/os/test.zig+2
......@@ -386,6 +386,8 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
386386test "dl_iterate_phdr" {
387387 if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos)
388388 return error.SkipZigTest;
389 if (builtin.position_independent_executable)
390 return error.SkipZigTest;
389391
390392 var counter: usize = 0;
391393 try os.dl_iterate_phdr(&counter, IterFnError, iter_fn);
lib/std/start.zig+6
......@@ -202,6 +202,12 @@ fn posixCallMainAndExit() noreturn {
202202 // Find the beginning of the auxiliary vector
203203 const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));
204204 std.os.linux.elf_aux_maybe = auxv;
205
206 // Do this as early as possible, the aux vector is needed
207 if (builtin.position_independent_executable) {
208 @import("os/linux/start_pie.zig").apply_relocations();
209 }
210
205211 // Initialize the TLS area
206212 std.os.linux.tls.initStaticTLS();
207213
src/Compilation.zig+29-4
......@@ -343,6 +343,10 @@ pub const InitOptions = struct {
343343 link_libc: bool = false,
344344 link_libcpp: bool = false,
345345 want_pic: ?bool = null,
346 /// This means that if the output mode is an executable it will be a
347 /// Position Independent Executable. If the output mode is not an
348 /// executable this field is ignored.
349 want_pie: ?bool = null,
346350 want_sanitize_c: ?bool = null,
347351 want_stack_check: ?bool = null,
348352 want_valgrind: ?bool = null,
......@@ -527,17 +531,30 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
527531 options.libc_installation,
528532 );
529533
534 const must_pie = target_util.requiresPIE(options.target);
535 const pie = if (options.want_pie) |explicit| pie: {
536 if (!explicit and must_pie) {
537 return error.TargetRequiresPIE;
538 }
539 break :pie explicit;
540 } else must_pie;
541
530542 const must_pic: bool = b: {
531543 if (target_util.requiresPIC(options.target, link_libc))
532544 break :b true;
533545 break :b link_mode == .Dynamic;
534546 };
535547 const pic = if (options.want_pic) |explicit| pic: {
536 if (!explicit and must_pic) {
537 return error.TargetRequiresPIC;
548 if (!explicit) {
549 if (must_pic) {
550 return error.TargetRequiresPIC;
551 }
552 if (pie) {
553 return error.PIERequiresPIC;
554 }
538555 }
539556 break :pic explicit;
540 } else must_pic;
557 } else pie or must_pic;
541558
542559 // Make a decision on whether to use Clang for translate-c and compiling C files.
543560 const use_clang = if (options.use_clang) |explicit| explicit else blk: {
......@@ -618,6 +635,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
618635 cache.hash.add(options.target.abi);
619636 cache.hash.add(ofmt);
620637 cache.hash.add(pic);
638 cache.hash.add(pie);
621639 cache.hash.add(stack_check);
622640 cache.hash.add(link_mode);
623641 cache.hash.add(options.function_sections);
......@@ -814,6 +832,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
814832 .version = options.version,
815833 .libc_installation = libc_dirs.libc_installation,
816834 .pic = pic,
835 .pie = pie,
817836 .valgrind = valgrind,
818837 .stack_check = stack_check,
819838 .single_threaded = single_threaded,
......@@ -898,7 +917,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
898917 try comp.addBuildingGLibCJobs();
899918 }
900919 if (comp.wantBuildMuslFromSource()) {
901 try comp.work_queue.ensureUnusedCapacity(5);
920 try comp.work_queue.ensureUnusedCapacity(6);
902921 if (target_util.libc_needs_crti_crtn(comp.getTarget())) {
903922 comp.work_queue.writeAssumeCapacity(&[_]Job{
904923 .{ .musl_crt_file = .crti_o },
......@@ -908,6 +927,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
908927 comp.work_queue.writeAssumeCapacity(&[_]Job{
909928 .{ .musl_crt_file = .crt1_o },
910929 .{ .musl_crt_file = .scrt1_o },
930 .{ .musl_crt_file = .rcrt1_o },
911931 .{ .musl_crt_file = .libc_a },
912932 });
913933 }
......@@ -2473,6 +2493,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
24732493 \\pub const have_error_return_tracing = {};
24742494 \\pub const valgrind_support = {};
24752495 \\pub const position_independent_code = {};
2496 \\pub const position_independent_executable = {};
24762497 \\pub const strip_debug_info = {};
24772498 \\pub const code_model = CodeModel.{};
24782499 \\
......@@ -2484,6 +2505,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
24842505 comp.bin_file.options.error_return_tracing,
24852506 comp.bin_file.options.valgrind,
24862507 comp.bin_file.options.pic,
2508 comp.bin_file.options.pie,
24872509 comp.bin_file.options.strip,
24882510 @tagName(comp.bin_file.options.machine_code_model),
24892511 });
......@@ -2587,6 +2609,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
25872609 .want_stack_check = false,
25882610 .want_valgrind = false,
25892611 .want_pic = comp.bin_file.options.pic,
2612 .want_pie = comp.bin_file.options.pie,
25902613 .emit_h = null,
25912614 .strip = comp.bin_file.options.strip,
25922615 .is_native_os = comp.bin_file.options.is_native_os,
......@@ -2795,6 +2818,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
27952818 .subsystem = subsystem,
27962819 .err_color = @enumToInt(comp.color),
27972820 .pic = comp.bin_file.options.pic,
2821 .pie = comp.bin_file.options.pie,
27982822 .link_libc = comp.bin_file.options.link_libc,
27992823 .link_libcpp = comp.bin_file.options.link_libcpp,
28002824 .strip = comp.bin_file.options.strip,
......@@ -2950,6 +2974,7 @@ pub fn build_crt_file(
29502974 .want_stack_check = false,
29512975 .want_valgrind = false,
29522976 .want_pic = comp.bin_file.options.pic,
2977 .want_pie = comp.bin_file.options.pie,
29532978 .emit_h = null,
29542979 .strip = comp.bin_file.options.strip,
29552980 .is_native_os = comp.bin_file.options.is_native_os,
src/clang_options_data.zig+16-2
......@@ -2460,7 +2460,14 @@ sepd1("exported_symbols_list"),
24602460 .pd2 = false,
24612461 .psl = false,
24622462},
2463flagpd1("fPIE"),
2463.{
2464 .name = "fPIE",
2465 .syntax = .flag,
2466 .zig_equivalent = .pie,
2467 .pd1 = true,
2468 .pd2 = false,
2469 .psl = false,
2470},
24642471flagpd1("fno-access-control"),
24652472flagpd1("faddrsig"),
24662473flagpd1("faggressive-function-elimination"),
......@@ -2775,7 +2782,14 @@ flagpd1("fnext-runtime"),
27752782 .pd2 = false,
27762783 .psl = false,
27772784},
2778flagpd1("fno-PIE"),
2785.{
2786 .name = "fno-PIE",
2787 .syntax = .flag,
2788 .zig_equivalent = .no_pie,
2789 .pd1 = true,
2790 .pd2 = false,
2791 .psl = false,
2792},
27792793flagpd1("fno-no-access-control"),
27802794flagpd1("fno-addrsig"),
27812795flagpd1("fno-aggressive-function-elimination"),
src/libcxx.zig+2
......@@ -171,6 +171,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
171171 .want_stack_check = false,
172172 .want_valgrind = false,
173173 .want_pic = comp.bin_file.options.pic,
174 .want_pie = comp.bin_file.options.pie,
174175 .emit_h = null,
175176 .strip = comp.bin_file.options.strip,
176177 .is_native_os = comp.bin_file.options.is_native_os,
......@@ -288,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
288289 .want_stack_check = false,
289290 .want_valgrind = false,
290291 .want_pic = comp.bin_file.options.pic,
292 .want_pie = comp.bin_file.options.pie,
291293 .emit_h = null,
292294 .strip = comp.bin_file.options.strip,
293295 .is_native_os = comp.bin_file.options.is_native_os,
src/libunwind.zig+1
......@@ -104,6 +104,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
104104 .want_stack_check = false,
105105 .want_valgrind = false,
106106 .want_pic = comp.bin_file.options.pic,
107 .want_pie = comp.bin_file.options.pie,
107108 .emit_h = null,
108109 .strip = comp.bin_file.options.strip,
109110 .is_native_os = comp.bin_file.options.is_native_os,
src/link.zig+1
......@@ -71,6 +71,7 @@ pub const Options = struct {
7171 bind_global_refs_locally: bool,
7272 is_native_os: bool,
7373 pic: bool,
74 pie: bool,
7475 valgrind: bool,
7576 stack_check: bool,
7677 single_threaded: bool,
src/link/Elf.zig+6-2
......@@ -1425,7 +1425,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
14251425 try argv.append("-shared");
14261426 }
14271427
1428 if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
1428 if (self.base.options.pie and self.base.options.output_mode == .Exe) {
14291429 try argv.append("-pie");
14301430 }
14311431
......@@ -1444,7 +1444,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
14441444 break :o "crtbegin_static.o";
14451445 }
14461446 } else if (self.base.options.link_mode == .Static) {
1447 break :o "crt1.o";
1447 if (self.base.options.pie) {
1448 break :o "rcrt1.o";
1449 } else {
1450 break :o "crt1.o";
1451 }
14481452 } else {
14491453 break :o "Scrt1.o";
14501454 }
src/main.zig+12
......@@ -270,6 +270,8 @@ const usage_build_generic =
270270 \\ --main-pkg-path Set the directory of the root package
271271 \\ -fPIC Force-enable Position Independent Code
272272 \\ -fno-PIC Force-disable Position Independent Code
273 \\ -fPIE Force-enable Position Independent Executable
274 \\ -fno-PIE Force-disable Position Independent Executable
273275 \\ -fstack-check Enable stack probing in unsafe builds
274276 \\ -fno-stack-check Disable stack probing in safe builds
275277 \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds
......@@ -457,6 +459,7 @@ fn buildOutputType(
457459 var want_native_include_dirs = false;
458460 var enable_cache: ?bool = null;
459461 var want_pic: ?bool = null;
462 var want_pie: ?bool = null;
460463 var want_sanitize_c: ?bool = null;
461464 var want_stack_check: ?bool = null;
462465 var want_valgrind: ?bool = null;
......@@ -795,6 +798,10 @@ fn buildOutputType(
795798 want_pic = true;
796799 } else if (mem.eql(u8, arg, "-fno-PIC")) {
797800 want_pic = false;
801 } else if (mem.eql(u8, arg, "-fPIE")) {
802 want_pie = true;
803 } else if (mem.eql(u8, arg, "-fno-PIE")) {
804 want_pie = false;
798805 } else if (mem.eql(u8, arg, "-fstack-check")) {
799806 want_stack_check = true;
800807 } else if (mem.eql(u8, arg, "-fno-stack-check")) {
......@@ -1006,6 +1013,8 @@ fn buildOutputType(
10061013 },
10071014 .pic => want_pic = true,
10081015 .no_pic => want_pic = false,
1016 .pie => want_pie = true,
1017 .no_pie => want_pie = false,
10091018 .nostdlib => ensure_libc_on_non_freestanding = false,
10101019 .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false,
10111020 .shared => {
......@@ -1640,6 +1649,7 @@ fn buildOutputType(
16401649 .link_libc = link_libc,
16411650 .link_libcpp = link_libcpp,
16421651 .want_pic = want_pic,
1652 .want_pie = want_pie,
16431653 .want_sanitize_c = want_sanitize_c,
16441654 .want_stack_check = want_stack_check,
16451655 .want_valgrind = want_valgrind,
......@@ -2773,6 +2783,8 @@ pub const ClangArgIterator = struct {
27732783 driver_punt,
27742784 pic,
27752785 no_pic,
2786 pie,
2787 no_pie,
27762788 nostdlib,
27772789 nostdlib_cpp,
27782790 shared,
src/musl.zig+18
......@@ -12,6 +12,7 @@ pub const CRTFile = enum {
1212 crti_o,
1313 crtn_o,
1414 crt1_o,
15 rcrt1_o,
1516 scrt1_o,
1617 libc_a,
1718};
......@@ -68,6 +69,23 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
6869 },
6970 });
7071 },
72 .rcrt1_o => {
73 var args = std.ArrayList([]const u8).init(arena);
74 try add_cc_args(comp, arena, &args, false);
75 try args.appendSlice(&[_][]const u8{
76 "-fPIC",
77 "-fno-stack-protector",
78 "-DCRT",
79 });
80 return comp.build_crt_file("rcrt1", .Obj, &[1]Compilation.CSourceFile{
81 .{
82 .src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
83 "libc", "musl", "crt", "rcrt1.c",
84 }),
85 .extra_flags = args.items,
86 },
87 });
88 },
7189 .scrt1_o => {
7290 var args = std.ArrayList([]const u8).init(arena);
7391 try add_cc_args(comp, arena, &args, false);
src/stage1.zig+1
......@@ -108,6 +108,7 @@ pub const Module = extern struct {
108108 subsystem: TargetSubsystem,
109109 err_color: ErrColor,
110110 pic: bool,
111 pie: bool,
111112 link_libc: bool,
112113 link_libcpp: bool,
113114 strip: bool,
src/stage1/all_types.hpp+1
......@@ -2177,6 +2177,7 @@ struct CodeGen {
21772177 bool is_test_build;
21782178 bool is_single_threaded;
21792179 bool have_pic;
2180 bool have_pie;
21802181 bool link_mode_dynamic;
21812182 bool dll_export_fns;
21822183 bool have_stack_probing;
src/stage1/codegen.cpp+9
......@@ -9043,6 +9043,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
90439043 buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
90449044 buf_appendf(contents, "pub const valgrind_support = false;\n");
90459045 buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic));
9046 buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));
90469047 buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));
90479048 buf_appendf(contents, "pub const code_model = CodeModel.default;\n");
90489049
......@@ -9170,6 +9171,14 @@ static void init(CodeGen *g) {
91709171 reloc_mode = LLVMRelocStatic;
91719172 }
91729173
9174 if (g->have_pic) {
9175 ZigLLVMSetModulePICLevel(g->module);
9176 }
9177
9178 if (g->have_pie) {
9179 ZigLLVMSetModulePIELevel(g->module);
9180 }
9181
91739182 const char *target_specific_cpu_args = "";
91749183 const char *target_specific_features = "";
91759184
src/stage1/stage1.cpp+1
......@@ -89,6 +89,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
8989 g->link_mode_dynamic = stage1->link_mode_dynamic;
9090 g->dll_export_fns = stage1->dll_export_fns;
9191 g->have_pic = stage1->pic;
92 g->have_pie = stage1->pie;
9293 g->have_stack_probing = stage1->enable_stack_probing;
9394 g->is_single_threaded = stage1->is_single_threaded;
9495 g->valgrind_enabled = stage1->valgrind_enabled;
src/stage1/stage1.h+1
......@@ -177,6 +177,7 @@ struct ZigStage1 {
177177 enum ErrColor err_color;
178178
179179 bool pic;
180 bool pie;
180181 bool link_libc;
181182 bool link_libcpp;
182183 bool strip;
src/zig_llvm.cpp+8
......@@ -855,6 +855,14 @@ void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) {
855855 unwrap(module)->addModuleFlag(Module::Warning, "CodeView", 1);
856856}
857857
858void ZigLLVMSetModulePICLevel(LLVMModuleRef module) {
859 unwrap(module)->setPICLevel(PICLevel::Level::BigPIC);
860}
861
862void ZigLLVMSetModulePIELevel(LLVMModuleRef module) {
863 unwrap(module)->setPIELevel(PIELevel::Level::Large);
864}
865
858866static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
859867 switch (Ordering) {
860868 case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic;
src/zig_llvm.h+2
......@@ -206,6 +206,8 @@ ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef modul
206206ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder);
207207ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
208208ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
209ZIG_EXTERN_C void ZigLLVMSetModulePICLevel(LLVMModuleRef module);
210ZIG_EXTERN_C void ZigLLVMSetModulePIELevel(LLVMModuleRef module);
209211
210212ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column,
211213 struct ZigLLVMDIScope *scope);
tools/update_clang_options.zig+8
......@@ -54,6 +54,14 @@ const known_options = [_]KnownOpt{
5454 .name = "fno-PIC",
5555 .ident = "no_pic",
5656 },
57 .{
58 .name = "fPIE",
59 .ident = "pie",
60 },
61 .{
62 .name = "fno-PIE",
63 .ident = "no_pie",
64 },
5765 .{
5866 .name = "nolibc",
5967 .ident = "nostdlib",