| 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 | 59 | r_ldbase: usize, |
| 60 | 60 | }; |
| 61 | 61 | |
| 62 | fn 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) | |
| 63 | extern var _DYNAMIC: [128]elf.Dyn; | |
| 64 | ||
| 65 | comptime { | |
| 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 | 74 | pub 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) { | |
| 81 | 76 | // No PT_DYNAMIC means this is either a statically-linked program or a |
| 82 | 77 | // badly corrupted one |
| 83 | 78 | return LinkMap.Iterator{ .current = null }; |
| 84 | }; | |
| 79 | } | |
| 85 | 80 | |
| 86 | 81 | 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) { | |
| 89 | 85 | 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 | } | |
| 93 | 91 | }, |
| 94 | 92 | 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 | } | |
| 99 | 99 | }, |
| 100 | 100 | else => {}, |
| 101 | 101 | } |
| 102 | 102 | } |
| 103 | return error.InvalidExe; | |
| 103 | return LinkMap.Iterator{ .current = null }; | |
| 104 | 104 | }; |
| 105 | 105 | |
| 106 | 106 | return LinkMap.Iterator{ .current = link_map_ptr }; |
lib/std/elf.zig+38| ... | ... | @@ -719,20 +719,48 @@ pub const Elf64_Syminfo = extern struct { |
| 719 | 719 | pub const Elf32_Rel = extern struct { |
| 720 | 720 | r_offset: Elf32_Addr, |
| 721 | 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 | 730 | pub const Elf64_Rel = extern struct { |
| 724 | 731 | r_offset: Elf64_Addr, |
| 725 | 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 | 741 | pub const Elf32_Rela = extern struct { |
| 728 | 742 | r_offset: Elf32_Addr, |
| 729 | 743 | r_info: Elf32_Word, |
| 730 | 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 | 753 | pub const Elf64_Rela = extern struct { |
| 733 | 754 | r_offset: Elf64_Addr, |
| 734 | 755 | r_info: Elf64_Xword, |
| 735 | 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 | 765 | pub const Elf32_Dyn = extern struct { |
| 738 | 766 | d_tag: Elf32_Sword, |
| ... | ... | @@ -917,6 +945,16 @@ pub const Dyn = switch (@sizeOf(usize)) { |
| 917 | 945 | 8 => Elf64_Dyn, |
| 918 | 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 | 958 | pub const Shdr = switch (@sizeOf(usize)) { |
| 921 | 959 | 4 => Elf32_Shdr, |
| 922 | 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 | 386 | test "dl_iterate_phdr" { |
| 387 | 387 | if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos) |
| 388 | 388 | return error.SkipZigTest; |
| 389 | if (builtin.position_independent_executable) | |
| 390 | return error.SkipZigTest; | |
| 389 | 391 | |
| 390 | 392 | var counter: usize = 0; |
| 391 | 393 | try os.dl_iterate_phdr(&counter, IterFnError, iter_fn); |
lib/std/start.zig+6| ... | ... | @@ -202,6 +202,12 @@ fn posixCallMainAndExit() noreturn { |
| 202 | 202 | // Find the beginning of the auxiliary vector |
| 203 | 203 | const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1)); |
| 204 | 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 | 211 | // Initialize the TLS area |
| 206 | 212 | std.os.linux.tls.initStaticTLS(); |
| 207 | 213 |
src/zig_llvm.cpp+8| ... | ... | @@ -855,6 +855,14 @@ void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) { |
| 855 | 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 | 866 | static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) { |
| 859 | 867 | switch (Ordering) { |
| 860 | 868 | case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic; |
src/zig_llvm.h+2| ... | ... | @@ -206,6 +206,8 @@ ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef modul |
| 206 | 206 | ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder); |
| 207 | 207 | ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); |
| 208 | 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 | 212 | ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, |
| 211 | 213 | struct ZigLLVMDIScope *scope); |