Skip to content

Commit 55ab50e

Browse files
committed
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.
2 parents 2fbe951 + 333eec5 commit 55ab50e

File tree

7 files changed

+220
-26
lines changed

7 files changed

+220
-26
lines changed

lib/std/dynamic_library.zig

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -59,48 +59,48 @@ const RDebug = extern struct {
5959
r_ldbase: usize,
6060
};
6161

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+
);
6771
}
68-
return error.InvalidExe;
6972
}
7073

7174
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) {
8176
// No PT_DYNAMIC means this is either a statically-linked program or a
8277
// badly corrupted one
8378
return LinkMap.Iterator{ .current = null };
84-
};
79+
}
8580

8681
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) {
8985
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+
}
9391
},
9492
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+
}
9999
},
100100
else => {},
101101
}
102102
}
103-
return error.InvalidExe;
103+
return LinkMap.Iterator{ .current = null };
104104
};
105105

106106
return LinkMap.Iterator{ .current = link_map_ptr };

lib/std/elf.zig

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,20 +719,48 @@ pub const Elf64_Syminfo = extern struct {
719719
pub const Elf32_Rel = extern struct {
720720
r_offset: Elf32_Addr,
721721
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+
}
722729
};
723730
pub const Elf64_Rel = extern struct {
724731
r_offset: Elf64_Addr,
725732
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+
}
726740
};
727741
pub const Elf32_Rela = extern struct {
728742
r_offset: Elf32_Addr,
729743
r_info: Elf32_Word,
730744
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+
}
731752
};
732753
pub const Elf64_Rela = extern struct {
733754
r_offset: Elf64_Addr,
734755
r_info: Elf64_Xword,
735756
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+
}
736764
};
737765
pub const Elf32_Dyn = extern struct {
738766
d_tag: Elf32_Sword,
@@ -917,6 +945,16 @@ pub const Dyn = switch (@sizeOf(usize)) {
917945
8 => Elf64_Dyn,
918946
else => @compileError("expected pointer size of 32 or 64"),
919947
};
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+
};
920958
pub const Shdr = switch (@sizeOf(usize)) {
921959
4 => Elf32_Shdr,
922960
8 => Elf64_Shdr,

lib/std/os/linux/start_pie.zig

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ fn iter_fn(info: *dl_phdr_info, size: usize, counter: *usize) IterFnError!void {
386386
test "dl_iterate_phdr" {
387387
if (builtin.os.tag == .windows or builtin.os.tag == .wasi or builtin.os.tag == .macos)
388388
return error.SkipZigTest;
389+
if (builtin.position_independent_executable)
390+
return error.SkipZigTest;
389391

390392
var counter: usize = 0;
391393
try os.dl_iterate_phdr(&counter, IterFnError, iter_fn);

lib/std/start.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,12 @@ fn posixCallMainAndExit() noreturn {
202202
// Find the beginning of the auxiliary vector
203203
const auxv = @ptrCast([*]std.elf.Auxv, @alignCast(@alignOf(usize), envp.ptr + envp_count + 1));
204204
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+
205211
// Initialize the TLS area
206212
std.os.linux.tls.initStaticTLS();
207213

src/zig_llvm.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,14 @@ void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module) {
855855
unwrap(module)->addModuleFlag(Module::Warning, "CodeView", 1);
856856
}
857857

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+
858866
static AtomicOrdering mapFromLLVMOrdering(LLVMAtomicOrdering Ordering) {
859867
switch (Ordering) {
860868
case LLVMAtomicOrderingNotAtomic: return AtomicOrdering::NotAtomic;

src/zig_llvm.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,8 @@ ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef modul
206206
ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder);
207207
ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
208208
ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
209+
ZIG_EXTERN_C void ZigLLVMSetModulePICLevel(LLVMModuleRef module);
210+
ZIG_EXTERN_C void ZigLLVMSetModulePIELevel(LLVMModuleRef module);
209211

210212
ZIG_EXTERN_C void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column,
211213
struct ZigLLVMDIScope *scope);

0 commit comments

Comments
 (0)