aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJacob Young <jacobly0@users.noreply.github.com>2023-04-01 03:08:55 -0400
committerJacob Young <jacobly0@users.noreply.github.com>2023-04-02 04:49:53 -0400
commit677427bc3ac839629654175f0a2aaaec9fd6fb6c (patch)
treedeb37ed3275cfef97f9d49d7e8a1eeea5a3c64db /src/link
parentccefa9dbf5369e0fadc75b9e705e74ec96a02859 (diff)
downloadzig-677427bc3ac839629654175f0a2aaaec9fd6fb6c.tar.gz
zig-677427bc3ac839629654175f0a2aaaec9fd6fb6c.zip
x86_64: implement error name
Diffstat (limited to 'src/link')
-rw-r--r--src/link/Coff.zig122
-rw-r--r--src/link/Elf.zig114
-rw-r--r--src/link/MachO.zig130
3 files changed, 362 insertions, 4 deletions
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index f3068f01a9..800f96e90c 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -49,6 +49,9 @@ imports_count_dirty: bool = true,
/// Virtual address of the entry point procedure relative to image base.
entry_addr: ?u32 = null,
+/// Table of tracked LazySymbols.
+lazy_syms: LazySymbolTable = .{},
+
/// Table of tracked Decls.
decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
@@ -142,6 +145,18 @@ const Section = struct {
free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
};
+const LazySymbolTable = std.ArrayHashMapUnmanaged(
+ link.File.LazySymbol,
+ LazySymbolMetadata,
+ link.File.LazySymbol.Context,
+ true,
+);
+
+const LazySymbolMetadata = struct {
+ atom: Atom.Index,
+ section: u16,
+};
+
const DeclMetadata = struct {
atom: Atom.Index,
section: u16,
@@ -1168,6 +1183,100 @@ pub fn updateDecl(self: *Coff, module: *Module, decl_index: Module.Decl.Index) !
return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
}
+fn updateLazySymbol(
+ self: *Coff,
+ lazy_sym: link.File.LazySymbol,
+ lazy_metadata: LazySymbolMetadata,
+) !void {
+ const gpa = self.base.allocator;
+ const mod = self.base.options.module.?;
+
+ var code_buffer = std.ArrayList(u8).init(gpa);
+ defer code_buffer.deinit();
+
+ const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
+ @tagName(lazy_sym.kind),
+ lazy_sym.ty.fmt(mod),
+ });
+ defer gpa.free(name);
+
+ const atom_index = lazy_metadata.atom;
+ const atom = self.getAtomPtr(atom_index);
+ const local_sym_index = atom.getSymbolIndex().?;
+
+ const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
+ mod.declPtr(owner_decl).srcLoc()
+ else
+ Module.SrcLoc{
+ .file_scope = undefined,
+ .parent_decl_node = undefined,
+ .lazy = .unneeded,
+ };
+ const res = try codegen.generateLazySymbol(
+ &self.base,
+ src,
+ lazy_sym,
+ &code_buffer,
+ .none,
+ .{ .parent_atom_index = local_sym_index },
+ );
+ const code = switch (res) {
+ .ok => code_buffer.items,
+ .fail => |em| {
+ log.err("{s}", .{em.msg});
+ return error.CodegenFail;
+ },
+ };
+
+ const required_alignment = atom.alignment;
+ const code_len = @intCast(u32, code.len);
+ const symbol = atom.getSymbolPtr(self);
+ try self.setSymbolName(symbol, name);
+ symbol.section_number = @intToEnum(coff.SectionNumber, lazy_metadata.section + 1);
+ symbol.type = .{ .complex_type = .NULL, .base_type = .NULL };
+
+ const vaddr = try self.allocateAtom(atom_index, code_len, required_alignment);
+ errdefer self.freeAtom(atom_index);
+
+ log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
+ log.debug(" (required alignment 0x{x})", .{required_alignment});
+
+ atom.size = code_len;
+ symbol.value = vaddr;
+
+ const got_target = SymbolWithLoc{ .sym_index = local_sym_index, .file = null };
+ const got_index = try self.allocateGotEntry(got_target);
+ const got_atom_index = try self.createGotAtom(got_target);
+ const got_atom = self.getAtom(got_atom_index);
+ self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
+ try self.writePtrWidthAtom(got_atom_index);
+
+ self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
+ try self.writeAtom(atom_index, code);
+}
+
+pub fn getOrCreateAtomForLazySymbol(
+ self: *Coff,
+ lazy_sym: link.File.LazySymbol,
+ alignment: u32,
+) !Atom.Index {
+ const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
+ .mod = self.base.options.module.?,
+ });
+ errdefer _ = self.lazy_syms.pop();
+ if (!gop.found_existing) {
+ gop.value_ptr.* = .{
+ .atom = try self.createAtom(),
+ .section = switch (lazy_sym.kind) {
+ .code => self.text_section_index.?,
+ .const_data => self.rdata_section_index.?,
+ },
+ };
+ self.getAtomPtr(gop.value_ptr.atom).alignment = alignment;
+ }
+ return gop.value_ptr.atom;
+}
+
pub fn getOrCreateAtomForDecl(self: *Coff, decl_index: Module.Decl.Index) !Atom.Index {
const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
if (!gop.found_existing) {
@@ -1498,6 +1607,19 @@ pub fn flushModule(self: *Coff, comp: *Compilation, prog_node: *std.Progress.Nod
sub_prog_node.activate();
defer sub_prog_node.end();
+ {
+ var lazy_it = self.lazy_syms.iterator();
+ while (lazy_it.next()) |lazy_entry| {
+ self.updateLazySymbol(
+ lazy_entry.key_ptr.*,
+ lazy_entry.value_ptr.*,
+ ) catch |err| switch (err) {
+ error.CodegenFail => return error.FlushFailure,
+ else => |e| return e,
+ };
+ }
+ }
+
const gpa = self.base.allocator;
while (self.unresolved.popOrNull()) |entry| {
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index 95104ec2e8..3b7c2efa0e 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -63,6 +63,12 @@ const Section = struct {
free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
};
+const LazySymbolMetadata = struct {
+ atom: Atom.Index,
+ shdr: u16,
+ alignment: u32,
+};
+
const DeclMetadata = struct {
atom: Atom.Index,
shdr: u16,
@@ -157,6 +163,9 @@ debug_line_header_dirty: bool = false,
error_flags: File.ErrorFlags = File.ErrorFlags{},
+/// Table of tracked LazySymbols.
+lazy_syms: LazySymbolTable = .{},
+
/// Table of tracked Decls.
decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
@@ -194,6 +203,7 @@ relocs: RelocTable = .{},
const RelocTable = std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Reloc));
const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
+const LazySymbolTable = std.ArrayHashMapUnmanaged(File.LazySymbol, LazySymbolMetadata, File.LazySymbol.Context, true);
/// When allocating, the ideal_capacity is calculated by
/// actual_capacity + (actual_capacity / ideal_factor)
@@ -1011,6 +1021,19 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
sub_prog_node.activate();
defer sub_prog_node.end();
+ {
+ var lazy_it = self.lazy_syms.iterator();
+ while (lazy_it.next()) |lazy_entry| {
+ self.updateLazySymbol(
+ lazy_entry.key_ptr.*,
+ lazy_entry.value_ptr.*,
+ ) catch |err| switch (err) {
+ error.CodegenFail => return error.FlushFailure,
+ else => |e| return e,
+ };
+ }
+ }
+
// TODO This linker code currently assumes there is only 1 compilation unit and it
// corresponds to the Zig source code.
const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
@@ -2344,6 +2367,24 @@ pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
}
}
+pub fn getOrCreateAtomForLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, alignment: u32) !Atom.Index {
+ const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
+ .mod = self.base.options.module.?,
+ });
+ errdefer _ = self.lazy_syms.pop();
+ if (!gop.found_existing) {
+ gop.value_ptr.* = .{
+ .atom = try self.createAtom(),
+ .shdr = switch (lazy_sym.kind) {
+ .code => self.text_section_index.?,
+ .const_data => self.rodata_section_index.?,
+ },
+ .alignment = alignment,
+ };
+ }
+ return gop.value_ptr.atom;
+}
+
pub fn getOrCreateAtomForDecl(self: *Elf, decl_index: Module.Decl.Index) !Atom.Index {
const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
if (!gop.found_existing) {
@@ -2610,6 +2651,79 @@ pub fn updateDecl(self: *Elf, module: *Module, decl_index: Module.Decl.Index) !v
return self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
}
+fn updateLazySymbol(self: *Elf, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void {
+ const gpa = self.base.allocator;
+ const mod = self.base.options.module.?;
+
+ 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 self.shstrtab.insert(gpa, name);
+ };
+ const name = self.shstrtab.get(name_str_index).?;
+
+ const atom_index = lazy_metadata.atom;
+ const atom = self.getAtom(atom_index);
+ const local_sym_index = atom.getSymbolIndex().?;
+
+ const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
+ mod.declPtr(owner_decl).srcLoc()
+ else
+ Module.SrcLoc{
+ .file_scope = undefined,
+ .parent_decl_node = undefined,
+ .lazy = .unneeded,
+ };
+ const res = try codegen.generateLazySymbol(
+ &self.base,
+ src,
+ lazy_sym,
+ &code_buffer,
+ .none,
+ .{ .parent_atom_index = local_sym_index },
+ );
+ const code = switch (res) {
+ .ok => code_buffer.items,
+ .fail => |em| {
+ log.err("{s}", .{em.msg});
+ return error.CodegenFail;
+ },
+ };
+
+ const shdr_index = lazy_metadata.shdr;
+ const phdr_index = self.sections.items(.phdr_index)[shdr_index];
+ const local_sym = atom.getSymbolPtr(self);
+ local_sym.* = .{
+ .st_name = name_str_index,
+ .st_info = (elf.STB_LOCAL << 4) | elf.STT_OBJECT,
+ .st_other = 0,
+ .st_shndx = shdr_index,
+ .st_value = 0,
+ .st_size = 0,
+ };
+ const required_alignment = lazy_metadata.alignment;
+ const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
+ errdefer self.freeAtom(atom_index);
+ log.debug("allocated text block for {s} at 0x{x}", .{ name, vaddr });
+
+ self.offset_table.items[atom.offset_table_index] = vaddr;
+ local_sym.st_value = vaddr;
+ local_sym.st_size = code.len;
+
+ try self.writeSymbol(local_sym_index);
+ try self.writeOffsetTableEntry(atom.offset_table_index);
+
+ const section_offset = vaddr - self.program_headers.items[phdr_index].p_vaddr;
+ const file_offset = self.sections.items(.shdr)[shdr_index].sh_offset + section_offset;
+ try self.base.file.?.pwriteAll(code, file_offset);
+}
+
pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
const gpa = self.base.allocator;
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 4c3301a3b4..7840f5d89d 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -218,6 +218,9 @@ bindings: BindingTable = .{},
/// this will be a table indexed by index into the list of Atoms.
lazy_bindings: BindingTable = .{},
+/// Table of tracked LazySymbols.
+lazy_syms: LazySymbolTable = .{},
+
/// Table of tracked Decls.
decls: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
@@ -229,6 +232,18 @@ const is_hot_update_compatible = switch (builtin.target.os.tag) {
else => false,
};
+const LazySymbolTable = std.ArrayHashMapUnmanaged(
+ link.File.LazySymbol,
+ LazySymbolMetadata,
+ link.File.LazySymbol.Context,
+ true,
+);
+
+const LazySymbolMetadata = struct {
+ atom: Atom.Index,
+ section: u8,
+};
+
const DeclMetadata = struct {
atom: Atom.Index,
section: u8,
@@ -497,6 +512,19 @@ pub fn flushModule(self: *MachO, comp: *Compilation, prog_node: *std.Progress.No
sub_prog_node.activate();
defer sub_prog_node.end();
+ {
+ var lazy_it = self.lazy_syms.iterator();
+ while (lazy_it.next()) |lazy_entry| {
+ self.updateLazySymbol(
+ lazy_entry.key_ptr.*,
+ lazy_entry.value_ptr.*,
+ ) catch |err| switch (err) {
+ error.CodegenFail => return error.FlushFailure,
+ else => |e| return e,
+ };
+ }
+ }
+
const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
if (self.d_sym) |*d_sym| {
@@ -2163,13 +2191,13 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
const name_str_index = blk: {
const index = unnamed_consts.items.len;
- const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
+ const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index });
defer gpa.free(name);
break :blk try self.strtab.insert(gpa, name);
};
- const name = self.strtab.get(name_str_index);
+ const name = self.strtab.get(name_str_index).?;
- log.debug("allocating symbol indexes for {?s}", .{name});
+ log.debug("allocating symbol indexes for {s}", .{name});
const atom_index = try self.createAtom();
@@ -2202,7 +2230,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
try unnamed_consts.append(gpa, atom_index);
- log.debug("allocated atom for {?s} at 0x{x}", .{ name, symbol.n_value });
+ log.debug("allocated atom for {s} at 0x{x}", .{ name, symbol.n_value });
log.debug(" (required alignment 0x{x})", .{required_alignment});
try self.writeAtom(atom_index, code);
@@ -2282,6 +2310,100 @@ pub fn updateDecl(self: *MachO, module: *Module, decl_index: Module.Decl.Index)
try self.updateDeclExports(module, decl_index, module.getDeclExports(decl_index));
}
+fn updateLazySymbol(self: *MachO, lazy_sym: File.LazySymbol, lazy_metadata: LazySymbolMetadata) !void {
+ const gpa = self.base.allocator;
+ const mod = self.base.options.module.?;
+
+ 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 self.strtab.insert(gpa, name);
+ };
+ const name = self.strtab.get(name_str_index).?;
+
+ const atom_index = lazy_metadata.atom;
+ const atom = self.getAtomPtr(atom_index);
+ const local_sym_index = atom.getSymbolIndex().?;
+
+ const src = if (lazy_sym.ty.getOwnerDeclOrNull()) |owner_decl|
+ mod.declPtr(owner_decl).srcLoc()
+ else
+ Module.SrcLoc{
+ .file_scope = undefined,
+ .parent_decl_node = undefined,
+ .lazy = .unneeded,
+ };
+ const res = try codegen.generateLazySymbol(
+ &self.base,
+ src,
+ lazy_sym,
+ &code_buffer,
+ .none,
+ .{ .parent_atom_index = local_sym_index },
+ );
+ const code = switch (res) {
+ .ok => code_buffer.items,
+ .fail => |em| {
+ log.err("{s}", .{em.msg});
+ return error.CodegenFail;
+ },
+ };
+
+ const required_alignment = atom.alignment;
+ const symbol = atom.getSymbolPtr(self);
+ symbol.n_strx = name_str_index;
+ symbol.n_type = macho.N_SECT;
+ symbol.n_sect = lazy_metadata.section + 1;
+ symbol.n_desc = 0;
+
+ const vaddr = try self.allocateAtom(atom_index, code.len, required_alignment);
+ errdefer self.freeAtom(atom_index);
+
+ log.debug("allocated atom for {s} at 0x{x}", .{ name, vaddr });
+ log.debug(" (required alignment 0x{x}", .{required_alignment});
+
+ atom.size = code.len;
+ symbol.n_value = vaddr;
+
+ const got_target = SymbolWithLoc{ .sym_index = local_sym_index, .file = null };
+ const got_index = try self.allocateGotEntry(got_target);
+ const got_atom_index = try self.createGotAtom(got_target);
+ const got_atom = self.getAtom(got_atom_index);
+ self.got_entries.items[got_index].sym_index = got_atom.getSymbolIndex().?;
+ try self.writePtrWidthAtom(got_atom_index);
+
+ self.markRelocsDirtyByTarget(atom.getSymbolWithLoc());
+ try self.writeAtom(atom_index, code);
+}
+
+pub fn getOrCreateAtomForLazySymbol(
+ self: *MachO,
+ lazy_sym: File.LazySymbol,
+ alignment: u32,
+) !Atom.Index {
+ const gop = try self.lazy_syms.getOrPutContext(self.base.allocator, lazy_sym, .{
+ .mod = self.base.options.module.?,
+ });
+ errdefer _ = self.lazy_syms.pop();
+ if (!gop.found_existing) {
+ gop.value_ptr.* = .{
+ .atom = try self.createAtom(),
+ .section = switch (lazy_sym.kind) {
+ .code => self.text_section_index.?,
+ .const_data => self.data_const_section_index.?,
+ },
+ };
+ self.getAtomPtr(gop.value_ptr.atom).alignment = alignment;
+ }
+ return gop.value_ptr.atom;
+}
+
pub fn getOrCreateAtomForDecl(self: *MachO, decl_index: Module.Decl.Index) !Atom.Index {
const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
if (!gop.found_existing) {