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.
This commit is contained in:
Jakub Konka 2023-10-03 14:55:18 +02:00 committed by Andrew Kelley
parent 0483b4a512
commit 0134e5d2a1
7 changed files with 150 additions and 72 deletions

View File

@ -739,7 +739,6 @@ fn lowerAnonDeclRef(
debug_output: DebugInfoOutput,
reloc_info: RelocInfo,
) CodeGenError!Result {
_ = src_loc;
_ = debug_output;
const target = bin_file.options.target;
const mod = bin_file.options.module.?;
@ -752,6 +751,12 @@ fn lowerAnonDeclRef(
return Result.ok;
}
const res = try bin_file.lowerAnonDecl(decl_val, src_loc);
switch (res) {
.ok => {},
.fail => |em| return .{ .fail = em },
}
const vaddr = try bin_file.getAnonDeclVAddr(decl_val, .{
.parent_atom_index = reloc_info.parent_atom_index,
.offset = code.items.len,

View File

@ -937,6 +937,22 @@ pub const File = struct {
}
}
pub const LowerResult = @import("codegen.zig").Result;
pub fn lowerAnonDecl(base: *File, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !LowerResult {
if (build_options.only_c) unreachable;
switch (base.tag) {
.coff => return @fieldParentPtr(Coff, "base", base).lowerAnonDecl(decl_val, src_loc),
.elf => return @fieldParentPtr(Elf, "base", base).lowerAnonDecl(decl_val, src_loc),
.macho => return @fieldParentPtr(MachO, "base", base).lowerAnonDecl(decl_val, src_loc),
.plan9 => return @fieldParentPtr(Plan9, "base", base).lowerAnonDecl(decl_val, src_loc),
.c => unreachable,
.wasm => return @fieldParentPtr(Wasm, "base", base).lowerAnonDecl(decl_val, src_loc),
.spirv => unreachable,
.nvptx => unreachable,
}
}
pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
if (build_options.only_c) unreachable;
switch (base.tag) {

View File

@ -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();
@ -1742,6 +1737,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/Coff lowerAnonDecl");
}
pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
_ = self;
_ = decl_val;
_ = reloc_info;

View File

@ -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,36 +3158,19 @@ 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 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, .{
.none = {},
}, .{
.parent_atom_index = sym_index,
});
const code = switch (res) {
.ok => code_buffer.items,
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);
@ -3163,13 +3178,48 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
return error.CodegenFail;
},
};
const sym = self.symbol(sym_index);
try unnamed_consts.append(gpa, sym.atom_index);
return sym_index;
}
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 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, 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 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(

View File

@ -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();
@ -2855,6 +2850,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/MachO lowerAnonDecl");
}
pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
_ = self;
_ = decl_val;
_ = reloc_info;

View File

@ -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();
@ -1433,6 +1428,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/Plan9 lowerAnonDecl");
}
pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
_ = self;
_ = decl_val;
_ = reloc_info;

View File

@ -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;