authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-13 20:56:49+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-16 10:37:19+01:00
logbd805e82b9984bc388217415d2a814550d4033a8
treef4127757ff5d9a2448538e0b166bdd3de833944e
parent594a6d5665fba5696903043bbcb76a8ce8d28d0b
signaturelock-open Commit is signed but in an unrecognized format.

Elf2: populate fixed bits in SPARC relocations


1 files changed, 45 insertions(+), 11 deletions(-)

src/link/Elf2.zig+45-11
......@@ -135,6 +135,18 @@ inputs: std.ArrayList(struct {
135135input_pending_index: u32,
136136input_sections: std.ArrayList(InputSection),
137137input_section_pending_index: u32,
138/// SPARC has some weird relocations which involve setting some bits to fixed constant values. When
139/// we encounter such a relocation, we queue the action here, and apply them during `idle`.
140one_shot_fixups: std.ArrayList(struct {
141 node: MappedFile.Node.Index,
142 offset: u64,
143 /// The syntax in these tag names matches the syntax used in `SymbolReloc.Type.Simple.dest`.
144 action: enum {
145 @"32[12:10] = 0b000",
146 @"32[12:10] = 0b111",
147 @"32[12:12] = 0b0",
148 },
149}),
138150navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct {
139151 lsi: Symbol.LocalIndex,
140152 /// The start index of the contiguous sequence of symbol relocations in this NAV.
......@@ -3356,6 +3368,7 @@ fn create(
33563368 .input_pending_index = 0,
33573369 .input_sections = .empty,
33583370 .input_section_pending_index = 0,
3371 .one_shot_fixups = .empty,
33593372 .navs = .empty,
33603373 .uavs = .empty,
33613374 .lazy = comptime .initFill(.{
......@@ -3405,6 +3418,7 @@ pub fn deinit(elf: *Elf) void {
34053418 for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m);
34063419 elf.inputs.deinit(gpa);
34073420 elf.input_sections.deinit(gpa);
3421 elf.one_shot_fixups.deinit(gpa);
34083422 elf.navs.deinit(gpa);
34093423 elf.uavs.deinit(gpa);
34103424 for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa);
......@@ -6615,36 +6629,36 @@ fn addRelocAssumeCapacity(
66156629
66166630 // The following relocations are all represented by the ABI as writing to a 13 bit
66176631 // field (32[12:0]), but masking out some bits of the value. To simplify our logic
6618 // for applying relocations, we instead [un]set any fixed bits right now, then model
6619 // the relocation as only writing to a smaller 10--12 bit field.
6620 // TODO: because we flush input sections lazily, we can't actually write these bits
6621 // immediately---we'll instead have to queue the writes somehow.
6632 // for applying relocations, we split this action up: we create a relocation writing
6633 // to the 10--12 bit long field which is actually variable, and queue a one-shot
6634 // task to set the constant bits. We can't just write the bits now unfortunately
6635 // because they may be in an input section which has not yet been loaded.
66226636 .PC10 => {
6623 // TODO: 32[12:10] = 0b000
6637 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
66246638 try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
66256639 },
66266640 .L44 => {
6627 // TODO: 32[12:12] = 0b0
6641 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:12] = 0b0" });
66286642 try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[11:0]", .cast = .trunc, .shift = .@"0" }));
66296643 },
66306644 .TLS_LDO_LOX10 => {
6631 // TODO: 32[12:10] = 0b000
6645 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
66326646 try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
66336647 },
66346648 .TLS_LE_LOX10 => {
6635 // TODO: 32[12:10] = 0b111
6649 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b111" });
66366650 try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
66376651 },
66386652 .GOT10 => {
6639 // TODO: 32[12:10] = 0b000
6653 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
66406654 elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
66416655 },
66426656 .TLS_GD_LO10 => {
6643 // TODO: 32[12:10] = 0b000
6657 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
66446658 elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
66456659 },
66466660 .TLS_LDM_LO10 => {
6647 // TODO: 32[12:10] = 0b000
6661 try elf.one_shot_fixups.append(elf.base.comp.gpa, .{ .node = node, .offset = offset, .action = .@"32[12:10] = 0b000" });
66486662 elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" }));
66496663 },
66506664 },
......@@ -7391,6 +7405,25 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
73917405 };
73927406 break :task;
73937407 }
7408 if (elf.one_shot_fixups.items.len > 0) {
7409 // Each of these is very simple, so an unreasonable amount of overhead would be
7410 // introduced if we only did one per `idle` call. Also, there is no risk of this work
7411 // being invalidated. So let's just flush the entire queue at once.
7412 for (elf.one_shot_fixups.items) |isw| {
7413 const dest_slice = isw.node.slice(&elf.mf)[isw.offset..][0..4];
7414 const old: u32 = std.mem.readInt(u32, dest_slice, elf.targetEndian());
7415 const new: u32 = switch (isw.action) {
7416 // zig fmt: off
7417 .@"32[12:10] = 0b000" => old & 0b11111111_11111111_11100011_11111111,
7418 .@"32[12:10] = 0b111" => old | 0b00000000_00000000_00011100_00000000,
7419 .@"32[12:12] = 0b0" => old & 0b11111111_11111111_11101111_11111111,
7420 // zig fmt: on
7421 };
7422 std.mem.writeInt(u32, dest_slice, new, elf.targetEndian());
7423 }
7424 elf.one_shot_fixups.clearRetainingCapacity();
7425 break :task;
7426 }
73947427 if (elf.changed_symtab_index.pop()) |kv| {
73957428 const sub_prog_node = elf.mf.update_prog_node.start(kv.key.slice(elf), 0);
73967429 defer sub_prog_node.end();
......@@ -7481,6 +7514,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool {
74817514 }
74827515 }
74837516 if (elf.input_sections.items.len > elf.input_section_pending_index) return true;
7517 if (elf.one_shot_fixups.items.len > 0) return true;
74847518 if (elf.changed_symtab_index.count() > 0) return true;
74857519 if (elf.mf.updates.items.len > 0) return true;
74867520 return false;