| ... | ... | @@ -135,6 +135,18 @@ inputs: std.ArrayList(struct { |
| 135 | 135 | input_pending_index: u32, |
| 136 | 136 | input_sections: std.ArrayList(InputSection), |
| 137 | 137 | input_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`. |
| 140 | one_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 | }), |
| 138 | 150 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct { |
| 139 | 151 | lsi: Symbol.LocalIndex, |
| 140 | 152 | /// The start index of the contiguous sequence of symbol relocations in this NAV. |
| ... | ... | @@ -3356,6 +3368,7 @@ fn create( |
| 3356 | 3368 | .input_pending_index = 0, |
| 3357 | 3369 | .input_sections = .empty, |
| 3358 | 3370 | .input_section_pending_index = 0, |
| 3371 | .one_shot_fixups = .empty, |
| 3359 | 3372 | .navs = .empty, |
| 3360 | 3373 | .uavs = .empty, |
| 3361 | 3374 | .lazy = comptime .initFill(.{ |
| ... | ... | @@ -3405,6 +3418,7 @@ pub fn deinit(elf: *Elf) void { |
| 3405 | 3418 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); |
| 3406 | 3419 | elf.inputs.deinit(gpa); |
| 3407 | 3420 | elf.input_sections.deinit(gpa); |
| 3421 | elf.one_shot_fixups.deinit(gpa); |
| 3408 | 3422 | elf.navs.deinit(gpa); |
| 3409 | 3423 | elf.uavs.deinit(gpa); |
| 3410 | 3424 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| ... | ... | @@ -6615,36 +6629,36 @@ fn addRelocAssumeCapacity( |
| 6615 | 6629 | |
| 6616 | 6630 | // The following relocations are all represented by the ABI as writing to a 13 bit |
| 6617 | 6631 | // 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. |
| 6622 | 6636 | .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" }); |
| 6624 | 6638 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.rel, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6625 | 6639 | }, |
| 6626 | 6640 | .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" }); |
| 6628 | 6642 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.abs, .{ .dest = .@"32[11:0]", .cast = .trunc, .shift = .@"0" })); |
| 6629 | 6643 | }, |
| 6630 | 6644 | .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" }); |
| 6632 | 6646 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.dtpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6633 | 6647 | }, |
| 6634 | 6648 | .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" }); |
| 6636 | 6650 | try elf.addSymbolRelocAssumeCapacity(node, offset, target, addend, .simple(.tpoff, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6637 | 6651 | }, |
| 6638 | 6652 | .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" }); |
| 6640 | 6654 | elf.addGotRelocAssumeCapacity(node, offset, .{ .symbol = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6641 | 6655 | }, |
| 6642 | 6656 | .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" }); |
| 6644 | 6658 | elf.addGotRelocAssumeCapacity(node, offset, .{ .tlsgd0 = target }, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6645 | 6659 | }, |
| 6646 | 6660 | .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" }); |
| 6648 | 6662 | elf.addGotRelocAssumeCapacity(node, offset, .tlsld0, addend, .simple(.offset, .{ .dest = .@"32[9:0]", .cast = .trunc, .shift = .@"0" })); |
| 6649 | 6663 | }, |
| 6650 | 6664 | }, |
| ... | ... | @@ -7391,6 +7405,25 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7391 | 7405 | }; |
| 7392 | 7406 | break :task; |
| 7393 | 7407 | } |
| 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 | } |
| 7394 | 7427 | if (elf.changed_symtab_index.pop()) |kv| { |
| 7395 | 7428 | const sub_prog_node = elf.mf.update_prog_node.start(kv.key.slice(elf), 0); |
| 7396 | 7429 | defer sub_prog_node.end(); |
| ... | ... | @@ -7481,6 +7514,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7481 | 7514 | } |
| 7482 | 7515 | } |
| 7483 | 7516 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; |
| 7517 | if (elf.one_shot_fixups.items.len > 0) return true; |
| 7484 | 7518 | if (elf.changed_symtab_index.count() > 0) return true; |
| 7485 | 7519 | if (elf.mf.updates.items.len > 0) return true; |
| 7486 | 7520 | return false; |