authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-13 15:12:28+02:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-08-14 21:56:41+02:00
log819ef521042e7e21db4ab5dd7a0dbe180bd31c57
tree716072fe0f7956bd67c44fa1ff58ae9a5bc59b2d
parente9bf8014bd29360353a9bfdff4aa9d5a45bc59f6

macho: merge linkWithZld with flush


1 files changed, 208 insertions(+), 215 deletions(-)

src/link/MachO.zig+208-215
...@@ -415,171 +415,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {...@@ -415,171 +415,6 @@ pub fn flush(self: *MachO, comp: *Compilation) !void {
415 }415 }
416 }416 }
417417
418 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
419 if (use_stage1) {
420 return self.linkWithZld(comp);
421 } else {
422 switch (self.base.options.effectiveOutputMode()) {
423 .Exe, .Obj => {},
424 .Lib => return error.TODOImplementWritingLibFiles,
425 }
426 return self.flushModule(comp);
427 }
428}
429
430pub fn flushModule(self: *MachO, comp: *Compilation) !void {
431 _ = comp;
432 const tracy = trace(@src());
433 defer tracy.end();
434
435 const output_mode = self.base.options.output_mode;
436 const target = self.base.options.target;
437
438 switch (output_mode) {
439 .Exe => {
440 if (self.entry_addr) |addr| {
441 // Update LC_MAIN with entry offset.
442 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
443 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
444 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
445 main_cmd.stacksize = self.base.options.stack_size_override orelse 0;
446 self.load_commands_dirty = true;
447 }
448 try self.writeRebaseInfoTable();
449 try self.writeBindInfoTable();
450 try self.writeLazyBindInfoTable();
451 try self.writeExportInfo();
452 try self.writeAllGlobalAndUndefSymbols();
453 try self.writeIndirectSymbolTable();
454 try self.writeStringTable();
455 try self.updateLinkeditSegmentSizes();
456
457 if (self.d_sym) |*ds| {
458 // Flush debug symbols bundle.
459 try ds.flushModule(self.base.allocator, self.base.options);
460 }
461
462 if (target.cpu.arch == .aarch64) {
463 // Preallocate space for the code signature.
464 // We need to do this at this stage so that we have the load commands with proper values
465 // written out to the file.
466 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
467 // where the code signature goes into.
468 try self.writeCodeSignaturePadding();
469 }
470 },
471 .Obj => {},
472 .Lib => return error.TODOImplementWritingLibFiles,
473 }
474
475 try self.writeLoadCommands();
476 try self.writeHeader();
477
478 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
479 log.debug("flushing. no_entry_point_found = true", .{});
480 self.error_flags.no_entry_point_found = true;
481 } else {
482 log.debug("flushing. no_entry_point_found = false", .{});
483 self.error_flags.no_entry_point_found = false;
484 }
485
486 assert(!self.got_entries_count_dirty);
487 assert(!self.load_commands_dirty);
488 assert(!self.rebase_info_dirty);
489 assert(!self.binding_info_dirty);
490 assert(!self.lazy_binding_info_dirty);
491 assert(!self.export_info_dirty);
492 assert(!self.strtab_dirty);
493 assert(!self.strtab_needs_relocation);
494
495 if (target.cpu.arch == .aarch64) {
496 switch (output_mode) {
497 .Exe, .Lib => try self.writeCodeSignature(), // code signing always comes last
498 else => {},
499 }
500 }
501}
502
503fn resolveSearchDir(
504 arena: *Allocator,
505 dir: []const u8,
506 syslibroot: ?[]const u8,
507) !?[]const u8 {
508 var candidates = std.ArrayList([]const u8).init(arena);
509
510 if (fs.path.isAbsolute(dir)) {
511 if (syslibroot) |root| {
512 const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir });
513 try candidates.append(full_path);
514 }
515 }
516
517 try candidates.append(dir);
518
519 for (candidates.items) |candidate| {
520 // Verify that search path actually exists
521 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
522 error.FileNotFound => continue,
523 else => |e| return e,
524 };
525 defer tmp.close();
526
527 return candidate;
528 }
529
530 return null;
531}
532
533fn resolveLib(
534 arena: *Allocator,
535 search_dirs: []const []const u8,
536 name: []const u8,
537 ext: []const u8,
538) !?[]const u8 {
539 const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext });
540
541 for (search_dirs) |dir| {
542 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name });
543
544 // Check if the file exists.
545 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
546 error.FileNotFound => continue,
547 else => |e| return e,
548 };
549 defer tmp.close();
550
551 return full_path;
552 }
553
554 return null;
555}
556
557fn resolveFramework(
558 arena: *Allocator,
559 search_dirs: []const []const u8,
560 name: []const u8,
561 ext: []const u8,
562) !?[]const u8 {
563 const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext });
564 const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name});
565
566 for (search_dirs) |dir| {
567 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name });
568
569 // Check if the file exists.
570 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
571 error.FileNotFound => continue,
572 else => |e| return e,
573 };
574 defer tmp.close();
575
576 return full_path;
577 }
578
579 return null;
580}
581
582fn linkWithZld(self: *MachO, comp: *Compilation) !void {
583 const tracy = trace(@src());418 const tracy = trace(@src());
584 defer tracy.end();419 defer tracy.end();
585420
...@@ -588,11 +423,11 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -588,11 +423,11 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
588 const arena = &arena_allocator.allocator;423 const arena = &arena_allocator.allocator;
589424
590 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.425 const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
426 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
591427
592 // If there is no Zig code to compile, then we should skip flushing the output file because it428 // If there is no Zig code to compile, then we should skip flushing the output file because it
593 // will not be part of the linker line anyway.429 // will not be part of the linker line anyway.
594 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {430 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
595 const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1;
596 if (use_stage1) {431 if (use_stage1) {
597 const obj_basename = try std.zig.binNameAlloc(arena, .{432 const obj_basename = try std.zig.binNameAlloc(arena, .{
598 .root_name = self.base.options.root_name,433 .root_name = self.base.options.root_name,
...@@ -604,8 +439,8 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -604,8 +439,8 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
604 break :blk full_obj_path;439 break :blk full_obj_path;
605 }440 }
606441
442 const obj_basename = self.base.intermediary_basename orelse break :blk null;
607 try self.flushModule(comp);443 try self.flushModule(comp);
608 const obj_basename = self.base.intermediary_basename.?;
609 const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});444 const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename});
610 break :blk full_obj_path;445 break :blk full_obj_path;
611 } else null;446 } else null;
...@@ -714,7 +549,9 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -714,7 +549,9 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
714 try positionals.append(p);549 try positionals.append(p);
715 }550 }
716551
717 try positionals.append(comp.compiler_rt_static_lib.?.full_object_path);552 if (comp.compiler_rt_static_lib) |lib| {
553 try positionals.append(lib.full_object_path);
554 }
718555
719 // libc++ dep556 // libc++ dep
720 if (self.base.options.link_libcpp) {557 if (self.base.options.link_libcpp) {
...@@ -899,56 +736,60 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -899,56 +736,60 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
899 Compilation.dump_argv(argv.items);736 Compilation.dump_argv(argv.items);
900 }737 }
901738
902 const sub_path = self.base.options.emit.?.sub_path;739 if (use_stage1) {
903 self.base.file = try directory.handle.createFile(sub_path, .{740 const sub_path = self.base.options.emit.?.sub_path;
904 .truncate = true,741 self.base.file = try directory.handle.createFile(sub_path, .{
905 .read = true,742 .truncate = true,
906 .mode = link.determineMode(self.base.options),743 .read = true,
907 });744 .mode = link.determineMode(self.base.options),
745 });
908746
909 // TODO mimicking insertion of null symbol from incremental linker.747 // TODO mimicking insertion of null symbol from incremental linker.
910 // This will need to moved.748 // This will need to moved.
911 try self.locals.append(self.base.allocator, .{749 try self.locals.append(self.base.allocator, .{
912 .n_strx = 0,750 .n_strx = 0,
913 .n_type = macho.N_UNDF,751 .n_type = macho.N_UNDF,
914 .n_sect = 0,752 .n_sect = 0,
915 .n_desc = 0,753 .n_desc = 0,
916 .n_value = 0,754 .n_value = 0,
917 });755 });
918 try self.strtab.append(self.base.allocator, 0);756 try self.strtab.append(self.base.allocator, 0);
757
758 try self.populateMetadata();
759 try self.addRpathLCs(rpaths.items);
760 try self.parseInputFiles(positionals.items, self.base.options.sysroot);
761 try self.parseLibs(libs.items, self.base.options.sysroot);
762 try self.resolveSymbols();
763 try self.parseTextBlocks();
764 try self.addLoadDylibLCs();
765 try self.addDataInCodeLC();
766 try self.addCodeSignatureLC();
919767
920 try self.populateMetadata();768 {
921 try self.addRpathLCs(rpaths.items);769 // Add dyld_stub_binder as the final GOT entry.
922 try self.parseInputFiles(positionals.items, self.base.options.sysroot);770 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{
923 try self.parseLibs(libs.items, self.base.options.sysroot);771 .strtab = &self.strtab,
924 try self.resolveSymbols();772 }) orelse unreachable;
925 try self.parseTextBlocks();773 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
926 try self.addLoadDylibLCs();774 const got_index = @intCast(u32, self.got_entries.items.len);
927 try self.addDataInCodeLC();775 const got_entry = GotIndirectionKey{
928 try self.addCodeSignatureLC();776 .where = .undef,
929777 .where_index = resolv.where_index,
930 {778 };
931 // Add dyld_stub_binder as the final GOT entry.779 try self.got_entries.append(self.base.allocator, got_entry);
932 const n_strx = self.strtab_dir.getAdapted(@as([]const u8, "dyld_stub_binder"), StringSliceAdapter{780 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index);
933 .strtab = &self.strtab,781 }
934 }) orelse unreachable;
935 const resolv = self.symbol_resolver.get(n_strx) orelse unreachable;
936 const got_index = @intCast(u32, self.got_entries.items.len);
937 const got_entry = GotIndirectionKey{
938 .where = .undef,
939 .where_index = resolv.where_index,
940 };
941 try self.got_entries.append(self.base.allocator, got_entry);
942 try self.got_entries_map.putNoClobber(self.base.allocator, got_entry, got_index);
943 }
944782
945 try self.sortSections();783 try self.sortSections();
946 try self.allocateTextSegment();784 try self.allocateTextSegment();
947 try self.allocateDataConstSegment();785 try self.allocateDataConstSegment();
948 try self.allocateDataSegment();786 try self.allocateDataSegment();
949 self.allocateLinkeditSegment();787 self.allocateLinkeditSegment();
950 try self.allocateTextBlocks();788 try self.allocateTextBlocks();
951 try self.flushZld();789 try self.flushZld();
790 } else {
791 try self.flushModule(comp);
792 }
952 }793 }
953794
954 if (!self.base.options.disable_lld_caching) {795 if (!self.base.options.disable_lld_caching) {
...@@ -967,6 +808,158 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {...@@ -967,6 +808,158 @@ fn linkWithZld(self: *MachO, comp: *Compilation) !void {
967 }808 }
968}809}
969810
811pub fn flushModule(self: *MachO, comp: *Compilation) !void {
812 _ = comp;
813 const tracy = trace(@src());
814 defer tracy.end();
815
816 const output_mode = self.base.options.output_mode;
817 const target = self.base.options.target;
818
819 switch (output_mode) {
820 .Exe => {
821 if (self.entry_addr) |addr| {
822 // Update LC_MAIN with entry offset.
823 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
824 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
825 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
826 main_cmd.stacksize = self.base.options.stack_size_override orelse 0;
827 self.load_commands_dirty = true;
828 }
829 try self.writeRebaseInfoTable();
830 try self.writeBindInfoTable();
831 try self.writeLazyBindInfoTable();
832 try self.writeExportInfo();
833 try self.writeAllGlobalAndUndefSymbols();
834 try self.writeIndirectSymbolTable();
835 try self.writeStringTable();
836 try self.updateLinkeditSegmentSizes();
837
838 if (self.d_sym) |*ds| {
839 // Flush debug symbols bundle.
840 try ds.flushModule(self.base.allocator, self.base.options);
841 }
842
843 if (target.cpu.arch == .aarch64) {
844 // Preallocate space for the code signature.
845 // We need to do this at this stage so that we have the load commands with proper values
846 // written out to the file.
847 // The most important here is to have the correct vm and filesize of the __LINKEDIT segment
848 // where the code signature goes into.
849 try self.writeCodeSignaturePadding();
850 }
851 },
852 .Obj => {},
853 .Lib => return error.TODOImplementWritingLibFiles,
854 }
855
856 try self.writeLoadCommands();
857 try self.writeHeader();
858
859 if (self.entry_addr == null and self.base.options.output_mode == .Exe) {
860 log.debug("flushing. no_entry_point_found = true", .{});
861 self.error_flags.no_entry_point_found = true;
862 } else {
863 log.debug("flushing. no_entry_point_found = false", .{});
864 self.error_flags.no_entry_point_found = false;
865 }
866
867 assert(!self.got_entries_count_dirty);
868 assert(!self.load_commands_dirty);
869 assert(!self.rebase_info_dirty);
870 assert(!self.binding_info_dirty);
871 assert(!self.lazy_binding_info_dirty);
872 assert(!self.export_info_dirty);
873 assert(!self.strtab_dirty);
874 assert(!self.strtab_needs_relocation);
875
876 if (target.cpu.arch == .aarch64) {
877 switch (output_mode) {
878 .Exe, .Lib => try self.writeCodeSignature(), // code signing always comes last
879 else => {},
880 }
881 }
882}
883
884fn resolveSearchDir(
885 arena: *Allocator,
886 dir: []const u8,
887 syslibroot: ?[]const u8,
888) !?[]const u8 {
889 var candidates = std.ArrayList([]const u8).init(arena);
890
891 if (fs.path.isAbsolute(dir)) {
892 if (syslibroot) |root| {
893 const full_path = try fs.path.join(arena, &[_][]const u8{ root, dir });
894 try candidates.append(full_path);
895 }
896 }
897
898 try candidates.append(dir);
899
900 for (candidates.items) |candidate| {
901 // Verify that search path actually exists
902 var tmp = fs.cwd().openDir(candidate, .{}) catch |err| switch (err) {
903 error.FileNotFound => continue,
904 else => |e| return e,
905 };
906 defer tmp.close();
907
908 return candidate;
909 }
910
911 return null;
912}
913
914fn resolveLib(
915 arena: *Allocator,
916 search_dirs: []const []const u8,
917 name: []const u8,
918 ext: []const u8,
919) !?[]const u8 {
920 const search_name = try std.fmt.allocPrint(arena, "lib{s}{s}", .{ name, ext });
921
922 for (search_dirs) |dir| {
923 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, search_name });
924
925 // Check if the file exists.
926 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
927 error.FileNotFound => continue,
928 else => |e| return e,
929 };
930 defer tmp.close();
931
932 return full_path;
933 }
934
935 return null;
936}
937
938fn resolveFramework(
939 arena: *Allocator,
940 search_dirs: []const []const u8,
941 name: []const u8,
942 ext: []const u8,
943) !?[]const u8 {
944 const search_name = try std.fmt.allocPrint(arena, "{s}{s}", .{ name, ext });
945 const prefix_path = try std.fmt.allocPrint(arena, "{s}.framework", .{name});
946
947 for (search_dirs) |dir| {
948 const full_path = try fs.path.join(arena, &[_][]const u8{ dir, prefix_path, search_name });
949
950 // Check if the file exists.
951 const tmp = fs.cwd().openFile(full_path, .{}) catch |err| switch (err) {
952 error.FileNotFound => continue,
953 else => |e| return e,
954 };
955 defer tmp.close();
956
957 return full_path;
958 }
959
960 return null;
961}
962
970fn parseObject(self: *MachO, path: []const u8) !bool {963fn parseObject(self: *MachO, path: []const u8) !bool {
971 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {964 const file = fs.cwd().openFile(path, .{}) catch |err| switch (err) {
972 error.FileNotFound => return false,965 error.FileNotFound => return false,