| ... | @@ -275,18 +275,15 @@ pub const SrcFn = struct { | ... | @@ -275,18 +275,15 @@ pub const SrcFn = struct { |
| 275 | }; | 275 | }; |
| 276 | }; | 276 | }; |
| 277 | | 277 | |
| 278 | pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Options) !*MachO { | 278 | pub fn openPath(allocator: *Allocator, options: link.Options) !*MachO { |
| 279 | assert(options.object_format == .macho); | 279 | assert(options.object_format == .macho); |
| 280 | | 280 | |
| 281 | if (build_options.have_llvm and options.use_llvm) { | 281 | const use_stage1 = build_options.is_stage1 and options.use_stage1; |
| 282 | const self = try createEmpty(allocator, options); | 282 | if (use_stage1 or options.emit == null) { |
| 283 | errdefer self.base.destroy(); | 283 | return createEmpty(allocator, options); |
| 284 | | | |
| 285 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); | | |
| 286 | return self; | | |
| 287 | } | 284 | } |
| 288 | | 285 | const emit = options.emit.?; |
| 289 | const file = try options.emit.?.directory.handle.createFile(sub_path, .{ | 286 | const file = try emit.directory.handle.createFile(emit.sub_path, .{ |
| 290 | .truncate = false, | 287 | .truncate = false, |
| 291 | .read = true, | 288 | .read = true, |
| 292 | .mode = link.determineMode(options), | 289 | .mode = link.determineMode(options), |
| ... | @@ -301,7 +298,20 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio | ... | @@ -301,7 +298,20 @@ pub fn openPath(allocator: *Allocator, sub_path: []const u8, options: link.Optio |
| 301 | | 298 | |
| 302 | self.base.file = file; | 299 | self.base.file = file; |
| 303 | | 300 | |
| 304 | if (options.output_mode == .Lib and options.link_mode == .Static) { | 301 | if (build_options.have_llvm and options.use_llvm and options.module != null) { |
| | 302 | // TODO this intermediary_basename isn't enough; in the case of `zig build-exe`, |
| | 303 | // we also want to put the intermediary object file in the cache while the |
| | 304 | // main emit directory is the cwd. |
| | 305 | const sub_path = try std.fmt.allocPrint(allocator, "{s}{s}", .{ |
| | 306 | emit.sub_path, options.object_format.fileExt(options.target.cpu.arch), |
| | 307 | }); |
| | 308 | self.llvm_object = try LlvmObject.create(allocator, sub_path, options); |
| | 309 | self.base.intermediary_basename = sub_path; |
| | 310 | } |
| | 311 | |
| | 312 | if (options.output_mode == .Lib and |
| | 313 | options.link_mode == .Static and self.base.intermediary_basename != null) |
| | 314 | { |
| 305 | return self; | 315 | return self; |
| 306 | } | 316 | } |
| 307 | | 317 | |
| ... | @@ -384,16 +394,22 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -384,16 +394,22 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 384 | return error.TODOImplementWritingStaticLibFiles; | 394 | return error.TODOImplementWritingStaticLibFiles; |
| 385 | } | 395 | } |
| 386 | } | 396 | } |
| | 397 | try self.flushModule(comp); |
| | 398 | } |
| 387 | | 399 | |
| | 400 | pub fn flushModule(self: *MachO, comp: *Compilation) !void { |
| 388 | const tracy = trace(@src()); | 401 | const tracy = trace(@src()); |
| 389 | defer tracy.end(); | 402 | defer tracy.end(); |
| 390 | | 403 | |
| | 404 | const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; |
| | 405 | if (!use_stage1 and self.base.options.output_mode == .Obj) |
| | 406 | return self.flushObject(comp); |
| | 407 | |
| 391 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); | 408 | var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator); |
| 392 | defer arena_allocator.deinit(); | 409 | defer arena_allocator.deinit(); |
| 393 | const arena = &arena_allocator.allocator; | 410 | const arena = &arena_allocator.allocator; |
| 394 | | 411 | |
| 395 | const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. | 412 | const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type. |
| 396 | const use_stage1 = build_options.is_stage1 and self.base.options.use_stage1; | | |
| 397 | | 413 | |
| 398 | // If there is no Zig code to compile, then we should skip flushing the output file because it | 414 | // If there is no Zig code to compile, then we should skip flushing the output file because it |
| 399 | // will not be part of the linker line anyway. | 415 | // will not be part of the linker line anyway. |
| ... | @@ -410,7 +426,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -410,7 +426,7 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 410 | } | 426 | } |
| 411 | | 427 | |
| 412 | const obj_basename = self.base.intermediary_basename orelse break :blk null; | 428 | const obj_basename = self.base.intermediary_basename orelse break :blk null; |
| 413 | try self.flushModule(comp); | 429 | try self.flushObject(comp); |
| 414 | const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename}); | 430 | const full_obj_path = try directory.join(arena, &[_][]const u8{obj_basename}); |
| 415 | break :blk full_obj_path; | 431 | break :blk full_obj_path; |
| 416 | } else null; | 432 | } else null; |
| ... | @@ -534,15 +550,16 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -534,15 +550,16 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 534 | .read = true, | 550 | .read = true, |
| 535 | .mode = link.determineMode(self.base.options), | 551 | .mode = link.determineMode(self.base.options), |
| 536 | }); | 552 | }); |
| 537 | try self.populateMissingMetadata(); | 553 | // Index 0 is always a null symbol. |
| 538 | try self.locals.append(self.base.allocator, .{ | 554 | try self.locals.append(self.base.allocator, .{ |
| 539 | .n_strx = 0, | 555 | .n_strx = 0, |
| 540 | .n_type = macho.N_UNDF, | 556 | .n_type = 0, |
| 541 | .n_sect = 0, | 557 | .n_sect = 0, |
| 542 | .n_desc = 0, | 558 | .n_desc = 0, |
| 543 | .n_value = 0, | 559 | .n_value = 0, |
| 544 | }); | 560 | }); |
| 545 | try self.strtab.append(self.base.allocator, 0); | 561 | try self.strtab.append(self.base.allocator, 0); |
| | 562 | try self.populateMissingMetadata(); |
| 546 | } | 563 | } |
| 547 | | 564 | |
| 548 | if (needs_full_relink) { | 565 | if (needs_full_relink) { |
| ... | @@ -887,7 +904,40 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -887,7 +904,40 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 887 | sect.offset = 0; | 904 | sect.offset = 0; |
| 888 | } | 905 | } |
| 889 | | 906 | |
| 890 | try self.flushModule(comp); | 907 | try self.setEntryPoint(); |
| | 908 | try self.updateSectionOrdinals(); |
| | 909 | try self.writeLinkeditSegment(); |
| | 910 | |
| | 911 | if (self.d_sym) |*ds| { |
| | 912 | // Flush debug symbols bundle. |
| | 913 | try ds.flushModule(self.base.allocator, self.base.options); |
| | 914 | } |
| | 915 | |
| | 916 | if (self.requires_adhoc_codesig) { |
| | 917 | // Preallocate space for the code signature. |
| | 918 | // We need to do this at this stage so that we have the load commands with proper values |
| | 919 | // written out to the file. |
| | 920 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment |
| | 921 | // where the code signature goes into. |
| | 922 | try self.writeCodeSignaturePadding(); |
| | 923 | } |
| | 924 | |
| | 925 | try self.writeLoadCommands(); |
| | 926 | try self.writeHeader(); |
| | 927 | |
| | 928 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { |
| | 929 | log.debug("flushing. no_entry_point_found = true", .{}); |
| | 930 | self.error_flags.no_entry_point_found = true; |
| | 931 | } else { |
| | 932 | log.debug("flushing. no_entry_point_found = false", .{}); |
| | 933 | self.error_flags.no_entry_point_found = false; |
| | 934 | } |
| | 935 | |
| | 936 | assert(!self.load_commands_dirty); |
| | 937 | |
| | 938 | if (self.requires_adhoc_codesig) { |
| | 939 | try self.writeCodeSignature(); // code signing always comes last |
| | 940 | } |
| 891 | } | 941 | } |
| 892 | | 942 | |
| 893 | cache: { | 943 | cache: { |
| ... | @@ -909,46 +959,14 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { | ... | @@ -909,46 +959,14 @@ pub fn flush(self: *MachO, comp: *Compilation) !void { |
| 909 | self.cold_start = false; | 959 | self.cold_start = false; |
| 910 | } | 960 | } |
| 911 | | 961 | |
| 912 | pub fn flushModule(self: *MachO, comp: *Compilation) !void { | 962 | pub fn flushObject(self: *MachO, comp: *Compilation) !void { |
| 913 | _ = comp; | | |
| 914 | | | |
| 915 | const tracy = trace(@src()); | 963 | const tracy = trace(@src()); |
| 916 | defer tracy.end(); | 964 | defer tracy.end(); |
| 917 | | 965 | |
| 918 | try self.setEntryPoint(); | 966 | if (build_options.have_llvm) |
| 919 | try self.updateSectionOrdinals(); | 967 | if (self.llvm_object) |llvm_object| return llvm_object.flushModule(comp); |
| 920 | try self.writeLinkeditSegment(); | | |
| 921 | | | |
| 922 | if (self.d_sym) |*ds| { | | |
| 923 | // Flush debug symbols bundle. | | |
| 924 | try ds.flushModule(self.base.allocator, self.base.options); | | |
| 925 | } | | |
| 926 | | | |
| 927 | if (self.requires_adhoc_codesig) { | | |
| 928 | // Preallocate space for the code signature. | | |
| 929 | // We need to do this at this stage so that we have the load commands with proper values | | |
| 930 | // written out to the file. | | |
| 931 | // The most important here is to have the correct vm and filesize of the __LINKEDIT segment | | |
| 932 | // where the code signature goes into. | | |
| 933 | try self.writeCodeSignaturePadding(); | | |
| 934 | } | | |
| 935 | | | |
| 936 | try self.writeLoadCommands(); | | |
| 937 | try self.writeHeader(); | | |
| 938 | | 968 | |
| 939 | if (self.entry_addr == null and self.base.options.output_mode == .Exe) { | 969 | return error.TODOImplementWritingObjFiles; |
| 940 | log.debug("flushing. no_entry_point_found = true", .{}); | | |
| 941 | self.error_flags.no_entry_point_found = true; | | |
| 942 | } else { | | |
| 943 | log.debug("flushing. no_entry_point_found = false", .{}); | | |
| 944 | self.error_flags.no_entry_point_found = false; | | |
| 945 | } | | |
| 946 | | | |
| 947 | assert(!self.load_commands_dirty); | | |
| 948 | | | |
| 949 | if (self.requires_adhoc_codesig) { | | |
| 950 | try self.writeCodeSignature(); // code signing always comes last | | |
| 951 | } | | |
| 952 | } | 970 | } |
| 953 | | 971 | |
| 954 | fn resolveSearchDir( | 972 | fn resolveSearchDir( |
| ... | @@ -3035,6 +3053,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match | ... | @@ -3035,6 +3053,7 @@ fn growAtom(self: *MachO, atom: *Atom, new_atom_size: u64, alignment: u64, match |
| 3035 | } | 3053 | } |
| 3036 | | 3054 | |
| 3037 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { | 3055 | pub fn allocateDeclIndexes(self: *MachO, decl: *Module.Decl) !void { |
| | 3056 | if (self.llvm_object) |_| return; |
| 3038 | if (decl.link.macho.local_sym_index != 0) return; | 3057 | if (decl.link.macho.local_sym_index != 0) return; |
| 3039 | | 3058 | |
| 3040 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); | 3059 | try self.locals.ensureUnusedCapacity(self.base.allocator, 1); |
| ... | @@ -3458,6 +3477,7 @@ pub fn updateDeclExports( | ... | @@ -3458,6 +3477,7 @@ pub fn updateDeclExports( |
| 3458 | } | 3477 | } |
| 3459 | | 3478 | |
| 3460 | pub fn deleteExport(self: *MachO, exp: Export) void { | 3479 | pub fn deleteExport(self: *MachO, exp: Export) void { |
| | 3480 | if (self.llvm_object) |_| return; |
| 3461 | const sym_index = exp.sym_index orelse return; | 3481 | const sym_index = exp.sym_index orelse return; |
| 3462 | self.globals_free_list.append(self.base.allocator, sym_index) catch {}; | 3482 | self.globals_free_list.append(self.base.allocator, sym_index) catch {}; |
| 3463 | const global = &self.globals.items[sym_index]; | 3483 | const global = &self.globals.items[sym_index]; |