authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-01 12:13:46+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2024-02-03 09:25:41+01:00
log352941b0308057b434f6db664e66a9ea793fac95
tree65838d3845e584b0ca65f42d85582b14a78e102b
parentf2e249e92020462ac29f34fc3d45cef3dc90a3b2

macho: emit incomplete object file


2 files changed, 63 insertions(+), 38 deletions(-)

src/link/MachO.zig+32-27
...@@ -285,8 +285,7 @@ pub fn createEmpty(...@@ -285,8 +285,7 @@ pub fn createEmpty(
285 };285 };
286 try self.d_sym.?.initMetadata(self);286 try self.d_sym.?.initMetadata(self);
287 } else {287 } else {
288 try self.reportUnexpectedError("TODO: implement generating and emitting __DWARF in .o file", .{});288 @panic("TODO: implement generating and emitting __DWARF in .o file");
289 return error.Unexpected;
290 },289 },
291 .code_view => unreachable,290 .code_view => unreachable,
292 }291 }
...@@ -2025,7 +2024,7 @@ pub fn sortSections(self: *MachO) !void {...@@ -2025,7 +2024,7 @@ pub fn sortSections(self: *MachO) !void {
20252024
2026 for (zo.symtab.items(.nlist)) |*sym| {2025 for (zo.symtab.items(.nlist)) |*sym| {
2027 if (sym.sect()) {2026 if (sym.sect()) {
2028 sym.n_sect = backlinks[sym.n_sect];2027 sym.n_sect = backlinks[sym.n_sect - 1] + 1;
2029 }2028 }
2030 }2029 }
20312030
...@@ -3391,8 +3390,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3391,8 +3390,6 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3391 .prot = macho.PROT.READ | macho.PROT.WRITE,3390 .prot = macho.PROT.READ | macho.PROT.WRITE,
3392 });3391 });
3393 }3392 }
3394 } else {
3395 @panic("TODO initMetadata when relocatable");
3396 }3393 }
33973394
3398 const appendSect = struct {3395 const appendSect = struct {
...@@ -3415,7 +3412,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3415,7 +3412,7 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
3415 },3412 },
3416 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,3413 .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
3417 });3414 });
3418 appendSect(self, self.zig_text_sect_index.?, self.zig_text_seg_index.?);3415 if (!self.base.isRelocatable()) appendSect(self, self.zig_text_sect_index.?, self.zig_text_seg_index.?);
3419 }3416 }
34203417
3421 if (!self.base.isRelocatable()) {3418 if (!self.base.isRelocatable()) {
...@@ -3427,33 +3424,35 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {...@@ -3427,33 +3424,35 @@ fn initMetadata(self: *MachO, options: InitMetadataOptions) !void {
34273424
3428 {3425 {
3429 self.zig_const_sect_index = try self.addSection("__CONST_ZIG", "__const_zig", .{});3426 self.zig_const_sect_index = try self.addSection("__CONST_ZIG", "__const_zig", .{});
3430 appendSect(self, self.zig_const_sect_index.?, self.zig_const_seg_index.?);3427 if (!self.base.isRelocatable()) appendSect(self, self.zig_const_sect_index.?, self.zig_const_seg_index.?);
3431 }3428 }
34323429
3433 {3430 {
3434 self.zig_data_sect_index = try self.addSection("__DATA_ZIG", "__data_zig", .{});3431 self.zig_data_sect_index = try self.addSection("__DATA_ZIG", "__data_zig", .{});
3435 appendSect(self, self.zig_data_sect_index.?, self.zig_data_seg_index.?);3432 if (!self.base.isRelocatable()) appendSect(self, self.zig_data_sect_index.?, self.zig_data_seg_index.?);
3436 }3433 }
34373434
3438 {3435 {
3439 self.zig_bss_sect_index = try self.addSection("__BSS_ZIG", "__bss_zig", .{3436 self.zig_bss_sect_index = try self.addSection("__BSS_ZIG", "__bss_zig", .{
3440 .flags = macho.S_ZEROFILL,3437 .flags = macho.S_ZEROFILL,
3441 });3438 });
3442 appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?);3439 if (!self.base.isRelocatable()) appendSect(self, self.zig_bss_sect_index.?, self.zig_bss_seg_index.?);
3443 }3440 }
3444}3441}
34453442
3446pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {3443pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
3447 const sect = &self.sections.items(.header)[sect_index];3444 const sect = &self.sections.items(.header)[sect_index];
3448 const seg_id = self.sections.items(.segment_id)[sect_index];
3449 const seg = &self.segments.items[seg_id];
34503445
3451 if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) {3446 if (needed_size > self.allocatedSize(sect.offset) and !sect.isZerofill()) {
3452 const existing_size = sect.size;3447 const existing_size = sect.size;
3453 sect.size = 0;3448 sect.size = 0;
34543449
3455 // Must move the entire section.3450 // Must move the entire section.
3456 const new_offset = self.findFreeSpace(needed_size, self.getPageSize());3451 const alignment = if (self.base.isRelocatable())
3452 try math.powi(u32, 2, sect.@"align")
3453 else
3454 self.getPageSize();
3455 const new_offset = self.findFreeSpace(needed_size, alignment);
34573456
3458 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{3457 log.debug("new '{s},{s}' file offset 0x{x} to 0x{x}", .{
3459 sect.segName(),3458 sect.segName(),
...@@ -3465,26 +3464,32 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {...@@ -3465,26 +3464,32 @@ pub fn growSection(self: *MachO, sect_index: u8, needed_size: u64) !void {
3465 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);3464 try self.copyRangeAllZeroOut(sect.offset, new_offset, existing_size);
34663465
3467 sect.offset = @intCast(new_offset);3466 sect.offset = @intCast(new_offset);
3468 seg.fileoff = new_offset;
3469 }3467 }
34703468
3471 sect.size = needed_size;3469 sect.size = needed_size;
3472 if (!sect.isZerofill()) {
3473 seg.filesize = needed_size;
3474 }
34753470
3476 const mem_capacity = self.allocatedVirtualSize(seg.vmaddr);3471 if (!self.base.isRelocatable()) {
3477 if (needed_size > mem_capacity) {3472 const seg_id = self.sections.items(.segment_id)[sect_index];
3478 var err = try self.addErrorWithNotes(2);3473 const seg = &self.segments.items[seg_id];
3479 try err.addMsg(self, "fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{3474 seg.fileoff = sect.offset;
3480 seg_id,
3481 seg.segName(),
3482 });
3483 try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{});
3484 try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
3485 }
34863475
3487 seg.vmsize = needed_size;3476 if (!sect.isZerofill()) {
3477 seg.filesize = needed_size;
3478 }
3479
3480 const mem_capacity = self.allocatedVirtualSize(seg.vmaddr);
3481 if (needed_size > mem_capacity) {
3482 var err = try self.addErrorWithNotes(2);
3483 try err.addMsg(self, "fatal linker error: cannot expand segment seg({d})({s}) in virtual memory", .{
3484 seg_id,
3485 seg.segName(),
3486 });
3487 try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{});
3488 try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
3489 }
3490
3491 seg.vmsize = needed_size;
3492 }
3488}3493}
34893494
3490pub fn getTarget(self: MachO) std.Target {3495pub fn getTarget(self: MachO) std.Target {
src/link/MachO/relocatable.zig+31-11
...@@ -12,7 +12,7 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u...@@ -12,7 +12,7 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
1212
13 if (module_obj_path) |path| try positionals.append(.{ .path = path });13 if (module_obj_path) |path| try positionals.append(.{ .path = path });
1414
15 if (positionals.items.len == 1) {15 if (macho_file.getZigObject() == null and positionals.items.len == 1) {
16 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all16 // Instead of invoking a full-blown `-r` mode on the input which sadly will strip all
17 // debug info segments/sections (this is apparently by design by Apple), we copy17 // debug info segments/sections (this is apparently by design by Apple), we copy
18 // the *only* input file over.18 // the *only* input file over.
...@@ -26,6 +26,11 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u...@@ -26,6 +26,11 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
26 return;26 return;
27 }27 }
2828
29 if (macho_file.getZigObject() != null and positionals.items.len > 0) {
30 try macho_file.reportUnexpectedError("TODO: build-obj for ZigObject and input object files", .{});
31 return error.FlushFailure;
32 }
33
29 for (positionals.items) |obj| {34 for (positionals.items) |obj| {
30 macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {35 macho_file.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
31 error.MalformedObject,36 error.MalformedObject,
...@@ -46,8 +51,8 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u...@@ -46,8 +51,8 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
4651
47 try macho_file.addUndefinedGlobals();52 try macho_file.addUndefinedGlobals();
48 try macho_file.resolveSymbols();53 try macho_file.resolveSymbols();
49 markExports(macho_file);54 try markExports(macho_file);
50 claimUnresolved(macho_file);55 try claimUnresolved(macho_file);
51 try initOutputSections(macho_file);56 try initOutputSections(macho_file);
52 try macho_file.sortSections();57 try macho_file.sortSections();
53 try macho_file.addAtomsToSections();58 try macho_file.addAtomsToSections();
...@@ -109,8 +114,13 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u...@@ -109,8 +114,13 @@ pub fn flush(macho_file: *MachO, comp: *Compilation, module_obj_path: ?[]const u
109 try writeHeader(macho_file, ncmds, sizeofcmds);114 try writeHeader(macho_file, ncmds, sizeofcmds);
110}115}
111116
112fn markExports(macho_file: *MachO) void {117fn markExports(macho_file: *MachO) error{OutOfMemory}!void {
113 for (macho_file.objects.items) |index| {118 var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1);
119 defer objects.deinit();
120 if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
121 objects.appendSliceAssumeCapacity(macho_file.objects.items);
122
123 for (objects.items) |index| {
114 for (macho_file.getFile(index).?.getSymbols()) |sym_index| {124 for (macho_file.getFile(index).?.getSymbols()) |sym_index| {
115 const sym = macho_file.getSymbol(sym_index);125 const sym = macho_file.getSymbol(sym_index);
116 const file = sym.getFile(macho_file) orelse continue;126 const file = sym.getFile(macho_file) orelse continue;
...@@ -122,13 +132,22 @@ fn markExports(macho_file: *MachO) void {...@@ -122,13 +132,22 @@ fn markExports(macho_file: *MachO) void {
122 }132 }
123}133}
124134
125fn claimUnresolved(macho_file: *MachO) void {135fn claimUnresolved(macho_file: *MachO) error{OutOfMemory}!void {
126 for (macho_file.objects.items) |index| {136 var objects = try std.ArrayList(File.Index).initCapacity(macho_file.base.comp.gpa, macho_file.objects.items.len + 1);
127 const object = macho_file.getFile(index).?.object;137 defer objects.deinit();
138 if (macho_file.getZigObject()) |zo| objects.appendAssumeCapacity(zo.index);
139 objects.appendSliceAssumeCapacity(macho_file.objects.items);
128140
129 for (object.symbols.items, 0..) |sym_index, i| {141 for (objects.items) |index| {
142 const file = macho_file.getFile(index).?;
143
144 for (file.getSymbols(), 0..) |sym_index, i| {
130 const nlist_idx = @as(Symbol.Index, @intCast(i));145 const nlist_idx = @as(Symbol.Index, @intCast(i));
131 const nlist = object.symtab.items(.nlist)[nlist_idx];146 const nlist = switch (file) {
147 .object => |x| x.symtab.items(.nlist)[nlist_idx],
148 .zig_object => |x| x.symtab.items(.nlist)[nlist_idx],
149 else => unreachable,
150 };
132 if (!nlist.ext()) continue;151 if (!nlist.ext()) continue;
133 if (!nlist.undf()) continue;152 if (!nlist.undf()) continue;
134153
...@@ -290,7 +309,7 @@ fn writeAtoms(macho_file: *MachO) !void {...@@ -290,7 +309,7 @@ fn writeAtoms(macho_file: *MachO) !void {
290 assert(atom.flags.alive);309 assert(atom.flags.alive);
291 const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow;310 const off = math.cast(usize, atom.value - header.addr) orelse return error.Overflow;
292 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;311 const atom_size = math.cast(usize, atom.size) orelse return error.Overflow;
293 try atom.getFile(macho_file).object.getAtomData(atom.*, code[off..][0..atom_size]);312 try atom.getData(macho_file, code[off..][0..atom_size]);
294 try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs);313 try atom.writeRelocs(macho_file, code[off..][0..atom_size], &relocs);
295 }314 }
296315
...@@ -501,5 +520,6 @@ const trace = @import("../../tracy.zig").trace;...@@ -501,5 +520,6 @@ const trace = @import("../../tracy.zig").trace;
501520
502const Atom = @import("Atom.zig");521const Atom = @import("Atom.zig");
503const Compilation = @import("../../Compilation.zig");522const Compilation = @import("../../Compilation.zig");
523const File = @import("file.zig").File;
504const MachO = @import("../MachO.zig");524const MachO = @import("../MachO.zig");
505const Symbol = @import("Symbol.zig");525const Symbol = @import("Symbol.zig");