From 560043dadfa8bf3a6c15d7f09bfbc60e48e0084c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Nov 2020 12:00:12 +0100 Subject: [PATCH 1/4] Fix logic for detecting _DYNAMIC symbol Prevent spurious crashes for non-PIE executables. --- lib/std/dynamic_library.zig | 18 +++--------------- lib/std/process.zig | 2 ++ 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/std/dynamic_library.zig b/lib/std/dynamic_library.zig index 0de4bed84d..6c99ee644b 100644 --- a/lib/std/dynamic_library.zig +++ b/lib/std/dynamic_library.zig @@ -59,24 +59,12 @@ const RDebug = extern struct { r_ldbase: usize, }; -// TODO: This should be weak (#1917) -extern var _DYNAMIC: [128]elf.Dyn; - -comptime { - if (std.Target.current.os.tag == .linux) { - asm ( - \\ .weak _DYNAMIC - \\ .hidden _DYNAMIC - ); - } -} - pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator { - if (@ptrToInt(&_DYNAMIC[0]) == 0) { + const _DYNAMIC = @extern([*]elf.Dyn, .{ .name = "_DYNAMIC", .linkage = .Weak }) orelse { // No PT_DYNAMIC means this is either a statically-linked program or a - // badly corrupted one + // badly corrupted dynamically-linked one. return LinkMap.Iterator{ .current = null }; - } + }; const link_map_ptr = init: { var i: usize = 0; diff --git a/lib/std/process.zig b/lib/std/process.zig index b083126b31..5fc262e8b0 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -686,6 +686,8 @@ pub fn getBaseAddress() usize { if (base != 0) { return base; } + // XXX: Wrong for PIE executables, it should look at the difference + // between _DYNAMIC and the PT_DYNAMIC phdr instead. const phdr = os.system.getauxval(std.elf.AT_PHDR); return phdr - @sizeOf(std.elf.Ehdr); }, From bfa7e5c7436f2dcea90de12f1c1e1993c025d0cf Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Nov 2020 12:36:03 +0100 Subject: [PATCH 2/4] Update stack_traces test --- test/stack_traces.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/stack_traces.zig b/test/stack_traces.zig index 151e0baf70..7566f2b88a 100644 --- a/test/stack_traces.zig +++ b/test/stack_traces.zig @@ -282,7 +282,7 @@ pub fn addCases(cases: *tests.StackTracesContext) void { \\source.zig:10:8: [address] in main (test) \\ foo(); \\ ^ - \\start.zig:331:29: [address] in std.start.posixCallMainAndExit (test) + \\start.zig:337:29: [address] in std.start.posixCallMainAndExit (test) \\ return root.main(); \\ ^ \\start.zig:162:5: [address] in std.start._start (test) From 0a84f85945a4d22c43b467c69ba7c26cd264659a Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Nov 2020 12:36:40 +0100 Subject: [PATCH 3/4] Minor code cleanup in start_pie.zig Thanks @daurnimator for catching this. --- lib/std/os/linux/start_pie.zig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/std/os/linux/start_pie.zig b/lib/std/os/linux/start_pie.zig index 551386f312..4ea47b7891 100644 --- a/lib/std/os/linux/start_pie.zig +++ b/lib/std/os/linux/start_pie.zig @@ -56,12 +56,13 @@ fn getDynamicSymbol() [*]elf.Dyn { : [ret] "=r" (-> usize) ), .riscv64 => asm volatile ( + \\ .weak _DYNAMIC + \\ .hidden _DYNAMIC \\ lla %[ret], _DYNAMIC : [ret] "=r" (-> usize) ), else => @compileError("???"), }; - if (addr == 0) unreachable; return @intToPtr([*]elf.Dyn, addr); } From 3e22077d46a02d1c4e02dd603b560978dc184a87 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Nov 2020 14:58:08 +0100 Subject: [PATCH 4/4] Fix the ELF base calculation Find the effective ELF load address in dl_iterate_phdr by computing the difference between the in-memory phdr and its p_vaddr specified in the ELF file. This makes the dl_iterate_phdr test pass and restores the stack traces. --- lib/std/os.zig | 19 +++++++++++++++---- lib/std/os/test.zig | 2 -- lib/std/process.zig | 2 -- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/std/os.zig b/lib/std/os.zig index 2a6c8b2a52..e7c618431c 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -4340,7 +4340,7 @@ pub fn dl_iterate_phdr( const elf_base = std.process.getBaseAddress(); const ehdr = @intToPtr(*elf.Ehdr, elf_base); - // Make sure the base address points to an ELF image + // Make sure the base address points to an ELF image. assert(mem.eql(u8, ehdr.e_ident[0..4], "\x7fELF")); const n_phdr = ehdr.e_phnum; const phdrs = (@intToPtr([*]elf.Phdr, elf_base + ehdr.e_phoff))[0..n_phdr]; @@ -4348,10 +4348,21 @@ pub fn dl_iterate_phdr( var it = dl.linkmap_iterator(phdrs) catch unreachable; // The executable has no dynamic link segment, create a single entry for - // the whole ELF image + // the whole ELF image. if (it.end()) { + // Find the base address for the ELF image, if this is a PIE the value + // is non-zero. + const base_address = for (phdrs) |*phdr| { + if (phdr.p_type == elf.PT_PHDR) { + break @ptrToInt(phdrs.ptr) - phdr.p_vaddr; + // We could try computing the difference between _DYNAMIC and + // the p_vaddr of the PT_DYNAMIC section, but using the phdr is + // good enough (Is it?). + } + } else unreachable; + var info = dl_phdr_info{ - .dlpi_addr = 0, + .dlpi_addr = base_address, .dlpi_name = "/proc/self/exe", .dlpi_phdr = phdrs.ptr, .dlpi_phnum = ehdr.e_phnum, @@ -4360,7 +4371,7 @@ pub fn dl_iterate_phdr( return callback(&info, @sizeOf(dl_phdr_info), context); } - // Last return value from the callback function + // Last return value from the callback function. while (it.next()) |entry| { var dlpi_phdr: [*]elf.Phdr = undefined; var dlpi_phnum: u16 = undefined; diff --git a/lib/std/os/test.zig b/lib/std/os/test.zig index 5a6f3bddff..a7123f9d86 100644 --- a/lib/std/os/test.zig +++ b/lib/std/os/test.zig @@ -386,8 +386,6 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void { test "dl_iterate_phdr" { if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos) return error.SkipZigTest; - if (builtin.position_independent_executable) - return error.SkipZigTest; var counter: usize = 0; try os.dl_iterate_phdr(&counter, IterFnError, iter_fn); diff --git a/lib/std/process.zig b/lib/std/process.zig index 5fc262e8b0..b083126b31 100644 --- a/lib/std/process.zig +++ b/lib/std/process.zig @@ -686,8 +686,6 @@ pub fn getBaseAddress() usize { if (base != 0) { return base; } - // XXX: Wrong for PIE executables, it should look at the difference - // between _DYNAMIC and the PT_DYNAMIC phdr instead. const phdr = os.system.getauxval(std.elf.AT_PHDR); return phdr - @sizeOf(std.elf.Ehdr); },