macho: init metadata and partially implement updateDecl

This commit is contained in:
Jakub Konka 2024-01-17 14:55:40 +01:00
parent bd9d8bd462
commit 0b2133d441
2 changed files with 134 additions and 3 deletions

View File

@ -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,

View File

@ -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;