authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-13 21:10:56+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-08-16 10:37:19+01:00
log58c84c59c000c341d7abcf98def0cd13d0e1630e
tree7b0c928593b8d663c0cd5f593d111ad0404c48eb
parent99e54fc4209af72eb34b7d32bc5efd28a2a7b1ba
signaturelock-open Commit is signed but in an unrecognized format.

Elf2: add segment for PLT on SPARC

On SPARC, because JUMP_SLOT relocations write directly to the PLT, the PLT is required to be RWX. Conventionally, this is achieved by placing it in the "data" segment and making that RWX instead of RW, but that just seems unnecessarily dangerous. Instead, let's try making a segment specifically for the PLT.

1 files changed, 54 insertions(+), 17 deletions(-)

src/link/Elf2.zig+54-17
......@@ -3521,6 +3521,10 @@ fn initHeaders(
35213521 rodata: u32,
35223522 text: u32,
35233523 data: u32,
3524 /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write
3525 /// directly to the PLT, we place the PLT in its own segment in order to avoid making the
3526 /// general data segment RWX.
3527 plt: u32,
35243528 tls: u32,
35253529 dynamic: u32,
35263530 relro: u32,
......@@ -3552,6 +3556,10 @@ fn initHeaders(
35523556 defer phnum += 1;
35533557 break :phndx phnum;
35543558 },
3559 .plt = if (plt.got_plt == null) phndx: {
3560 defer phnum += 1;
3561 break :phndx phnum;
3562 } else undefined,
35553563 .tls = if (comp.config.any_non_single_threaded) phndx: {
35563564 defer phnum += 1;
35573565 break :phndx phnum;
......@@ -3721,6 +3729,16 @@ fn initHeaders(
37213729 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data });
37223730 elf.phdrs.items[phndx.data] = elf.ni.data;
37233731
3732 if (plt.got_plt == null) {
3733 const plt_ni = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{
3734 .alignment = node_block_align,
3735 .moved = true,
3736 .bubbles_moved = false,
3737 });
3738 elf.nodes.appendAssumeCapacity(.{ .segment = phndx.plt });
3739 elf.phdrs.items[phndx.plt] = plt_ni;
3740 }
3741
37243742 elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{
37253743 // Must be at least `addr_align` for the `PT_DYNAMIC` node to be placed inside this one
37263744 // later (if `have_dynamic_section`). Keep in sync with `elf.ni.data` alignment above.
......@@ -3844,6 +3862,20 @@ fn initHeaders(
38443862 .@"align" = @intCast(page_align.toByteUnits()),
38453863 };
38463864
3865 if (plt.got_plt == null) {
3866 const ph_plt = &phdr[phndx.plt];
3867 ph_plt.* = .{
3868 .type = .NULL,
3869 .offset = 0,
3870 .vaddr = @intCast(base_vaddr),
3871 .paddr = @intCast(base_vaddr),
3872 .filesz = 0,
3873 .memsz = 0,
3874 .flags = .{ .R = true, .W = true, .X = true },
3875 .@"align" = @intCast(page_align.toByteUnits()),
3876 };
3877 }
3878
38473879 if (comp.config.any_non_single_threaded) {
38483880 const ph_tls = &phdr[phndx.tls];
38493881 ph_tls.* = .{
......@@ -4001,29 +4033,34 @@ fn initHeaders(
40014033 .addralign = addr_align,
40024034 .entsize = @intCast(addr_align.toByteUnits()),
40034035 });
4004 if (plt.got_plt) |got_plt| elf.shndx.got_plt = try elf.addSection(
4005 if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data,
4006 .{
4036 if (plt.got_plt) |got_plt| {
4037 const got_plt_segment_ni = if (elf.options.z_now) elf.ni.data_rel_ro else elf.ni.data;
4038 elf.shndx.got_plt = try elf.addSection(got_plt_segment_ni, .{
40074039 .name = ".got.plt",
40084040 .type = .PROGBITS,
40094041 .flags = .{ .WRITE = true, .ALLOC = true },
40104042 .size = got_plt.header_entries * elf.targetPtrSize(),
40114043 .addralign = addr_align,
40124044 .entsize = @intCast(addr_align.toByteUnits()),
4013 },
4014 );
4015 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
4016 .name = ".plt",
4017 .type = .PROGBITS,
4018 .flags = .{
4019 .ALLOC = true,
4020 .EXECINSTR = true,
4021 .WRITE = plt.got_plt == null,
4022 },
4023 .size = plt.entry_size * plt.header_entries,
4024 .addralign = plt.@"align",
4025 .node_align = node_block_align,
4026 });
4045 });
4046 elf.shndx.plt = try elf.addSection(elf.ni.text, .{
4047 .name = ".plt",
4048 .type = .PROGBITS,
4049 .flags = .{ .ALLOC = true, .EXECINSTR = true },
4050 .size = plt.entry_size * plt.header_entries,
4051 .addralign = plt.@"align",
4052 .node_align = node_block_align,
4053 });
4054 } else {
4055 elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt], .{
4056 .name = ".plt",
4057 .type = .PROGBITS,
4058 .flags = .{ .ALLOC = true, .WRITE = true, .EXECINSTR = true },
4059 .size = plt.entry_size * plt.header_entries,
4060 .addralign = plt.@"align",
4061 .node_align = node_block_align,
4062 });
4063 }
40274064 if (plt.plt_sec != null) elf.shndx.plt_sec = try elf.addSection(elf.ni.text, .{
40284065 .name = ".plt.sec",
40294066 .flags = .{ .ALLOC = true, .EXECINSTR = true },