aboutsummaryrefslogtreecommitdiff
path: root/src/link
diff options
context:
space:
mode:
authorJakub Konka <kubkon@jakubkonka.com>2023-10-03 14:55:18 +0200
committerAndrew Kelley <andrew@ziglang.org>2023-10-03 12:49:12 -0700
commit0134e5d2a1a5042b1485b7bb121870d2eaeb00b6 (patch)
tree1c5e41cffa699a0e396a08771152d6e024a61af5 /src/link
parent0483b4a5126c0d07b1e9ad298729e8d34b5d2272 (diff)
downloadzig-0134e5d2a1a5042b1485b7bb121870d2eaeb00b6.tar.gz
zig-0134e5d2a1a5042b1485b7bb121870d2eaeb00b6.zip
codegen: separate getAnonDeclVAddr into lowerAnonDecl and the former
Implement the stub for Elf. I believe that separating the concerns, namely, having an interface function that is responsible for signalling the linker to lower the anon decl only, and a separate function to obtain the decl's vaddr is preferable since it allows us to handle codegen errors in a simpler way.
Diffstat (limited to 'src/link')
-rw-r--r--src/link/Coff.zig16
-rw-r--r--src/link/Elf.zig125
-rw-r--r--src/link/MachO.zig16
-rw-r--r--src/link/Plan9.zig16
-rw-r--r--src/link/Wasm.zig16
5 files changed, 123 insertions, 66 deletions
diff --git a/src/link/Coff.zig b/src/link/Coff.zig
index 8aebd0de6a..bfd7c9da46 100644
--- a/src/link/Coff.zig
+++ b/src/link/Coff.zig
@@ -1727,13 +1727,8 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link
return 0;
}
-pub fn getAnonDeclVAddr(
- self: *Coff,
- decl_val: InternPool.Index,
- reloc_info: link.File.RelocInfo,
-) !u64 {
- // This is basically the same as lowerUnnamedConst except it needs
- // to return the same thing as `getDeclVAddr`
+pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
+ // This is basically the same as lowerUnnamedConst.
// example:
// const ty = mod.intern_pool.typeOf(decl_val).toType();
// const val = decl_val.toValue();
@@ -1744,6 +1739,13 @@ pub fn getAnonDeclVAddr(
// ...
_ = self;
_ = decl_val;
+ _ = src_loc;
+ _ = @panic("TODO: link/Coff lowerAnonDecl");
+}
+
+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");
}
diff --git a/src/link/Elf.zig b/src/link/Elf.zig
index eff720eac4..a9a4757883 100644
--- a/src/link/Elf.zig
+++ b/src/link/Elf.zig
@@ -155,12 +155,14 @@ last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFre
/// value assigned to label `foo` is an unnamed constant belonging/associated
/// with `Decl` `main`, and lives as long as that `Decl`.
unnamed_consts: UnnamedConstTable = .{},
+anon_decls: AnonDeclTable = .{},
comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
+const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index);
const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
/// When allocating, the ideal_capacity is calculated by
@@ -321,6 +323,7 @@ pub fn deinit(self: *Elf) void {
}
self.unnamed_consts.deinit(gpa);
}
+ self.anon_decls.deinit(gpa);
if (self.dwarf) |*dw| {
dw.deinit();
@@ -348,13 +351,8 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.
return vaddr;
}
-pub fn getAnonDeclVAddr(
- self: *Elf,
- decl_val: InternPool.Index,
- reloc_info: link.File.RelocInfo,
-) !u64 {
- // This is basically the same as lowerUnnamedConst except it needs
- // to return the same thing as `getDeclVAddr`
+pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
+ // This is basically the same as lowerUnnamedConst.
// example:
// const ty = mod.intern_pool.typeOf(decl_val).toType();
// const val = decl_val.toValue();
@@ -363,10 +361,44 @@ pub fn getAnonDeclVAddr(
// 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;
- _ = reloc_info;
- _ = @panic("TODO: link/Elf getAnonDeclVAddr");
+ 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.rodata_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 sym_index = switch (res) {
+ .ok => |sym_index| sym_index,
+ .fail => |em| return .{ .fail = em },
+ };
+ gop.value_ptr.* = sym_index;
+ }
+ return .ok;
+}
+
+pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
+ const sym_index = self.anon_decls.get(decl_val).?;
+ const sym = self.symbol(sym_index);
+ const vaddr = sym.value;
+ const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
+ try parent_atom.addReloc(self, .{
+ .r_offset = reloc_info.offset,
+ .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64,
+ .r_addend = reloc_info.addend,
+ });
+ return vaddr;
}
/// Returns end pos of collision, if any.
@@ -3126,50 +3158,68 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
pub fn lowerUnnamedConst(self: *Elf, typed_value: 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 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 name_str_index = blk: {
- 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);
- break :blk try self.strtab.insert(gpa, name);
+ 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(name, typed_value, self.rodata_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 = self.symbol(sym_index);
+ try unnamed_consts.append(gpa, sym.atom_index);
+ return sym_index;
+}
+
+const LowerConstResult = union(enum) {
+ ok: Symbol.Index,
+ fail: *Module.ErrorMsg,
+};
+
+fn lowerConst(
+ self: *Elf,
+ name: []const u8,
+ tv: TypedValue,
+ output_section_index: 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 zig_module = self.file(self.zig_module_index.?).?.zig_module;
const sym_index = try zig_module.addAtom(self);
- const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{
+ const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{
.none = {},
}, .{
.parent_atom_index = sym_index,
});
const code = switch (res) {
.ok => code_buffer.items,
- .fail => |em| {
- decl.analysis = .codegen_failure;
- try mod.failed_decls.put(mod.gpa, decl_index, em);
- log.err("{s}", .{em.msg});
- return error.CodegenFail;
- },
+ .fail => |em| return .{ .fail = em },
};
- const required_alignment = typed_value.ty.abiAlignment(mod);
- const shdr_index = self.rodata_section_index.?;
- const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
+ const required_alignment = tv.ty.abiAlignment(mod);
+ const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
const local_sym = self.symbol(sym_index);
+ const name_str_index = try self.strtab.insert(gpa, name);
local_sym.name_offset = name_str_index;
- local_sym.output_section_index = self.rodata_section_index.?;
+ local_sym.output_section_index = output_section_index;
const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];
local_esym.st_name = name_str_index;
local_esym.st_info |= elf.STT_OBJECT;
@@ -3179,21 +3229,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
atom_ptr.name_offset = name_str_index;
atom_ptr.alignment = required_alignment;
atom_ptr.size = code.len;
- atom_ptr.output_section_index = self.rodata_section_index.?;
+ atom_ptr.output_section_index = output_section_index;
try atom_ptr.allocate(self);
+ // TODO rename and re-audit this method
errdefer self.freeDeclMetadata(sym_index);
local_sym.value = atom_ptr.value;
local_esym.st_value = atom_ptr.value;
- try unnamed_consts.append(gpa, atom_ptr.atom_index);
-
const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
- const file_offset = self.shdrs.items[shdr_index].sh_offset + section_offset;
+ const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
try self.base.file.?.pwriteAll(code, file_offset);
- return sym_index;
+ return .{ .ok = sym_index };
}
pub fn updateDeclExports(
diff --git a/src/link/MachO.zig b/src/link/MachO.zig
index 3786eccba9..10e6c614de 100644
--- a/src/link/MachO.zig
+++ b/src/link/MachO.zig
@@ -2840,13 +2840,8 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
return 0;
}
-pub fn getAnonDeclVAddr(
- self: *MachO,
- decl_val: InternPool.Index,
- reloc_info: link.File.RelocInfo,
-) !u64 {
- // This is basically the same as lowerUnnamedConst except it needs
- // to return the same thing as `getDeclVAddr`
+pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
+ // This is basically the same as lowerUnnamedConst.
// example:
// const ty = mod.intern_pool.typeOf(decl_val).toType();
// const val = decl_val.toValue();
@@ -2857,6 +2852,13 @@ pub fn getAnonDeclVAddr(
// ...
_ = self;
_ = decl_val;
+ _ = src_loc;
+ _ = @panic("TODO: link/MachO lowerAnonDecl");
+}
+
+pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
+ _ = self;
+ _ = decl_val;
_ = reloc_info;
_ = @panic("TODO: link/MachO getAnonDeclVAddr");
}
diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig
index ba333c666c..5355e19e1b 100644
--- a/src/link/Plan9.zig
+++ b/src/link/Plan9.zig
@@ -1418,13 +1418,8 @@ pub fn getDeclVAddr(
return undefined;
}
-pub fn getAnonDeclVAddr(
- self: *Plan9,
- decl_val: InternPool.Index,
- reloc_info: link.File.RelocInfo,
-) !u64 {
- // This is basically the same as lowerUnnamedConst except it needs
- // to return the same thing as `getDeclVAddr`
+pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
+ // This is basically the same as lowerUnnamedConst.
// example:
// const ty = mod.intern_pool.typeOf(decl_val).toType();
// const val = decl_val.toValue();
@@ -1435,6 +1430,13 @@ pub fn getAnonDeclVAddr(
// ...
_ = self;
_ = decl_val;
+ _ = src_loc;
+ _ = @panic("TODO: link/Plan9 lowerAnonDecl");
+}
+
+pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
+ _ = self;
+ _ = decl_val;
_ = reloc_info;
_ = @panic("TODO: link/Plan9 getAnonDeclVAddr");
}
diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig
index 9ae580bb9e..34244d2247 100644
--- a/src/link/Wasm.zig
+++ b/src/link/Wasm.zig
@@ -1679,13 +1679,8 @@ pub fn getDeclVAddr(
return target_symbol_index;
}
-pub fn getAnonDeclVAddr(
- wasm: *Wasm,
- decl_val: InternPool.Index,
- reloc_info: link.File.RelocInfo,
-) !u64 {
- // This is basically the same as lowerUnnamedConst except it needs
- // to return the same thing as `getDeclVAddr`
+pub fn lowerAnonDecl(self: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
+ // This is basically the same as lowerUnnamedConst.
// example:
// const ty = mod.intern_pool.typeOf(decl_val).toType();
// const val = decl_val.toValue();
@@ -1694,6 +1689,13 @@ pub fn getAnonDeclVAddr(
// 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/Wasm lowerAnonDecl");
+}
+
+pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
_ = wasm;
_ = decl_val;
_ = reloc_info;