authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-03 14:55:18+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-03 12:49:12-07:00
log0134e5d2a1a5042b1485b7bb121870d2eaeb00b6
tree1c5e41cffa699a0e396a08771152d6e024a61af5
parent0483b4a5126c0d07b1e9ad298729e8d34b5d2272

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.

7 files changed, 145 insertions(+), 67 deletions(-)

src/codegen.zig+6-1
......@@ -739,7 +739,6 @@ fn lowerAnonDeclRef(
739739 debug_output: DebugInfoOutput,
740740 reloc_info: RelocInfo,
741741) CodeGenError!Result {
742 _ = src_loc;
743742 _ = debug_output;
744743 const target = bin_file.options.target;
745744 const mod = bin_file.options.module.?;
......@@ -752,6 +751,12 @@ fn lowerAnonDeclRef(
752751 return Result.ok;
753752 }
754753
754 const res = try bin_file.lowerAnonDecl(decl_val, src_loc);
755 switch (res) {
756 .ok => {},
757 .fail => |em| return .{ .fail = em },
758 }
759
755760 const vaddr = try bin_file.getAnonDeclVAddr(decl_val, .{
756761 .parent_atom_index = reloc_info.parent_atom_index,
757762 .offset = code.items.len,
src/link.zig+16
......@@ -937,6 +937,22 @@ pub const File = struct {
937937 }
938938 }
939939
940 pub const LowerResult = @import("codegen.zig").Result;
941
942 pub fn lowerAnonDecl(base: *File, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !LowerResult {
943 if (build_options.only_c) unreachable;
944 switch (base.tag) {
945 .coff => return @fieldParentPtr(Coff, "base", base).lowerAnonDecl(decl_val, src_loc),
946 .elf => return @fieldParentPtr(Elf, "base", base).lowerAnonDecl(decl_val, src_loc),
947 .macho => return @fieldParentPtr(MachO, "base", base).lowerAnonDecl(decl_val, src_loc),
948 .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerAnonDecl(decl_val, src_loc),
949 .c => unreachable,
950 .wasm => return @fieldParentPtr(Wasm, "base", base).lowerAnonDecl(decl_val, src_loc),
951 .spirv => unreachable,
952 .nvptx => unreachable,
953 }
954 }
955
940956 pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
941957 if (build_options.only_c) unreachable;
942958 switch (base.tag) {
src/link/Coff.zig+9-7
......@@ -1727,13 +1727,8 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link
17271727 return 0;
17281728}
17291729
1730pub fn getAnonDeclVAddr(
1731 self: *Coff,
1732 decl_val: InternPool.Index,
1733 reloc_info: link.File.RelocInfo,
1734) !u64 {
1735 // This is basically the same as lowerUnnamedConst except it needs
1736 // to return the same thing as `getDeclVAddr`
1730pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1731 // This is basically the same as lowerUnnamedConst.
17371732 // example:
17381733 // const ty = mod.intern_pool.typeOf(decl_val).toType();
17391734 // const val = decl_val.toValue();
......@@ -1742,6 +1737,13 @@ pub fn getAnonDeclVAddr(
17421737 // be used by more than one function, however, its address is being used so we need
17431738 // to put it in some location.
17441739 // ...
1740 _ = self;
1741 _ = decl_val;
1742 _ = src_loc;
1743 _ = @panic("TODO: link/Coff lowerAnonDecl");
1744}
1745
1746pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
17451747 _ = self;
17461748 _ = decl_val;
17471749 _ = reloc_info;
src/link/Elf.zig+87-38
......@@ -155,12 +155,14 @@ last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFre
155155/// value assigned to label `foo` is an unnamed constant belonging/associated
156156/// with `Decl` `main`, and lives as long as that `Decl`.
157157unnamed_consts: UnnamedConstTable = .{},
158anon_decls: AnonDeclTable = .{},
158159
159160comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
160161comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
161162comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
162163
163164const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
165const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index);
164166const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
165167
166168/// When allocating, the ideal_capacity is calculated by
......@@ -321,6 +323,7 @@ pub fn deinit(self: *Elf) void {
321323 }
322324 self.unnamed_consts.deinit(gpa);
323325 }
326 self.anon_decls.deinit(gpa);
324327
325328 if (self.dwarf) |*dw| {
326329 dw.deinit();
......@@ -348,13 +351,8 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.
348351 return vaddr;
349352}
350353
351pub fn getAnonDeclVAddr(
352 self: *Elf,
353 decl_val: InternPool.Index,
354 reloc_info: link.File.RelocInfo,
355) !u64 {
356 // This is basically the same as lowerUnnamedConst except it needs
357 // to return the same thing as `getDeclVAddr`
354pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
355 // This is basically the same as lowerUnnamedConst.
358356 // example:
359357 // const ty = mod.intern_pool.typeOf(decl_val).toType();
360358 // const val = decl_val.toValue();
......@@ -363,10 +361,44 @@ pub fn getAnonDeclVAddr(
363361 // be used by more than one function, however, its address is being used so we need
364362 // to put it in some location.
365363 // ...
366 _ = self;
367 _ = decl_val;
368 _ = reloc_info;
369 _ = @panic("TODO: link/Elf getAnonDeclVAddr");
364 const gpa = self.base.allocator;
365 const gop = try self.anon_decls.getOrPut(gpa, decl_val);
366 if (!gop.found_existing) {
367 const mod = self.base.options.module.?;
368 const ty = mod.intern_pool.typeOf(decl_val).toType();
369 const val = decl_val.toValue();
370 const tv = TypedValue{ .ty = ty, .val = val };
371 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});
372 defer gpa.free(name);
373 const res = self.lowerConst(name, tv, self.rodata_section_index.?, src_loc) catch |err| switch (err) {
374 else => {
375 // TODO improve error message
376 const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{
377 @errorName(err),
378 });
379 return .{ .fail = em };
380 },
381 };
382 const sym_index = switch (res) {
383 .ok => |sym_index| sym_index,
384 .fail => |em| return .{ .fail = em },
385 };
386 gop.value_ptr.* = sym_index;
387 }
388 return .ok;
389}
390
391pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
392 const sym_index = self.anon_decls.get(decl_val).?;
393 const sym = self.symbol(sym_index);
394 const vaddr = sym.value;
395 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
396 try parent_atom.addReloc(self, .{
397 .r_offset = reloc_info.offset,
398 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64,
399 .r_addend = reloc_info.addend,
400 });
401 return vaddr;
370402}
371403
372404/// Returns end pos of collision, if any.
......@@ -3126,50 +3158,68 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
31263158
31273159pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
31283160 const gpa = self.base.allocator;
3129
3130 var code_buffer = std.ArrayList(u8).init(gpa);
3131 defer code_buffer.deinit();
3132
31333161 const mod = self.base.options.module.?;
31343162 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
31353163 if (!gop.found_existing) {
31363164 gop.value_ptr.* = .{};
31373165 }
31383166 const unnamed_consts = gop.value_ptr;
3139
31403167 const decl = mod.declPtr(decl_index);
3141 const name_str_index = blk: {
3142 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3143 const index = unnamed_consts.items.len;
3144 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
3145 defer gpa.free(name);
3146 break :blk try self.strtab.insert(gpa, name);
3168 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3169 const index = unnamed_consts.items.len;
3170 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
3171 defer gpa.free(name);
3172 const sym_index = switch (try self.lowerConst(name, typed_value, self.rodata_section_index.?, decl.srcLoc(mod))) {
3173 .ok => |sym_index| sym_index,
3174 .fail => |em| {
3175 decl.analysis = .codegen_failure;
3176 try mod.failed_decls.put(mod.gpa, decl_index, em);
3177 log.err("{s}", .{em.msg});
3178 return error.CodegenFail;
3179 },
31473180 };
3181 const sym = self.symbol(sym_index);
3182 try unnamed_consts.append(gpa, sym.atom_index);
3183 return sym_index;
3184}
3185
3186const LowerConstResult = union(enum) {
3187 ok: Symbol.Index,
3188 fail: *Module.ErrorMsg,
3189};
3190
3191fn lowerConst(
3192 self: *Elf,
3193 name: []const u8,
3194 tv: TypedValue,
3195 output_section_index: u16,
3196 src_loc: Module.SrcLoc,
3197) !LowerConstResult {
3198 const gpa = self.base.allocator;
3199
3200 var code_buffer = std.ArrayList(u8).init(gpa);
3201 defer code_buffer.deinit();
31483202
3203 const mod = self.base.options.module.?;
31493204 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
31503205 const sym_index = try zig_module.addAtom(self);
31513206
3152 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{
3207 const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{
31533208 .none = {},
31543209 }, .{
31553210 .parent_atom_index = sym_index,
31563211 });
31573212 const code = switch (res) {
31583213 .ok => code_buffer.items,
3159 .fail => |em| {
3160 decl.analysis = .codegen_failure;
3161 try mod.failed_decls.put(mod.gpa, decl_index, em);
3162 log.err("{s}", .{em.msg});
3163 return error.CodegenFail;
3164 },
3214 .fail => |em| return .{ .fail = em },
31653215 };
31663216
3167 const required_alignment = typed_value.ty.abiAlignment(mod);
3168 const shdr_index = self.rodata_section_index.?;
3169 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
3217 const required_alignment = tv.ty.abiAlignment(mod);
3218 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
31703219 const local_sym = self.symbol(sym_index);
3220 const name_str_index = try self.strtab.insert(gpa, name);
31713221 local_sym.name_offset = name_str_index;
3172 local_sym.output_section_index = self.rodata_section_index.?;
3222 local_sym.output_section_index = output_section_index;
31733223 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];
31743224 local_esym.st_name = name_str_index;
31753225 local_esym.st_info |= elf.STT_OBJECT;
......@@ -3179,21 +3229,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
31793229 atom_ptr.name_offset = name_str_index;
31803230 atom_ptr.alignment = required_alignment;
31813231 atom_ptr.size = code.len;
3182 atom_ptr.output_section_index = self.rodata_section_index.?;
3232 atom_ptr.output_section_index = output_section_index;
31833233
31843234 try atom_ptr.allocate(self);
3235 // TODO rename and re-audit this method
31853236 errdefer self.freeDeclMetadata(sym_index);
31863237
31873238 local_sym.value = atom_ptr.value;
31883239 local_esym.st_value = atom_ptr.value;
31893240
3190 try unnamed_consts.append(gpa, atom_ptr.atom_index);
3191
31923241 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
3193 const file_offset = self.shdrs.items[shdr_index].sh_offset + section_offset;
3242 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
31943243 try self.base.file.?.pwriteAll(code, file_offset);
31953244
3196 return sym_index;
3245 return .{ .ok = sym_index };
31973246}
31983247
31993248pub fn updateDeclExports(
src/link/MachO.zig+9-7
......@@ -2840,13 +2840,8 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
28402840 return 0;
28412841}
28422842
2843pub fn getAnonDeclVAddr(
2844 self: *MachO,
2845 decl_val: InternPool.Index,
2846 reloc_info: link.File.RelocInfo,
2847) !u64 {
2848 // This is basically the same as lowerUnnamedConst except it needs
2849 // to return the same thing as `getDeclVAddr`
2843pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
2844 // This is basically the same as lowerUnnamedConst.
28502845 // example:
28512846 // const ty = mod.intern_pool.typeOf(decl_val).toType();
28522847 // const val = decl_val.toValue();
......@@ -2855,6 +2850,13 @@ pub fn getAnonDeclVAddr(
28552850 // be used by more than one function, however, its address is being used so we need
28562851 // to put it in some location.
28572852 // ...
2853 _ = self;
2854 _ = decl_val;
2855 _ = src_loc;
2856 _ = @panic("TODO: link/MachO lowerAnonDecl");
2857}
2858
2859pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
28582860 _ = self;
28592861 _ = decl_val;
28602862 _ = reloc_info;
src/link/Plan9.zig+9-7
......@@ -1418,13 +1418,8 @@ pub fn getDeclVAddr(
14181418 return undefined;
14191419}
14201420
1421pub fn getAnonDeclVAddr(
1422 self: *Plan9,
1423 decl_val: InternPool.Index,
1424 reloc_info: link.File.RelocInfo,
1425) !u64 {
1426 // This is basically the same as lowerUnnamedConst except it needs
1427 // to return the same thing as `getDeclVAddr`
1421pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1422 // This is basically the same as lowerUnnamedConst.
14281423 // example:
14291424 // const ty = mod.intern_pool.typeOf(decl_val).toType();
14301425 // const val = decl_val.toValue();
......@@ -1433,6 +1428,13 @@ pub fn getAnonDeclVAddr(
14331428 // be used by more than one function, however, its address is being used so we need
14341429 // to put it in some location.
14351430 // ...
1431 _ = self;
1432 _ = decl_val;
1433 _ = src_loc;
1434 _ = @panic("TODO: link/Plan9 lowerAnonDecl");
1435}
1436
1437pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
14361438 _ = self;
14371439 _ = decl_val;
14381440 _ = reloc_info;
src/link/Wasm.zig+9-7
......@@ -1679,13 +1679,8 @@ pub fn getDeclVAddr(
16791679 return target_symbol_index;
16801680}
16811681
1682pub fn getAnonDeclVAddr(
1683 wasm: *Wasm,
1684 decl_val: InternPool.Index,
1685 reloc_info: link.File.RelocInfo,
1686) !u64 {
1687 // This is basically the same as lowerUnnamedConst except it needs
1688 // to return the same thing as `getDeclVAddr`
1682pub fn lowerAnonDecl(self: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1683 // This is basically the same as lowerUnnamedConst.
16891684 // example:
16901685 // const ty = mod.intern_pool.typeOf(decl_val).toType();
16911686 // const val = decl_val.toValue();
......@@ -1694,6 +1689,13 @@ pub fn getAnonDeclVAddr(
16941689 // be used by more than one function, however, its address is being used so we need
16951690 // to put it in some location.
16961691 // ...
1692 _ = self;
1693 _ = decl_val;
1694 _ = src_loc;
1695 _ = @panic("TODO: link/Wasm lowerAnonDecl");
1696}
1697
1698pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
16971699 _ = wasm;
16981700 _ = decl_val;
16991701 _ = reloc_info;