mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 22:04:21 +00:00
This prevents it from trying to access thread local storage before it has set up thread local storage, particularly when code coverage instrumentation is enabled.
120 lines
3.9 KiB
Zig
120 lines
3.9 KiB
Zig
const std = @import("std");
|
|
const builtin = @import("builtin");
|
|
const elf = std.elf;
|
|
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 R_SPARC_RELATIVE = 22;
|
|
|
|
const R_RELATIVE = switch (builtin.cpu.arch) {
|
|
.x86 => R_386_RELATIVE,
|
|
.x86_64 => R_AMD64_RELATIVE,
|
|
.arm => R_ARM_RELATIVE,
|
|
.aarch64 => R_AARCH64_RELATIVE,
|
|
.riscv64 => R_RISCV_RELATIVE,
|
|
else => @compileError("Missing R_RELATIVE definition for this target"),
|
|
};
|
|
|
|
// Obtain a pointer to the _DYNAMIC array.
|
|
// We have to compute its address as a PC-relative quantity not to require a
|
|
// relocation that, at this point, is not yet applied.
|
|
fn getDynamicSymbol() [*]elf.Dyn {
|
|
return switch (builtin.cpu.arch) {
|
|
.x86 => asm volatile (
|
|
\\ .weak _DYNAMIC
|
|
\\ .hidden _DYNAMIC
|
|
\\ call 1f
|
|
\\ 1: pop %[ret]
|
|
\\ lea _DYNAMIC-1b(%[ret]), %[ret]
|
|
: [ret] "=r" (-> [*]elf.Dyn),
|
|
),
|
|
.x86_64 => asm volatile (
|
|
\\ .weak _DYNAMIC
|
|
\\ .hidden _DYNAMIC
|
|
\\ lea _DYNAMIC(%%rip), %[ret]
|
|
: [ret] "=r" (-> [*]elf.Dyn),
|
|
),
|
|
// 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" (-> [*]elf.Dyn),
|
|
),
|
|
// 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" (-> [*]elf.Dyn),
|
|
),
|
|
.riscv64 => asm volatile (
|
|
\\ .weak _DYNAMIC
|
|
\\ .hidden _DYNAMIC
|
|
\\ lla %[ret], _DYNAMIC
|
|
: [ret] "=r" (-> [*]elf.Dyn),
|
|
),
|
|
else => {
|
|
@compileError("PIE startup is not yet supported for this target!");
|
|
},
|
|
};
|
|
}
|
|
|
|
pub fn relocate(phdrs: []elf.Phdr) void {
|
|
@setRuntimeSafety(false);
|
|
@disableInstrumentation();
|
|
|
|
const dynv = getDynamicSymbol();
|
|
// Recover the delta applied by the loader by comparing the effective and
|
|
// the theoretical load addresses for the `_DYNAMIC` symbol.
|
|
const base_addr = base: {
|
|
for (phdrs) |*phdr| {
|
|
if (phdr.p_type != elf.PT_DYNAMIC) continue;
|
|
break :base @intFromPtr(dynv) - phdr.p_vaddr;
|
|
}
|
|
// This is not supposed to happen for well-formed binaries.
|
|
@trap();
|
|
};
|
|
|
|
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 => {},
|
|
}
|
|
}
|
|
}
|
|
|
|
// Apply the relocations.
|
|
if (rel_addr != 0) {
|
|
const rel = std.mem.bytesAsSlice(elf.Rel, @as([*]u8, @ptrFromInt(rel_addr))[0..rel_size]);
|
|
for (rel) |r| {
|
|
if (r.r_type() != R_RELATIVE) continue;
|
|
@as(*usize, @ptrFromInt(base_addr + r.r_offset)).* += base_addr;
|
|
}
|
|
}
|
|
if (rela_addr != 0) {
|
|
const rela = std.mem.bytesAsSlice(elf.Rela, @as([*]u8, @ptrFromInt(rela_addr))[0..rela_size]);
|
|
for (rela) |r| {
|
|
if (r.r_type() != R_RELATIVE) continue;
|
|
@as(*usize, @ptrFromInt(base_addr + r.r_offset)).* = base_addr + @as(usize, @bitCast(r.r_addend));
|
|
}
|
|
}
|
|
}
|