From b1eba5a996ed862aefae49a1a7d1480a788095ff Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Sun, 10 Mar 2024 23:45:29 +0100 Subject: elf+aarch64: actually write out thunks, and add a proper link test --- src/link/Elf.zig | 10 ++++++++++ src/link/Elf/thunks.zig | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/link/Elf.zig b/src/link/Elf.zig index d26f49ca09..ed6ffbcd08 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -4565,6 +4565,16 @@ fn writeAtoms(self: *Elf) !void { try self.base.file.?.pwriteAll(buffer, sh_offset); } + for (self.thunks.items) |th| { + const shdr = self.shdrs.items[th.output_section_index]; + const offset = th.value + shdr.sh_offset; + const buffer = try gpa.alloc(u8, th.size(self)); + defer gpa.free(buffer); + var stream = std.io.fixedBufferStream(buffer); + try th.write(self, stream.writer()); + try self.base.file.?.pwriteAll(buffer, offset); + } + try self.reportUndefinedSymbols(&undefs); if (has_reloc_errors) return error.FlushFailure; diff --git a/src/link/Elf/thunks.zig b/src/link/Elf/thunks.zig index 398a2acd93..586cbed236 100644 --- a/src/link/Elf/thunks.zig +++ b/src/link/Elf/thunks.zig @@ -103,7 +103,7 @@ pub const Thunk = struct { } pub fn write(thunk: Thunk, elf_file: *Elf, writer: anytype) !void { - switch (elf_file.options.cpu_arch.?) { + switch (elf_file.getTarget().cpu.arch) { .aarch64 => try aarch64.write(thunk, elf_file, writer), .x86_64, .riscv64 => unreachable, else => @panic("unhandled arch"), -- cgit v1.2.3 From faa4bdb0175ee142834be320326063ae99dac1e4 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 12 Mar 2024 00:07:07 +0100 Subject: elf+aarch64: fix off-by-one in converging on groups interleaved with thunks --- src/link/Elf/thunks.zig | 6 ++-- test/link/elf.zig | 76 +++++++++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/link/Elf/thunks.zig b/src/link/Elf/thunks.zig index 586cbed236..119529b512 100644 --- a/src/link/Elf/thunks.zig +++ b/src/link/Elf/thunks.zig @@ -1,6 +1,7 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { const gpa = elf_file.base.comp.gpa; const cpu_arch = elf_file.getTarget().cpu.arch; + const max_distance = maxAllowedDistance(cpu_arch); const shdr = &elf_file.shdrs.items[shndx]; const atoms = elf_file.output_sections.get(shndx).?.items; assert(atoms.len > 0); @@ -17,12 +18,11 @@ pub fn createThunks(shndx: u32, elf_file: *Elf) !void { start_atom.value = try advance(shdr, start_atom.size, start_atom.alignment); i += 1; - while (i < atoms.len and - shdr.sh_size - start_atom.value < maxAllowedDistance(cpu_arch)) : (i += 1) - { + while (i < atoms.len) : (i += 1) { const atom_index = atoms[i]; const atom = elf_file.atom(atom_index).?; assert(atom.flags.alive); + if (atom.alignment.forward(shdr.sh_size) - start_atom.value >= max_distance) break; atom.value = try advance(shdr, atom.size, atom.alignment); } diff --git a/test/link/elf.zig b/test/link/elf.zig index 1920feb30c..fd6af3160f 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -2671,36 +2671,56 @@ fn testStrip(b: *Build, opts: Options) *Step { fn testThunks(b: *Build, opts: Options) *Step { const test_step = addTestStep(b, "thunks", opts); - const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = - \\#include - \\__attribute__((aligned(0x8000000))) int bar() { - \\ return 42; - \\} - \\int foobar(); - \\int foo() { - \\ return bar() - foobar(); - \\} - \\__attribute__((aligned(0x8000000))) int foobar() { - \\ return 42; - \\} - \\int main() { - \\ printf("bar=%d, foo=%d, foobar=%d", bar(), foo(), foobar()); - \\ return foo(); - \\} - }); - exe.link_function_sections = true; - exe.linkLibC(); + const src = + \\#include + \\__attribute__((aligned(0x8000000))) int bar() { + \\ return 42; + \\} + \\int foobar(); + \\int foo() { + \\ return bar() - foobar(); + \\} + \\__attribute__((aligned(0x8000000))) int foobar() { + \\ return 42; + \\} + \\int main() { + \\ printf("bar=%d, foo=%d, foobar=%d", bar(), foo(), foobar()); + \\ return foo(); + \\} + ; - const run = addRunArtifact(exe); - run.expectStdOutEqual("bar=42, foo=0, foobar=42"); - run.expectExitCode(0); - test_step.dependOn(&run.step); + { + const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = src }); + exe.link_function_sections = true; + exe.linkLibC(); - const check = exe.checkObject(); - check.max_bytes = std.math.maxInt(u32); - check.checkInSymtab(); - check.checkContains("_libc_start_main$thunk"); - test_step.dependOn(&check.step); + const run = addRunArtifact(exe); + run.expectStdOutEqual("bar=42, foo=0, foobar=42"); + run.expectExitCode(0); + test_step.dependOn(&run.step); + + const check = exe.checkObject(); + check.max_bytes = std.math.maxInt(u32); + check.checkInSymtab(); + check.checkContains("__libc_start_main$thunk"); + test_step.dependOn(&check.step); + } + + { + const exe = addExecutable(b, opts, .{ .name = "main2", .c_source_bytes = src }); + exe.linkLibC(); + + const run = addRunArtifact(exe); + run.expectStdOutEqual("bar=42, foo=0, foobar=42"); + run.expectExitCode(0); + test_step.dependOn(&run.step); + + const check = exe.checkObject(); + check.max_bytes = std.math.maxInt(u32); + check.checkInSymtab(); + check.checkContains("__libc_start_main$thunk"); + test_step.dependOn(&check.step); + } return test_step; } -- cgit v1.2.3 From 55c085b893892f89e7d9930f3ec6c22537ebb54f Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 12 Mar 2024 13:25:29 +0100 Subject: elf: re-use output buffer for emitting thunks --- src/link/Elf.zig | 40 +++++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 15 deletions(-) (limited to 'src') diff --git a/src/link/Elf.zig b/src/link/Elf.zig index ed6ffbcd08..e6182b4333 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -4565,14 +4565,20 @@ fn writeAtoms(self: *Elf) !void { try self.base.file.?.pwriteAll(buffer, sh_offset); } - for (self.thunks.items) |th| { - const shdr = self.shdrs.items[th.output_section_index]; - const offset = th.value + shdr.sh_offset; - const buffer = try gpa.alloc(u8, th.size(self)); - defer gpa.free(buffer); - var stream = std.io.fixedBufferStream(buffer); - try th.write(self, stream.writer()); - try self.base.file.?.pwriteAll(buffer, offset); + if (self.requiresThunks()) { + var buffer = std.ArrayList(u8).init(gpa); + defer buffer.deinit(); + + for (self.thunks.items) |th| { + const thunk_size = th.size(self); + try buffer.ensureUnusedCapacity(thunk_size); + const shdr = self.shdrs.items[th.output_section_index]; + const offset = th.value + shdr.sh_offset; + try th.write(self, buffer.writer()); + assert(buffer.items.len == thunk_size); + try self.base.file.?.pwriteAll(buffer.items, offset); + buffer.clearRetainingCapacity(); + } } try self.reportUndefinedSymbols(&undefs); @@ -4603,12 +4609,12 @@ pub fn updateSymtabSize(self: *Elf) !void { nlocals += 1; } - for (self.thunks.items) |*th| { + if (self.requiresThunks()) for (self.thunks.items) |*th| { th.output_symtab_ctx.ilocal = nlocals + 1; th.calcSymtabSize(self); nlocals += th.output_symtab_ctx.nlocals; strsize += th.output_symtab_ctx.strsize; - } + }; for (files.items) |index| { const file_ptr = self.file(index).?; @@ -4840,9 +4846,9 @@ pub fn writeSymtab(self: *Elf) !void { self.writeSectionSymbols(); - for (self.thunks.items) |th| { + if (self.requiresThunks()) for (self.thunks.items) |th| { th.writeSymtab(self); - } + }; if (self.zigObjectPtr()) |zig_object| { zig_object.asFile().writeSymtab(self); @@ -6007,10 +6013,14 @@ fn fmtDumpState( try writer.print("linker_defined({d}) : (linker defined)\n", .{index}); try writer.print("{}\n", .{linker_defined.fmtSymtab(self)}); } - try writer.writeAll("thunks\n"); - for (self.thunks.items, 0..) |th, index| { - try writer.print("thunk({d}) : {}\n", .{ index, th.fmt(self) }); + + if (self.requiresThunks()) { + try writer.writeAll("thunks\n"); + for (self.thunks.items, 0..) |th, index| { + try writer.print("thunk({d}) : {}\n", .{ index, th.fmt(self) }); + } } + try writer.print("{}\n", .{self.zig_got.fmt(self)}); try writer.print("{}\n", .{self.got.fmt(self)}); try writer.print("{}\n", .{self.plt.fmt(self)}); -- cgit v1.2.3