diff options
| author | mlugg <mlugg@mlugg.co.uk> | 2025-10-10 11:20:19 +0100 |
|---|---|---|
| committer | Matthew Lugg <mlugg@mlugg.co.uk> | 2025-10-10 20:33:30 +0100 |
| commit | 45143c6f04c84e8a519aa24e4d79e9385b5d5e2f (patch) | |
| tree | b36a125db7a5861a14f61154b6200535548eee2a /src | |
| parent | d629a146f5d3a487fa666c0a51f9e0683dde76b8 (diff) | |
| download | zig-45143c6f04c84e8a519aa24e4d79e9385b5d5e2f.tar.gz zig-45143c6f04c84e8a519aa24e4d79e9385b5d5e2f.zip | |
MachO: emit absolute path in N_OSO stabs
This path being relative is unconventional and causes issues for us
if the output artifact is ever used from a different cwd than the one it
was built from. The behavior implemented by this commit of always
emitting these paths as absolute was actually the behavior in 0.14.x,
but it regressed in 0.15.1 due to internal reworks to path handling
which led to relative paths being more common in the compiler internals.
Resolves: #25433
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 16 | ||||
| -rw-r--r-- | src/link/MachO/Archive.zig | 24 | ||||
| -rw-r--r-- | src/link/MachO/Object.zig | 81 | ||||
| -rw-r--r-- | src/link/MachO/relocatable.zig | 2 |
4 files changed, 58 insertions, 65 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 3e7e3a4e8a..11127495ab 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -919,7 +919,16 @@ fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !v const tracy = trace(@src()); defer tracy.end(); - const gpa = self.base.comp.gpa; + const comp = self.base.comp; + const gpa = comp.gpa; + + const abs_path = try std.fs.path.resolvePosix(gpa, &.{ + comp.dirs.cwd, + path.root_dir.path orelse ".", + path.sub_path, + }); + errdefer gpa.free(abs_path); + const mtime: u64 = mtime: { const file = self.getFileHandle(handle); const stat = file.stat() catch break :mtime 0; @@ -928,10 +937,7 @@ fn addObject(self: *MachO, path: Path, handle: File.HandleIndex, offset: u64) !v const index = @as(File.Index, @intCast(try self.files.addOne(gpa))); self.files.set(index, .{ .object = .{ .offset = offset, - .path = .{ - .root_dir = path.root_dir, - .sub_path = try gpa.dupe(u8, path.sub_path), - }, + .path = abs_path, .file_handle = handle, .mtime = mtime, .index = index, diff --git a/src/link/MachO/Archive.zig b/src/link/MachO/Archive.zig index 007e630bfb..058efdbafc 100644 --- a/src/link/MachO/Archive.zig +++ b/src/link/MachO/Archive.zig @@ -5,8 +5,9 @@ pub fn deinit(self: *Archive, allocator: Allocator) void { } pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File.HandleIndex, fat_arch: ?fat.Arch) !void { - const gpa = macho_file.base.comp.gpa; - const diags = &macho_file.base.comp.link_diags; + const comp = macho_file.base.comp; + const gpa = comp.gpa; + const diags = &comp.link_diags; var arena = std.heap.ArenaAllocator.init(gpa); defer arena.deinit(); @@ -55,23 +56,30 @@ pub fn unpack(self: *Archive, macho_file: *MachO, path: Path, handle_index: File mem.eql(u8, name, SYMDEF_SORTED) or mem.eql(u8, name, SYMDEF64_SORTED)) continue; + const abs_path = try std.fs.path.resolvePosix(gpa, &.{ + comp.dirs.cwd, + path.root_dir.path orelse ".", + path.sub_path, + }); + errdefer gpa.free(abs_path); + + const o_basename = try gpa.dupe(u8, name); + errdefer gpa.free(o_basename); + const object: Object = .{ .offset = pos, .in_archive = .{ - .path = .{ - .root_dir = path.root_dir, - .sub_path = try gpa.dupe(u8, path.sub_path), - }, + .path = abs_path, .size = hdr_size, }, - .path = Path.initCwd(try gpa.dupe(u8, name)), + .path = o_basename, .file_handle = handle_index, .index = undefined, .alive = false, .mtime = hdr.date() catch 0, }; - log.debug("extracting object '{f}' from archive '{f}'", .{ object.path, path }); + log.debug("extracting object '{s}' from archive '{f}'", .{ o_basename, path }); try self.objects.append(gpa, object); } diff --git a/src/link/MachO/Object.zig b/src/link/MachO/Object.zig index 90d96b85d9..7cec09ba91 100644 --- a/src/link/MachO/Object.zig +++ b/src/link/MachO/Object.zig @@ -1,8 +1,9 @@ /// Non-zero for fat object files or archives offset: u64, -/// Archive files cannot contain subdirectories, so only the basename is needed -/// for output. However, the full path is kept for error reporting. -path: Path, +/// If `in_archive` is not `null`, this is the basename of the object in the archive. Otherwise, +/// this is a fully-resolved absolute path, because that is the path we need to embed in stabs to +/// ensure the output does not depend on its cwd. +path: []u8, file_handle: File.HandleIndex, mtime: u64, index: File.Index, @@ -41,8 +42,8 @@ output_symtab_ctx: MachO.SymtabCtx = .{}, output_ar_state: Archive.ArState = .{}, pub fn deinit(self: *Object, allocator: Allocator) void { - if (self.in_archive) |*ar| allocator.free(ar.path.sub_path); - allocator.free(self.path.sub_path); + if (self.in_archive) |*ar| allocator.free(ar.path); + allocator.free(self.path); for (self.sections.items(.relocs), self.sections.items(.subsections)) |*relocs, *sub| { relocs.deinit(allocator); sub.deinit(allocator); @@ -1703,7 +1704,7 @@ pub fn updateArSize(self: *Object, macho_file: *MachO) !void { pub fn writeAr(self: Object, ar_format: Archive.Format, macho_file: *MachO, writer: anytype) !void { // Header const size = try macho_file.cast(usize, self.output_ar_state.size); - const basename = std.fs.path.basename(self.path.sub_path); + const basename = std.fs.path.basename(self.path); try Archive.writeHeader(basename, size, ar_format, writer); // Data const file = macho_file.getFileHandle(self.file_handle); @@ -1756,12 +1757,7 @@ pub fn calcSymtabSize(self: *Object, macho_file: *MachO) void { self.calcStabsSize(macho_file); } -fn pathLen(path: Path) usize { - // +1 for the path separator - return (if (path.root_dir.path) |p| p.len + @intFromBool(path.sub_path.len != 0) else 0) + path.sub_path.len; -} - -pub fn calcStabsSize(self: *Object, macho_file: *MachO) void { +fn calcStabsSize(self: *Object, macho_file: *MachO) void { if (self.compile_unit) |cu| { const comp_dir = cu.getCompDir(self.*); const tu_name = cu.getTuName(self.*); @@ -1771,9 +1767,11 @@ pub fn calcStabsSize(self: *Object, macho_file: *MachO) void { self.output_symtab_ctx.strsize += @as(u32, @intCast(tu_name.len + 1)); // tu_name if (self.in_archive) |ar| { - self.output_symtab_ctx.strsize += @intCast(pathLen(ar.path) + 1 + self.path.basename().len + 1 + 1); + // "/path/to/archive.a(object.o)\x00" + self.output_symtab_ctx.strsize += @intCast(ar.path.len + self.path.len + 3); } else { - self.output_symtab_ctx.strsize += @intCast(pathLen(self.path) + 1); + // "/path/to/object.o\x00" + self.output_symtab_ctx.strsize += @intCast(self.path.len + 1); } for (self.symbols.items, 0..) |sym, i| { @@ -2018,7 +2016,7 @@ pub fn writeSymtab(self: Object, macho_file: *MachO, ctx: anytype) void { self.writeStabs(n_strx, macho_file, ctx); } -pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void { +fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) void { const writeFuncStab = struct { inline fn writeFuncStab( n_strx: u32, @@ -2103,38 +2101,20 @@ pub fn writeStabs(self: Object, stroff: u32, macho_file: *MachO, ctx: anytype) v }; index += 1; if (self.in_archive) |ar| { - if (ar.path.root_dir.path) |p| { - @memcpy(ctx.strtab.items[n_strx..][0..p.len], p); - n_strx += @intCast(p.len); - if (ar.path.sub_path.len != 0) { - ctx.strtab.items[n_strx] = '/'; - n_strx += 1; - } - } - @memcpy(ctx.strtab.items[n_strx..][0..ar.path.sub_path.len], ar.path.sub_path); - n_strx += @intCast(ar.path.sub_path.len); - ctx.strtab.items[n_strx] = '('; - n_strx += 1; - const basename = self.path.basename(); - @memcpy(ctx.strtab.items[n_strx..][0..basename.len], basename); - n_strx += @intCast(basename.len); - ctx.strtab.items[n_strx] = ')'; - n_strx += 1; - ctx.strtab.items[n_strx] = 0; + // "/path/to/archive.a(object.o)\x00" + @memcpy(ctx.strtab.items[n_strx..][0..ar.path.len], ar.path); + n_strx += @intCast(ar.path.len); + ctx.strtab.items[n_strx..][0] = '('; n_strx += 1; + @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path); + n_strx += @intCast(self.path.len); + ctx.strtab.items[n_strx..][0..2].* = ")\x00".*; + n_strx += 2; } else { - if (self.path.root_dir.path) |p| { - @memcpy(ctx.strtab.items[n_strx..][0..p.len], p); - n_strx += @intCast(p.len); - if (self.path.sub_path.len != 0) { - ctx.strtab.items[n_strx] = '/'; - n_strx += 1; - } - } - @memcpy(ctx.strtab.items[n_strx..][0..self.path.sub_path.len], self.path.sub_path); - n_strx += @intCast(self.path.sub_path.len); - ctx.strtab.items[n_strx] = 0; - n_strx += 1; + // "/path/to/object.o\x00" + @memcpy(ctx.strtab.items[n_strx..][0..self.path.len], self.path); + ctx.strtab.items[n_strx..][self.path.len] = 0; + n_strx += @intCast(self.path.len + 1); } for (self.symbols.items, 0..) |sym, i| { @@ -2621,11 +2601,9 @@ pub fn fmtPath(self: Object) std.fmt.Alt(Object, formatPath) { fn formatPath(object: Object, w: *Writer) Writer.Error!void { if (object.in_archive) |ar| { - try w.print("{f}({s})", .{ - ar.path, object.path.basename(), - }); + try w.print("{s}({s})", .{ ar.path, object.path }); } else { - try w.print("{f}", .{object.path}); + try w.writeAll(object.path); } } @@ -2716,7 +2694,9 @@ const CompileUnit = struct { }; const InArchive = struct { - path: Path, + /// This is a fully-resolved absolute path, because that is the path we need to embed in stabs + /// to ensure the output does not depend on its cwd. + path: []u8, size: u32, }; @@ -3094,7 +3074,6 @@ const log = std.log.scoped(.link); const macho = std.macho; const math = std.math; const mem = std.mem; -const Path = std.Build.Cache.Path; const Allocator = std.mem.Allocator; const Writer = std.Io.Writer; diff --git a/src/link/MachO/relocatable.zig b/src/link/MachO/relocatable.zig index 920125136b..09807a2845 100644 --- a/src/link/MachO/relocatable.zig +++ b/src/link/MachO/relocatable.zig @@ -191,7 +191,7 @@ pub fn flushStaticLib(macho_file: *MachO, comp: *Compilation, module_obj_path: ? pos = mem.alignForward(usize, pos, 2); state.file_off = pos; pos += @sizeOf(Archive.ar_hdr); - pos += mem.alignForward(usize, o.path.basename().len + 1, ptr_width); + pos += mem.alignForward(usize, std.fs.path.basename(o.path).len + 1, ptr_width); pos += try macho_file.cast(usize, state.size); }, else => unreachable, |
