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 {...@@ -5885,6 +5885,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
5885 reloc: struct {5885 reloc: struct {
5886 type: MachineRelocType,5886 type: MachineRelocType,
5887 dynsym_index: u32,5887 dynsym_index: u32,
5888 addend: i64,
5888 },5889 },
5889 } = switch (elf.got.keys()[got_index]) {5890 } = switch (elf.got.keys()[got_index]) {
5890 .reserved => .{ .unsigned = 0 },5891 .reserved => .{ .unsigned = 0 },
...@@ -5918,20 +5919,25 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -5918,20 +5919,25 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
5918 const sym_value = sym_id.value(elf);5919 const sym_value = sym_id.value(elf);
5919 break :val .{ .signed = @bitCast(sym_value -% tls_size) };5920 break :val .{ .signed = @bitCast(sym_value -% tls_size) };
5920 }5921 }
5921 break :val .{5922 const reloc_type: MachineRelocType = switch (elf.ehdrField(.machine)) {
5922 .reloc = .{5923 else => |machine| @panic(@tagName(machine)),
5923 .type = switch (elf.ehdrField(.machine)) {5924 .X86_64 => .{ .X86_64 = .TPOFF64 },
5924 else => |machine| @panic(@tagName(machine)),5925 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },
5925 .X86_64 => .{ .X86_64 = .TPOFF64 },5926 };
5926 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 },5927 break :val switch (sym_id.unwrap()) {
5927 },5928 // For global symbols, just target the right dynsym with no addend.
5928 .dynsym_index = switch (sym_id.unwrap()) {5929 .global => |name| .{ .reloc = .{
5929 .global => |name| elf.globalByName(name).?.dynsym_index,5930 .type = reloc_type,
5930 // TODO: I have no idea if compilers are even allowed to emit this, but if they5931 .dynsym_index = elf.globalByName(name).?.dynsym_index,
5931 // are then I guess we need to add this local symbol to `.dynsym`?5932 .addend = 0,
5932 .local => @panic("TODO(Elf2): GOT tpoff entry referencing local symbol"),5933 } },
5933 },5934 // For local symbols, target the null symbol (index 0) so we get the offset to the
5934 },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 } },
5935 };5941 };
5936 },5942 },
5937 .symbol, .tlsgd1 => |sym_id, tag| val: {5943 .symbol, .tlsgd1 => |sym_id, tag| val: {
...@@ -5974,6 +5980,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -5974,6 +5980,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
5974 break :val .{ .reloc = .{5980 break :val .{ .reloc = .{
5975 .type = if (tag == .symbol) .globDat(elf) else .dtpOffAddr(elf),5981 .type = if (tag == .symbol) .globDat(elf) else .dtpOffAddr(elf),
5976 .dynsym_index = elf.globalByName(name).?.dynsym_index,5982 .dynsym_index = elf.globalByName(name).?.dynsym_index,
5983 .addend = 0,
5977 } };5984 } };
5978 },5985 },
5979 .tlsgd0 => |sym| switch (elf.shndx.dynamic) {5986 .tlsgd0 => |sym| switch (elf.shndx.dynamic) {
...@@ -6010,6 +6017,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -6010,6 +6017,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
6010 break :dsi elf.globalByName(name).?.dynsym_index;6017 break :dsi elf.globalByName(name).?.dynsym_index;
6011 },6018 },
6012 },6019 },
6020 .addend = 0,
6013 },6021 },
6014 },6022 },
6015 },6023 },
...@@ -6022,6 +6030,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -6022,6 +6030,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
6022 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },6030 .LOONGARCH => .{ .LOONGARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 },
6023 },6031 },
6024 .dynsym_index = 0,6032 .dynsym_index = 0,
6033 .addend = 0,
6025 } },6034 } },
6026 },6035 },
6027 .tlsld1 => .{ .unsigned = 0 },6036 .tlsld1 => .{ .unsigned = 0 },
...@@ -6065,7 +6074,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {...@@ -6065,7 +6074,7 @@ fn updateGotEntry(elf: *Elf, got_index: usize) void {
6065 .type = reloc.type,6074 .type = reloc.type,
6066 .offset = got_entry_addr,6075 .offset = got_entry_addr,
6067 .raw_sym_index = reloc.dynsym_index,6076 .raw_sym_index = reloc.dynsym_index,
6068 .addend = 0,6077 .addend = reloc.addend,
6069 }).toOptional(),6078 }).toOptional(),
6070 };6079 };
6071}6080}