diff options
| -rw-r--r-- | src/link/MachO.zig | 13 | ||||
| -rw-r--r-- | src/link/MachO/thunks.zig | 29 | ||||
| -rw-r--r-- | test/link/elf.zig | 57 | ||||
| -rw-r--r-- | test/link/macho.zig | 27 |
4 files changed, 76 insertions, 50 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 65f31ae5dc..d99fc2185e 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -1909,7 +1909,7 @@ fn calcSectionSizes(self: *MachO) !void { } } - // At this point, we can also calculate symtab and data-in-code linkedit section sizes + // At this point, we can also calculate most of the symtab and data-in-code linkedit section sizes if (self.getZigObject()) |zo| { tp.spawnWg(&wg, File.calcSymtabSize, .{ zo.asFile(), self }); } @@ -2463,6 +2463,9 @@ fn writeSectionsAndUpdateLinkeditSizes(self: *MachO) !void { if (self.getInternalObject()) |obj| { tp.spawnWg(&wg, File.writeSymtab, .{ obj.asFile(), self, self }); } + if (self.requiresThunks()) for (self.thunks.items) |th| { + tp.spawnWg(&wg, Thunk.writeSymtab, .{ th, self, self }); + }; } if (self.has_errors.swap(false, .seq_cst)) return error.FlushFailure; @@ -2725,6 +2728,14 @@ fn calcSymtabSize(self: *MachO) !void { var nimports: u32 = 0; var strsize: u32 = 1; + if (self.requiresThunks()) for (self.thunks.items) |*th| { + th.output_symtab_ctx.ilocal = nlocals; + th.output_symtab_ctx.stroff = strsize; + th.calcSymtabSize(self); + nlocals += th.output_symtab_ctx.nlocals; + strsize += th.output_symtab_ctx.strsize; + }; + for (files.items) |index| { const file = self.getFile(index).?; const ctx = switch (file) { diff --git a/src/link/MachO/thunks.zig b/src/link/MachO/thunks.zig index 37013c54c4..4248785c54 100644 --- a/src/link/MachO/thunks.zig +++ b/src/link/MachO/thunks.zig @@ -85,6 +85,7 @@ pub const Thunk = struct { value: u64 = 0, out_n_sect: u8 = 0, symbols: std.AutoArrayHashMapUnmanaged(MachO.Ref, void) = .{}, + output_symtab_ctx: MachO.SymtabCtx = .{}, pub fn deinit(thunk: *Thunk, allocator: Allocator) void { thunk.symbols.deinit(allocator); @@ -116,6 +117,34 @@ pub const Thunk = struct { } } + pub fn calcSymtabSize(thunk: *Thunk, macho_file: *MachO) void { + thunk.output_symtab_ctx.nlocals = @as(u32, @intCast(thunk.symbols.keys().len)); + for (thunk.symbols.keys()) |ref| { + const sym = ref.getSymbol(macho_file).?; + thunk.output_symtab_ctx.strsize += @as(u32, @intCast(sym.getName(macho_file).len + "__thunk".len + 1)); + } + } + + pub fn writeSymtab(thunk: Thunk, macho_file: *MachO, ctx: anytype) void { + var n_strx = thunk.output_symtab_ctx.stroff; + for (thunk.symbols.keys(), thunk.output_symtab_ctx.ilocal..) |ref, ilocal| { + const sym = ref.getSymbol(macho_file).?; + const name = sym.getName(macho_file); + const out_sym = &ctx.symtab.items[ilocal]; + out_sym.n_strx = n_strx; + @memcpy(ctx.strtab.items[n_strx..][0..name.len], name); + n_strx += @intCast(name.len); + @memcpy(ctx.strtab.items[n_strx..][0.."__thunk".len], "__thunk"); + n_strx += @intCast("__thunk".len); + ctx.strtab.items[n_strx] = 0; + n_strx += 1; + out_sym.n_type = macho.N_SECT; + out_sym.n_sect = @intCast(thunk.out_n_sect + 1); + out_sym.n_value = @intCast(thunk.getTargetAddress(ref, macho_file)); + out_sym.n_desc = 0; + } + } + pub fn format( thunk: Thunk, comptime unused_fmt_string: []const u8, diff --git a/test/link/elf.zig b/test/link/elf.zig index 5539638ba7..98253811b2 100644 --- a/test/link/elf.zig +++ b/test/link/elf.zig @@ -2973,44 +2973,27 @@ fn testStrip(b: *Build, opts: Options) *Step { fn testThunks(b: *Build, opts: Options) *Step { const test_step = addTestStep(b, "thunks", opts); - const src = - \\#include <stdio.h> - \\__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 exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = src }); - exe.link_function_sections = true; - exe.linkLibC(); - - 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 = "main2", .c_source_bytes = src }); - exe.linkLibC(); + const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = + \\void foo(); + \\__attribute__((section(".bar"))) void bar() { + \\ return foo(); + \\} + \\__attribute__((section(".foo"))) void foo() { + \\ return bar(); + \\} + \\int main() { + \\ foo(); + \\ bar(); + \\ return 0; + \\} + }); - 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.checkInSymtab(); + check.checkContains("foo$thunk"); + check.checkInSymtab(); + check.checkContains("bar$thunk"); + test_step.dependOn(&check.step); return test_step; } diff --git a/test/link/macho.zig b/test/link/macho.zig index 30982e6ba2..730edcf3a9 100644 --- a/test/link/macho.zig +++ b/test/link/macho.zig @@ -2204,25 +2204,28 @@ fn testThunks(b: *Build, opts: Options) *Step { const exe = addExecutable(b, opts, .{ .name = "main", .c_source_bytes = \\#include <stdio.h> - \\__attribute__((aligned(0x8000000))) int bar() { - \\ return 42; + \\void bar() { + \\ printf("bar"); \\} - \\int foobar(); - \\int foo() { - \\ return bar() - foobar(); - \\} - \\__attribute__((aligned(0x8000000))) int foobar() { - \\ return 42; + \\void foo() { + \\ fprintf(stdout, "foo"); \\} \\int main() { - \\ printf("bar=%d, foo=%d, foobar=%d", bar(), foo(), foobar()); - \\ return foo(); + \\ foo(); + \\ bar(); + \\ return 0; \\} }); + const check = exe.checkObject(); + check.checkInSymtab(); + check.checkContains("_printf__thunk"); + check.checkInSymtab(); + check.checkContains("_fprintf__thunk"); + test_step.dependOn(&check.step); + const run = addRunArtifact(exe); - run.expectStdOutEqual("bar=42, foo=0, foobar=42"); - run.expectExitCode(0); + run.expectStdOutEqual("foobar"); test_step.dependOn(&run.step); return test_step; |
