From d5b9d18bf0f0eed9eb37089e4531db24b06c9f94 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Tue, 3 Oct 2023 15:23:01 +0200 Subject: [PATCH] coff: implement lowering anon decls --- src/link/Coff.zig | 117 +++++++++++++++++++++++++++++++--------------- 1 file changed, 80 insertions(+), 37 deletions(-) diff --git a/src/link/Coff.zig b/src/link/Coff.zig index bfd7c9da46..94b3c63741 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -82,6 +82,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, /// value assigned to label `foo` is an unnamed constant belonging/associated /// with `Decl` `main`, and lives as long as that `Decl`. unnamed_const_atoms: UnnamedConstTable = .{}, +anon_decls: AnonDeclTable = .{}, /// A table of relocations indexed by the owning them `Atom`. /// Note that once we refactor `Atom`'s lifetime and ownership rules, @@ -107,6 +108,7 @@ const HotUpdateState = struct { loaded_base_address: ?std.os.windows.HMODULE = null, }; +const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index); const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); @@ -323,6 +325,7 @@ pub fn deinit(self: *Coff) void { atoms.deinit(gpa); } self.unnamed_const_atoms.deinit(gpa); + self.anon_decls.deinit(gpa); for (self.relocs.values()) |*relocs| { relocs.deinit(gpa); @@ -1077,39 +1080,19 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air: pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { const gpa = self.base.allocator; - var code_buffer = std.ArrayList(u8).init(gpa); - defer code_buffer.deinit(); - const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); - const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); if (!gop.found_existing) { gop.value_ptr.* = .{}; } const unnamed_consts = gop.value_ptr; - - const atom_index = try self.createAtom(); - - const sym_name = blk: { - const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); - - const index = unnamed_consts.items.len; - break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); - }; + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const index = unnamed_consts.items.len; + const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(sym_name); - { - const atom = self.getAtom(atom_index); - const sym = atom.getSymbolPtr(self); - try self.setSymbolName(sym, sym_name); - sym.section_number = @as(coff.SectionNumber, @enumFromInt(self.rdata_section_index.? + 1)); - } - - const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .none, .{ - .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, - }); - var code = switch (res) { - .ok => code_buffer.items, + const atom_index = switch (try self.lowerConst(sym_name, tv, self.rdata_section_index.?, decl.srcLoc(mod))) { + .ok => |atom_index| atom_index, .fail => |em| { decl.analysis = .codegen_failure; try mod.failed_decls.put(mod.gpa, decl_index, em); @@ -1117,6 +1100,34 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In return error.CodegenFail; }, }; + try unnamed_consts.append(gpa, atom_index); + return self.getAtom(atom_index).getSymbolIndex().?; +} + +const LowerConstResult = union(enum) { + ok: Atom.Index, + fail: *Module.ErrorMsg, +}; + +fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult { + const gpa = self.base.allocator; + + var code_buffer = std.ArrayList(u8).init(gpa); + defer code_buffer.deinit(); + + const mod = self.base.options.module.?; + const atom_index = try self.createAtom(); + const sym = self.getAtom(atom_index).getSymbolPtr(self); + try self.setSymbolName(sym, name); + sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1)); + + const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .none, .{ + .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, + }); + var code = switch (res) { + .ok => code_buffer.items, + .fail => |em| return .{ .fail = em }, + }; const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0)); const atom = self.getAtomPtr(atom_index); @@ -1124,14 +1135,12 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); errdefer self.freeAtom(atom_index); - try unnamed_consts.append(gpa, atom_index); - - log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value }); + log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(self).value }); log.debug(" (required alignment 0x{x})", .{required_alignment}); try self.writeAtom(atom_index, code); - return atom.getSymbolIndex().?; + return .{ .ok = atom_index }; } pub fn updateDecl( @@ -1737,17 +1746,51 @@ pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, src_loc: Module.Sr // be used by more than one function, however, its address is being used so we need // to put it in some location. // ... - _ = self; - _ = decl_val; - _ = src_loc; - _ = @panic("TODO: link/Coff lowerAnonDecl"); + const gpa = self.base.allocator; + const gop = try self.anon_decls.getOrPut(gpa, decl_val); + if (!gop.found_existing) { + const mod = self.base.options.module.?; + const ty = mod.intern_pool.typeOf(decl_val).toType(); + const val = decl_val.toValue(); + const tv = TypedValue{ .ty = ty, .val = val }; + const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)}); + defer gpa.free(name); + const res = self.lowerConst(name, tv, self.rdata_section_index.?, src_loc) catch |err| switch (err) { + else => { + // TODO improve error message + const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{ + @errorName(err), + }); + return .{ .fail = em }; + }, + }; + const atom_index = switch (res) { + .ok => |atom_index| atom_index, + .fail => |em| return .{ .fail = em }, + }; + gop.value_ptr.* = atom_index; + } + return .ok; } pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 { - _ = self; - _ = decl_val; - _ = reloc_info; - _ = @panic("TODO: link/Coff getAnonDeclVAddr"); + assert(self.llvm_object == null); + + const this_atom_index = self.anon_decls.get(decl_val).?; + const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?; + const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?; + const target = SymbolWithLoc{ .sym_index = sym_index, .file = null }; + try Atom.addRelocation(self, atom_index, .{ + .type = .direct, + .target = target, + .offset = @as(u32, @intCast(reloc_info.offset)), + .addend = reloc_info.addend, + .pcrel = false, + .length = 3, + }); + try Atom.addBaseRelocation(self, atom_index, @as(u32, @intCast(reloc_info.offset))); + + return 0; } pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {