Skip to content

Commit abc717f

Browse files
committed
modernize the PIE patch for the latest master branch
This is the part of #3960 that has to be rewritten to apply to latest master branch code.
1 parent 55ab50e commit abc717f

18 files changed

+272
-15
lines changed

lib/libc/musl/ldso/dlstart.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
#include <stddef.h>
2+
#include "dynlink.h"
3+
#include "libc.h"
4+
5+
#ifndef START
6+
#define START "_dlstart"
7+
#endif
8+
9+
#define SHARED
10+
11+
#include "crt_arch.h"
12+
13+
#ifndef GETFUNCSYM
14+
#define GETFUNCSYM(fp, sym, got) do { \
15+
hidden void sym(); \
16+
static void (*static_func_ptr)() = sym; \
17+
__asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \
18+
*(fp) = static_func_ptr; } while(0)
19+
#endif
20+
21+
hidden void _dlstart_c(size_t *sp, size_t *dynv)
22+
{
23+
size_t i, aux[AUX_CNT], dyn[DYN_CNT];
24+
size_t *rel, rel_size, base;
25+
26+
int argc = *sp;
27+
char **argv = (void *)(sp+1);
28+
29+
for (i=argc+1; argv[i]; i++);
30+
size_t *auxv = (void *)(argv+i+1);
31+
32+
for (i=0; i<AUX_CNT; i++) aux[i] = 0;
33+
for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT)
34+
aux[auxv[i]] = auxv[i+1];
35+
36+
#if DL_FDPIC
37+
struct fdpic_loadseg *segs, fakeseg;
38+
size_t j;
39+
if (dynv) {
40+
/* crt_arch.h entry point asm is responsible for reserving
41+
* space and moving the extra fdpic arguments to the stack
42+
* vector where they are easily accessible from C. */
43+
segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs;
44+
} else {
45+
/* If dynv is null, the entry point was started from loader
46+
* that is not fdpic-aware. We can assume normal fixed-
47+
* displacement ELF loading was performed, but when ldso was
48+
* run as a command, finding the Ehdr is a heursitic: we
49+
* have to assume Phdrs start in the first 4k of the file. */
50+
base = aux[AT_BASE];
51+
if (!base) base = aux[AT_PHDR] & -4096;
52+
segs = &fakeseg;
53+
segs[0].addr = base;
54+
segs[0].p_vaddr = 0;
55+
segs[0].p_memsz = -1;
56+
Ehdr *eh = (void *)base;
57+
Phdr *ph = (void *)(base + eh->e_phoff);
58+
size_t phnum = eh->e_phnum;
59+
size_t phent = eh->e_phentsize;
60+
while (phnum-- && ph->p_type != PT_DYNAMIC)
61+
ph = (void *)((size_t)ph + phent);
62+
dynv = (void *)(base + ph->p_vaddr);
63+
}
64+
#endif
65+
66+
for (i=0; i<DYN_CNT; i++) dyn[i] = 0;
67+
for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT)
68+
dyn[dynv[i]] = dynv[i+1];
69+
70+
#if DL_FDPIC
71+
for (i=0; i<DYN_CNT; i++) {
72+
if (i==DT_RELASZ || i==DT_RELSZ) continue;
73+
if (!dyn[i]) continue;
74+
for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
75+
dyn[i] += segs[j].addr - segs[j].p_vaddr;
76+
}
77+
base = 0;
78+
79+
const Sym *syms = (void *)dyn[DT_SYMTAB];
80+
81+
rel = (void *)dyn[DT_RELA];
82+
rel_size = dyn[DT_RELASZ];
83+
for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
84+
if (!IS_RELATIVE(rel[1], syms)) continue;
85+
for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
86+
size_t *rel_addr = (void *)
87+
(rel[0] + segs[j].addr - segs[j].p_vaddr);
88+
if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) {
89+
*rel_addr += segs[rel_addr[1]].addr
90+
- segs[rel_addr[1]].p_vaddr
91+
+ syms[R_SYM(rel[1])].st_value;
92+
rel_addr[1] = dyn[DT_PLTGOT];
93+
} else {
94+
size_t val = syms[R_SYM(rel[1])].st_value;
95+
for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++);
96+
*rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val;
97+
}
98+
}
99+
#else
100+
/* If the dynamic linker is invoked as a command, its load
101+
* address is not available in the aux vector. Instead, compute
102+
* the load address as the difference between &_DYNAMIC and the
103+
* virtual address in the PT_DYNAMIC program header. */
104+
base = aux[AT_BASE];
105+
if (!base) {
106+
size_t phnum = aux[AT_PHNUM];
107+
size_t phentsize = aux[AT_PHENT];
108+
Phdr *ph = (void *)aux[AT_PHDR];
109+
for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) {
110+
if (ph->p_type == PT_DYNAMIC) {
111+
base = (size_t)dynv - ph->p_vaddr;
112+
break;
113+
}
114+
}
115+
}
116+
117+
/* MIPS uses an ugly packed form for GOT relocations. Since we
118+
* can't make function calls yet and the code is tiny anyway,
119+
* it's simply inlined here. */
120+
if (NEED_MIPS_GOT_RELOCS) {
121+
size_t local_cnt = 0;
122+
size_t *got = (void *)(base + dyn[DT_PLTGOT]);
123+
for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO)
124+
local_cnt = dynv[i+1];
125+
for (i=0; i<local_cnt; i++) got[i] += base;
126+
}
127+
128+
rel = (void *)(base+dyn[DT_REL]);
129+
rel_size = dyn[DT_RELSZ];
130+
for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) {
131+
if (!IS_RELATIVE(rel[1], 0)) continue;
132+
size_t *rel_addr = (void *)(base + rel[0]);
133+
*rel_addr += base;
134+
}
135+
136+
rel = (void *)(base+dyn[DT_RELA]);
137+
rel_size = dyn[DT_RELASZ];
138+
for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
139+
if (!IS_RELATIVE(rel[1], 0)) continue;
140+
size_t *rel_addr = (void *)(base + rel[0]);
141+
*rel_addr = base + rel[2];
142+
}
143+
#endif
144+
145+
stage2_func dls2;
146+
GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]);
147+
dls2((void *)base, sp);
148+
}

