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.master
commit
55ab50efbd
|
@ -59,48 +59,48 @@ const RDebug = extern struct {
|
|||
r_ldbase: usize,
|
||||
};
|
||||
|
||||
fn elf_get_va_offset(phdrs: []elf.Phdr) !usize {
|
||||
for (phdrs) |*phdr| {
|
||||
if (phdr.p_type == elf.PT_LOAD) {
|
||||
return @ptrToInt(phdr) - phdr.p_vaddr;
|
||||
}
|
||||
// TODO: This should be weak (#1917)
|
||||
extern var _DYNAMIC: [128]elf.Dyn;
|
||||
|
||||
comptime {
|
||||
if (builtin.os == .linux) {
|
||||
asm (
|
||||
\\ .weak _DYNAMIC
|
||||
\\ .hidden _DYNAMIC
|
||||
);
|
||||
}
|
||||
return error.InvalidExe;
|
||||
}
|
||||
|
||||
pub fn linkmap_iterator(phdrs: []elf.Phdr) !LinkMap.Iterator {
|
||||
const va_offset = try elf_get_va_offset(phdrs);
|
||||
|
||||
const dyn_table = init: {
|
||||
for (phdrs) |*phdr| {
|
||||
if (phdr.p_type == elf.PT_DYNAMIC) {
|
||||
const ptr = @intToPtr([*]elf.Dyn, va_offset + phdr.p_vaddr);
|
||||
break :init ptr[0 .. phdr.p_memsz / @sizeOf(elf.Dyn)];
|
||||
}
|
||||
}
|
||||
if (@ptrToInt(&_DYNAMIC[0]) == 0) {
|
||||
// No PT_DYNAMIC means this is either a statically-linked program or a
|
||||
// badly corrupted one
|
||||
return LinkMap.Iterator{ .current = null };
|
||||
};
|
||||
}
|
||||
|
||||
const link_map_ptr = init: {
|
||||
for (dyn_table) |*dyn| {
|
||||
switch (dyn.d_tag) {
|
||||
var i: usize = 0;
|
||||
while (_DYNAMIC[i].d_tag != elf.DT_NULL) : (i += 1) {
|
||||
switch (_DYNAMIC[i].d_tag) {
|
||||
elf.DT_DEBUG => {
|
||||
const r_debug = @intToPtr(*RDebug, dyn.d_val);
|
||||
if (r_debug.r_version != 1) return error.InvalidExe;
|
||||
break :init r_debug.r_map;
|
||||
const ptr = @intToPtr(?*RDebug, _DYNAMIC[i].d_val);
|
||||
if (ptr) |r_debug| {
|
||||
if (r_debug.r_version != 1) return error.InvalidExe;
|
||||
break :init r_debug.r_map;
|
||||
}
|
||||
},
|
||||
elf.DT_PLTGOT => {
|
||||
const got_table = @intToPtr([*]usize, dyn.d_val);
|
||||
// The address to the link_map structure is stored in the
|
||||
// second slot
|
||||
break :init @intToPtr(?*LinkMap, got_table[1]);
|
||||
const ptr = @intToPtr(?[*]usize, _DYNAMIC[i].d_val);
|
||||
if (ptr) |got_table| {
|
||||
// The address to the link_map structure is stored in
|
||||
// the second slot
|
||||
break :init @intToPtr(?*LinkMap, got_table[1]);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
return error.InvalidExe;
|
||||
return LinkMap.Iterator{ .current = null };
|
||||
};
|
||||
|
||||
return LinkMap.Iterator{ .current = link_map_ptr };
|
||||
|
|
|
@ -719,20 +719,48 @@ pub const Elf64_Syminfo = extern struct {
|
|||
pub const Elf32_Rel = extern struct {
|
||||
r_offset: Elf32_Addr,
|
||||
r_info: Elf32_Word,
|
||||
|
||||
pub inline fn r_sym(self: @This()) u24 {
|
||||
return @truncate(u24, self.r_info >> 8);
|
||||
}
|
||||
pub inline fn r_type(self: @This()) u8 {
|
||||
return @truncate(u8, self.r_info & 0xff);
|
||||
}
|
||||
};
|
||||
pub const Elf64_Rel = extern struct {
|
||||
r_offset: Elf64_Addr,
|
||||
r_info: Elf64_Xword,
|
||||
|
||||
pub inline fn r_sym(self: @This()) u32 {
|
||||
return @truncate(u32, self.r_info >> 32);
|
||||
}
|
||||
pub inline fn r_type(self: @This()) u32 {
|
||||
return @truncate(u32, self.r_info & 0xffffffff);
|
||||
}
|
||||
};
|
||||
pub const Elf32_Rela = extern struct {
|
||||
r_offset: Elf32_Addr,
|
||||
r_info: Elf32_Word,
|
||||
r_addend: Elf32_Sword,
|
||||
|
||||
pub inline fn r_sym(self: @This()) u24 {
|
||||
return @truncate(u24, self.r_info >> 8);
|
||||
}
|
||||
pub inline fn r_type(self: @This()) u8 {
|
||||
return @truncate(u8, self.r_info & 0xff);
|
||||
}
|
||||
};
|
||||
pub const Elf64_Rela = extern struct {
|
||||
r_offset: Elf64_Addr,
|
||||
r_info: Elf64_Xword,
|
||||
r_addend: Elf64_Sxword,
|
||||
|
||||
pub inline fn r_sym(self: @This()) u32 {
|
||||
return @truncate(u32, self.r_info >> 32);
|
||||
}
|
||||
pub inline fn r_type(self: @This()) u32 {
|
||||
return @truncate(u32, self.r_info & 0xffffffff);
|
||||
}
|
||||
};
|
||||
pub const Elf32_Dyn = extern struct {
|
||||
d_tag: Elf32_Sword,
|
||||
|
@ -917,6 +945,16 @@ pub const Dyn = switch (@sizeOf(usize)) {
|
|||
8 => Elf64_Dyn,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
};
|
||||
pub const Rel = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Rel,
|
||||
8 => Elf64_Rel,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
};
|
||||
pub const Rela = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Rela,
|
||||
8 => Elf64_Rela,
|
||||
else => @compileError("expected pointer size of 32 or 64"),
|
||||
};
|
||||
pub const Shdr = switch (@sizeOf(usize)) {
|
||||
4 => Elf32_Shdr,
|
||||
8 => Elf64_Shdr,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -386,6 +386,8 @@ 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);
|
||||
|
|
|
@ -202,6 +202,12 @@ fn posixCallMainAndExit() noreturn {
|
|||
// Find the beginning of the auxiliary vector
|
||||
const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), 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();
|
||||
}
|
||||
|
||||
// Initialize the TLS area
|
||||
std.os.linux.tls.initStaticTLS();
|
||||
|
||||
|
|
|
@ -855,6 +855,14 @@ void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) {
|
|||
unwrap(module)->addModuleFlag(Module::Warning, "CodeView", 1);
|
||||
}
|
||||
|
||||
void ZigLLVMSetModulePICLevel(LLVMModuleRef module) {
|
||||
unwrap(module)->setPICLevel(PICLevel::Level::BigPIC);
|
||||
}
|
||||
|
||||
void ZigLLVMSetModulePIELevel(LLVMModuleRef module) {
|
||||
unwrap(module)->setPIELevel(PIELevel::Level::Large);
|
||||
}
|
||||
|
||||
static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
|
||||
switch (Ordering) {
|
||||
case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic;
|
||||
|
|
|
@ -206,6 +206,8 @@ ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef modul
|
|||
ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder);
|
||||
ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
|
||||
ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
|
||||
ZIG_EXTERN_C void ZigLLVMSetModulePICLevel(LLVMModuleRef module);
|
||||
ZIG_EXTERN_C void ZigLLVMSetModulePIELevel(LLVMModuleRef module);
|
||||
|
||||
ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column,
|
||||
struct ZigLLVMDIScope *scope);
|
||||
|
|
Loading…
Reference in New Issue