| author | |
| committer | |
| log | c7170e4a5480581db5f30913eebd9ad4f7cd121e |
| tree | fba79b8f4241c94f886e7708d18081e8fc0e31fe |
| parent | 98d5bfbd4d21e99363a0a68ef5a0d0104c302ecb |
| parent | abc717f203060f7ab16d36f2afe681d838b46801 |
Closes #4503
Revives #3960
Merges branch 'pie' into master23 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 | |||
| 21 | hidden 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 { | ... | @@ -1286,6 +1286,9 @@ pub const LibExeObjStep = struct { |
| 1286 | /// Position Independent Code | 1286 | /// Position Independent Code |
| 1287 | force_pic: ?bool = null, | 1287 | force_pic: ?bool = null, |
| 1288 | 1288 | ||
| 1289 | /// Position Independent Executable | ||
| 1290 | pie: ?bool = null, | ||
| 1291 | |||
| 1289 | subsystem: ?builtin.SubSystem = null, | 1292 | subsystem: ?builtin.SubSystem = null, |
| 1290 | 1293 | ||
| 1291 | const LinkObject = union(enum) { | 1294 | const LinkObject = union(enum) { |
| ... | @@ -2307,6 +2310,14 @@ pub const LibExeObjStep = struct { | ... | @@ -2307,6 +2310,14 @@ pub const LibExeObjStep = struct { |
| 2307 | } | 2310 | } |
| 2308 | } | 2311 | } |
| 2309 | 2312 | ||
| 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 | |||
| 2310 | if (self.subsystem) |subsystem| { | 2321 | if (self.subsystem) |subsystem| { |
| 2311 | try zig_args.append("--subsystem"); | 2322 | try zig_args.append("--subsystem"); |
| 2312 | try zig_args.append(switch (subsystem) { | 2323 | try zig_args.append(switch (subsystem) { |
lib/std/dynamic_library.zig+26-26| ... | @@ -59,48 +59,48 @@ const RDebug = extern struct { | ... | @@ -59,48 +59,48 @@ const RDebug = extern struct { |
| 59 | r_ldbase: usize, | 59 | r_ldbase: usize, |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | fn elf_get_va_offset(phdrs: []elf.Phdr) !usize { | 62 | // TODO: This should be weak (#1917) |
| 63 | for (phdrs) |*phdr| { | 63 | extern var _DYNAMIC: [128]elf.Dyn; |
| 64 | if (phdr.p_type == elf.PT_LOAD) { | 64 | |
| 65 | return @ptrToInt(phdr) - phdr.p_vaddr; | 65 | comptime { |
| 66 | } | 66 | if (std.Target.current.os.tag == .linux) { |
| 67 | asm ( | ||
| 68 | \\ .weak _DYNAMIC | ||
| 69 | \\ .hidden _DYNAMIC | ||
| 70 | ); | ||
| 67 | } | 71 | } |
| 68 | return error.InvalidExe; | ||
| 69 | } | 72 | } |
| 70 | 73 | ||
| 71 | pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator { | 74 | pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator { |
| 72 | const va_offset = try elf_get_va_offset(phdrs); | 75 | if (@ptrToInt(&_DYNAMIC[0]) == 0) { |
| 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 | } | ||
| 81 | // No PT_DYNAMIC means this is either a statically-linked program or a | 76 | // No PT_DYNAMIC means this is either a statically-linked program or a |
| 82 | // badly corrupted one | 77 | // badly corrupted one |
| 83 | return LinkMap.Iterator{ .current = null }; | 78 | return LinkMap.Iterator{ .current = null }; |
| 84 | }; | 79 | } |
| 85 | 80 | ||
| 86 | const link_map_ptr = init: { | 81 | const link_map_ptr = init: { |
| 87 | for (dyn_table) |*dyn| { | 82 | var i: usize = 0; |
| 88 | switch (dyn.d_tag) { | 83 | while (_DYNAMIC[i].d_tag != elf.DT_NULL) : (i += 1) { |
| 84 | switch (_DYNAMIC[i].d_tag) { | ||
| 89 | elf.DT_DEBUG => { | 85 | elf.DT_DEBUG => { |
| 90 | const r_debug = @intToPtr(*RDebug, dyn.d_val); | 86 | const ptr = @intToPtr(?*RDebug, _DYNAMIC[i].d_val); |
| 91 | if (r_debug.r_version != 1) return error.InvalidExe; | 87 | if (ptr) |r_debug| { |
| 92 | break :init r_debug.r_map; | 88 | if (r_debug.r_version != 1) return error.InvalidExe; |
| 89 | break :init r_debug.r_map; | ||
| 90 | } | ||
| 93 | }, | 91 | }, |
| 94 | elf.DT_PLTGOT => { | 92 | elf.DT_PLTGOT => { |
| 95 | const got_table = @intToPtr([*]usize, dyn.d_val); | 93 | const ptr = @intToPtr(?[*]usize, _DYNAMIC[i].d_val); |
| 96 | // The address to the link_map structure is stored in the | 94 | if (ptr) |got_table| { |
| 97 | // second slot | 95 | // The address to the link_map structure is stored in |
| 98 | break :init @intToPtr(?*LinkMap, got_table[1]); | 96 | // the second slot |
| 97 | break :init @intToPtr(?*LinkMap, got_table[1]); | ||
| 98 | } | ||
| 99 | }, | 99 | }, |
| 100 | else => {}, | 100 | else => {}, |
| 101 | } | 101 | } |
| 102 | } | 102 | } |
| 103 | return error.InvalidExe; | 103 | return LinkMap.Iterator{ .current = null }; |
| 104 | }; | 104 | }; |
| 105 | 105 | ||
| 106 | return LinkMap.Iterator{ .current = link_map_ptr }; | 106 | return LinkMap.Iterator{ .current = link_map_ptr }; |
lib/std/elf.zig+38| ... | @@ -719,20 +719,48 @@ pub const Elf64_Syminfo = extern struct { | ... | @@ -719,20 +719,48 @@ pub const Elf64_Syminfo = extern struct { |
| 719 | pub const Elf32_Rel = extern struct { | 719 | pub const Elf32_Rel = extern struct { |
| 720 | r_offset: Elf32_Addr, | 720 | r_offset: Elf32_Addr, |
| 721 | r_info: Elf32_Word, | 721 | 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 | } | ||
| 722 | }; | 729 | }; |
| 723 | pub const Elf64_Rel = extern struct { | 730 | pub const Elf64_Rel = extern struct { |
| 724 | r_offset: Elf64_Addr, | 731 | r_offset: Elf64_Addr, |
| 725 | r_info: Elf64_Xword, | 732 | 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 | } | ||
| 726 | }; | 740 | }; |
| 727 | pub const Elf32_Rela = extern struct { | 741 | pub const Elf32_Rela = extern struct { |
| 728 | r_offset: Elf32_Addr, | 742 | r_offset: Elf32_Addr, |
| 729 | r_info: Elf32_Word, | 743 | r_info: Elf32_Word, |
| 730 | r_addend: Elf32_Sword, | 744 | 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 | } | ||
| 731 | }; | 752 | }; |
| 732 | pub const Elf64_Rela = extern struct { | 753 | pub const Elf64_Rela = extern struct { |
| 733 | r_offset: Elf64_Addr, | 754 | r_offset: Elf64_Addr, |
| 734 | r_info: Elf64_Xword, | 755 | r_info: Elf64_Xword, |
| 735 | r_addend: Elf64_Sxword, | 756 | 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 | } | ||
| 736 | }; | 764 | }; |
| 737 | pub const Elf32_Dyn = extern struct { | 765 | pub const Elf32_Dyn = extern struct { |
| 738 | d_tag: Elf32_Sword, | 766 | d_tag: Elf32_Sword, |
| ... | @@ -917,6 +945,16 @@ pub const Dyn = switch (@sizeOf(usize)) { | ... | @@ -917,6 +945,16 @@ pub const Dyn = switch (@sizeOf(usize)) { |
| 917 | 8 => Elf64_Dyn, | 945 | 8 => Elf64_Dyn, |
| 918 | else => @compileError("expected pointer size of 32 or 64"), | 946 | else => @compileError("expected pointer size of 32 or 64"), |
| 919 | }; | 947 | }; |
| 948 | pub const Rel = switch (@sizeOf(usize)) { | ||
| 949 | 4 => Elf32_Rel, | ||
| 950 | 8 => Elf64_Rel, | ||
| 951 | else => @compileError("expected pointer size of 32 or 64"), | ||
| 952 | }; | ||
| 953 | pub const Rela = switch (@sizeOf(usize)) { | ||
| 954 | 4 => Elf32_Rela, | ||
| 955 | 8 => Elf64_Rela, | ||
| 956 | else => @compileError("expected pointer size of 32 or 64"), | ||
| 957 | }; | ||
| 920 | pub const Shdr = switch (@sizeOf(usize)) { | 958 | pub const Shdr = switch (@sizeOf(usize)) { |
| 921 | 4 => Elf32_Shdr, | 959 | 4 => Elf32_Shdr, |
| 922 | 8 => Elf64_Shdr, | 960 | 8 => Elf64_Shdr, |
lib/std/os/linux/start_pie.zig created+138| ... | @@ -0,0 +1,138 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const elf = std.elf; | ||
| 3 | const builtin = @import("builtin"); | ||
| 4 | const assert = std.debug.assert; | ||
| 5 | |||
| 6 | const R_AMD64_RELATIVE = 8; | ||
| 7 | const R_386_RELATIVE = 8; | ||
| 8 | const R_ARM_RELATIVE = 23; | ||
| 9 | const R_AARCH64_RELATIVE = 1027; | ||
| 10 | const R_RISCV_RELATIVE = 3; | ||
| 11 | |||
| 12 | const 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 | ||
| 23 | fn 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 | |||
| 68 | pub 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 { | ... | @@ -386,6 +386,8 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { |
| 386 | test "dl_iterate_phdr" { | 386 | test "dl_iterate_phdr" { |
| 387 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos) | 387 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos) |
| 388 | return error.SkipZigTest; | 388 | return error.SkipZigTest; |
| 389 | if (builtin.position_independent_executable) | ||
| 390 | return error.SkipZigTest; | ||
| 389 | 391 | ||
| 390 | var counter: usize = 0; | 392 | var counter: usize = 0; |
| 391 | try os.dl_iterate_phdr(&counter, IterFnError, iter_fn); | 393 | try os.dl_iterate_phdr(&counter, IterFnError, iter_fn); |
lib/std/start.zig+6| ... | @@ -202,6 +202,12 @@ fn posixCallMainAndExit() noreturn { | ... | @@ -202,6 +202,12 @@ fn posixCallMainAndExit() noreturn { |
| 202 | // Find the beginning of the auxiliary vector | 202 | // Find the beginning of the auxiliary vector |
| 203 | const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1)); | 203 | const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1)); |
| 204 | std.os.linux.elf_aux_maybe = auxv; | 204 | 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 | |||
| 205 | // Initialize the TLS area | 211 | // Initialize the TLS area |
| 206 | std.os.linux.tls.initStaticTLS(); | 212 | std.os.linux.tls.initStaticTLS(); |
| 207 | 213 |
src/Compilation.zig+29-4| ... | @@ -343,6 +343,10 @@ pub const InitOptions = struct { | ... | @@ -343,6 +343,10 @@ pub const InitOptions = struct { |
| 343 | link_libc: bool = false, | 343 | link_libc: bool = false, |
| 344 | link_libcpp: bool = false, | 344 | link_libcpp: bool = false, |
| 345 | want_pic: ?bool = null, | 345 | 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, | ||
| 346 | want_sanitize_c: ?bool = null, | 350 | want_sanitize_c: ?bool = null, |
| 347 | want_stack_check: ?bool = null, | 351 | want_stack_check: ?bool = null, |
| 348 | want_valgrind: ?bool = null, | 352 | want_valgrind: ?bool = null, |
| ... | @@ -527,17 +531,30 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -527,17 +531,30 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 527 | options.libc_installation, | 531 | options.libc_installation, |
| 528 | ); | 532 | ); |
| 529 | 533 | ||
| 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 | |||
| 530 | const must_pic: bool = b: { | 542 | const must_pic: bool = b: { |
| 531 | if (target_util.requiresPIC(options.target, link_libc)) | 543 | if (target_util.requiresPIC(options.target, link_libc)) |
| 532 | break :b true; | 544 | break :b true; |
| 533 | break :b link_mode == .Dynamic; | 545 | break :b link_mode == .Dynamic; |
| 534 | }; | 546 | }; |
| 535 | const pic = if (options.want_pic) |explicit| pic: { | 547 | const pic = if (options.want_pic) |explicit| pic: { |
| 536 | if (!explicit and must_pic) { | 548 | if (!explicit) { |
| 537 | return error.TargetRequiresPIC; | 549 | if (must_pic) { |
| 550 | return error.TargetRequiresPIC; | ||
| 551 | } | ||
| 552 | if (pie) { | ||
| 553 | return error.PIERequiresPIC; | ||
| 554 | } | ||
| 538 | } | 555 | } |
| 539 | break :pic explicit; | 556 | break :pic explicit; |
| 540 | } else must_pic; | 557 | } else pie or must_pic; |
| 541 | 558 | ||
| 542 | // Make a decision on whether to use Clang for translate-c and compiling C files. | 559 | // Make a decision on whether to use Clang for translate-c and compiling C files. |
| 543 | const use_clang = if (options.use_clang) |explicit| explicit else blk: { | 560 | const use_clang = if (options.use_clang) |explicit| explicit else blk: { |
| ... | @@ -618,6 +635,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -618,6 +635,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 618 | cache.hash.add(options.target.abi); | 635 | cache.hash.add(options.target.abi); |
| 619 | cache.hash.add(ofmt); | 636 | cache.hash.add(ofmt); |
| 620 | cache.hash.add(pic); | 637 | cache.hash.add(pic); |
| 638 | cache.hash.add(pie); | ||
| 621 | cache.hash.add(stack_check); | 639 | cache.hash.add(stack_check); |
| 622 | cache.hash.add(link_mode); | 640 | cache.hash.add(link_mode); |
| 623 | cache.hash.add(options.function_sections); | 641 | cache.hash.add(options.function_sections); |
| ... | @@ -814,6 +832,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -814,6 +832,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 814 | .version = options.version, | 832 | .version = options.version, |
| 815 | .libc_installation = libc_dirs.libc_installation, | 833 | .libc_installation = libc_dirs.libc_installation, |
| 816 | .pic = pic, | 834 | .pic = pic, |
| 835 | .pie = pie, | ||
| 817 | .valgrind = valgrind, | 836 | .valgrind = valgrind, |
| 818 | .stack_check = stack_check, | 837 | .stack_check = stack_check, |
| 819 | .single_threaded = single_threaded, | 838 | .single_threaded = single_threaded, |
| ... | @@ -898,7 +917,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -898,7 +917,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 898 | try comp.addBuildingGLibCJobs(); | 917 | try comp.addBuildingGLibCJobs(); |
| 899 | } | 918 | } |
| 900 | if (comp.wantBuildMuslFromSource()) { | 919 | if (comp.wantBuildMuslFromSource()) { |
| 901 | try comp.work_queue.ensureUnusedCapacity(5); | 920 | try comp.work_queue.ensureUnusedCapacity(6); |
| 902 | if (target_util.libc_needs_crti_crtn(comp.getTarget())) { | 921 | if (target_util.libc_needs_crti_crtn(comp.getTarget())) { |
| 903 | comp.work_queue.writeAssumeCapacity(&[_]Job{ | 922 | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 904 | .{ .musl_crt_file = .crti_o }, | 923 | .{ .musl_crt_file = .crti_o }, |
| ... | @@ -908,6 +927,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { | ... | @@ -908,6 +927,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation { |
| 908 | comp.work_queue.writeAssumeCapacity(&[_]Job{ | 927 | comp.work_queue.writeAssumeCapacity(&[_]Job{ |
| 909 | .{ .musl_crt_file = .crt1_o }, | 928 | .{ .musl_crt_file = .crt1_o }, |
| 910 | .{ .musl_crt_file = .scrt1_o }, | 929 | .{ .musl_crt_file = .scrt1_o }, |
| 930 | .{ .musl_crt_file = .rcrt1_o }, | ||
| 911 | .{ .musl_crt_file = .libc_a }, | 931 | .{ .musl_crt_file = .libc_a }, |
| 912 | }); | 932 | }); |
| 913 | } | 933 | } |
| ... | @@ -2473,6 +2493,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 | ... | @@ -2473,6 +2493,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 |
| 2473 | \\pub const have_error_return_tracing = {}; | 2493 | \\pub const have_error_return_tracing = {}; |
| 2474 | \\pub const valgrind_support = {}; | 2494 | \\pub const valgrind_support = {}; |
| 2475 | \\pub const position_independent_code = {}; | 2495 | \\pub const position_independent_code = {}; |
| 2496 | \\pub const position_independent_executable = {}; | ||
| 2476 | \\pub const strip_debug_info = {}; | 2497 | \\pub const strip_debug_info = {}; |
| 2477 | \\pub const code_model = CodeModel.{}; | 2498 | \\pub const code_model = CodeModel.{}; |
| 2478 | \\ | 2499 | \\ |
| ... | @@ -2484,6 +2505,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 | ... | @@ -2484,6 +2505,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8 |
| 2484 | comp.bin_file.options.error_return_tracing, | 2505 | comp.bin_file.options.error_return_tracing, |
| 2485 | comp.bin_file.options.valgrind, | 2506 | comp.bin_file.options.valgrind, |
| 2486 | comp.bin_file.options.pic, | 2507 | comp.bin_file.options.pic, |
| 2508 | comp.bin_file.options.pie, | ||
| 2487 | comp.bin_file.options.strip, | 2509 | comp.bin_file.options.strip, |
| 2488 | @tagName(comp.bin_file.options.machine_code_model), | 2510 | @tagName(comp.bin_file.options.machine_code_model), |
| 2489 | }); | 2511 | }); |
| ... | @@ -2587,6 +2609,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR | ... | @@ -2587,6 +2609,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR |
| 2587 | .want_stack_check = false, | 2609 | .want_stack_check = false, |
| 2588 | .want_valgrind = false, | 2610 | .want_valgrind = false, |
| 2589 | .want_pic = comp.bin_file.options.pic, | 2611 | .want_pic = comp.bin_file.options.pic, |
| 2612 | .want_pie = comp.bin_file.options.pie, | ||
| 2590 | .emit_h = null, | 2613 | .emit_h = null, |
| 2591 | .strip = comp.bin_file.options.strip, | 2614 | .strip = comp.bin_file.options.strip, |
| 2592 | .is_native_os = comp.bin_file.options.is_native_os, | 2615 | .is_native_os = comp.bin_file.options.is_native_os, |
| ... | @@ -2795,6 +2818,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node | ... | @@ -2795,6 +2818,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node |
| 2795 | .subsystem = subsystem, | 2818 | .subsystem = subsystem, |
| 2796 | .err_color = @enumToInt(comp.color), | 2819 | .err_color = @enumToInt(comp.color), |
| 2797 | .pic = comp.bin_file.options.pic, | 2820 | .pic = comp.bin_file.options.pic, |
| 2821 | .pie = comp.bin_file.options.pie, | ||
| 2798 | .link_libc = comp.bin_file.options.link_libc, | 2822 | .link_libc = comp.bin_file.options.link_libc, |
| 2799 | .link_libcpp = comp.bin_file.options.link_libcpp, | 2823 | .link_libcpp = comp.bin_file.options.link_libcpp, |
| 2800 | .strip = comp.bin_file.options.strip, | 2824 | .strip = comp.bin_file.options.strip, |
| ... | @@ -2950,6 +2974,7 @@ pub fn build_crt_file( | ... | @@ -2950,6 +2974,7 @@ pub fn build_crt_file( |
| 2950 | .want_stack_check = false, | 2974 | .want_stack_check = false, |
| 2951 | .want_valgrind = false, | 2975 | .want_valgrind = false, |
| 2952 | .want_pic = comp.bin_file.options.pic, | 2976 | .want_pic = comp.bin_file.options.pic, |
| 2977 | .want_pie = comp.bin_file.options.pie, | ||
| 2953 | .emit_h = null, | 2978 | .emit_h = null, |
| 2954 | .strip = comp.bin_file.options.strip, | 2979 | .strip = comp.bin_file.options.strip, |
| 2955 | .is_native_os = comp.bin_file.options.is_native_os, | 2980 | .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"), | ... | @@ -2460,7 +2460,14 @@ sepd1("exported_symbols_list"), |
| 2460 | .pd2 = false, | 2460 | .pd2 = false, |
| 2461 | .psl = false, | 2461 | .psl = false, |
| 2462 | }, | 2462 | }, |
| 2463 | flagpd1("fPIE"), | 2463 | .{ |
| 2464 | .name = "fPIE", | ||
| 2465 | .syntax = .flag, | ||
| 2466 | .zig_equivalent = .pie, | ||
| 2467 | .pd1 = true, | ||
| 2468 | .pd2 = false, | ||
| 2469 | .psl = false, | ||
| 2470 | }, | ||
| 2464 | flagpd1("fno-access-control"), | 2471 | flagpd1("fno-access-control"), |
| 2465 | flagpd1("faddrsig"), | 2472 | flagpd1("faddrsig"), |
| 2466 | flagpd1("faggressive-function-elimination"), | 2473 | flagpd1("faggressive-function-elimination"), |
| ... | @@ -2775,7 +2782,14 @@ flagpd1("fnext-runtime"), | ... | @@ -2775,7 +2782,14 @@ flagpd1("fnext-runtime"), |
| 2775 | .pd2 = false, | 2782 | .pd2 = false, |
| 2776 | .psl = false, | 2783 | .psl = false, |
| 2777 | }, | 2784 | }, |
| 2778 | flagpd1("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 | }, | ||
| 2779 | flagpd1("fno-no-access-control"), | 2793 | flagpd1("fno-no-access-control"), |
| 2780 | flagpd1("fno-addrsig"), | 2794 | flagpd1("fno-addrsig"), |
| 2781 | flagpd1("fno-aggressive-function-elimination"), | 2795 | flagpd1("fno-aggressive-function-elimination"), |
src/libcxx.zig+2| ... | @@ -171,6 +171,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { | ... | @@ -171,6 +171,7 @@ pub fn buildLibCXX(comp: *Compilation) !void { |
| 171 | .want_stack_check = false, | 171 | .want_stack_check = false, |
| 172 | .want_valgrind = false, | 172 | .want_valgrind = false, |
| 173 | .want_pic = comp.bin_file.options.pic, | 173 | .want_pic = comp.bin_file.options.pic, |
| 174 | .want_pie = comp.bin_file.options.pie, | ||
| 174 | .emit_h = null, | 175 | .emit_h = null, |
| 175 | .strip = comp.bin_file.options.strip, | 176 | .strip = comp.bin_file.options.strip, |
| 176 | .is_native_os = comp.bin_file.options.is_native_os, | 177 | .is_native_os = comp.bin_file.options.is_native_os, |
| ... | @@ -288,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { | ... | @@ -288,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void { |
| 288 | .want_stack_check = false, | 289 | .want_stack_check = false, |
| 289 | .want_valgrind = false, | 290 | .want_valgrind = false, |
| 290 | .want_pic = comp.bin_file.options.pic, | 291 | .want_pic = comp.bin_file.options.pic, |
| 292 | .want_pie = comp.bin_file.options.pie, | ||
| 291 | .emit_h = null, | 293 | .emit_h = null, |
| 292 | .strip = comp.bin_file.options.strip, | 294 | .strip = comp.bin_file.options.strip, |
| 293 | .is_native_os = comp.bin_file.options.is_native_os, | 295 | .is_native_os = comp.bin_file.options.is_native_os, |
src/libunwind.zig+1| ... | @@ -104,6 +104,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { | ... | @@ -104,6 +104,7 @@ pub fn buildStaticLib(comp: *Compilation) !void { |
| 104 | .want_stack_check = false, | 104 | .want_stack_check = false, |
| 105 | .want_valgrind = false, | 105 | .want_valgrind = false, |
| 106 | .want_pic = comp.bin_file.options.pic, | 106 | .want_pic = comp.bin_file.options.pic, |
| 107 | .want_pie = comp.bin_file.options.pie, | ||
| 107 | .emit_h = null, | 108 | .emit_h = null, |
| 108 | .strip = comp.bin_file.options.strip, | 109 | .strip = comp.bin_file.options.strip, |
| 109 | .is_native_os = comp.bin_file.options.is_native_os, | 110 | .is_native_os = comp.bin_file.options.is_native_os, |
src/link.zig+1| ... | @@ -71,6 +71,7 @@ pub const Options = struct { | ... | @@ -71,6 +71,7 @@ pub const Options = struct { |
| 71 | bind_global_refs_locally: bool, | 71 | bind_global_refs_locally: bool, |
| 72 | is_native_os: bool, | 72 | is_native_os: bool, |
| 73 | pic: bool, | 73 | pic: bool, |
| 74 | pie: bool, | ||
| 74 | valgrind: bool, | 75 | valgrind: bool, |
| 75 | stack_check: bool, | 76 | stack_check: bool, |
| 76 | single_threaded: bool, | 77 | single_threaded: bool, |
src/link/Elf.zig+6-2| ... | @@ -1425,7 +1425,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1425,7 +1425,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1425 | try argv.append("-shared"); | 1425 | try argv.append("-shared"); |
| 1426 | } | 1426 | } |
| 1427 | 1427 | ||
| 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) { |
| 1429 | try argv.append("-pie"); | 1429 | try argv.append("-pie"); |
| 1430 | } | 1430 | } |
| 1431 | 1431 | ||
| ... | @@ -1444,7 +1444,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { | ... | @@ -1444,7 +1444,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void { |
| 1444 | break :o "crtbegin_static.o"; | 1444 | break :o "crtbegin_static.o"; |
| 1445 | } | 1445 | } |
| 1446 | } else if (self.base.options.link_mode == .Static) { | 1446 | } 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 | } | ||
| 1448 | } else { | 1452 | } else { |
| 1449 | break :o "Scrt1.o"; | 1453 | break :o "Scrt1.o"; |
| 1450 | } | 1454 | } |
src/main.zig+12| ... | @@ -270,6 +270,8 @@ const usage_build_generic = | ... | @@ -270,6 +270,8 @@ const usage_build_generic = |
| 270 | \\ --main-pkg-path Set the directory of the root package | 270 | \\ --main-pkg-path Set the directory of the root package |
| 271 | \\ -fPIC Force-enable Position Independent Code | 271 | \\ -fPIC Force-enable Position Independent Code |
| 272 | \\ -fno-PIC Force-disable Position Independent Code | 272 | \\ -fno-PIC Force-disable Position Independent Code |
| 273 | \\ -fPIE Force-enable Position Independent Executable | ||
| 274 | \\ -fno-PIE Force-disable Position Independent Executable | ||
| 273 | \\ -fstack-check Enable stack probing in unsafe builds | 275 | \\ -fstack-check Enable stack probing in unsafe builds |
| 274 | \\ -fno-stack-check Disable stack probing in safe builds | 276 | \\ -fno-stack-check Disable stack probing in safe builds |
| 275 | \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds | 277 | \\ -fsanitize-c Enable C undefined behavior detection in unsafe builds |
| ... | @@ -457,6 +459,7 @@ fn buildOutputType( | ... | @@ -457,6 +459,7 @@ fn buildOutputType( |
| 457 | var want_native_include_dirs = false; | 459 | var want_native_include_dirs = false; |
| 458 | var enable_cache: ?bool = null; | 460 | var enable_cache: ?bool = null; |
| 459 | var want_pic: ?bool = null; | 461 | var want_pic: ?bool = null; |
| 462 | var want_pie: ?bool = null; | ||
| 460 | var want_sanitize_c: ?bool = null; | 463 | var want_sanitize_c: ?bool = null; |
| 461 | var want_stack_check: ?bool = null; | 464 | var want_stack_check: ?bool = null; |
| 462 | var want_valgrind: ?bool = null; | 465 | var want_valgrind: ?bool = null; |
| ... | @@ -795,6 +798,10 @@ fn buildOutputType( | ... | @@ -795,6 +798,10 @@ fn buildOutputType( |
| 795 | want_pic = true; | 798 | want_pic = true; |
| 796 | } else if (mem.eql(u8, arg, "-fno-PIC")) { | 799 | } else if (mem.eql(u8, arg, "-fno-PIC")) { |
| 797 | want_pic = false; | 800 | 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; | ||
| 798 | } else if (mem.eql(u8, arg, "-fstack-check")) { | 805 | } else if (mem.eql(u8, arg, "-fstack-check")) { |
| 799 | want_stack_check = true; | 806 | want_stack_check = true; |
| 800 | } else if (mem.eql(u8, arg, "-fno-stack-check")) { | 807 | } else if (mem.eql(u8, arg, "-fno-stack-check")) { |
| ... | @@ -1006,6 +1013,8 @@ fn buildOutputType( | ... | @@ -1006,6 +1013,8 @@ fn buildOutputType( |
| 1006 | }, | 1013 | }, |
| 1007 | .pic => want_pic = true, | 1014 | .pic => want_pic = true, |
| 1008 | .no_pic => want_pic = false, | 1015 | .no_pic => want_pic = false, |
| 1016 | .pie => want_pie = true, | ||
| 1017 | .no_pie => want_pie = false, | ||
| 1009 | .nostdlib => ensure_libc_on_non_freestanding = false, | 1018 | .nostdlib => ensure_libc_on_non_freestanding = false, |
| 1010 | .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, | 1019 | .nostdlib_cpp => ensure_libcpp_on_non_freestanding = false, |
| 1011 | .shared => { | 1020 | .shared => { |
| ... | @@ -1640,6 +1649,7 @@ fn buildOutputType( | ... | @@ -1640,6 +1649,7 @@ fn buildOutputType( |
| 1640 | .link_libc = link_libc, | 1649 | .link_libc = link_libc, |
| 1641 | .link_libcpp = link_libcpp, | 1650 | .link_libcpp = link_libcpp, |
| 1642 | .want_pic = want_pic, | 1651 | .want_pic = want_pic, |
| 1652 | .want_pie = want_pie, | ||
| 1643 | .want_sanitize_c = want_sanitize_c, | 1653 | .want_sanitize_c = want_sanitize_c, |
| 1644 | .want_stack_check = want_stack_check, | 1654 | .want_stack_check = want_stack_check, |
| 1645 | .want_valgrind = want_valgrind, | 1655 | .want_valgrind = want_valgrind, |
| ... | @@ -2773,6 +2783,8 @@ pub const ClangArgIterator = struct { | ... | @@ -2773,6 +2783,8 @@ pub const ClangArgIterator = struct { |
| 2773 | driver_punt, | 2783 | driver_punt, |
| 2774 | pic, | 2784 | pic, |
| 2775 | no_pic, | 2785 | no_pic, |
| 2786 | pie, | ||
| 2787 | no_pie, | ||
| 2776 | nostdlib, | 2788 | nostdlib, |
| 2777 | nostdlib_cpp, | 2789 | nostdlib_cpp, |
| 2778 | shared, | 2790 | shared, |
src/musl.zig+18| ... | @@ -12,6 +12,7 @@ pub const CRTFile = enum { | ... | @@ -12,6 +12,7 @@ pub const CRTFile = enum { |
| 12 | crti_o, | 12 | crti_o, |
| 13 | crtn_o, | 13 | crtn_o, |
| 14 | crt1_o, | 14 | crt1_o, |
| 15 | rcrt1_o, | ||
| 15 | scrt1_o, | 16 | scrt1_o, |
| 16 | libc_a, | 17 | libc_a, |
| 17 | }; | 18 | }; |
| ... | @@ -68,6 +69,23 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { | ... | @@ -68,6 +69,23 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void { |
| 68 | }, | 69 | }, |
| 69 | }); | 70 | }); |
| 70 | }, | 71 | }, |
| 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 | }, | ||
| 71 | .scrt1_o => { | 89 | .scrt1_o => { |
| 72 | var args = std.ArrayList([]const u8).init(arena); | 90 | var args = std.ArrayList([]const u8).init(arena); |
| 73 | try add_cc_args(comp, arena, &args, false); | 91 | try add_cc_args(comp, arena, &args, false); |
src/stage1.zig+1| ... | @@ -108,6 +108,7 @@ pub const Module = extern struct { | ... | @@ -108,6 +108,7 @@ pub const Module = extern struct { |
| 108 | subsystem: TargetSubsystem, | 108 | subsystem: TargetSubsystem, |
| 109 | err_color: ErrColor, | 109 | err_color: ErrColor, |
| 110 | pic: bool, | 110 | pic: bool, |
| 111 | pie: bool, | ||
| 111 | link_libc: bool, | 112 | link_libc: bool, |
| 112 | link_libcpp: bool, | 113 | link_libcpp: bool, |
| 113 | strip: bool, | 114 | strip: bool, |
src/stage1/all_types.hpp+1| ... | @@ -2177,6 +2177,7 @@ struct CodeGen { | ... | @@ -2177,6 +2177,7 @@ struct CodeGen { |
| 2177 | bool is_test_build; | 2177 | bool is_test_build; |
| 2178 | bool is_single_threaded; | 2178 | bool is_single_threaded; |
| 2179 | bool have_pic; | 2179 | bool have_pic; |
| 2180 | bool have_pie; | ||
| 2180 | bool link_mode_dynamic; | 2181 | bool link_mode_dynamic; |
| 2181 | bool dll_export_fns; | 2182 | bool dll_export_fns; |
| 2182 | bool have_stack_probing; | 2183 | bool have_stack_probing; |
src/stage1/codegen.cpp+9| ... | @@ -9043,6 +9043,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -9043,6 +9043,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 9043 | buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); | 9043 | buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing)); |
| 9044 | buf_appendf(contents, "pub const valgrind_support = false;\n"); | 9044 | buf_appendf(contents, "pub const valgrind_support = false;\n"); |
| 9045 | buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic)); | 9045 | 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)); | ||
| 9046 | buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); | 9047 | buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols)); |
| 9047 | buf_appendf(contents, "pub const code_model = CodeModel.default;\n"); | 9048 | buf_appendf(contents, "pub const code_model = CodeModel.default;\n"); |
| 9048 | 9049 | ||
| ... | @@ -9170,6 +9171,14 @@ static void init(CodeGen *g) { | ... | @@ -9170,6 +9171,14 @@ static void init(CodeGen *g) { |
| 9170 | reloc_mode = LLVMRelocStatic; | 9171 | reloc_mode = LLVMRelocStatic; |
| 9171 | } | 9172 | } |
| 9172 | 9173 | ||
| 9174 | if (g->have_pic) { | ||
| 9175 | ZigLLVMSetModulePICLevel(g->module); | ||
| 9176 | } | ||
| 9177 | |||
| 9178 | if (g->have_pie) { | ||
| 9179 | ZigLLVMSetModulePIELevel(g->module); | ||
| 9180 | } | ||
| 9181 | |||
| 9173 | const char *target_specific_cpu_args = ""; | 9182 | const char *target_specific_cpu_args = ""; |
| 9174 | const char *target_specific_features = ""; | 9183 | const char *target_specific_features = ""; |
| 9175 | 9184 |
src/stage1/stage1.cpp+1| ... | @@ -89,6 +89,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { | ... | @@ -89,6 +89,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) { |
| 89 | g->link_mode_dynamic = stage1->link_mode_dynamic; | 89 | g->link_mode_dynamic = stage1->link_mode_dynamic; |
| 90 | g->dll_export_fns = stage1->dll_export_fns; | 90 | g->dll_export_fns = stage1->dll_export_fns; |
| 91 | g->have_pic = stage1->pic; | 91 | g->have_pic = stage1->pic; |
| 92 | g->have_pie = stage1->pie; | ||
| 92 | g->have_stack_probing = stage1->enable_stack_probing; | 93 | g->have_stack_probing = stage1->enable_stack_probing; |
| 93 | g->is_single_threaded = stage1->is_single_threaded; | 94 | g->is_single_threaded = stage1->is_single_threaded; |
| 94 | g->valgrind_enabled = stage1->valgrind_enabled; | 95 | g->valgrind_enabled = stage1->valgrind_enabled; |
src/stage1/stage1.h+1| ... | @@ -177,6 +177,7 @@ struct ZigStage1 { | ... | @@ -177,6 +177,7 @@ struct ZigStage1 { |
| 177 | enum ErrColor err_color; | 177 | enum ErrColor err_color; |
| 178 | 178 | ||
| 179 | bool pic; | 179 | bool pic; |
| 180 | bool pie; | ||
| 180 | bool link_libc; | 181 | bool link_libc; |
| 181 | bool link_libcpp; | 182 | bool link_libcpp; |
| 182 | bool strip; | 183 | bool strip; |
src/zig_llvm.cpp+8| ... | @@ -855,6 +855,14 @@ void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) { | ... | @@ -855,6 +855,14 @@ void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) { |
| 855 | unwrap(module)->addModuleFlag(Module::Warning, "CodeView", 1); | 855 | unwrap(module)->addModuleFlag(Module::Warning, "CodeView", 1); |
| 856 | } | 856 | } |
| 857 | 857 | ||
| 858 | void ZigLLVMSetModulePICLevel(LLVMModuleRef module) { | ||
| 859 | unwrap(module)->setPICLevel(PICLevel::Level::BigPIC); | ||
| 860 | } | ||
| 861 | |||
| 862 | void ZigLLVMSetModulePIELevel(LLVMModuleRef module) { | ||
| 863 | unwrap(module)->setPIELevel(PIELevel::Level::Large); | ||
| 864 | } | ||
| 865 | |||
| 858 | static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) { | 866 | static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) { |
| 859 | switch (Ordering) { | 867 | switch (Ordering) { |
| 860 | case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic; | 868 | case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic; |
src/zig_llvm.h+2| ... | @@ -206,6 +206,8 @@ ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef modul | ... | @@ -206,6 +206,8 @@ ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef modul |
| 206 | ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder); | 206 | ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder); |
| 207 | ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); | 207 | ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); |
| 208 | ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module); | 208 | ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module); |
| 209 | ZIG_EXTERN_C void ZigLLVMSetModulePICLevel(LLVMModuleRef module); | ||
| 210 | ZIG_EXTERN_C void ZigLLVMSetModulePIELevel(LLVMModuleRef module); | ||
| 209 | 211 | ||
| 210 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, | 212 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, |
| 211 | struct ZigLLVMDIScope *scope); | 213 | struct ZigLLVMDIScope *scope); |
tools/update_clang_options.zig+8| ... | @@ -54,6 +54,14 @@ const known_options = [_]KnownOpt{ | ... | @@ -54,6 +54,14 @@ const known_options = [_]KnownOpt{ |
| 54 | .name = "fno-PIC", | 54 | .name = "fno-PIC", |
| 55 | .ident = "no_pic", | 55 | .ident = "no_pic", |
| 56 | }, | 56 | }, |
| 57 | .{ | ||
| 58 | .name = "fPIE", | ||
| 59 | .ident = "pie", | ||
| 60 | }, | ||
| 61 | .{ | ||
| 62 | .name = "fno-PIE", | ||
| 63 | .ident = "no_pie", | ||
| 64 | }, | ||
| 57 | .{ | 65 | .{ |
| 58 | .name = "nolibc", | 66 | .name = "nolibc", |
| 59 | .ident = "nostdlib", | 67 | .ident = "nostdlib", |