lib/std/build.zig

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1286,6 +1286,9 @@ pub const LibExeObjStep = struct {
12861286
/// Position Independent Code
12871287
force_pic: ?bool = null,
12881288

1289+
/// Position Independent Executable
1290+
pie: ?bool = null,
1291+
12891292
subsystem: ?builtin.SubSystem = null,
12901293

12911294
const LinkObject = union(enum) {
@@ -2307,6 +2310,14 @@ pub const LibExeObjStep = struct {
23072310
}
23082311
}
23092312

2313+
if (self.pie) |pie| {
2314+
if (pie) {
2315+
try zig_args.append("-fPIE");
2316+
} else {
2317+
try zig_args.append("-fno-PIE");
2318+
}
2319+
}
2320+
23102321
if (self.subsystem) |subsystem| {
23112322
try zig_args.append("--subsystem");
23122323
try zig_args.append(switch (subsystem) {

lib/std/dynamic_library.zig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const RDebug = extern struct {
6363
extern var _DYNAMIC: [128]elf.Dyn;
6464

6565
comptime {
66-
if (builtin.os == .linux) {
66+
if (std.Target.current.os.tag == .linux) {
6767
asm (
6868
\\ .weak _DYNAMIC
6969
\\ .hidden _DYNAMIC

lib/std/os/linux/start_pie.zig

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,25 +111,25 @@ pub fn apply_relocations() void {
111111
var i: usize = 0;
112112
while (dynv[i].d_tag != elf.DT_NULL) : (i += 1) {
113113
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,
114+
elf.DT_REL => rel_addr = base_addr + dynv[i].d_val,
115+
elf.DT_RELA => rela_addr = base_addr + dynv[i].d_val,
116+
elf.DT_RELSZ => rel_size = dynv[i].d_val,
117+
elf.DT_RELASZ => rela_size = dynv[i].d_val,
118118
else => {},
119119
}
120120
}
121121
}
122122

123123
// Perform the relocations
124124
if (rel_addr != 0) {
125-
const rel = @bytesToSlice(elf.Rel, @intToPtr([*]u8, rel_addr)[0..rel_size]);
125+
const rel = std.mem.bytesAsSlice(elf.Rel, @intToPtr([*]u8, rel_addr)[0..rel_size]);
126126
for (rel) |r| {
127127
if (r.r_type() != ARCH_RELATIVE_RELOC) continue;
128128
@intToPtr(*usize, base_addr + r.r_offset).* += base_addr;
129129
}
130130
}
131131
if (rela_addr != 0) {
132-
const rela = @bytesToSlice(elf.Rela, @intToPtr([*]u8, rela_addr)[0..rela_size]);
132+
const rela = std.mem.bytesAsSlice(elf.Rela, @intToPtr([*]u8, rela_addr)[0..rela_size]);
133133
for (rela) |r| {
134134
if (r.r_type() != ARCH_RELATIVE_RELOC) continue;
135135
@intToPtr(*usize, base_addr + r.r_offset).* += base_addr + @bitCast(usize, r.r_addend);

src/Compilation.zig

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,10 @@ pub const InitOptions = struct {
343343
link_libc: bool = false,
344344
link_libcpp: bool = false,
345345
want_pic: ?bool = null,
346+
/// This means that if the output mode is an executable it will be a
347+
/// Position Independent Executable. If the output mode is not an
348+
/// executable this field is ignored.
349+
want_pie: ?bool = null,
346350
want_sanitize_c: ?bool = null,
347351
want_stack_check: ?bool = null,
348352
want_valgrind: ?bool = null,
@@ -527,17 +531,30 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
527531
options.libc_installation,
528532
);
529533

534+
const must_pie = target_util.requiresPIE(options.target);
535+
const pie = if (options.want_pie) |explicit| pie: {
536+
if (!explicit and must_pie) {
537+
return error.TargetRequiresPIE;
538+
}
539+
break :pie explicit;
540+
} else must_pie;
541+
530542
const must_pic: bool = b: {
531543
if (target_util.requiresPIC(options.target, link_libc))
532544
break :b true;
533545
break :b link_mode == .Dynamic;
534546
};
535547
const pic = if (options.want_pic) |explicit| pic: {
536-
if (!explicit and must_pic) {
537-
return error.TargetRequiresPIC;
548+
if (!explicit) {
549+
if (must_pic) {
550+
return error.TargetRequiresPIC;
551+
}
552+
if (pie) {
553+
return error.PIERequiresPIC;
554+
}
538555
}
539556
break :pic explicit;
540-
} else must_pic;
557+
} else pie or must_pic;
541558

542559
// Make a decision on whether to use Clang for translate-c and compiling C files.
543560
const use_clang = if (options.use_clang) |explicit| explicit else blk: {
@@ -618,6 +635,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
618635
cache.hash.add(options.target.abi);
619636
cache.hash.add(ofmt);
620637
cache.hash.add(pic);
638+
cache.hash.add(pie);
621639
cache.hash.add(stack_check);
622640
cache.hash.add(link_mode);
623641
cache.hash.add(options.function_sections);
@@ -814,6 +832,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
814832
.version = options.version,
815833
.libc_installation = libc_dirs.libc_installation,
816834
.pic = pic,
835+
.pie = pie,
817836
.valgrind = valgrind,
818837
.stack_check = stack_check,
819838
.single_threaded = single_threaded,
@@ -898,7 +917,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
898917
try comp.addBuildingGLibCJobs();
899918
}
900919
if (comp.wantBuildMuslFromSource()) {
901-
try comp.work_queue.ensureUnusedCapacity(5);
920+
try comp.work_queue.ensureUnusedCapacity(6);
902921
if (target_util.libc_needs_crti_crtn(comp.getTarget())) {
903922
comp.work_queue.writeAssumeCapacity(&[_]Job{
904923
.{ .musl_crt_file = .crti_o },
@@ -908,6 +927,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
908927
comp.work_queue.writeAssumeCapacity(&[_]Job{
909928
.{ .musl_crt_file = .crt1_o },
910929
.{ .musl_crt_file = .scrt1_o },
930+
.{ .musl_crt_file = .rcrt1_o },
911931
.{ .musl_crt_file = .libc_a },
912932
});
913933
}
@@ -2473,6 +2493,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
24732493
\\pub const have_error_return_tracing = {};
24742494
\\pub const valgrind_support = {};
24752495
\\pub const position_independent_code = {};
2496+
\\pub const position_independent_executable = {};
24762497
\\pub const strip_debug_info = {};
24772498
\\pub const code_model = CodeModel.{};
24782499
\\
@@ -2484,6 +2505,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
24842505
comp.bin_file.options.error_return_tracing,
24852506
comp.bin_file.options.valgrind,
24862507
comp.bin_file.options.pic,
2508+
comp.bin_file.options.pie,
24872509
comp.bin_file.options.strip,
24882510
@tagName(comp.bin_file.options.machine_code_model),
24892511
});
@@ -2587,6 +2609,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
25872609
.want_stack_check = false,
25882610
.want_valgrind = false,
25892611
.want_pic = comp.bin_file.options.pic,
2612+
.want_pie = comp.bin_file.options.pie,
25902613
.emit_h = null,
25912614
.strip = comp.bin_file.options.strip,
25922615
.is_native_os = comp.bin_file.options.is_native_os,
@@ -2795,6 +2818,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
27952818
.subsystem = subsystem,
27962819
.err_color = @enumToInt(comp.color),
27972820
.pic = comp.bin_file.options.pic,
2821+
.pie = comp.bin_file.options.pie,
27982822
.link_libc = comp.bin_file.options.link_libc,
27992823
.link_libcpp = comp.bin_file.options.link_libcpp,
28002824
.strip = comp.bin_file.options.strip,
@@ -2950,6 +2974,7 @@ pub fn build_crt_file(
29502974
.want_stack_check = false,
29512975
.want_valgrind = false,
29522976
.want_pic = comp.bin_file.options.pic,
2977+
.want_pie = comp.bin_file.options.pie,
29532978
.emit_h = null,
29542979
.strip = comp.bin_file.options.strip,
29552980
.is_native_os = comp.bin_file.options.is_native_os,

src/clang_options_data.zig

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2460,7 +2460,14 @@ sepd1("exported_symbols_list"),
24602460
.pd2 = false,
24612461
.psl = false,
24622462
},
2463-
flagpd1("fPIE"),
2463+
.{
2464+
.name = "fPIE",
2465+
.syntax = .flag,
2466+
.zig_equivalent = .pie,
2467+
.pd1 = true,
2468+
.pd2 = false,
2469+
.psl = false,
2470+
},
24642471
flagpd1("fno-access-control"),
24652472
flagpd1("faddrsig"),
24662473
flagpd1("faggressive-function-elimination"),
@@ -2775,7 +2782,14 @@ flagpd1("fnext-runtime"),
27752782
.pd2 = false,
27762783
.psl = false,
27772784
},
2778-
flagpd1("fno-PIE"),
2785+
.{
2786+
.name = "fno-PIE",
2787+
.syntax = .flag,
2788+
.zig_equivalent = .no_pie,
2789+
.pd1 = true,
2790+
.pd2 = false,
2791+
.psl = false,
2792+
},
27792793
flagpd1("fno-no-access-control"),
27802794
flagpd1("fno-addrsig"),
27812795
flagpd1("fno-aggressive-function-elimination"),

src/libcxx.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
171171
.want_stack_check = false,
172172
.want_valgrind = false,
173173
.want_pic = comp.bin_file.options.pic,
174+
.want_pie = comp.bin_file.options.pie,
174175
.emit_h = null,
175176
.strip = comp.bin_file.options.strip,
176177
.is_native_os = comp.bin_file.options.is_native_os,
@@ -288,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
288289
.want_stack_check = false,
289290
.want_valgrind = false,
290291
.want_pic = comp.bin_file.options.pic,
292+
.want_pie = comp.bin_file.options.pie,
291293
.emit_h = null,
292294
.strip = comp.bin_file.options.strip,
293295
.is_native_os = comp.bin_file.options.is_native_os,

src/libunwind.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
104104
.want_stack_check = false,
105105
.want_valgrind = false,
106106
.want_pic = comp.bin_file.options.pic,
107+
.want_pie = comp.bin_file.options.pie,
107108
.emit_h = null,
108109
.strip = comp.bin_file.options.strip,
109110
.is_native_os = comp.bin_file.options.is_native_os,

src/link.zig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ pub const Options = struct {
7171
bind_global_refs_locally: bool,
7272
is_native_os: bool,
7373
pic: bool,
74+
pie: bool,
7475
valgrind: bool,
7576
stack_check: bool,
7677
single_threaded: bool,

0 commit comments

Comments
 (0)