mirror of
https://github.com/ziglang/zig.git
synced 2025-12-29 09:33:18 +00:00
Support PIE (Position Independent Executables)
Closes #4503 Revives #3960 Merges branch 'pie' into master
This commit is contained in:
commit
c7170e4a54
148
lib/libc/musl/ldso/dlstart.c
Normal file
148
lib/libc/musl/ldso/dlstart.c
Normal file
@ -0,0 +1,148 @@
|
||||
#include <stddef.h>
|
||||
#include "dynlink.h"
|
||||
#include "libc.h"
|
||||
|
||||
#ifndef START
|
||||
#define START "_dlstart"
|
||||
#endif
|
||||
|
||||
#define SHARED
|
||||
|
||||
#include "crt_arch.h"
|
||||
|
||||
#ifndef GETFUNCSYM
|
||||
#define GETFUNCSYM(fp, sym, got) do { \
|
||||
hidden void sym(); \
|
||||
static void (*static_func_ptr)() = sym; \
|
||||
__asm__ __volatile__ ( "" : "+m"(static_func_ptr) : : "memory"); \
|
||||
*(fp) = static_func_ptr; } while(0)
|
||||
#endif
|
||||
|
||||
hidden void _dlstart_c(size_t *sp, size_t *dynv)
|
||||
{
|
||||
size_t i, aux[AUX_CNT], dyn[DYN_CNT];
|
||||
size_t *rel, rel_size, base;
|
||||
|
||||
int argc = *sp;
|
||||
char **argv = (void *)(sp+1);
|
||||
|
||||
for (i=argc+1; argv[i]; i++);
|
||||
size_t *auxv = (void *)(argv+i+1);
|
||||
|
||||
for (i=0; i<AUX_CNT; i++) aux[i] = 0;
|
||||
for (i=0; auxv[i]; i+=2) if (auxv[i]<AUX_CNT)
|
||||
aux[auxv[i]] = auxv[i+1];
|
||||
|
||||
#if DL_FDPIC
|
||||
struct fdpic_loadseg *segs, fakeseg;
|
||||
size_t j;
|
||||
if (dynv) {
|
||||
/* crt_arch.h entry point asm is responsible for reserving
|
||||
* space and moving the extra fdpic arguments to the stack
|
||||
* vector where they are easily accessible from C. */
|
||||
segs = ((struct fdpic_loadmap *)(sp[-1] ? sp[-1] : sp[-2]))->segs;
|
||||
} else {
|
||||
/* If dynv is null, the entry point was started from loader
|
||||
* that is not fdpic-aware. We can assume normal fixed-
|
||||
* displacement ELF loading was performed, but when ldso was
|
||||
* run as a command, finding the Ehdr is a heursitic: we
|
||||
* have to assume Phdrs start in the first 4k of the file. */
|
||||
base = aux[AT_BASE];
|
||||
if (!base) base = aux[AT_PHDR] & -4096;
|
||||
segs = &fakeseg;
|
||||
segs[0].addr = base;
|
||||
segs[0].p_vaddr = 0;
|
||||
segs[0].p_memsz = -1;
|
||||
Ehdr *eh = (void *)base;
|
||||
Phdr *ph = (void *)(base + eh->e_phoff);
|
||||
size_t phnum = eh->e_phnum;
|
||||
size_t phent = eh->e_phentsize;
|
||||
while (phnum-- && ph->p_type != PT_DYNAMIC)
|
||||
ph = (void *)((size_t)ph + phent);
|
||||
dynv = (void *)(base + ph->p_vaddr);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i=0; i<DYN_CNT; i++) dyn[i] = 0;
|
||||
for (i=0; dynv[i]; i+=2) if (dynv[i]<DYN_CNT)
|
||||
dyn[dynv[i]] = dynv[i+1];
|
||||
|
||||
#if DL_FDPIC
|
||||
for (i=0; i<DYN_CNT; i++) {
|
||||
if (i==DT_RELASZ || i==DT_RELSZ) continue;
|
||||
if (!dyn[i]) continue;
|
||||
for (j=0; dyn[i]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
|
||||
dyn[i] += segs[j].addr - segs[j].p_vaddr;
|
||||
}
|
||||
base = 0;
|
||||
|
||||
const Sym *syms = (void *)dyn[DT_SYMTAB];
|
||||
|
||||
rel = (void *)dyn[DT_RELA];
|
||||
rel_size = dyn[DT_RELASZ];
|
||||
for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
|
||||
if (!IS_RELATIVE(rel[1], syms)) continue;
|
||||
for (j=0; rel[0]-segs[j].p_vaddr >= segs[j].p_memsz; j++);
|
||||
size_t *rel_addr = (void *)
|
||||
(rel[0] + segs[j].addr - segs[j].p_vaddr);
|
||||
if (R_TYPE(rel[1]) == REL_FUNCDESC_VAL) {
|
||||
*rel_addr += segs[rel_addr[1]].addr
|
||||
- segs[rel_addr[1]].p_vaddr
|
||||
+ syms[R_SYM(rel[1])].st_value;
|
||||
rel_addr[1] = dyn[DT_PLTGOT];
|
||||
} else {
|
||||
size_t val = syms[R_SYM(rel[1])].st_value;
|
||||
for (j=0; val-segs[j].p_vaddr >= segs[j].p_memsz; j++);
|
||||
*rel_addr = rel[2] + segs[j].addr - segs[j].p_vaddr + val;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* If the dynamic linker is invoked as a command, its load
|
||||
* address is not available in the aux vector. Instead, compute
|
||||
* the load address as the difference between &_DYNAMIC and the
|
||||
* virtual address in the PT_DYNAMIC program header. */
|
||||
base = aux[AT_BASE];
|
||||
if (!base) {
|
||||
size_t phnum = aux[AT_PHNUM];
|
||||
size_t phentsize = aux[AT_PHENT];
|
||||
Phdr *ph = (void *)aux[AT_PHDR];
|
||||
for (i=phnum; i--; ph = (void *)((char *)ph + phentsize)) {
|
||||
if (ph->p_type == PT_DYNAMIC) {
|
||||
base = (size_t)dynv - ph->p_vaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* MIPS uses an ugly packed form for GOT relocations. Since we
|
||||
* can't make function calls yet and the code is tiny anyway,
|
||||
* it's simply inlined here. */
|
||||
if (NEED_MIPS_GOT_RELOCS) {
|
||||
size_t local_cnt = 0;
|
||||
size_t *got = (void *)(base + dyn[DT_PLTGOT]);
|
||||
for (i=0; dynv[i]; i+=2) if (dynv[i]==DT_MIPS_LOCAL_GOTNO)
|
||||
local_cnt = dynv[i+1];
|
||||
for (i=0; i<local_cnt; i++) got[i] += base;
|
||||
}
|
||||
|
||||
rel = (void *)(base+dyn[DT_REL]);
|
||||
rel_size = dyn[DT_RELSZ];
|
||||
for (; rel_size; rel+=2, rel_size-=2*sizeof(size_t)) {
|
||||
if (!IS_RELATIVE(rel[1], 0)) continue;
|
||||
size_t *rel_addr = (void *)(base + rel[0]);
|
||||
*rel_addr += base;
|
||||
}
|
||||
|
||||
rel = (void *)(base+dyn[DT_RELA]);
|
||||
rel_size = dyn[DT_RELASZ];
|
||||
for (; rel_size; rel+=3, rel_size-=3*sizeof(size_t)) {
|
||||
if (!IS_RELATIVE(rel[1], 0)) continue;
|
||||
size_t *rel_addr = (void *)(base + rel[0]);
|
||||
*rel_addr = base + rel[2];
|
||||
}
|
||||
#endif
|
||||
|
||||
stage2_func dls2;
|
||||
GETFUNCSYM(&dls2, __dls2, base+dyn[DT_PLTGOT]);
|
||||
dls2((void *)base, sp);
|
||||
}
|
||||
@ -1286,6 +1286,9 @@ pub const LibExeObjStep = struct {
|
||||
/// Position Independent Code
|
||||
force_pic: ?bool = null,
|
||||
|
||||
/// Position Independent Executable
|
||||
pie: ?bool = null,
|
||||
|
||||
subsystem: ?builtin.SubSystem = null,
|
||||
|
||||
const LinkObject = union(enum) {
|
||||
@ -2307,6 +2310,14 @@ pub const LibExeObjStep = struct {
|
||||
}
|
||||
}
|
||||
|
||||
if (self.pie) |pie| {
|
||||
if (pie) {
|
||||
try zig_args.append("-fPIE");
|
||||
} else {
|
||||
try zig_args.append("-fno-PIE");
|
||||
}
|
||||
}
|
||||
|
||||
if (self.subsystem) |subsystem| {
|
||||
try zig_args.append("--subsystem");
|
||||
try zig_args.append(switch (subsystem) {
|
||||
|
||||
@ -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 (std.Target.current.os.tag == .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,
|
||||
|
||||
138
lib/std/os/linux/start_pie.zig
Normal file
138
lib/std/os/linux/start_pie.zig
Normal file
@ -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_val,
|
||||
elf.DT_RELA => rela_addr = base_addr + dynv[i].d_val,
|
||||
elf.DT_RELSZ => rel_size = dynv[i].d_val,
|
||||
elf.DT_RELASZ => rela_size = dynv[i].d_val,
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform the relocations
|
||||
if (rel_addr != 0) {
|
||||
const rel = std.mem.bytesAsSlice(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 = std.mem.bytesAsSlice(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();
|
||||
|
||||
|
||||
@ -343,6 +343,10 @@ pub const InitOptions = struct {
|
||||
link_libc: bool = false,
|
||||
link_libcpp: bool = false,
|
||||
want_pic: ?bool = null,
|
||||
/// This means that if the output mode is an executable it will be a
|
||||
/// Position Independent Executable. If the output mode is not an
|
||||
/// executable this field is ignored.
|
||||
want_pie: ?bool = null,
|
||||
want_sanitize_c: ?bool = null,
|
||||
want_stack_check: ?bool = null,
|
||||
want_valgrind: ?bool = null,
|
||||
@ -527,17 +531,30 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
options.libc_installation,
|
||||
);
|
||||
|
||||
const must_pie = target_util.requiresPIE(options.target);
|
||||
const pie = if (options.want_pie) |explicit| pie: {
|
||||
if (!explicit and must_pie) {
|
||||
return error.TargetRequiresPIE;
|
||||
}
|
||||
break :pie explicit;
|
||||
} else must_pie;
|
||||
|
||||
const must_pic: bool = b: {
|
||||
if (target_util.requiresPIC(options.target, link_libc))
|
||||
break :b true;
|
||||
break :b link_mode == .Dynamic;
|
||||
};
|
||||
const pic = if (options.want_pic) |explicit| pic: {
|
||||
if (!explicit and must_pic) {
|
||||
return error.TargetRequiresPIC;
|
||||
if (!explicit) {
|
||||
if (must_pic) {
|
||||
return error.TargetRequiresPIC;
|
||||
}
|
||||
if (pie) {
|
||||
return error.PIERequiresPIC;
|
||||
}
|
||||
}
|
||||
break :pic explicit;
|
||||
} else must_pic;
|
||||
} else pie or must_pic;
|
||||
|
||||
// Make a decision on whether to use Clang for translate-c and compiling C files.
|
||||
const use_clang = if (options.use_clang) |explicit| explicit else blk: {
|
||||
@ -618,6 +635,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
cache.hash.add(options.target.abi);
|
||||
cache.hash.add(ofmt);
|
||||
cache.hash.add(pic);
|
||||
cache.hash.add(pie);
|
||||
cache.hash.add(stack_check);
|
||||
cache.hash.add(link_mode);
|
||||
cache.hash.add(options.function_sections);
|
||||
@ -814,6 +832,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
.version = options.version,
|
||||
.libc_installation = libc_dirs.libc_installation,
|
||||
.pic = pic,
|
||||
.pie = pie,
|
||||
.valgrind = valgrind,
|
||||
.stack_check = stack_check,
|
||||
.single_threaded = single_threaded,
|
||||
@ -898,7 +917,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
try comp.addBuildingGLibCJobs();
|
||||
}
|
||||
if (comp.wantBuildMuslFromSource()) {
|
||||
try comp.work_queue.ensureUnusedCapacity(5);
|
||||
try comp.work_queue.ensureUnusedCapacity(6);
|
||||
if (target_util.libc_needs_crti_crtn(comp.getTarget())) {
|
||||
comp.work_queue.writeAssumeCapacity(&[_]Job{
|
||||
.{ .musl_crt_file = .crti_o },
|
||||
@ -908,6 +927,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
|
||||
comp.work_queue.writeAssumeCapacity(&[_]Job{
|
||||
.{ .musl_crt_file = .crt1_o },
|
||||
.{ .musl_crt_file = .scrt1_o },
|
||||
.{ .musl_crt_file = .rcrt1_o },
|
||||
.{ .musl_crt_file = .libc_a },
|
||||
});
|
||||
}
|
||||
@ -2473,6 +2493,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
|
||||
\\pub const have_error_return_tracing = {};
|
||||
\\pub const valgrind_support = {};
|
||||
\\pub const position_independent_code = {};
|
||||
\\pub const position_independent_executable = {};
|
||||
\\pub const strip_debug_info = {};
|
||||
\\pub const code_model = CodeModel.{};
|
||||
\\
|
||||
@ -2484,6 +2505,7 @@ pub fn generateBuiltinZigSource(comp: *Compilation, allocator: *Allocator) ![]u8
|
||||
comp.bin_file.options.error_return_tracing,
|
||||
comp.bin_file.options.valgrind,
|
||||
comp.bin_file.options.pic,
|
||||
comp.bin_file.options.pie,
|
||||
comp.bin_file.options.strip,
|
||||
@tagName(comp.bin_file.options.machine_code_model),
|
||||
});
|
||||
@ -2587,6 +2609,7 @@ fn buildStaticLibFromZig(comp: *Compilation, src_basename: []const u8, out: *?CR
|
||||
.want_stack_check = false,
|
||||
.want_valgrind = false,
|
||||
.want_pic = comp.bin_file.options.pic,
|
||||
.want_pie = comp.bin_file.options.pie,
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
@ -2795,6 +2818,7 @@ fn updateStage1Module(comp: *Compilation, main_progress_node: *std.Progress.Node
|
||||
.subsystem = subsystem,
|
||||
.err_color = @enumToInt(comp.color),
|
||||
.pic = comp.bin_file.options.pic,
|
||||
.pie = comp.bin_file.options.pie,
|
||||
.link_libc = comp.bin_file.options.link_libc,
|
||||
.link_libcpp = comp.bin_file.options.link_libcpp,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
@ -2950,6 +2974,7 @@ pub fn build_crt_file(
|
||||
.want_stack_check = false,
|
||||
.want_valgrind = false,
|
||||
.want_pic = comp.bin_file.options.pic,
|
||||
.want_pie = comp.bin_file.options.pie,
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
|
||||
@ -2460,7 +2460,14 @@ sepd1("exported_symbols_list"),
|
||||
.pd2 = false,
|
||||
.psl = false,
|
||||
},
|
||||
flagpd1("fPIE"),
|
||||
.{
|
||||
.name = "fPIE",
|
||||
.syntax = .flag,
|
||||
.zig_equivalent = .pie,
|
||||
.pd1 = true,
|
||||
.pd2 = false,
|
||||
.psl = false,
|
||||
},
|
||||
flagpd1("fno-access-control"),
|
||||
flagpd1("faddrsig"),
|
||||
flagpd1("faggressive-function-elimination"),
|
||||
@ -2775,7 +2782,14 @@ flagpd1("fnext-runtime"),
|
||||
.pd2 = false,
|
||||
.psl = false,
|
||||
},
|
||||
flagpd1("fno-PIE"),
|
||||
.{
|
||||
.name = "fno-PIE",
|
||||
.syntax = .flag,
|
||||
.zig_equivalent = .no_pie,
|
||||
.pd1 = true,
|
||||
.pd2 = false,
|
||||
.psl = false,
|
||||
},
|
||||
flagpd1("fno-no-access-control"),
|
||||
flagpd1("fno-addrsig"),
|
||||
flagpd1("fno-aggressive-function-elimination"),
|
||||
|
||||
@ -171,6 +171,7 @@ pub fn buildLibCXX(comp: *Compilation) !void {
|
||||
.want_stack_check = false,
|
||||
.want_valgrind = false,
|
||||
.want_pic = comp.bin_file.options.pic,
|
||||
.want_pie = comp.bin_file.options.pie,
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
@ -288,6 +289,7 @@ pub fn buildLibCXXABI(comp: *Compilation) !void {
|
||||
.want_stack_check = false,
|
||||
.want_valgrind = false,
|
||||
.want_pic = comp.bin_file.options.pic,
|
||||
.want_pie = comp.bin_file.options.pie,
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
|
||||
@ -104,6 +104,7 @@ pub fn buildStaticLib(comp: *Compilation) !void {
|
||||
.want_stack_check = false,
|
||||
.want_valgrind = false,
|
||||
.want_pic = comp.bin_file.options.pic,
|
||||
.want_pie = comp.bin_file.options.pie,
|
||||
.emit_h = null,
|
||||
.strip = comp.bin_file.options.strip,
|
||||
.is_native_os = comp.bin_file.options.is_native_os,
|
||||
|
||||
@ -71,6 +71,7 @@ pub const Options = struct {
|
||||
bind_global_refs_locally: bool,
|
||||
is_native_os: bool,
|
||||
pic: bool,
|
||||
pie: bool,
|
||||
valgrind: bool,
|
||||
stack_check: bool,
|
||||
single_threaded: bool,
|
||||
|
||||
@ -1425,7 +1425,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
|
||||
try argv.append("-shared");
|
||||
}
|
||||
|
||||
if (target_util.requiresPIE(target) and self.base.options.output_mode == .Exe) {
|
||||
if (self.base.options.pie and self.base.options.output_mode == .Exe) {
|
||||
try argv.append("-pie");
|
||||
}
|
||||
|
||||
@ -1444,7 +1444,11 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
|
||||
break :o "crtbegin_static.o";
|
||||
}
|
||||
} else if (self.base.options.link_mode == .Static) {
|
||||
break :o "crt1.o";
|
||||
if (self.base.options.pie) {
|
||||
break :o "rcrt1.o";
|
||||
} else {
|
||||
break :o "crt1.o";
|
||||
}
|
||||
} else {
|
||||
break :o "Scrt1.o";
|
||||
}
|
||||
|
||||
12
src/main.zig
12
src/main.zig
@ -270,6 +270,8 @@ const usage_build_generic =
|
||||
\\ --main-pkg-path Set the directory of the root package
|
||||
\\ -fPIC Force-enable Position Independent Code
|
||||
\\ -fno-PIC Force-disable Position Independent Code
|
||||
\\ -fPIE Force-enable Position Independent Executable
|
||||
\\ -fno-PIE Force-disable Position Independent Executable
|
||||
\\ -fstack-check Enable stack probing in unsafe builds
|
||||
\\ -fno-stack-check Disable stack probing in safe builds
|
||||
\\ -fsanitize-c Enable C undefined behavior detection in unsafe builds
|
||||
@ -457,6 +459,7 @@ fn buildOutputType(
|
||||
var want_native_include_dirs = false;
|
||||
var enable_cache: ?bool = null;
|
||||
var want_pic: ?bool = null;
|
||||
var want_pie: ?bool = null;
|
||||
var want_sanitize_c: ?bool = null;
|
||||
var want_stack_check: ?bool = null;
|
||||
var want_valgrind: ?bool = null;
|
||||
@ -795,6 +798,10 @@ fn buildOutputType(
|
||||
want_pic = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-PIC")) {
|
||||
want_pic = false;
|
||||
} else if (mem.eql(u8, arg, "-fPIE")) {
|
||||
want_pie = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-PIE")) {
|
||||
want_pie = false;
|
||||
} else if (mem.eql(u8, arg, "-fstack-check")) {
|
||||
want_stack_check = true;
|
||||
} else if (mem.eql(u8, arg, "-fno-stack-check")) {
|
||||
@ -1006,6 +1013,8 @@ fn buildOutputType(
|
||||
},
|
||||
.pic => want_pic = true,
|
||||
.no_pic => want_pic = false,
|
||||
.pie => want_pie = true,
|
||||
.no_pie => want_pie = false,
|
||||
.nostdlib => ensure_libc_on_non_freestanding = false,
|
||||
.nostdlib_cpp => ensure_libcpp_on_non_freestanding = false,
|
||||
.shared => {
|
||||
@ -1640,6 +1649,7 @@ fn buildOutputType(
|
||||
.link_libc = link_libc,
|
||||
.link_libcpp = link_libcpp,
|
||||
.want_pic = want_pic,
|
||||
.want_pie = want_pie,
|
||||
.want_sanitize_c = want_sanitize_c,
|
||||
.want_stack_check = want_stack_check,
|
||||
.want_valgrind = want_valgrind,
|
||||
@ -2773,6 +2783,8 @@ pub const ClangArgIterator = struct {
|
||||
driver_punt,
|
||||
pic,
|
||||
no_pic,
|
||||
pie,
|
||||
no_pie,
|
||||
nostdlib,
|
||||
nostdlib_cpp,
|
||||
shared,
|
||||
|
||||
18
src/musl.zig
18
src/musl.zig
@ -12,6 +12,7 @@ pub const CRTFile = enum {
|
||||
crti_o,
|
||||
crtn_o,
|
||||
crt1_o,
|
||||
rcrt1_o,
|
||||
scrt1_o,
|
||||
libc_a,
|
||||
};
|
||||
@ -68,6 +69,23 @@ pub fn buildCRTFile(comp: *Compilation, crt_file: CRTFile) !void {
|
||||
},
|
||||
});
|
||||
},
|
||||
.rcrt1_o => {
|
||||
var args = std.ArrayList([]const u8).init(arena);
|
||||
try add_cc_args(comp, arena, &args, false);
|
||||
try args.appendSlice(&[_][]const u8{
|
||||
"-fPIC",
|
||||
"-fno-stack-protector",
|
||||
"-DCRT",
|
||||
});
|
||||
return comp.build_crt_file("rcrt1", .Obj, &[1]Compilation.CSourceFile{
|
||||
.{
|
||||
.src_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{
|
||||
"libc", "musl", "crt", "rcrt1.c",
|
||||
}),
|
||||
.extra_flags = args.items,
|
||||
},
|
||||
});
|
||||
},
|
||||
.scrt1_o => {
|
||||
var args = std.ArrayList([]const u8).init(arena);
|
||||
try add_cc_args(comp, arena, &args, false);
|
||||
|
||||
@ -108,6 +108,7 @@ pub const Module = extern struct {
|
||||
subsystem: TargetSubsystem,
|
||||
err_color: ErrColor,
|
||||
pic: bool,
|
||||
pie: bool,
|
||||
link_libc: bool,
|
||||
link_libcpp: bool,
|
||||
strip: bool,
|
||||
|
||||
@ -2177,6 +2177,7 @@ struct CodeGen {
|
||||
bool is_test_build;
|
||||
bool is_single_threaded;
|
||||
bool have_pic;
|
||||
bool have_pie;
|
||||
bool link_mode_dynamic;
|
||||
bool dll_export_fns;
|
||||
bool have_stack_probing;
|
||||
|
||||
@ -9043,6 +9043,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) {
|
||||
buf_appendf(contents, "pub const have_error_return_tracing = %s;\n", bool_to_str(g->have_err_ret_tracing));
|
||||
buf_appendf(contents, "pub const valgrind_support = false;\n");
|
||||
buf_appendf(contents, "pub const position_independent_code = %s;\n", bool_to_str(g->have_pic));
|
||||
buf_appendf(contents, "pub const position_independent_executable = %s;\n", bool_to_str(g->have_pie));
|
||||
buf_appendf(contents, "pub const strip_debug_info = %s;\n", bool_to_str(g->strip_debug_symbols));
|
||||
buf_appendf(contents, "pub const code_model = CodeModel.default;\n");
|
||||
|
||||
@ -9170,6 +9171,14 @@ static void init(CodeGen *g) {
|
||||
reloc_mode = LLVMRelocStatic;
|
||||
}
|
||||
|
||||
if (g->have_pic) {
|
||||
ZigLLVMSetModulePICLevel(g->module);
|
||||
}
|
||||
|
||||
if (g->have_pie) {
|
||||
ZigLLVMSetModulePIELevel(g->module);
|
||||
}
|
||||
|
||||
const char *target_specific_cpu_args = "";
|
||||
const char *target_specific_features = "";
|
||||
|
||||
|
||||
@ -89,6 +89,7 @@ void zig_stage1_build_object(struct ZigStage1 *stage1) {
|
||||
g->link_mode_dynamic = stage1->link_mode_dynamic;
|
||||
g->dll_export_fns = stage1->dll_export_fns;
|
||||
g->have_pic = stage1->pic;
|
||||
g->have_pie = stage1->pie;
|
||||
g->have_stack_probing = stage1->enable_stack_probing;
|
||||
g->is_single_threaded = stage1->is_single_threaded;
|
||||
g->valgrind_enabled = stage1->valgrind_enabled;
|
||||
|
||||
@ -177,6 +177,7 @@ struct ZigStage1 {
|
||||
enum ErrColor err_color;
|
||||
|
||||
bool pic;
|
||||
bool pie;
|
||||
bool link_libc;
|
||||
bool link_libcpp;
|
||||
bool strip;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -54,6 +54,14 @@ const known_options = [_]KnownOpt{
|
||||
.name = "fno-PIC",
|
||||
.ident = "no_pic",
|
||||
},
|
||||
.{
|
||||
.name = "fPIE",
|
||||
.ident = "pie",
|
||||
},
|
||||
.{
|
||||
.name = "fno-PIE",
|
||||
.ident = "no_pie",
|
||||
},
|
||||
.{
|
||||
.name = "nolibc",
|
||||
.ident = "nostdlib",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user