From c98d229844e4b12ba2c61291fdf7fa0376f4e087 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 18 Jan 2024 17:13:19 +0100 Subject: [PATCH] macho: fill in more blanks in ZigObject --- src/link/MachO/ZigObject.zig | 277 +++++++++++++++++++++++++++++++++-- 1 file changed, 263 insertions(+), 14 deletions(-) diff --git a/src/link/MachO/ZigObject.zig b/src/link/MachO/ZigObject.zig index ceb9c7fe61..2f2434f211 100644 --- a/src/link/MachO/ZigObject.zig +++ b/src/link/MachO/ZigObject.zig @@ -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);