aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/link/MachO.zig13
-rw-r--r--src/link/MachO/thunks.zig29
-rw-r--r--test/link/elf.zig57
-rw-r--r--test/link/macho.zig27
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;