authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-18 19:05:06+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-03-18 19:05:06+01:00
log46171bf6c89dc2c2b8f155c8511b62e5cd52e3bc
tree7ae0f3662be1266e37bb8ef4ede4fe5ebe5c4b6f
parentee705e3ac71205142a4457acd2677f7be921d62b

macho+zld: clean up how to interface with link.zig and openPath()


1 files changed, 42 insertions(+), 27 deletions(-)

src/link/MachO.zig+42-27
...@@ -60,6 +60,17 @@ pub const SearchStrategy = enum {...@@ -60,6 +60,17 @@ pub const SearchStrategy = enum {
60 dylibs_first,60 dylibs_first,
61};61};
6262
63/// Mode of operation of the linker.
64pub const Mode = enum {
65 /// Incremental mode will preallocate segments/sections and is compatible with
66 /// watch and HCS modes of operation.
67 incremental,
68 /// Zld mode will link relocatables in a traditional, one-shot
69 /// fashion (default for LLVM backend). It acts as a drop-in replacement for
70 /// LLD.
71 zld,
72};
73
63const Section = struct {74const Section = struct {
64 header: macho.section_64,75 header: macho.section_64,
65 segment_index: u8,76 segment_index: u8,
...@@ -98,10 +109,7 @@ d_sym: ?DebugSymbols = null,...@@ -98,10 +109,7 @@ d_sym: ?DebugSymbols = null,
98/// For x86_64 that's 4KB, whereas for aarch64, that's 16KB.109/// For x86_64 that's 4KB, whereas for aarch64, that's 16KB.
99page_size: u16,110page_size: u16,
100111
101/// Mode of operation: incremental - will preallocate segments/sections and is compatible with112mode: Mode,
102/// watch and HCS modes of operation; one_shot - will link relocatables in a traditional, one-shot
103/// fashion (default for LLVM backend).
104mode: enum { incremental, one_shot },
105113
106dyld_info_cmd: macho.dyld_info_command = .{},114dyld_info_cmd: macho.dyld_info_command = .{},
107symtab_cmd: macho.symtab_command = .{},115symtab_cmd: macho.symtab_command = .{},
...@@ -314,33 +322,42 @@ pub const default_headerpad_size: u32 = 0x1000;...@@ -314,33 +322,42 @@ pub const default_headerpad_size: u32 = 0x1000;
314pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {322pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
315 assert(options.target.ofmt == .macho);323 assert(options.target.ofmt == .macho);
316324
317 if (options.emit == null or options.module == null) {325 if (options.emit == null) {
318 return createEmpty(allocator, options);326 return createEmpty(allocator, options);
319 }327 }
320328
321 const emit = options.emit.?;329 const emit = options.emit.?;
330 const mode: Mode = mode: {
331 if (options.use_llvm or options.module == null or options.cache_mode == .whole)
332 break :mode .zld;
333 break :mode .incremental;
334 };
335 const sub_path = if (mode == .zld) blk: {
336 if (options.module == null) {
337 // No point in opening a file, we would not write anything to it.
338 // Initialize with empty.
339 return createEmpty(allocator, options);
340 }
341 // Open a temporary object file, not the final output file because we
342 // want to link with LLD.
343 break :blk try std.fmt.allocPrint(allocator, "{s}{s}", .{
344 emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
345 });
346 } else emit.sub_path;
347 errdefer if (mode == .zld) allocator.free(sub_path);
348
322 const self = try createEmpty(allocator, options);349 const self = try createEmpty(allocator, options);
323 errdefer {350 errdefer self.base.destroy();
324 self.base.file = null;
325 self.base.destroy();
326 }
327351
328 if (build_options.have_llvm and options.use_llvm and options.module != null) {352 if (mode == .zld) {
329 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,353 // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`,
330 // we also want to put the intermediary object file in the cache while the354 // we also want to put the intermediary object file in the cache while the
331 // main emit directory is the cwd.355 // main emit directory is the cwd.
332 self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{356 self.base.intermediary_basename = sub_path;
333 emit.sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),357 return self;
334 });
335 }358 }
336359
337 if (self.base.intermediary_basename != null) switch (options.output_mode) {360 const file = try emit.directory.handle.createFile(sub_path, .{
338 .Obj => return self,
339 .Lib => if (options.link_mode == .Static) return self,
340 else => {},
341 };
342
343 const file = try emit.directory.handle.createFile(emit.sub_path, .{
344 .truncate = false,361 .truncate = false,
345 .read = true,362 .read = true,
346 .mode = link.determineMode(options),363 .mode = link.determineMode(options),
...@@ -348,23 +365,21 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {...@@ -348,23 +365,21 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
348 errdefer file.close();365 errdefer file.close();
349 self.base.file = file;366 self.base.file = file;
350367
351 if (self.mode == .one_shot) return self;
352
353 if (!options.strip and options.module != null) {368 if (!options.strip and options.module != null) {
354 // Create dSYM bundle.369 // Create dSYM bundle.
355 log.debug("creating {s}.dSYM bundle", .{emit.sub_path});370 log.debug("creating {s}.dSYM bundle", .{sub_path});
356371
357 const d_sym_path = try fmt.allocPrint(372 const d_sym_path = try fmt.allocPrint(
358 allocator,373 allocator,
359 "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",374 "{s}.dSYM" ++ fs.path.sep_str ++ "Contents" ++ fs.path.sep_str ++ "Resources" ++ fs.path.sep_str ++ "DWARF",
360 .{emit.sub_path},375 .{sub_path},
361 );376 );
362 defer allocator.free(d_sym_path);377 defer allocator.free(d_sym_path);
363378
364 var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});379 var d_sym_bundle = try emit.directory.handle.makeOpenPath(d_sym_path, .{});
365 defer d_sym_bundle.close();380 defer d_sym_bundle.close();
366381
367 const d_sym_file = try d_sym_bundle.createFile(emit.sub_path, .{382 const d_sym_file = try d_sym_bundle.createFile(sub_path, .{
368 .truncate = false,383 .truncate = false,
369 .read = true,384 .read = true,
370 });385 });
...@@ -413,7 +428,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {...@@ -413,7 +428,7 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*MachO {
413 },428 },
414 .page_size = page_size,429 .page_size = page_size,
415 .mode = if (use_llvm or options.module == null or options.cache_mode == .whole)430 .mode = if (use_llvm or options.module == null or options.cache_mode == .whole)
416 .one_shot431 .zld
417 else432 else
418 .incremental,433 .incremental,
419 };434 };
...@@ -447,7 +462,7 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) li...@@ -447,7 +462,7 @@ pub fn flush(self: *MachO, comp: *Compilation, prog_node: *std.Progress.Node) li
447 }462 }
448463
449 switch (self.mode) {464 switch (self.mode) {
450 .one_shot => return zld.linkWithZld(self, comp, prog_node),465 .zld => return zld.linkWithZld(self, comp, prog_node),
451 .incremental => return self.flushModule(comp, prog_node),466 .incremental => return self.flushModule(comp, prog_node),
452 }467 }
453}468}