ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
33.82k stars 2.47k forks source link

Packed Relocations in PIE Start #17229

Open tf2spi opened 12 months ago

tf2spi commented 12 months ago

Linkers like LLVM's lld and GNU's ld support emitting packed relocations at link-time

For ld, it supports emitting RELR relocations, and for lld, it supports emitting both RELR relocations and Android's APS2 relocations by using the following flags.

# format = android, relr, or android+relr
# Android = APS2 relocations for both REL and RELA
ld.lld --pack-dyn-relocs=format

# Output RELR relocations
ld -z pack-relative-relocs

Zig currently does not support either of these relocations for when compiling static PIE binaries.

Google Chromium's docs on Native Relocations and the MaskRay Blog Post give basic statistics on the space savings gained using these relocations. It's hard to find much more in-depth statistics on them.

RELR Example

It's easiest to see Zig segfaulting on unimplemented RELRs when mixing C code and Zig code.

// main.zig
const std = @import("std");

extern const message: [*:0]const u8;
pub fn main() void {
    std.debug.print("{s}", .{
        message,
    });
}
// helper.c
#include <stddef.h>
#include <stdint.h>
const char *message = "Hello World!\n";
void *memcpy(void *dst, const void *src, size_t len) {
    while(len--)
        ((uint8_t *)dst)[len] = ((uint8_t *)src)[len];
    return dst;
}
void *memset(void *dst, int c, size_t len) {
    while(len--)
        ((uint8_t *)dst)[len] = c;
    return dst;
}

Compile with these commands on amd64


$ zig version
0.12.0-dev.415+5af5d87ad

# This will emit an error, but main.o will still be produced
$ zig build-exe -fPIE -OReleaseSmall main.zig
...

$ gcc -static-pie -nostdlib -fpic -Wl,-zpack-relative-relocs helper.c main.o
$ ./a.out
Segmentation fault (core dumped)

Proposal

If any new relocation types are added to std.os.linux.start_pie.relocate, it'd be best to add RELR relocations before adding the android-specific relocations like APS2. Not only is the former not operating-system specific, it's shown to be more effective at compressing relative relocations on average while being simpler to implement.

If RELR is added, adding the appropriate linker flags to emit RELR relocation would make integrating this into current zig projects much easier as well.

alexrp commented 3 weeks ago

RELR support was added in https://github.com/ziglang/zig/pull/20893. Still need to add a frontend flag to actually emit these relocations.

I am not personally convinced that APS2 is worth the effort. It just seems like a worse RELR?