macho: fill in more blanks in ZigObject

This commit is contained in:
Jakub Konka 2024-01-18 17:13:19 +01:00
parent 6cd4c7612f
commit c98d229844

View File

@ -259,12 +259,47 @@ pub fn lowerAnonDecl(
explicit_alignment: InternPool.Alignment,
src_loc: Module.SrcLoc,
) !codegen.Result {
_ = self;
_ = macho_file;
_ = decl_val;
_ = explicit_alignment;
_ = src_loc;
@panic("TODO lowerAnonDecl");
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const ty = Type.fromInterned(mod.intern_pool.typeOf(decl_val));
const decl_alignment = switch (explicit_alignment) {
.none => ty.abiAlignment(mod),
else => explicit_alignment,
};
if (self.anon_decls.get(decl_val)) |metadata| {
const existing_alignment = macho_file.getSymbol(metadata.symbol_index).getAtom(macho_file).?.alignment;
if (decl_alignment.order(existing_alignment).compare(.lte))
return .ok;
}
const val = Value.fromInterned(decl_val);
const tv = TypedValue{ .ty = ty, .val = val };
var name_buf: [32]u8 = undefined;
const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
@intFromEnum(decl_val),
}) catch unreachable;
const res = self.lowerConst(
macho_file,
name,
tv,
decl_alignment,
macho_file.zig_const_section_index.?,
src_loc,
) catch |err| switch (err) {
error.OutOfMemory => return error.OutOfMemory,
else => |e| return .{ .fail = try Module.ErrorMsg.create(
gpa,
src_loc,
"unable to lower constant value: {s}",
.{@errorName(e)},
) },
};
const sym_index = switch (res) {
.ok => |sym_index| sym_index,
.fail => |em| return .{ .fail = em },
};
try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
return .ok;
}
fn freeUnnamedConsts(self: *ZigObject, macho_file: *MachO, decl_index: InternPool.DeclIndex) void {
@ -591,11 +626,100 @@ pub fn lowerUnnamedConst(
typed_value: TypedValue,
decl_index: InternPool.DeclIndex,
) !u32 {
_ = self;
_ = macho_file;
_ = typed_value;
_ = decl_index;
@panic("TODO lowerUnnamedConst");
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = .{};
}
const unnamed_consts = gop.value_ptr;
const decl = mod.declPtr(decl_index);
const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
const index = unnamed_consts.items.len;
const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
defer gpa.free(name);
const sym_index = switch (try self.lowerConst(
macho_file,
name,
typed_value,
typed_value.ty.abiAlignment(mod),
macho_file.zig_const_section_index.?,
decl.srcLoc(mod),
)) {
.ok => |sym_index| sym_index,
.fail => |em| {
decl.analysis = .codegen_failure;
try mod.failed_decls.put(mod.gpa, decl_index, em);
log.err("{s}", .{em.msg});
return error.CodegenFail;
},
};
const sym = macho_file.getSymbol(sym_index);
try unnamed_consts.append(gpa, sym.atom);
return sym_index;
}
const LowerConstResult = union(enum) {
ok: Symbol.Index,
fail: *Module.ErrorMsg,
};
fn lowerConst(
self: *ZigObject,
macho_file: *MachO,
name: []const u8,
tv: TypedValue,
required_alignment: InternPool.Alignment,
output_section_index: u8,
src_loc: Module.SrcLoc,
) !LowerConstResult {
const gpa = macho_file.base.comp.gpa;
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const sym_index = try self.addAtom(macho_file);
const res = try codegen.generateSymbol(&macho_file.base, src_loc, tv, &code_buffer, .{
.none = {},
}, .{
.parent_atom_index = sym_index,
});
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| return .{ .fail = em },
};
const sym = macho_file.getSymbol(sym_index);
const name_str_index = try macho_file.strings.insert(gpa, name);
sym.name = name_str_index;
sym.out_n_sect = output_section_index;
const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
nlist.n_strx = name_str_index;
nlist.n_type = macho.N_SECT;
nlist.n_sect = output_section_index + 1;
self.symtab.items(.size)[sym.nlist_idx] = code.len;
const atom = sym.getAtom(macho_file).?;
atom.flags.alive = true;
atom.name = name_str_index;
atom.alignment = required_alignment;
atom.size = code.len;
atom.out_n_sect = output_section_index;
try atom.allocate(macho_file);
// TODO rename and re-audit this method
errdefer self.freeDeclMetadata(macho_file, sym_index);
sym.value = 0;
nlist.n_value = 0;
const sect = macho_file.sections.items(.header)[output_section_index];
const file_offset = sect.offset + atom.value - sect.addr;
try macho_file.base.file.?.pwriteAll(code, file_offset);
return .{ .ok = sym_index };
}
pub fn updateExports(
@ -692,6 +816,91 @@ pub fn updateExports(
}
}
fn updateLazySymbol(
self: *ZigObject,
macho_file: *MachO,
lazy_sym: link.File.LazySymbol,
symbol_index: Symbol.Index,
) !void {
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
var required_alignment: InternPool.Alignment = .none;
var code_buffer = std.ArrayList(u8).init(gpa);
defer code_buffer.deinit();
const name_str_index = blk: {
const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
@tagName(lazy_sym.kind),
lazy_sym.ty.fmt(mod),
});
defer gpa.free(name);
break :blk try macho_file.strings.insert(gpa, name);
};
const src = if (lazy_sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
mod.declPtr(owner_decl).srcLoc(mod)
else
Module.SrcLoc{
.file_scope = undefined,
.parent_decl_node = undefined,
.lazy = .unneeded,
};
const res = try codegen.generateLazySymbol(
&macho_file.base,
src,
lazy_sym,
&required_alignment,
&code_buffer,
.none,
.{ .parent_atom_index = symbol_index },
);
const code = switch (res) {
.ok => code_buffer.items,
.fail => |em| {
log.err("{s}", .{em.msg});
return error.CodegenFail;
},
};
const output_section_index = switch (lazy_sym.kind) {
.code => macho_file.zig_text_section_index.?,
.const_data => macho_file.zig_const_section_index.?,
};
const sym = macho_file.getSymbol(symbol_index);
sym.name = name_str_index;
sym.out_n_sect = output_section_index;
const nlist = &self.symtab.items(.nlist)[sym.nlist_idx];
nlist.n_strx = name_str_index;
nlist.n_type = macho.N_SECT;
nlist.n_sect = output_section_index + 1;
self.symtab.items(.size)[sym.nlist_idx] = code.len;
const atom = sym.getAtom(macho_file).?;
atom.flags.alive = true;
atom.name = name_str_index;
atom.alignment = required_alignment;
atom.size = code.len;
atom.out_n_sect = output_section_index;
try atom.allocate(macho_file);
errdefer self.freeDeclMetadata(macho_file, symbol_index);
sym.value = 0;
sym.flags.needs_zig_got = true;
nlist.st_value = 0;
if (!macho_file.base.isRelocatable()) {
const gop = try sym.getOrCreateZigGotEntry(symbol_index, macho_file);
try macho_file.zig_got.writeOne(macho_file, gop.index);
}
const sect = macho_file.sections.items(.header)[output_section_index];
const file_offset = sect.offset + atom.value - sect.addr;
try macho_file.base.file.?.pwriteAll(code, file_offset);
}
/// Must be called only after a successful call to `updateDecl`.
pub fn updateDeclLineNumber(
self: *ZigObject,
@ -701,7 +910,7 @@ pub fn updateDeclLineNumber(
_ = self;
_ = mod;
_ = decl_index;
@panic("TODO updateDeclLineNumber");
// TODO: Dwarf
}
pub fn deleteDeclExport(
@ -751,6 +960,46 @@ pub fn getOrCreateMetadataForDecl(
return gop.value_ptr.symbol_index;
}
pub fn getOrCreateMetadataForLazySymbol(
self: *ZigObject,
macho_file: *MachO,
lazy_sym: link.File.LazySymbol,
) !Symbol.Index {
const gpa = macho_file.base.comp.gpa;
const mod = macho_file.base.comp.module.?;
const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));
errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
if (!gop.found_existing) gop.value_ptr.* = .{};
const metadata: struct {
symbol_index: *Symbol.Index,
state: *LazySymbolMetadata.State,
} = switch (lazy_sym.kind) {
.code => .{
.symbol_index = &gop.value_ptr.text_symbol_index,
.state = &gop.value_ptr.text_state,
},
.const_data => .{
.symbol_index = &gop.value_ptr.const_symbol_index,
.state = &gop.value_ptr.const_state,
},
};
switch (metadata.state.*) {
.unused => {
const symbol_index = try self.addAtom(macho_file);
const sym = macho_file.getSymbol(symbol_index);
sym.flags.needs_zig_got = true;
metadata.symbol_index.* = symbol_index;
},
.pending_flush => return metadata.symbol_index.*,
.flushed => {},
}
metadata.state.* = .pending_flush;
const symbol_index = metadata.symbol_index.*;
// anyerror needs to be deferred until flushModule
if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(macho_file, lazy_sym, symbol_index);
return symbol_index;
}
pub fn asFile(self: *ZigObject) File {
return .{ .zig_object = self };
}
@ -822,9 +1071,9 @@ const DeclMetadata = struct {
const LazySymbolMetadata = struct {
const State = enum { unused, pending_flush, flushed };
text_symbol_index: Symbol.Index = undefined,
data_const_symbol_index: Symbol.Index = undefined,
const_symbol_index: Symbol.Index = undefined,
text_state: State = .unused,
rodata_state: State = .unused,
const_state: State = .unused,
};
const DeclTable = std.AutoHashMapUnmanaged(InternPool.DeclIndex, DeclMetadata);