mirror of
https://github.com/ziglang/zig.git
synced 2026-01-07 14:03:26 +00:00
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:
parent
0483b4a512
commit
0134e5d2a1
@ -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,
|
||||
|
||||
16
src/link.zig
16
src/link.zig
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
135
src/link/Elf.zig
135
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,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(
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user