authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-22 12:39:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-22 12:39:44-07:00
log55ab50efbd5e475442ac9c3b841e461ee331ee2c
treeb105283bee898de86fbaa03491bcaa513e64a51c
parent2fbe9519acec0d7b9c9dcc41a877fec912337124
parent333eec557f8ab89d74e9d66e55eea037ba0433cb

Merge branch 'piepiepie' of https://github.com/LemonBoy/zig into pie

Conflicts: lib/std/dynamic_library.zig (fixed in this commit) src/all_types.hpp src/codegen.cpp src/link.cpp src/main.cpp Will manually apply the diffs to these deleted files to the new zig code in a followup commit.

7 files changed, 220 insertions(+), 26 deletions(-)

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};
6161
62fn elf_get_va_offset(phdrs: []elf.Phdr) !usize {62// TODO: This should be weak (#1917)
63 for (phdrs) |*phdr| {63extern var _DYNAMIC: [128]elf.Dyn;
64 if (phdr.p_type == elf.PT_LOAD) {64
65 return @ptrToInt(phdr) - phdr.p_vaddr;65comptime {
66 }66 if (builtin.os == .linux) {
67 asm (
68 \\ .weak _DYNAMIC
69 \\ .hidden _DYNAMIC
70 );
67 }71 }
68 return error.InvalidExe;
69}72}
7073
71pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {74pub 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 a76 // No PT_DYNAMIC means this is either a statically-linked program or a
82 // badly corrupted one77 // badly corrupted one
83 return LinkMap.Iterator{ .current = null };78 return LinkMap.Iterator{ .current = null };
84 };79 }
8580
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 the94 if (ptr) |got_table| {
97 // second slot95 // 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 };
105105
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 {
719pub const Elf32_Rel = extern struct {719pub 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};
723pub const Elf64_Rel = extern struct {730pub 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};
727pub const Elf32_Rela = extern struct {741pub 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};
732pub const Elf64_Rela = extern struct {753pub 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};
737pub const Elf32_Dyn = extern struct {765pub 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};
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};
920pub const Shdr = switch (@sizeOf(usize)) {958pub 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 @@
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_un.d_ptr,
115 elf.DT_RELA => rela_addr = base_addr + dynv[i].d_un.d_ptr,
116 elf.DT_RELSZ => rel_size = dynv[i].d_un.d_val,
117 elf.DT_RELASZ => rela_size = dynv[i].d_un.d_val,
118 else => {},
119 }
120 }
121 }
122
123 // Perform the relocations
124 if (rel_addr != 0) {
125 const rel = @bytesToSlice(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 = @bytesToSlice(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 {
386test "dl_iterate_phdr" {386test "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;
389391
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 vector202 // 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 area211 // Initialize the TLS area
206 std.os.linux.tls.initStaticTLS();212 std.os.linux.tls.initStaticTLS();
207213
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}
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
858static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {866static 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
206ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder);206ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder);
207ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);207ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
208ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);208ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
209ZIG_EXTERN_C void ZigLLVMSetModulePICLevel(LLVMModuleRef module);
210ZIG_EXTERN_C void ZigLLVMSetModulePIELevel(LLVMModuleRef module);
209211
210ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column,212ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column,
211 struct ZigLLVMDIScope *scope);213 struct ZigLLVMDIScope *scope);