diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-17 14:55:40 +0100 |
|---|---|---|
| committer | Jakub Konka <kubkon@jakubkonka.com> | 2024-01-24 12:34:41 +0100 |
| commit | 0b2133d4412e8f3c67a1eb6ddbb43afc02196703 (patch) | |
| tree | 8c288057862097a13b0fb0ab313af3a1c2696556 /src | |
| parent | bd9d8bd462799c552eed9812484add68e498a3ee (diff) | |
| download | zig-0b2133d4412e8f3c67a1eb6ddbb43afc02196703.tar.gz zig-0b2133d4412e8f3c67a1eb6ddbb43afc02196703.zip | |
macho: init metadata and partially implement updateDecl
Diffstat (limited to 'src')
| -rw-r--r-- | src/link/MachO.zig | 79 | ||||
| -rw-r--r-- | src/link/MachO/ZigObject.zig | 58 |
2 files changed, 134 insertions, 3 deletions
diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 856a65594c..912ac6a43e 100644 --- a/src/link/MachO.zig +++ b/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, diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index b18b7b4c9d..7aaca00366 100644 --- a/src/link/MachO/ZigObject.zig +++ b/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; |
