Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 3.2k
Initial support for static PIE executables#3960
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,138 @@ | ||
| const std = @import("std"); | ||
| const elf = std.elf; | ||
| const builtin = @import("builtin"); | ||
| const assert = std.debug.assert; | ||
| const R_AMD64_RELATIVE = 8; | ||
| const R_386_RELATIVE = 8; | ||
| const R_ARM_RELATIVE = 23; | ||
| const R_AARCH64_RELATIVE = 1027; | ||
| const R_RISCV_RELATIVE = 3; | ||
| const ARCH_RELATIVE_RELOC = switch (builtin.arch) { | ||
| .i386 => R_386_RELATIVE, | ||
| .x86_64 => R_AMD64_RELATIVE, | ||
| .arm => R_ARM_RELATIVE, | ||
| .aarch64 => R_AARCH64_RELATIVE, | ||
| .riscv64 => R_RISCV_RELATIVE, | ||
| else => @compileError("unsupported architecture"), | ||
| }; | ||
| // Just a convoluted (but necessary) way to obtain the address of the _DYNAMIC[] | ||
| // vector as PC-relative so that we can use it before any relocation is applied | ||
| fn getDynamicSymbol() [*]elf.Dyn { | ||
| const addr = switch (builtin.arch) { | ||
| .i386 => asm volatile ( | ||
| \\ .weak _DYNAMIC | ||
| \\ .hidden _DYNAMIC | ||
| \\ call 1f | ||
| \\ 1: pop %[ret] | ||
| \\ lea _DYNAMIC-1b(%[ret]), %[ret] | ||
| : [ret] "=r" (-> usize) | ||
| ), | ||
| .x86_64 => asm volatile ( | ||
| \\ .weak _DYNAMIC | ||
| \\ .hidden _DYNAMIC | ||
| \\ lea _DYNAMIC(%%rip), %[ret] | ||
| : [ret] "=r" (-> usize) | ||
| ), | ||
| // Work around the limited offset range of `ldr` | ||
| .arm => asm volatile ( | ||
| \\ .weak _DYNAMIC | ||
| \\ .hidden _DYNAMIC | ||
| \\ ldr %[ret], 1f | ||
| \\ add %[ret], pc | ||
| \\ b 2f | ||
| \\ 1: .word _DYNAMIC-1b | ||
| \\ 2: | ||
| : [ret] "=r" (-> usize) | ||
| ), | ||
| // A simple `adr` is not enough as it has a limited offset range | ||
| .aarch64 => asm volatile ( | ||
| \\ .weak _DYNAMIC | ||
| \\ .hidden _DYNAMIC | ||
| \\ adrp %[ret], _DYNAMIC | ||
| \\ add %[ret], %[ret], #:lo12:_DYNAMIC | ||
| : [ret] "=r" (-> usize) | ||
| ), | ||
| .riscv64 => asm volatile ( | ||
| \\ lla %[ret], _DYNAMIC | ||
| : [ret] "=r" (-> usize) | ||
| ), | ||
| else => @compileError("???"), | ||
| }; | ||
| if (addr == 0) unreachable; | ||
| return @intToPtr([*]elf.Dyn, addr); | ||
| } | ||
| pub fn apply_relocations() void { | ||
| @setRuntimeSafety(false); | ||
| const dynv = getDynamicSymbol(); | ||
| const auxv = std.os.linux.elf_aux_maybe.?; | ||
| var at_phent: usize = undefined; | ||
| var at_phnum: usize = undefined; | ||
| var at_phdr: usize = undefined; | ||
| var at_hwcap: usize = undefined; | ||
| { | ||
| var i: usize = 0; | ||
| while (auxv[i].a_type != std.elf.AT_NULL) : (i += 1) { | ||
| switch (auxv[i].a_type) { | ||
| elf.AT_PHENT => at_phent = auxv[i].a_un.a_val, | ||
| elf.AT_PHNUM => at_phnum = auxv[i].a_un.a_val, | ||
| elf.AT_PHDR => at_phdr = auxv[i].a_un.a_val, | ||
| else => continue, | ||
| } | ||
| } | ||
| } | ||
| // Sanity check | ||
| assert(at_phent == @sizeOf(elf.Phdr)); | ||
| // Search the TLS section | ||
| const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum]; | ||
| const base_addr = blk: { | ||
| for (phdrs) |*phdr| { | ||
| if (phdr.p_type == elf.PT_DYNAMIC) { | ||
| break :blk @ptrToInt(&dynv[0]) - phdr.p_vaddr; | ||
| } | ||
| } | ||
| unreachable; | ||
| }; | ||
| var rel_addr: usize = 0; | ||
| var rela_addr: usize = 0; | ||
| var rel_size: usize = 0; | ||
| var rela_size: usize = 0; | ||
| { | ||
| var i: usize = 0; | ||
| while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) { | ||
| switch (dynv[i].d_tag) { | ||
| elf.DT_REL => rel_addr = base_addr + dynv[i].d_un.d_ptr, | ||
| elf.DT_RELA => rela_addr = base_addr + dynv[i].d_un.d_ptr, | ||
| elf.DT_RELSZ => rel_size = dynv[i].d_un.d_val, | ||
| elf.DT_RELASZ => rela_size = dynv[i].d_un.d_val, | ||
| else => {}, | ||
| } | ||
| } | ||
| } | ||
| // Perform the relocations | ||
| if (rel_addr != 0) { | ||
| const rel = @bytesToSlice(elf.Rel, @intToPtr([*]u8, rel_addr)[0..rel_size]); | ||
| for (rel) |r| { | ||
| if (r.r_type() != ARCH_RELATIVE_RELOC) continue; | ||
| @intToPtr(*usize, base_addr + r.r_offset).* += base_addr; | ||
| } | ||
| } | ||
| if (rela_addr != 0) { | ||
| const rela = @bytesToSlice(elf.Rela, @intToPtr([*]u8, rela_addr)[0..rela_size]); | ||
| for (rela) |r| { | ||
| if (r.r_type() != ARCH_RELATIVE_RELOC) continue; | ||
| @intToPtr(*usize, base_addr + r.r_offset).* += base_addr + @bitCast(usize, r.r_addend); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -155,6 +155,12 @@ fn posixCallMainAndExit() noreturn { | ||
| // Find the beginning of the auxiliary vector | ||
| const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1); | ||
| std.os.linux.elf_aux_maybe = auxv; | ||
| // Do this as early as possible, the aux vector is needed | ||
| if (builtin.position_independent_executable) { | ||
| @import("os/linux/start_pie.zig").apply_relocations(); | ||
Contributor There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it make sense to pass in auxv instead of using it indirectly via the global? | ||
| } | ||
| // Initialize the TLS area | ||
| const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size"); | ||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Case-styling? Or is this a traditional name from somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still not used to camelCase all the identifiers, will change it later :)