authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-01 08:48:18+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-07-07 13:05:31+01:00
log0e8bb9188f77ba39d8d4d86d6a5abe378009c5df
tree29df19a8ef58bd96b5b90a6fed52b13c14adfad8
parent3210dc4b006cd8718e5fee5530ad4383b0230959
signaturelock-open Commit is signed but in an unrecognized format.

Elf2: support GOT tpoff relocs on local symbols


1 files changed, 24 insertions(+), 15 deletions(-)

src/link/Elf2.zig+24-15
......@@ -5885,6 +5885,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
58855885 reloc: struct {
58865886 type: MachineRelocType,
58875887 dynsym_index: u32,
5888 addend: i64,
58885889 },
58895890 } = switch (elf.got.keys()[got_index]) {
58905891 .reserved => .{ .unsigned = 0 },
......@@ -5918,20 +5919,25 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
59185919 const sym_value = sym_id.value(elf);
59195920 break :val .{ .signed = @bitCast(sym_value -% tls_size) };
59205921 }
5921 break :val .{
5922 .reloc = .{
5923 .type = switch (elf.ehdrField(.machine)) {
5924 else => |machine| @panic(@tagName(machine)),
5925 .X86_64 => .{ .X86_64 = .TPOFF64 },
5926 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },
5927 },
5928 .dynsym_index = switch (sym_id.unwrap()) {
5929 .global => |name| elf.globalByName(name).?.dynsym_index,
5930 // TODO: I have no idea if compilers are even allowed to emit this, but if they
5931 // are then I guess we need to add this local symbol to `.dynsym`?
5932 .local => @panic("TODO(Elf2): GOT tpoff entry referencing local symbol"),
5933 },
5934 },
5922 const reloc_type: MachineRelocType = switch (elf.ehdrField(.machine)) {
5923 else => |machine| @panic(@tagName(machine)),
5924 .X86_64 => .{ .X86_64 = .TPOFF64 },
5925 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },
5926 };
5927 break :val switch (sym_id.unwrap()) {
5928 // For global symbols, just target the right dynsym with no addend.
5929 .global => |name| .{ .reloc = .{
5930 .type = reloc_type,
5931 .dynsym_index = elf.globalByName(name).?.dynsym_index,
5932 .addend = 0,
5933 } },
5934 // For local symbols, target the null symbol (index 0) so we get the offset to the
5935 // base of our TLS block, and then use `addend` to offset to the right symbol.
5936 .local => .{ .reloc = .{
5937 .type = reloc_type,
5938 .dynsym_index = 0,
5939 .addend = @intCast(sym_id.value(elf)),
5940 } },
59355941 };
59365942 },
59375943 .symbol, .tlsgd1 => |sym_id, tag| val: {
......@@ -5974,6 +5980,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
59745980 break :val .{ .reloc = .{
59755981 .type = if (tag == .symbol) .globDat(elf) else .dtpOffAddr(elf),
59765982 .dynsym_index = elf.globalByName(name).?.dynsym_index,
5983 .addend = 0,
59775984 } };
59785985 },
59795986 .tlsgd0 => |sym| switch (elf.shndx.dynamic) {
......@@ -6010,6 +6017,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
60106017 break :dsi elf.globalByName(name).?.dynsym_index;
60116018 },
60126019 },
6020 .addend = 0,
60136021 },
60146022 },
60156023 },
......@@ -6022,6 +6030,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
60226030 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
60236031 },
60246032 .dynsym_index = 0,
6033 .addend = 0,
60256034 } },
60266035 },
60276036 .tlsld1 => .{ .unsigned = 0 },
......@@ -6065,7 +6074,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
60656074 .type = reloc.type,
60666075 .offset = got_entry_addr,
60676076 .raw_sym_index = reloc.dynsym_index,
6068 .addend = 0,
6077 .addend = reloc.addend,
60696078 }).toOptional(),
60706079 };
60716080}