Commit 34f9360ea2
Changed files (4)
src
link
src/link/MachO/Atom.zig
@@ -314,8 +314,9 @@ pub fn parseRelocs(self: *Atom, relocs: []align(1) const macho.relocation_info,
const sect_id = @intCast(u16, rel.r_symbolnum - 1);
const sym_index = object.sections_as_symbols.get(sect_id) orelse blk: {
const sect = object.getSourceSection(sect_id);
- const out_sect_id = (try context.macho_file.getOutputSection(sect)) orelse
+ const gop = (try context.macho_file.getOutputSection(sect)) orelse
unreachable;
+ const out_sect_id = gop.sect_id;
const sym_index = @intCast(u32, object.symtab.items.len);
try object.symtab.append(gpa, .{
.n_strx = 0,
src/link/MachO/Object.zig
@@ -220,15 +220,15 @@ fn filterRelocs(
pub fn scanInputSections(self: Object, macho_file: *MachO) !void {
for (self.sections.items) |sect| {
- const sect_id = (try macho_file.getOutputSection(sect)) orelse {
+ const gop = (try macho_file.getOutputSection(sect)) orelse {
log.debug(" unhandled section", .{});
continue;
};
- const output = macho_file.sections.items(.header)[sect_id];
+ const output = macho_file.sections.items(.header)[gop.sect_id];
log.debug("mapping '{s},{s}' into output sect({d}, '{s},{s}')", .{
sect.segName(),
sect.sectName(),
- sect_id + 1,
+ gop.sect_id + 1,
output.segName(),
output.sectName(),
});
@@ -335,10 +335,11 @@ pub fn splitIntoAtoms(self: *Object, macho_file: *MachO, object_id: u32) !void {
log.debug("splitting section '{s},{s}' into atoms", .{ sect.segName(), sect.sectName() });
// Get matching segment/section in the final artifact.
- const out_sect_id = (try macho_file.getOutputSection(sect)) orelse {
+ const gop = (try macho_file.getOutputSection(sect)) orelse {
log.debug(" unhandled section", .{});
continue;
};
+ const out_sect_id = gop.sect_id;
log.debug(" output sect({d}, '{s},{s}')", .{
out_sect_id + 1,
src/link/MachO/zld.zig
@@ -198,7 +198,7 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
.n_value = 0,
});
try macho_file.strtab.buffer.append(gpa, 0);
- try macho_file.populateMissingMetadata();
+ try initSections(macho_file);
var lib_not_found = false;
var framework_not_found = false;
@@ -646,6 +646,116 @@ pub fn linkWithZld(macho_file: *MachO, comp: *Compilation, prog_node: *std.Progr
}
}
+fn initSections(macho_file: *MachO) !void {
+ const gpa = macho_file.base.allocator;
+ const cpu_arch = macho_file.base.options.target.cpu.arch;
+ const pagezero_vmsize = macho_file.calcPagezeroSize();
+
+ if (macho_file.pagezero_segment_cmd_index == null) {
+ if (pagezero_vmsize > 0) {
+ macho_file.pagezero_segment_cmd_index = @intCast(u8, macho_file.segments.items.len);
+ try macho_file.segments.append(gpa, .{
+ .segname = MachO.makeStaticString("__PAGEZERO"),
+ .vmsize = pagezero_vmsize,
+ .cmdsize = @sizeOf(macho.segment_command_64),
+ });
+ }
+ }
+
+ if (macho_file.text_segment_cmd_index == null) {
+ macho_file.text_segment_cmd_index = @intCast(u8, macho_file.segments.items.len);
+ try macho_file.segments.append(gpa, .{
+ .segname = MachO.makeStaticString("__TEXT"),
+ .vmaddr = pagezero_vmsize,
+ .vmsize = 0,
+ .filesize = 0,
+ .maxprot = macho.PROT.READ | macho.PROT.EXEC,
+ .initprot = macho.PROT.READ | macho.PROT.EXEC,
+ .cmdsize = @sizeOf(macho.segment_command_64),
+ });
+ }
+
+ if (macho_file.text_section_index == null) {
+ macho_file.text_section_index = try macho_file.initSection("__TEXT", "__text", .{
+ .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+ });
+ }
+
+ if (macho_file.stubs_section_index == null) {
+ const stub_size: u4 = switch (cpu_arch) {
+ .x86_64 => 6,
+ .aarch64 => 3 * @sizeOf(u32),
+ else => unreachable, // unhandled architecture type
+ };
+ macho_file.stubs_section_index = try macho_file.initSection("__TEXT", "__stubs", .{
+ .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+ .reserved2 = stub_size,
+ });
+ }
+
+ if (macho_file.stub_helper_section_index == null) {
+ macho_file.stub_helper_section_index = try macho_file.initSection("__TEXT", "__stub_helper", .{
+ .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+ });
+ }
+
+ if (macho_file.data_const_segment_cmd_index == null) {
+ macho_file.data_const_segment_cmd_index = @intCast(u8, macho_file.segments.items.len);
+ try macho_file.segments.append(gpa, .{
+ .segname = MachO.makeStaticString("__DATA_CONST"),
+ .vmaddr = 0,
+ .vmsize = 0,
+ .fileoff = 0,
+ .filesize = 0,
+ .maxprot = macho.PROT.READ | macho.PROT.WRITE,
+ .initprot = macho.PROT.READ | macho.PROT.WRITE,
+ .cmdsize = @sizeOf(macho.segment_command_64),
+ });
+ }
+
+ if (macho_file.got_section_index == null) {
+ macho_file.got_section_index = try macho_file.initSection("__DATA_CONST", "__got", .{
+ .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
+ });
+ }
+
+ if (macho_file.data_segment_cmd_index == null) {
+ macho_file.data_segment_cmd_index = @intCast(u8, macho_file.segments.items.len);
+ try macho_file.segments.append(gpa, .{
+ .segname = MachO.makeStaticString("__DATA"),
+ .vmaddr = 0,
+ .vmsize = 0,
+ .fileoff = 0,
+ .filesize = 0,
+ .maxprot = macho.PROT.READ | macho.PROT.WRITE,
+ .initprot = macho.PROT.READ | macho.PROT.WRITE,
+ .cmdsize = @sizeOf(macho.segment_command_64),
+ });
+ }
+
+ if (macho_file.la_symbol_ptr_section_index == null) {
+ macho_file.la_symbol_ptr_section_index = try macho_file.initSection("__DATA", "__la_symbol_ptr", .{
+ .flags = macho.S_LAZY_SYMBOL_POINTERS,
+ });
+ }
+
+ if (macho_file.data_section_index == null) {
+ macho_file.data_section_index = try macho_file.initSection("__DATA", "__data", .{});
+ }
+
+ if (macho_file.linkedit_segment_cmd_index == null) {
+ macho_file.linkedit_segment_cmd_index = @intCast(u8, macho_file.segments.items.len);
+ try macho_file.segments.append(gpa, .{
+ .segname = MachO.makeStaticString("__LINKEDIT"),
+ .vmaddr = 0,
+ .fileoff = 0,
+ .maxprot = macho.PROT.READ,
+ .initprot = macho.PROT.READ,
+ .cmdsize = @sizeOf(macho.segment_command_64),
+ });
+ }
+}
+
fn writeAtoms(macho_file: *MachO) !void {
assert(macho_file.mode == .one_shot);
src/link/MachO.zig
@@ -304,13 +304,9 @@ pub fn openPath(allocator: Allocator, options: link.Options) !*MachO {
errdefer file.close();
self.base.file = file;
- if (!options.strip and options.module != null) blk: {
- // TODO once I add support for converting (and relocating) DWARF info from relocatable
- // object files, this check becomes unnecessary.
- // For now, for LLVM backend we fallback to the old-fashioned stabs approach used by
- // stage1.
- if (build_options.have_llvm and options.use_llvm) break :blk;
+ if (self.mode == .one_shot) return self;
+ if (!options.strip and options.module != null) {
// Create dSYM bundle.
const dir = options.module.?.zig_cache_artifact_directory;
log.debug("creating {s}.dSYM bundle in {?s}", .{ emit.sub_path, dir.path });
@@ -1038,30 +1034,32 @@ pub fn parseDependentLibs(self: *MachO, syslibroot: ?[]const u8, dependent_libs:
}
}
-pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
+const GetOutputSectionResult = struct {
+ found_existing: bool,
+ sect_id: u8,
+};
+
+pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?GetOutputSectionResult {
const segname = sect.segName();
const sectname = sect.sectName();
- const res: ?u8 = blk: {
+
+ var found_existing: bool = true;
+ const sect_id: u8 = blk: {
if (mem.eql(u8, "__LLVM", segname)) {
log.debug("TODO LLVM section: type 0x{x}, name '{s},{s}'", .{
sect.flags, segname, sectname,
});
- break :blk null;
+ return null;
}
if (sect.isCode()) {
if (self.text_section_index == null) {
- self.text_section_index = try self.initSection(
- "__TEXT",
- "__text",
- sect.size,
- sect.@"align",
- .{
- .flags = macho.S_REGULAR |
- macho.S_ATTR_PURE_INSTRUCTIONS |
- macho.S_ATTR_SOME_INSTRUCTIONS,
- },
- );
+ self.text_section_index = try self.initSection("__TEXT", "__text", .{
+ .flags = macho.S_REGULAR |
+ macho.S_ATTR_PURE_INSTRUCTIONS |
+ macho.S_ATTR_SOME_INSTRUCTIONS,
+ });
+ found_existing = false;
}
break :blk self.text_section_index.?;
}
@@ -1073,7 +1071,7 @@ pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
sect.flags, segname, sectname,
});
}
- break :blk null;
+ return null;
}
switch (sect.@"type"()) {
@@ -1081,42 +1079,30 @@ pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
macho.S_8BYTE_LITERALS,
macho.S_16BYTE_LITERALS,
=> {
- break :blk self.getSectionByName("__TEXT", "__const") orelse try self.initSection(
- "__TEXT",
- "__const",
- sect.size,
- sect.@"align",
- .{},
- );
+ if (self.getSectionByName("__TEXT", "__const")) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection("__TEXT", "__const", .{});
},
macho.S_CSTRING_LITERALS => {
if (mem.startsWith(u8, sectname, "__objc")) {
- break :blk self.getSectionByName(segname, sectname) orelse try self.initSection(
- segname,
- sectname,
- sect.size,
- sect.@"align",
- .{},
- );
+ if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection(segname, sectname, .{});
}
- break :blk self.getSectionByName("__TEXT", "__cstring") orelse try self.initSection(
- "__TEXT",
- "__cstring",
- sect.size,
- sect.@"align",
- .{ .flags = macho.S_CSTRING_LITERALS },
- );
+ if (self.getSectionByName("__TEXT", "__cstring")) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection("__TEXT", "__cstring", .{
+ .flags = macho.S_CSTRING_LITERALS,
+ });
},
macho.S_MOD_INIT_FUNC_POINTERS,
macho.S_MOD_TERM_FUNC_POINTERS,
=> {
- break :blk self.getSectionByName("__DATA_CONST", sectname) orelse try self.initSection(
- "__DATA_CONST",
- sectname,
- sect.size,
- sect.@"align",
- .{ .flags = sect.flags },
- );
+ if (self.getSectionByName("__DATA_CONST", sectname)) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection("__DATA_CONST", sectname, .{
+ .flags = sect.flags,
+ });
},
macho.S_LITERAL_POINTERS,
macho.S_ZEROFILL,
@@ -1125,22 +1111,14 @@ pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
macho.S_THREAD_LOCAL_REGULAR,
macho.S_THREAD_LOCAL_ZEROFILL,
=> {
- break :blk self.getSectionByName(segname, sectname) orelse try self.initSection(
- segname,
- sectname,
- sect.size,
- sect.@"align",
- .{ .flags = sect.flags },
- );
+ if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection(segname, sectname, .{ .flags = sect.flags });
},
macho.S_COALESCED => {
- break :blk self.getSectionByName(segname, sectname) orelse try self.initSection(
- segname,
- sectname,
- sect.size,
- sect.@"align",
- .{},
- );
+ if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection(segname, sectname, .{});
},
macho.S_REGULAR => {
if (mem.eql(u8, segname, "__TEXT")) {
@@ -1150,13 +1128,9 @@ pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
mem.eql(u8, sectname, "__gosymtab") or
mem.eql(u8, sectname, "__gopclntab"))
{
- break :blk self.getSectionByName("__DATA_CONST", "__const") orelse try self.initSection(
- "__DATA_CONST",
- "__const",
- sect.size,
- sect.@"align",
- .{},
- );
+ if (self.getSectionByName("__DATA_CONST", "__const")) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection("__DATA_CONST", "__const", .{});
}
}
if (mem.eql(u8, segname, "__DATA")) {
@@ -1165,39 +1139,29 @@ pub fn getOutputSection(self: *MachO, sect: macho.section_64) !?u8 {
mem.eql(u8, sectname, "__objc_classlist") or
mem.eql(u8, sectname, "__objc_imageinfo"))
{
- break :blk self.getSectionByName("__DATA_CONST", sectname) orelse
- try self.initSection(
- "__DATA_CONST",
- sectname,
- sect.size,
- sect.@"align",
- .{},
- );
+ if (self.getSectionByName("__DATA_CONST", sectname)) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection("__DATA_CONST", sectname, .{});
} else if (mem.eql(u8, sectname, "__data")) {
if (self.data_section_index == null) {
- self.data_section_index = try self.initSection(
- segname,
- sectname,
- sect.size,
- sect.@"align",
- .{},
- );
+ self.data_section_index = try self.initSection(segname, sectname, .{});
+ found_existing = false;
}
break :blk self.data_section_index.?;
}
}
- break :blk self.getSectionByName(segname, sectname) orelse try self.initSection(
- segname,
- sectname,
- sect.size,
- sect.@"align",
- .{},
- );
+ if (self.getSectionByName(segname, sectname)) |sect_id| break :blk sect_id;
+ found_existing = false;
+ break :blk try self.initSection(segname, sectname, .{});
},
- else => break :blk null,
+ else => return null,
}
};
- return res;
+
+ return GetOutputSectionResult{
+ .found_existing = found_existing,
+ .sect_id = sect_id,
+ };
}
pub fn createEmptyAtom(gpa: Allocator, sym_index: u32, size: u64, alignment: u32) !*Atom {
@@ -1399,12 +1363,17 @@ pub fn createTlvPtrAtom(self: *MachO, target: SymbolWithLoc) !*Atom {
const sym = atom.getSymbolPtr(self);
sym.n_type = macho.N_SECT;
- const sect_id = (try self.getOutputSection(.{
+ const gop = (try self.getOutputSection(.{
.segname = makeStaticString("__DATA"),
.sectname = makeStaticString("__thread_ptrs"),
.flags = macho.S_THREAD_LOCAL_VARIABLE_POINTERS,
})).?;
- sym.n_sect = sect_id + 1;
+ if (self.mode == .incremental and !gop.found_existing) {
+ // TODO allocate section
+ const needed_size: u64 = self.page_size;
+ try self.allocateSection(gop.sect_id, needed_size, @alignOf(u64));
+ }
+ sym.n_sect = gop.sect_id + 1;
try self.allocateAtomCommon(atom);
@@ -1754,16 +1723,20 @@ pub fn createTentativeDefAtoms(self: *MachO) !void {
// text blocks for each tentative definition.
const size = sym.n_value;
const alignment = (sym.n_desc >> 8) & 0x0f;
- const n_sect = (try self.getOutputSection(.{
+ const gop = (try self.getOutputSection(.{
.segname = makeStaticString("__DATA"),
.sectname = makeStaticString("__bss"),
.flags = macho.S_ZEROFILL,
})).?;
+ if (self.mode == .incremental and !gop.found_existing) {
+ // TODO allocate section
+ try self.allocateSection(gop.sect_id, size, alignment);
+ }
sym.* = .{
.n_strx = sym.n_strx,
.n_type = macho.N_SECT | macho.N_EXT,
- .n_sect = n_sect,
+ .n_sect = gop.sect_id,
.n_desc = 0,
.n_value = 0,
};
@@ -2883,16 +2856,19 @@ fn getOutputSectionAtom(
const align_log_2 = math.log2(alignment);
const zig_ty = ty.zigTypeTag();
const mode = self.base.options.optimize_mode;
+
const sect_id: u8 = blk: {
// TODO finish and audit this function
if (val.isUndefDeep()) {
if (mode == .ReleaseFast or mode == .ReleaseSmall) {
- break :blk (try self.getOutputSection(.{
+ const gop = (try self.getOutputSection(.{
.segname = makeStaticString("__DATA"),
.sectname = makeStaticString("__bss"),
- .size = code.len,
- .@"align" = align_log_2,
})).?;
+ if (!gop.found_existing) {
+ try self.allocateSection(gop.sect_id, code.len, align_log_2);
+ }
+ break :blk gop.sect_id;
} else {
break :blk self.data_section_index.?;
}
@@ -2903,12 +2879,14 @@ fn getOutputSectionAtom(
}
if (needsPointerRebase(ty, val, mod)) {
- break :blk (try self.getOutputSection(.{
+ const gop = (try self.getOutputSection(.{
.segname = makeStaticString("__DATA_CONST"),
.sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
})).?;
+ if (!gop.found_existing) {
+ try self.allocateSection(gop.sect_id, code.len, align_log_2);
+ }
+ break :blk gop.sect_id;
}
switch (zig_ty) {
@@ -2922,13 +2900,15 @@ fn getOutputSectionAtom(
.const_slice_u8_sentinel_0,
.manyptr_const_u8_sentinel_0,
=> {
- break :blk (try self.getOutputSection(.{
+ const gop = (try self.getOutputSection(.{
.segname = makeStaticString("__TEXT"),
.sectname = makeStaticString("__cstring"),
.flags = macho.S_CSTRING_LITERALS,
- .size = code.len,
- .@"align" = align_log_2,
})).?;
+ if (!gop.found_existing) {
+ try self.allocateSection(gop.sect_id, code.len, align_log_2);
+ }
+ break :blk gop.sect_id;
},
else => {},
}
@@ -2936,13 +2916,16 @@ fn getOutputSectionAtom(
},
else => {},
}
- break :blk (try self.getOutputSection(.{
+ const gop = (try self.getOutputSection(.{
.segname = makeStaticString("__TEXT"),
.sectname = makeStaticString("__const"),
- .size = code.len,
- .@"align" = align_log_2,
})).?;
+ if (!gop.found_existing) {
+ try self.allocateSection(gop.sect_id, code.len, align_log_2);
+ }
+ break :blk gop.sect_id;
};
+
const header = self.sections.items(.header)[sect_id];
log.debug(" allocating atom '{s}' in '{s},{s}', ord({d})", .{
name,
@@ -3255,40 +3238,36 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
}
pub fn populateMissingMetadata(self: *MachO) !void {
+ assert(self.mode == .incremental);
+
const gpa = self.base.allocator;
const cpu_arch = self.base.options.target.cpu.arch;
- const pagezero_vmsize = self.base.options.pagezero_size orelse default_pagezero_vmsize;
- const aligned_pagezero_vmsize = mem.alignBackwardGeneric(u64, pagezero_vmsize, self.page_size);
-
- if (self.pagezero_segment_cmd_index == null) blk: {
- if (self.base.options.output_mode == .Lib) break :blk;
- if (aligned_pagezero_vmsize == 0) break :blk;
- if (aligned_pagezero_vmsize != pagezero_vmsize) {
- log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});
- log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
+ const pagezero_vmsize = self.calcPagezeroSize();
+
+ if (self.pagezero_segment_cmd_index == null) {
+ if (pagezero_vmsize > 0) {
+ self.pagezero_segment_cmd_index = @intCast(u8, self.segments.items.len);
+ try self.segments.append(gpa, .{
+ .segname = makeStaticString("__PAGEZERO"),
+ .vmsize = pagezero_vmsize,
+ .cmdsize = @sizeOf(macho.segment_command_64),
+ });
}
- self.pagezero_segment_cmd_index = @intCast(u8, self.segments.items.len);
- try self.segments.append(gpa, .{
- .segname = makeStaticString("__PAGEZERO"),
- .vmsize = aligned_pagezero_vmsize,
- .cmdsize = @sizeOf(macho.segment_command_64),
- });
}
if (self.text_segment_cmd_index == null) {
self.text_segment_cmd_index = @intCast(u8, self.segments.items.len);
- const needed_size = if (self.mode == .incremental) blk: {
- const headerpad_size = @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size);
- const program_code_size_hint = self.base.options.program_code_size_hint;
- const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
- const ideal_size = headerpad_size + program_code_size_hint + got_size_hint;
- const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
- log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
- break :blk needed_size;
- } else 0;
+ const headerpad_size = @maximum(self.base.options.headerpad_size orelse 0, default_headerpad_size);
+ const program_code_size_hint = self.base.options.program_code_size_hint;
+ const got_size_hint = @sizeOf(u64) * self.base.options.symbol_count_hint;
+ const ideal_size = headerpad_size + program_code_size_hint + got_size_hint;
+ const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
+
+ log.debug("found __TEXT segment free space 0x{x} to 0x{x}", .{ 0, needed_size });
+
try self.segments.append(gpa, .{
.segname = makeStaticString("__TEXT"),
- .vmaddr = aligned_pagezero_vmsize,
+ .vmaddr = pagezero_vmsize,
.vmsize = needed_size,
.filesize = needed_size,
.maxprot = macho.PROT.READ | macho.PROT.EXEC,
@@ -3303,16 +3282,11 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.aarch64 => 2,
else => unreachable, // unhandled architecture type
};
- const needed_size = if (self.mode == .incremental) self.base.options.program_code_size_hint else 0;
- self.text_section_index = try self.initSection(
- "__TEXT",
- "__text",
- needed_size,
- alignment,
- .{
- .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
- },
- );
+ const needed_size = self.base.options.program_code_size_hint;
+ self.text_section_index = try self.initSection("__TEXT", "__text", .{
+ .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+ });
+ try self.allocateSection(self.text_section_index.?, needed_size, alignment);
}
if (self.stubs_section_index == null) {
@@ -3326,17 +3300,12 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.aarch64 => 3 * @sizeOf(u32),
else => unreachable, // unhandled architecture type
};
- const needed_size = if (self.mode == .incremental) stub_size * self.base.options.symbol_count_hint else 0;
- self.stubs_section_index = try self.initSection(
- "__TEXT",
- "__stubs",
- needed_size,
- alignment,
- .{
- .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
- .reserved2 = stub_size,
- },
- );
+ const needed_size = stub_size * self.base.options.symbol_count_hint;
+ self.stubs_section_index = try self.initSection("__TEXT", "__stubs", .{
+ .flags = macho.S_SYMBOL_STUBS | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+ .reserved2 = stub_size,
+ });
+ try self.allocateSection(self.stubs_section_index.?, needed_size, alignment);
}
if (self.stub_helper_section_index == null) {
@@ -3355,37 +3324,26 @@ pub fn populateMissingMetadata(self: *MachO) !void {
.aarch64 => 3 * @sizeOf(u32),
else => unreachable,
};
- const needed_size = if (self.mode == .incremental)
- stub_size * self.base.options.symbol_count_hint + preamble_size
- else
- 0;
- self.stub_helper_section_index = try self.initSection(
- "__TEXT",
- "__stub_helper",
- needed_size,
- alignment,
- .{
- .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
- },
- );
+ const needed_size = stub_size * self.base.options.symbol_count_hint + preamble_size;
+ self.stub_helper_section_index = try self.initSection("__TEXT", "__stub_helper", .{
+ .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+ });
+ try self.allocateSection(self.stub_helper_section_index.?, needed_size, alignment);
}
if (self.data_const_segment_cmd_index == null) {
self.data_const_segment_cmd_index = @intCast(u8, self.segments.items.len);
- var vmaddr: u64 = 0;
- var fileoff: u64 = 0;
- var needed_size: u64 = 0;
- if (self.mode == .incremental) {
- const base = self.getSegmentAllocBase(&.{self.text_segment_cmd_index.?});
- vmaddr = base.vmaddr;
- fileoff = base.fileoff;
- const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
- needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
- log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
- fileoff,
- fileoff + needed_size,
- });
- }
+ const base = self.getSegmentAllocBase(&.{self.text_segment_cmd_index.?});
+ const vmaddr = base.vmaddr;
+ const fileoff = base.fileoff;
+ const ideal_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
+ const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
+
+ log.debug("found __DATA_CONST segment free space 0x{x} to 0x{x}", .{
+ fileoff,
+ fileoff + needed_size,
+ });
+
try self.segments.append(gpa, .{
.segname = makeStaticString("__DATA_CONST"),
.vmaddr = vmaddr,
@@ -3399,38 +3357,27 @@ pub fn populateMissingMetadata(self: *MachO) !void {
}
if (self.got_section_index == null) {
- const needed_size = if (self.mode == .incremental)
- @sizeOf(u64) * self.base.options.symbol_count_hint
- else
- 0;
+ const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
- self.got_section_index = try self.initSection(
- "__DATA_CONST",
- "__got",
- needed_size,
- alignment,
- .{
- .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
- },
- );
+ self.got_section_index = try self.initSection("__DATA_CONST", "__got", .{
+ .flags = macho.S_NON_LAZY_SYMBOL_POINTERS,
+ });
+ try self.allocateSection(self.got_section_index.?, needed_size, alignment);
}
if (self.data_segment_cmd_index == null) {
self.data_segment_cmd_index = @intCast(u8, self.segments.items.len);
- var vmaddr: u64 = 0;
- var fileoff: u64 = 0;
- var needed_size: u64 = 0;
- if (self.mode == .incremental) {
- const base = self.getSegmentAllocBase(&.{self.data_const_segment_cmd_index.?});
- vmaddr = base.vmaddr;
- fileoff = base.fileoff;
- const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
- needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
- log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{
- fileoff,
- fileoff + needed_size,
- });
- }
+ const base = self.getSegmentAllocBase(&.{self.data_const_segment_cmd_index.?});
+ const vmaddr = base.vmaddr;
+ const fileoff = base.fileoff;
+ const ideal_size = 2 * @sizeOf(u64) * self.base.options.symbol_count_hint;
+ const needed_size = mem.alignForwardGeneric(u64, padToIdeal(ideal_size), self.page_size);
+
+ log.debug("found __DATA segment free space 0x{x} to 0x{x}", .{
+ fileoff,
+ fileoff + needed_size,
+ });
+
try self.segments.append(gpa, .{
.segname = makeStaticString("__DATA"),
.vmaddr = vmaddr,
@@ -3444,47 +3391,29 @@ pub fn populateMissingMetadata(self: *MachO) !void {
}
if (self.la_symbol_ptr_section_index == null) {
- const needed_size = if (self.mode == .incremental)
- @sizeOf(u64) * self.base.options.symbol_count_hint
- else
- 0;
+ const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
- self.la_symbol_ptr_section_index = try self.initSection(
- "__DATA",
- "__la_symbol_ptr",
- needed_size,
- alignment,
- .{
- .flags = macho.S_LAZY_SYMBOL_POINTERS,
- },
- );
+ self.la_symbol_ptr_section_index = try self.initSection("__DATA", "__la_symbol_ptr", .{
+ .flags = macho.S_LAZY_SYMBOL_POINTERS,
+ });
+ try self.allocateSection(self.la_symbol_ptr_section_index.?, needed_size, alignment);
}
if (self.data_section_index == null) {
- const needed_size = if (self.mode == .incremental)
- @sizeOf(u64) * self.base.options.symbol_count_hint
- else
- 0;
+ const needed_size = @sizeOf(u64) * self.base.options.symbol_count_hint;
const alignment: u16 = 3; // 2^3 = @sizeOf(u64)
- self.data_section_index = try self.initSection(
- "__DATA",
- "__data",
- needed_size,
- alignment,
- .{},
- );
+ self.data_section_index = try self.initSection("__DATA", "__data", .{});
+ try self.allocateSection(self.data_section_index.?, needed_size, alignment);
}
if (self.linkedit_segment_cmd_index == null) {
self.linkedit_segment_cmd_index = @intCast(u8, self.segments.items.len);
- var vmaddr: u64 = 0;
- var fileoff: u64 = 0;
- if (self.mode == .incremental) {
- const base = self.getSegmentAllocBase(&.{self.data_segment_cmd_index.?});
- vmaddr = base.vmaddr;
- fileoff = base.fileoff;
- log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
- }
+ const base = self.getSegmentAllocBase(&.{self.data_segment_cmd_index.?});
+ const vmaddr = base.vmaddr;
+ const fileoff = base.fileoff;
+
+ log.debug("found __LINKEDIT segment free space at 0x{x}", .{fileoff});
+
try self.segments.append(gpa, .{
.segname = makeStaticString("__LINKEDIT"),
.vmaddr = vmaddr,
@@ -3586,6 +3515,18 @@ fn calcLCsSize(self: *MachO, assume_max_path_len: bool) !u32 {
return @intCast(u32, sizeofcmds);
}
+pub fn calcPagezeroSize(self: *MachO) u64 {
+ const pagezero_vmsize = self.base.options.pagezero_size orelse default_pagezero_vmsize;
+ const aligned_pagezero_vmsize = mem.alignBackwardGeneric(u64, pagezero_vmsize, self.page_size);
+ if (self.base.options.output_mode == .Lib) return 0;
+ if (aligned_pagezero_vmsize == 0) return 0;
+ if (aligned_pagezero_vmsize != pagezero_vmsize) {
+ log.warn("requested __PAGEZERO size (0x{x}) is not page aligned", .{pagezero_vmsize});
+ log.warn(" rounding down to 0x{x}", .{aligned_pagezero_vmsize});
+ }
+ return aligned_pagezero_vmsize;
+}
+
pub fn calcMinHeaderPad(self: *MachO) !u64 {
var padding: u32 = (try self.calcLCsSize(false)) + (self.base.options.headerpad_size orelse 0);
log.debug("minimum requested headerpad size 0x{x}", .{padding + @sizeOf(macho.mach_header_64)});
@@ -3603,69 +3544,42 @@ pub fn calcMinHeaderPad(self: *MachO) !u64 {
return offset;
}
-const InitSectionOpts = struct {
- flags: u32 = macho.S_REGULAR,
- reserved1: u32 = 0,
- reserved2: u32 = 0,
-};
-
-fn initSection(
- self: *MachO,
- segname: []const u8,
- sectname: []const u8,
- size: u64,
- alignment: u32,
- opts: InitSectionOpts,
-) !u8 {
- const segment_id = self.getSegmentByName(segname).?;
+fn allocateSection(self: *MachO, sect_id: u8, size: u64, alignment: u32) !void {
+ const segment_id = self.sections.items(.segment_index)[sect_id];
const seg = &self.segments.items[segment_id];
- const index = try self.insertSection(segment_id, .{
- .sectname = makeStaticString(sectname),
- .segname = seg.segname,
- .flags = opts.flags,
- .reserved1 = opts.reserved1,
- .reserved2 = opts.reserved2,
- });
- seg.cmdsize += @sizeOf(macho.section_64);
- seg.nsects += 1;
-
- if (self.mode == .incremental) {
- const header = &self.sections.items(.header)[index];
- header.size = size;
- header.@"align" = alignment;
-
- const prev_end_off = if (index > 0) blk: {
- const prev_section = self.sections.get(index - 1);
- if (prev_section.segment_index == segment_id) {
- const prev_header = prev_section.header;
- break :blk prev_header.offset + padToIdeal(prev_header.size);
- } else break :blk seg.fileoff;
- } else 0;
- const alignment_pow_2 = try math.powi(u32, 2, alignment);
- // TODO better prealloc for __text section
- // const padding: u64 = if (index == 0) try self.calcMinHeaderPad() else 0;
- const padding: u64 = if (index == 0) 0x1000 else 0;
- const off = mem.alignForwardGeneric(u64, padding + prev_end_off, alignment_pow_2);
-
- if (!header.isZerofill()) {
- header.offset = @intCast(u32, off);
- }
- header.addr = seg.vmaddr + off - seg.fileoff;
-
- // TODO Will this break if we are inserting section that is not the last section
- // in a segment?
- const max_size = self.allocatedSize(segment_id, off);
+ const header = &self.sections.items(.header)[sect_id];
+ header.size = size;
+ header.@"align" = alignment;
+
+ const prev_end_off = if (sect_id > 0) blk: {
+ const prev_section = self.sections.get(sect_id - 1);
+ if (prev_section.segment_index == segment_id) {
+ const prev_header = prev_section.header;
+ break :blk prev_header.offset + padToIdeal(prev_header.size);
+ } else break :blk seg.fileoff;
+ } else 0;
+ const alignment_pow_2 = try math.powi(u32, 2, alignment);
+ // TODO better prealloc for __text section
+ // const padding: u64 = if (sect_id == 0) try self.calcMinHeaderPad() else 0;
+ const padding: u64 = if (sect_id == 0) 0x1000 else 0;
+ const off = mem.alignForwardGeneric(u64, padding + prev_end_off, alignment_pow_2);
- if (size > max_size) {
- try self.growSection(index, @intCast(u32, size));
- }
+ if (!header.isZerofill()) {
+ header.offset = @intCast(u32, off);
+ }
+ header.addr = seg.vmaddr + off - seg.fileoff;
- log.debug("allocating {s},{s} section at 0x{x}", .{ header.segName(), header.sectName(), off });
+ // TODO Will this break if we are inserting section that is not the last section
+ // in a segment?
+ const max_size = self.allocatedSize(segment_id, off);
- self.updateSectionOrdinals(index + 1);
+ if (size > max_size) {
+ try self.growSection(sect_id, @intCast(u32, size));
}
- return index;
+ log.debug("allocating {s},{s} section at 0x{x}", .{ header.segName(), header.sectName(), off });
+
+ self.updateSectionOrdinals(sect_id + 1);
}
fn getSectionPrecedence(header: macho.section_64) u4 {
@@ -3690,6 +3604,32 @@ fn getSectionPrecedence(header: macho.section_64) u4 {
}
}
+const InitSectionOpts = struct {
+ flags: u32 = macho.S_REGULAR,
+ reserved1: u32 = 0,
+ reserved2: u32 = 0,
+};
+
+pub fn initSection(
+ self: *MachO,
+ segname: []const u8,
+ sectname: []const u8,
+ opts: InitSectionOpts,
+) !u8 {
+ const segment_id = self.getSegmentByName(segname).?;
+ const seg = &self.segments.items[segment_id];
+ const index = try self.insertSection(segment_id, .{
+ .sectname = makeStaticString(sectname),
+ .segname = seg.segname,
+ .flags = opts.flags,
+ .reserved1 = opts.reserved1,
+ .reserved2 = opts.reserved2,
+ });
+ seg.cmdsize += @sizeOf(macho.section_64);
+ seg.nsects += 1;
+ return index;
+}
+
fn insertSection(self: *MachO, segment_index: u8, header: macho.section_64) !u8 {
const precedence = getSectionPrecedence(header);
const indexes = self.getSectionIndexes(segment_index);