Commit 0b2133d441
Changed files (2)
src
link
src/link/MachO/ZigObject.zig
@@ -295,7 +295,8 @@ pub fn updateDecl(
return;
},
};
- _ = code;
+ const sect_index = try self.getDeclOutputSection(macho_file, decl, code);
+ _ = sect_index;
// const addr = try self.updateDeclCode(decl_index, code);
// if (decl_state) |*ds| {
@@ -313,6 +314,59 @@ pub fn updateDecl(
// try self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
}
+fn getDeclOutputSection(
+ self: *ZigObject,
+ macho_file: *MachO,
+ decl: *const Module.Decl,
+ code: []const u8,
+) error{OutOfMemory}!u8 {
+ _ = self;
+ const mod = macho_file.base.comp.module.?;
+ const any_non_single_threaded = macho_file.base.comp.config.any_non_single_threaded;
+ const sect_id: u8 = switch (decl.ty.zigTypeTag(mod)) {
+ .Fn => macho_file.zig_text_section_index.?,
+ else => blk: {
+ if (decl.getOwnedVariable(mod)) |variable| {
+ if (variable.is_threadlocal and any_non_single_threaded) {
+ const is_all_zeroes = for (code) |byte| {
+ if (byte != 0) break false;
+ } else true;
+ if (is_all_zeroes) break :blk macho_file.getSectionByName("__DATA", "__thread_bss") orelse try macho_file.addSection(
+ "__DATA",
+ "__thread_bss",
+ .{ .flags = macho.S_THREAD_LOCAL_ZEROFILL },
+ );
+ break :blk macho_file.getSectionByName("__DATA", "__thread_data") orelse try macho_file.addSection(
+ "__DATA",
+ "__thread_data",
+ .{ .flags = macho.S_THREAD_LOCAL_REGULAR },
+ );
+ }
+
+ if (variable.is_const) break :blk macho_file.zig_data_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.
+ break :blk switch (macho_file.base.comp.root_mod.optimize_mode) {
+ .Debug, .ReleaseSafe => macho_file.zig_data_section_index.?,
+ .ReleaseFast, .ReleaseSmall => macho_file.zig_bss_section_index.?,
+ };
+ }
+
+ // TODO I blatantly copied the logic from the Wasm linker, but is there a less
+ // intrusive check for all zeroes than this?
+ const is_all_zeroes = for (code) |byte| {
+ if (byte != 0) break false;
+ } else true;
+ 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.?;
+ },
+ };
+ return sect_id;
+}
+
pub fn lowerUnnamedConst(
self: *ZigObject,
macho_file: *MachO,
@@ -386,7 +440,7 @@ pub fn getOrCreateMetadataForDecl(
const sym_index = try self.addAtom(macho_file);
const mod = macho_file.base.comp.module.?;
const decl = mod.declPtr(decl_index);
- const sym = macho_file.getSymbol(self.symbols.items[sym_index]);
+ const sym = macho_file.getSymbol(sym_index);
if (decl.getOwnedVariable(mod)) |variable| {
if (variable.is_threadlocal and any_non_single_threaded) {
sym.flags.tlv = true;
src/link/MachO.zig
@@ -82,6 +82,18 @@ lazy_bind: LazyBindSection = .{},
export_trie: ExportTrieSection = .{},
unwind_info: UnwindInfo = .{},
+/// Tracked loadable segments during incremental linking.
+zig_text_seg_index: ?u8 = null,
+zig_data_const_seg_index: ?u8 = null,
+zig_data_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_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,
weak_defines: bool = false,
@@ -234,8 +246,11 @@ pub fn createEmpty(
} });
self.zig_object = index;
try self.getZigObject().?.init(self);
+ try self.initMetadata(.{
+ .symbol_count_hint = options.symbol_count_hint,
+ .program_code_size_hint = options.program_code_size_hint,
+ });
- // TODO init metadata
// TODO init dwarf
// if (comp.config.debug_format != .strip) {
@@ -3103,6 +3118,45 @@ fn findFreeSpace(self: *MachO, object_size: u64, min_alignment: u32) u64 {
return start;
}
+const InitMetadataOptions = struct {
+ symbol_count_hint: u64,
+ program_code_size_hint: u64,
+};
+
+// 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.
+ }
+
+ if (self.zig_text_section_index == null) {
+ self.zig_text_section_index = try self.addSection("__TEXT", "__text", .{
+ .flags = macho.S_REGULAR | macho.S_ATTR_PURE_INSTRUCTIONS | macho.S_ATTR_SOME_INSTRUCTIONS,
+ });
+ }
+
+ if (self.zig_got_section_index == null and !self.base.isRelocatable()) {
+ self.zig_got_section_index = try self.addSection("__DATA_CONST", "__got_zig", .{});
+ }
+
+ if (self.zig_data_const_section_index == null) {
+ self.zig_data_const_section_index = try self.addSection("__DATA_CONST", "__const", .{});
+ }
+
+ if (self.zig_data_section_index == null) {
+ self.zig_data_section_index = try self.addSection("__DATA", "__data", .{});
+ }
+
+ if (self.zig_bss_section_index == null) {
+ self.zig_bss_section_index = try self.addSection("__DATA", "_bss", .{
+ .flags = macho.S_ZEROFILL,
+ });
+ }
+}
+
pub fn getTarget(self: MachO) std.Target {
return self.base.comp.root_mod.resolved_target.result;
}
@@ -3148,6 +3202,29 @@ inline fn requiresThunks(self: MachO) bool {
return self.getTarget().cpu.arch == .aarch64;
}
+pub fn addSegment(self: *MachO, name: []const u8, opts: struct {
+ vmaddr: u64 = 0,
+ vmsize: u64 = 0,
+ fileoff: u64 = 0,
+ filesize: u64 = 0,
+ prot: macho.vm_prot_t = macho.PROT.NONE,
+}) error{OutOfMemory}!u8 {
+ const gpa = self.base.comp.gpa;
+ const index = @as(u8, @intCast(self.segments.items.len));
+ try self.segments.append(gpa, .{
+ .segname = makeStaticString(name),
+ .vmaddr = opts.vmaddr,
+ .vmsize = opts.vmsize,
+ .fileoff = opts.fileoff,
+ .filesize = opts.filesize,
+ .maxprot = opts.prot,
+ .initprot = opts.prot,
+ .nsects = 0,
+ .cmdsize = @sizeOf(macho.segment_command_64),
+ });
+ return index;
+}
+
const AddSectionOpts = struct {
flags: u32 = macho.S_REGULAR,
reserved1: u32 = 0,