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) = .{},...@@ -185,12 +185,12 @@ misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
185lazy_syms: LazySymbolTable = .{},185lazy_syms: LazySymbolTable = .{},
186186
187/// Table of tracked Decls.187/// Table of tracked Decls.
188decls: std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata) = .{},188decls: DeclTable = .{},
189189
190/// List of atoms that are owned directly by the linker.190/// List of atoms that are owned directly by the linker.
191atoms: std.ArrayListUnmanaged(Atom) = .{},191atoms: std.ArrayListUnmanaged(Atom) = .{},
192/// Table of last atom index in a section and matching atom free list if any.192/// 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
195/// Table of unnamed constants associated with a parent `Decl`.195/// Table of unnamed constants associated with a parent `Decl`.
196/// We store them here so that we can free the constants whenever the `Decl`196/// 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) = .{}...@@ -220,8 +220,10 @@ comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}
220220
221const AtomList = std.ArrayListUnmanaged(Atom.Index);221const AtomList = std.ArrayListUnmanaged(Atom.Index);
222const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));222const 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);
224const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);225const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
226const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
225227
226/// When allocating, the ideal_capacity is calculated by228/// When allocating, the ideal_capacity is calculated by
227/// actual_capacity + (actual_capacity / ideal_factor)229/// actual_capacity + (actual_capacity / ideal_factor)
...@@ -445,7 +447,14 @@ pub fn deinit(self: *Elf) void {...@@ -445,7 +447,14 @@ pub fn deinit(self: *Elf) void {
445 }447 }
446 self.unnamed_consts.deinit(gpa);448 self.unnamed_consts.deinit(gpa);
447 }449 }
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
450 if (self.dwarf) |*dw| {459 if (self.dwarf) |*dw| {
451 dw.deinit();460 dw.deinit();
...@@ -497,8 +506,8 @@ pub fn lowerAnonDecl(...@@ -497,8 +506,8 @@ pub fn lowerAnonDecl(
497 .none => ty.abiAlignment(mod),506 .none => ty.abiAlignment(mod),
498 else => explicit_alignment,507 else => explicit_alignment,
499 };508 };
500 if (self.anon_decls.get(decl_val)) |sym_index| {509 if (self.anon_decls.get(decl_val)) |metadata| {
501 const existing_alignment = self.symbol(sym_index).atom(self).?.alignment;510 const existing_alignment = self.symbol(metadata.symbol_index).atom(self).?.alignment;
502 if (decl_alignment.order(existing_alignment).compare(.lte))511 if (decl_alignment.order(existing_alignment).compare(.lte))
503 return .ok;512 return .ok;
504 }513 }
...@@ -528,13 +537,13 @@ pub fn lowerAnonDecl(...@@ -528,13 +537,13 @@ pub fn lowerAnonDecl(
528 .ok => |sym_index| sym_index,537 .ok => |sym_index| sym_index,
529 .fail => |em| return .{ .fail = em },538 .fail => |em| return .{ .fail = em },
530 };539 };
531 try self.anon_decls.put(gpa, decl_val, sym_index);540 try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
532 return .ok;541 return .ok;
533}542}
534543
535pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {544pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
536 assert(self.llvm_object == null);545 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;
538 const sym = self.symbol(sym_index);547 const sym = self.symbol(sym_index);
539 const vaddr = sym.value;548 const vaddr = sym.value;
540 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;549 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...@@ -3122,10 +3131,7 @@ pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Sy
3122 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);3131 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
3123 if (!gop.found_existing) {3132 if (!gop.found_existing) {
3124 const zig_module = self.file(self.zig_module_index.?).?.zig_module;3133 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3125 gop.value_ptr.* = .{3134 gop.value_ptr.* = .{ .symbol_index = try zig_module.addAtom(self) };
3126 .symbol_index = try zig_module.addAtom(self),
3127 .exports = .{},
3128 };
3129 }3135 }
3130 return gop.value_ptr.symbol_index;3136 return gop.value_ptr.symbol_index;
3131}3137}
...@@ -3573,31 +3579,30 @@ pub fn updateExports(...@@ -3573,31 +3579,30 @@ pub fn updateExports(
3573 defer tracy.end();3579 defer tracy.end();
35743580
3575 const gpa = self.base.allocator;3581 const gpa = self.base.allocator;
35763582 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3577 const decl_index = switch (exported) {3583 const metadata = switch (exported) {
3578 .decl_index => |i| i,3584 .decl_index => |decl_index| blk: {
3579 .value => |val| {3585 _ = try self.getOrCreateMetadataForDecl(decl_index);
3580 _ = val;3586 break :blk self.decls.getPtr(decl_index).?;
3581 @panic("TODO: implement ELF linker code for exporting a constant value");
3582 },3587 },
3588 // TODO is it possible to request export before const being lowered?
3589 .value => |value| self.anon_decls.getPtr(value).?,
3583 };3590 };
3584 const zig_module = self.file(self.zig_module_index.?).?.zig_module;3591 const sym_index = metadata.symbol_index;
3585 const decl = mod.declPtr(decl_index);3592 const esym_index = self.symbol(sym_index).esym_index;
3586 const decl_sym_index = try self.getOrCreateMetadataForDecl(decl_index);3593 const esym = zig_module.local_esyms.items(.elf_sym)[esym_index];
3587 const decl_esym_index = self.symbol(decl_sym_index).esym_index;3594 const esym_shndx = zig_module.local_esyms.items(.shndx)[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).?;
35913595
3592 for (exports) |exp| {3596 for (exports) |exp| {
3593 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
3594 if (exp.opts.section.unwrap()) |section_name| {3597 if (exp.opts.section.unwrap()) |section_name| {
3595 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {3598 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
3596 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);3599 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3597 mod.failed_exports.putAssumeCapacityNoClobber(3600 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3598 exp,3601 gpa,
3599 try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: ExportOptions.section", .{}),3602 exp.getSrcLoc(mod),
3600 );3603 "Unimplemented: ExportOptions.section",
3604 .{},
3605 ));
3601 continue;3606 continue;
3602 }3607 }
3603 }3608 }
...@@ -3607,34 +3612,37 @@ pub fn updateExports(...@@ -3607,34 +3612,37 @@ pub fn updateExports(
3607 .Weak => elf.STB_WEAK,3612 .Weak => elf.STB_WEAK,
3608 .LinkOnce => {3613 .LinkOnce => {
3609 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);3614 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3610 mod.failed_exports.putAssumeCapacityNoClobber(3615 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3611 exp,3616 gpa,
3612 try Module.ErrorMsg.create(gpa, decl.srcLoc(mod), "Unimplemented: GlobalLinkage.LinkOnce", .{}),3617 exp.getSrcLoc(mod),
3613 );3618 "Unimplemented: GlobalLinkage.LinkOnce",
3619 .{},
3620 ));
3614 continue;3621 continue;
3615 },3622 },
3616 };3623 };
3617 const stt_bits: u8 = @as(u4, @truncate(decl_esym.st_info));3624 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
36183625 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
3619 const name_off = try self.strtab.insert(gpa, exp_name);3626 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: {3627 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
3621 const sym_index = try zig_module.addGlobalEsym(gpa);3628 const global_esym_index = try zig_module.addGlobalEsym(gpa);
3622 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);3629 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);
3623 const esym = zig_module.elfSym(sym_index);3630 const global_esym = zig_module.elfSym(global_esym_index);
3624 esym.st_name = name_off;3631 global_esym.st_name = name_off;
3625 lookup_gop.value_ptr.* = sym_index;3632 lookup_gop.value_ptr.* = global_esym_index;
3626 try decl_metadata.exports.append(gpa, sym_index);3633 try metadata.exports.append(gpa, global_esym_index);
3627 const gop = try self.getOrPutGlobal(name_off);3634 const gop = try self.getOrPutGlobal(name_off);
3628 try zig_module.global_symbols.append(gpa, gop.index);3635 try zig_module.global_symbols.append(gpa, gop.index);
3629 break :blk sym_index;3636 break :blk global_esym_index;
3630 };3637 };
3631 const global_esym_index = sym_index & ZigModule.symbol_mask;3638
3632 const global_esym = &zig_module.global_esyms.items(.elf_sym)[global_esym_index];3639 const actual_esym_index = global_esym_index & ZigModule.symbol_mask;
3633 global_esym.st_value = self.symbol(decl_sym_index).value;3640 const global_esym = &zig_module.global_esyms.items(.elf_sym)[actual_esym_index];
3634 global_esym.st_shndx = decl_esym.st_shndx;3641 global_esym.st_value = self.symbol(sym_index).value;
3642 global_esym.st_shndx = esym.st_shndx;
3635 global_esym.st_info = (stb_bits << 4) | stt_bits;3643 global_esym.st_info = (stb_bits << 4) | stt_bits;
3636 global_esym.st_name = name_off;3644 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;
3638 }3646 }
3639}3647}
36403648
test/behavior/export_builtin.zig+2-1
...@@ -54,7 +54,7 @@ test "exporting using field access" {...@@ -54,7 +54,7 @@ test "exporting using field access" {
54test "exporting comptime-known value" {54test "exporting comptime-known value" {
55 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;55 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
56 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;56 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;
58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;58 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
59 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;59 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
60 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;60 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
...@@ -71,6 +71,7 @@ test "exporting comptime var" {...@@ -71,6 +71,7 @@ test "exporting comptime var" {
71 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;71 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;72 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
73 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;73 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;
74 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;75 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
75 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;76 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
76 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;77 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;