| author | |
| committer | |
| log | 55ab50efbd5e475442ac9c3b841e461ee331ee2c |
| tree | b105283bee898de86fbaa03491bcaa513e64a51c |
| parent | 2fbe9519acec0d7b9c9dcc41a877fec912337124 |
| parent | 333eec557f8ab89d74e9d66e55eea037ba0433cb |
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 | }; |
| 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 (builtin.os == .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_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 { |
| 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/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); |