authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-29 10:20:04+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-29 18:55:58+01:00
log209fd8cb9326ed8376bf17e847209ff0598d3aa6
treedaffc3704dae1db1c59631d263a7519e1bc42557
parentfa022d1ecc148280a3b6e95312087b4e8c0c6166

elf: add partial implementation of exporting anon decls


2 files changed, 58 insertions(+), 49 deletions(-)

src/link/Elf.zig+56-48
......@@ -185,12 +185,12 @@ misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
185185lazy_syms: LazySymbolTable = .{},
186186
187187/// Table of tracked Decls.
188decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},
188decls: DeclTable = .{},
189189
190190/// List of atoms that are owned directly by the linker.
191191atoms: std.ArrayListUnmanaged(Atom) = .{},
192192/// Table of last atom index in a section and matching atom free list if any.
193last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList) = .{},
193last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
194194
195195/// Table of unnamed constants associated with a parent `Decl`.
196196/// We store them here so that we can free the constants whenever the `Decl`
......@@ -220,8 +220,10 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}
220220
221221const AtomList = std.ArrayListUnmanaged(Atom.Index);
222222const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
223const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index);
223const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
224const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
224225const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
226const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
225227
226228/// When allocating, the ideal_capacity is calculated by
227229/// actual_capacity + (actual_capacity / ideal_factor)
......@@ -445,7 +447,14 @@ pub fn deinit(self: *Elf) void {
445447 }
446448 self.unnamed_consts.deinit(gpa);
447449 }
448 self.anon_decls.deinit(gpa);
450
451 {
452 var it = self.anon_decls.iterator();
453 while (it.next()) |entry| {
454 entry.value_ptr.exports.deinit(gpa);
455 }
456 self.anon_decls.deinit(gpa);
457 }
449458
450459 if (self.dwarf) |*dw| {
451460 dw.deinit();
......@@ -497,8 +506,8 @@ pub fn lowerAnonDecl(
497506 .none => ty.abiAlignment(mod),
498507 else => explicit_alignment,
499508 };
500 if (self.anon_decls.get(decl_val)) |sym_index| {
501 const existing_alignment = self.symbol(sym_index).atom(self).?.alignment;
509 if (self.anon_decls.get(decl_val)) |metadata| {
510 const existing_alignment = self.symbol(metadata.symbol_index).atom(self).?.alignment;
502511 if (decl_alignment.order(existing_alignment).compare(.lte))
503512 return .ok;
504513 }
......@@ -528,13 +537,13 @@ pub fn lowerAnonDecl(
528537 .ok => |sym_index| sym_index,
529538 .fail => |em| return .{ .fail = em },
530539 };
531 try self.anon_decls.put(gpa, decl_val, sym_index);
540 try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
532541 return .ok;
533542}
534543
535544pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
536545 assert(self.llvm_object == null);
537 const sym_index = self.anon_decls.get(decl_val).?;
546 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
538547 const sym = self.symbol(sym_index);
539548 const vaddr = sym.value;
540549 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
......@@ -3122,10 +3131,7 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy
31223131 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
31233132 if (!gop.found_existing) {
31243133 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3125 gop.value_ptr.* = .{
3126 .symbol_index = try zig_module.addAtom(self),
3127 .exports = .{},
3128 };
3134 gop.value_ptr.* = .{ .symbol_index = try zig_module.addAtom(self) };
31293135 }
31303136 return gop.value_ptr.symbol_index;
31313137}
......@@ -3573,31 +3579,30 @@ pub fn updateExports(
35733579 defer tracy.end();
35743580
35753581 const gpa = self.base.allocator;
3576
3577 const decl_index = switch (exported) {
3578 .decl_index => |i| i,
3579 .value => |val| {
3580 _ = val;
3581 @panic("TODO: implement ELF linker code for exporting a constant value");
3582 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3583 const metadata = switch (exported) {
3584 .decl_index => |decl_index| blk: {
3585 _ = try self.getOrCreateMetadataForDecl(decl_index);
3586 break :blk self.decls.getPtr(decl_index).?;
35823587 },
3588 // TODO is it possible to request export before const being lowered?
3589 .value => |value| self.anon_decls.getPtr(value).?,
35833590 };
3584 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3585 const decl = mod.declPtr(decl_index);
3586 const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
3587 const decl_esym_index = self.symbol(decl_sym_index).esym_index;
3588 const decl_esym = zig_module.local_esyms.items(.elf_sym)[decl_esym_index];
3589 const decl_esym_shndx = zig_module.local_esyms.items(.shndx)[decl_esym_index];
3590 const decl_metadata = self.decls.getPtr(decl_index).?;
3591 const sym_index = metadata.symbol_index;
3592 const esym_index = self.symbol(sym_index).esym_index;
3593 const esym = zig_module.local_esyms.items(.elf_sym)[esym_index];
3594 const esym_shndx = zig_module.local_esyms.items(.shndx)[esym_index];
35913595
35923596 for (exports) |exp| {
3593 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
35943597 if (exp.opts.section.unwrap()) |section_name| {
35953598 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
35963599 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3597 mod.failed_exports.putAssumeCapacityNoClobber(
3598 exp,
3599 try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}),
3600 );
3600 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3601 gpa,
3602 exp.getSrcLoc(mod),
3603 "Unimplemented: ExportOptions.section",
3604 .{},
3605 ));
36013606 continue;
36023607 }
36033608 }
......@@ -3607,34 +3612,37 @@ pub fn updateExports(
36073612 .Weak => elf.STB_WEAK,
36083613 .LinkOnce => {
36093614 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3610 mod.failed_exports.putAssumeCapacityNoClobber(
3611 exp,
3612 try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}),
3613 );
3615 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3616 gpa,
3617 exp.getSrcLoc(mod),
3618 "Unimplemented: GlobalLinkage.LinkOnce",
3619 .{},
3620 ));
36143621 continue;
36153622 },
36163623 };
3617 const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info));
3618
3624 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
3625 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
36193626 const name_off = try self.strtab.insert(gpa, exp_name);
3620 const sym_index = if (decl_metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
3621 const sym_index = try zig_module.addGlobalEsym(gpa);
3627 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
3628 const global_esym_index = try zig_module.addGlobalEsym(gpa);
36223629 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);
3623 const esym = zig_module.elfSym(sym_index);
3624 esym.st_name = name_off;
3625 lookup_gop.value_ptr.* = sym_index;
3626 try decl_metadata.exports.append(gpa, sym_index);
3630 const global_esym = zig_module.elfSym(global_esym_index);
3631 global_esym.st_name = name_off;
3632 lookup_gop.value_ptr.* = global_esym_index;
3633 try metadata.exports.append(gpa, global_esym_index);
36273634 const gop = try self.getOrPutGlobal(name_off);
36283635 try zig_module.global_symbols.append(gpa, gop.index);
3629 break :blk sym_index;
3636 break :blk global_esym_index;
36303637 };
3631 const global_esym_index = sym_index & ZigModule.symbol_mask;
3632 const global_esym = &zig_module.global_esyms.items(.elf_sym)[global_esym_index];
3633 global_esym.st_value = self.symbol(decl_sym_index).value;
3634 global_esym.st_shndx = decl_esym.st_shndx;
3638
3639 const actual_esym_index = global_esym_index & ZigModule.symbol_mask;
3640 const global_esym = &zig_module.global_esyms.items(.elf_sym)[actual_esym_index];
3641 global_esym.st_value = self.symbol(sym_index).value;
3642 global_esym.st_shndx = esym.st_shndx;
36353643 global_esym.st_info = (stb_bits << 4) | stt_bits;
36363644 global_esym.st_name = name_off;
3637 zig_module.global_esyms.items(.shndx)[global_esym_index] = decl_esym_shndx;
3645 zig_module.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
36383646 }
36393647}
36403648
test/behavior/export_builtin.zig+2-1
......@@ -54,7 +54,7 @@ test "exporting using field access" {
5454test "exporting comptime-known value" {
5555 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
5656 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
57 if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
5858 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
5959 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
6060 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
......@@ -71,6 +71,7 @@ test "exporting comptime var" {
7171 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
7272 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
7373 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
74 // if (builtin.zig_backend == .stage2_x86_64 and builtin.target.ofmt != .elf) return error.SkipZigTest;
7475 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
7576 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
7677 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;