diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 035c59ac21..9ab4a9397e 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -85,15 +85,17 @@ unwind_info: UnwindInfo = .{}, /// Tracked loadable segments during incremental linking. zig_text_seg_index: ?u8 = null, -zig_data_const_seg_index: ?u8 = null, +zig_got_seg_index: ?u8 = null, +zig_const_seg_index: ?u8 = null, zig_data_seg_index: ?u8 = null, +zig_bss_seg_index: ?u8 = null, /// Tracked section headers with incremental updates to Zig object. zig_text_section_index: ?u8 = null, -zig_data_const_section_index: ?u8 = null, +zig_got_section_index: ?u8 = null, +zig_const_section_index: ?u8 = null, zig_data_section_index: ?u8 = null, zig_bss_section_index: ?u8 = null, -zig_got_section_index: ?u8 = null, has_tlv: bool = false, binds_to_weak: bool = false, @@ -252,6 +254,8 @@ pub fn createEmpty( .program_code_size_hint = options.program_code_size_hint, }); + std.debug.print("{}", .{self.dumpState()}); + // TODO init dwarf // if (comp.config.debug_format != .strip) { @@ -3082,33 +3086,45 @@ pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { } fn detectAllocCollision(self: *MachO, start: u64, size: u64) ?u64 { - // TODO: header and load commands have to be part of the __TEXT segment - const header_size = self.segments.items[self.header_segment_cmd_index.?].filesize; + // Conservatively commit one page size as reserved space for the headers as we + // expect it to grow and everything else be moved in flush anyhow. + const header_size = self.getPageSize(); if (start < header_size) return header_size; const end = start + padToIdeal(size); for (self.sections.items(.header)) |header| { - const tight_size = header.size; - const increased_size = padToIdeal(tight_size); + if (header.isZerofill()) continue; + const increased_size = padToIdeal(header.size); const test_end = header.offset + increased_size; if (end > header.offset and start < test_end) { return test_end; } } + for (self.segments.items) |seg| { + const increased_size = padToIdeal(seg.filesize); + const test_end = seg.fileoff +| increased_size; + if (end > seg.fileoff and start < test_end) { + return test_end; + } + } + return null; } fn allocatedSize(self: *MachO, start: u64) u64 { - if (start == 0) - return 0; + if (start == 0) return 0; var min_pos: u64 = std.math.maxInt(u64); for (self.sections.items(.header)) |header| { if (header.offset <= start) continue; if (header.offset < min_pos) min_pos = header.offset; } + for (self.segments.items) |seg| { + if (seg.fileoff <= start) continue; + if (seg.fileoff < min_pos) min_pos = seg.fileoff; + } return min_pos - start; } @@ -3126,36 +3142,113 @@ const InitMetadataOptions = struct { }; // TODO: move to ZigObject -// TODO: bring back pre-alloc of segments/sections fn initMetadata(self: *MachO, options: InitMetadataOptions) !void { - _ = options; - if (!self.base.isRelocatable()) { - // TODO: If we are not emitting a relocatable object file, init segments. + const base_vmaddr = blk: { + const pagezero_size = self.pagezero_size orelse default_pagezero_size; + break :blk mem.alignBackward(u64, pagezero_size, self.getPageSize()); + }; + + { + const filesize = options.program_code_size_hint; + const off = self.findFreeSpace(filesize, self.getPageSize()); + self.zig_text_seg_index = try self.addSegment("__TEXT_ZIG", .{ + .fileoff = off, + .filesize = filesize, + .vmaddr = base_vmaddr + 0x8000000, + .vmsize = filesize, + .prot = macho.PROT.READ | macho.PROT.EXEC, + }); + } + + { + const filesize = options.symbol_count_hint * @sizeOf(u64); + const off = self.findFreeSpace(filesize, self.getPageSize()); + self.zig_got_seg_index = try self.addSegment("__GOT_ZIG", .{ + .fileoff = off, + .filesize = filesize, + .vmaddr = base_vmaddr + 0x4000000, + .vmsize = filesize, + .prot = macho.PROT.READ | macho.PROT.WRITE, + }); + } + + { + const filesize: u64 = 1024; + const off = self.findFreeSpace(filesize, self.getPageSize()); + self.zig_const_seg_index = try self.addSegment("__CONST_ZIG", .{ + .fileoff = off, + .filesize = filesize, + .vmaddr = base_vmaddr + 0xc000000, + .vmsize = filesize, + .prot = macho.PROT.READ | macho.PROT.WRITE, + }); + } + + { + const filesize: u64 = 1024; + const off = self.findFreeSpace(filesize, self.getPageSize()); + self.zig_data_seg_index = try self.addSegment("__DATA_ZIG", .{ + .fileoff = off, + .filesize = filesize, + .vmaddr = base_vmaddr + 0x10000000, + .vmsize = filesize, + .prot = macho.PROT.READ | macho.PROT.WRITE, + }); + } + + { + const memsize: u64 = 1024; + self.zig_bss_seg_index = try self.addSegment("__BSS_ZIG", .{ + .vmaddr = base_vmaddr + 0x14000000, + .vmsize = memsize, + .prot = macho.PROT.READ | macho.PROT.WRITE, + }); + } + } else { + @panic("TODO initMetadata when relocatable"); } + const appendSect = struct { + fn appendSect(macho_file: *MachO, sect_id: u8, seg_id: u8) void { + const sect = &macho_file.sections.items(.header)[sect_id]; + const seg = &macho_file.segments.items[seg_id]; + seg.cmdsize += @sizeOf(macho.section_64); + seg.nsects += 1; + sect.addr = seg.vmaddr; + sect.offset = @intCast(seg.fileoff); + sect.size = seg.vmsize; + macho_file.sections.items(.segment_id)[sect_id] = seg_id; + } + }.appendSect; + if (self.zig_text_section_index == null) { - self.zig_text_section_index = try self.addSection("__TEXT", "__text", .{ + self.zig_text_section_index = try self.addSection("__TEXT_ZIG", "__text_zig", .{ .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS, }); + appendSect(self, self.zig_text_section_index.?, self.zig_text_seg_index.?); } if (self.zig_got_section_index == null and !self.base.isRelocatable()) { - self.zig_got_section_index = try self.addSection("__DATA_CONST", "__got_zig", .{}); + self.zig_got_section_index = try self.addSection("__GOT_ZIG", "__got_zig", .{}); + appendSect(self, self.zig_got_section_index.?, self.zig_got_seg_index.?); } - if (self.zig_data_const_section_index == null) { - self.zig_data_const_section_index = try self.addSection("__DATA_CONST", "__const", .{}); + if (self.zig_const_section_index == null) { + self.zig_const_section_index = try self.addSection("__CONST_ZIG", "__const_zig", .{}); + appendSect(self, self.zig_const_section_index.?, self.zig_const_seg_index.?); } if (self.zig_data_section_index == null) { - self.zig_data_section_index = try self.addSection("__DATA", "__data", .{}); + self.zig_data_section_index = try self.addSection("__DATA_ZIG", "__data_zig", .{}); + appendSect(self, self.zig_data_section_index.?, self.zig_data_seg_index.?); } if (self.zig_bss_section_index == null) { - self.zig_bss_section_index = try self.addSection("__DATA", "_bss", .{ + self.zig_bss_section_index = try self.addSection("__BSS_ZIG", "__bss_zig", .{ .flags = macho.S_ZEROFILL, }); + appendSect(self, self.zig_bss_section_index.?, self.zig_bss_seg_index.?); } } diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index 4e0cb76a40..c574900bce 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -478,7 +478,7 @@ fn getDeclOutputSection( ); } - if (variable.is_const) break :blk macho_file.zig_data_const_section_index.?; + if (variable.is_const) break :blk macho_file.zig_const_section_index.?; if (Value.fromInterned(variable.init).isUndefDeep(mod)) { // TODO: get the optimize_mode from the Module that owns the decl instead // of using the root module here. @@ -496,7 +496,7 @@ fn getDeclOutputSection( if (is_all_zeroes) break :blk macho_file.zig_bss_section_index.?; break :blk macho_file.zig_data_section_index.?; } - break :blk macho_file.zig_data_const_section_index.?; + break :blk macho_file.zig_const_section_index.?; }, }; return sect_id;