authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-30 19:08:44+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-30 19:09:13+01:00
log9bdbb6312f78764c0a5760ab035341f6cf09255b
treed38925bb791a1b606f3b49ac5c97267eb470ec6e
parentb2e847a41a817a78b5aa3a8f1e0afa5a33ad9194

elf: move incremental codegen bits into ZigObject.zig


9 files changed, 1016 insertions(+), 879 deletions(-)

src/arch/aarch64/CodeGen.zig+1-1
...@@ -4316,7 +4316,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4316,7 +4316,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4316 if (try self.air.value(callee, mod)) |func_value| {4316 if (try self.air.value(callee, mod)) |func_value| {
4317 if (func_value.getFunction(mod)) |func| {4317 if (func_value.getFunction(mod)) |func| {
4318 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4318 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4319 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);4319 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
4320 const sym = elf_file.symbol(sym_index);4320 const sym = elf_file.symbol(sym_index);
4321 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);4321 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
4322 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));4322 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/arm/CodeGen.zig+1-1
...@@ -4302,7 +4302,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4302,7 +4302,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4302 if (try self.air.value(callee, mod)) |func_value| {4302 if (try self.air.value(callee, mod)) |func_value| {
4303 if (func_value.getFunction(mod)) |func| {4303 if (func_value.getFunction(mod)) |func| {
4304 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4304 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4305 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);4305 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
4306 const sym = elf_file.symbol(sym_index);4306 const sym = elf_file.symbol(sym_index);
4307 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);4307 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
4308 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));4308 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/riscv64/CodeGen.zig+1-1
...@@ -1752,7 +1752,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1752,7 +1752,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1752 if (try self.air.value(callee, mod)) |func_value| {1752 if (try self.air.value(callee, mod)) |func_value| {
1753 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {1753 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
1754 .func => |func| {1754 .func => |func| {
1755 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);1755 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
1756 const sym = elf_file.symbol(sym_index);1756 const sym = elf_file.symbol(sym_index);
1757 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);1757 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
1758 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));1758 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/sparc64/CodeGen.zig+1-1
...@@ -1347,7 +1347,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1347,7 +1347,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1347 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {1347 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
1348 .func => |func| {1348 .func => |func| {
1349 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {1349 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1350 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);1350 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
1351 const sym = elf_file.symbol(sym_index);1351 const sym = elf_file.symbol(sym_index);
1352 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);1352 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
1353 break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));1353 break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/x86_64/CodeGen.zig+4-4
...@@ -134,7 +134,7 @@ const Owner = union(enum) {...@@ -134,7 +134,7 @@ const Owner = union(enum) {
134 const mod = ctx.bin_file.options.module.?;134 const mod = ctx.bin_file.options.module.?;
135 const decl_index = mod.funcOwnerDeclIndex(func_index);135 const decl_index = mod.funcOwnerDeclIndex(func_index);
136 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {136 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
137 return elf_file.getOrCreateMetadataForDecl(decl_index);137 return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
138 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {138 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
139 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);139 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
140 return macho_file.getAtom(atom).getSymbolIndex().?;140 return macho_file.getAtom(atom).getSymbolIndex().?;
...@@ -147,7 +147,7 @@ const Owner = union(enum) {...@@ -147,7 +147,7 @@ const Owner = union(enum) {
147 },147 },
148 .lazy_sym => |lazy_sym| {148 .lazy_sym => |lazy_sym| {
149 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {149 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
150 return elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|150 return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
151 ctx.fail("{s} creating lazy symbol", .{@errorName(err)});151 ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
152 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {152 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
153 const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|153 const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
...@@ -10233,7 +10233,7 @@ fn genCall(self: *Self, info: union(enum) {...@@ -10233,7 +10233,7 @@ fn genCall(self: *Self, info: union(enum) {
10233 .func => |func| {10233 .func => |func| {
10234 try mod.markDeclAlive(mod.declPtr(func.owner_decl));10234 try mod.markDeclAlive(mod.declPtr(func.owner_decl));
10235 if (self.bin_file.cast(link.File.Elf)) |elf_file| {10235 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
10236 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);10236 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
10237 const sym = elf_file.symbol(sym_index);10237 const sym = elf_file.symbol(sym_index);
10238 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);10238 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
10239 if (self.bin_file.options.pic) {10239 if (self.bin_file.options.pic) {
...@@ -13100,7 +13100,7 @@ fn genLazySymbolRef(...@@ -13100,7 +13100,7 @@ fn genLazySymbolRef(
13100 lazy_sym: link.File.LazySymbol,13100 lazy_sym: link.File.LazySymbol,
13101) InnerError!void {13101) InnerError!void {
13102 if (self.bin_file.cast(link.File.Elf)) |elf_file| {13102 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
13103 const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|13103 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
13104 return self.fail("{s} creating lazy symbol", .{@errorName(err)});13104 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
13105 const sym = elf_file.symbol(sym_index);13105 const sym = elf_file.symbol(sym_index);
13106 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);13106 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
src/codegen.zig+1-1
...@@ -907,7 +907,7 @@ fn genDeclRef(...@@ -907,7 +907,7 @@ fn genDeclRef(
907 elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true;907 elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true;
908 return GenResult.mcv(.{ .load_symbol = sym_index });908 return GenResult.mcv(.{ .load_symbol = sym_index });
909 }909 }
910 const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);910 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
911 const sym = elf_file.symbol(sym_index);911 const sym = elf_file.symbol(sym_index);
912 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);912 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
913 return GenResult.mcv(.{ .load_symbol = sym.esym_index });913 return GenResult.mcv(.{ .load_symbol = sym.esym_index });
src/link/Elf.zig+107-845
...@@ -1,7 +1,5 @@...@@ -1,7 +1,5 @@
1base: link.File,1base: link.File,
22
3dwarf: ?Dwarf = null,
4
5ptr_width: PtrWidth,3ptr_width: PtrWidth,
64
7/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.5/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
...@@ -102,7 +100,7 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},...@@ -102,7 +100,7 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
102/// .zig.got section100/// .zig.got section
103zig_got: ZigGotSection = .{},101zig_got: ZigGotSection = .{},
104102
105/// Tracked section headers with incremental updates to Zig module103/// Tracked section headers with incremental updates to Zig object
106zig_text_section_index: ?u16 = null,104zig_text_section_index: ?u16 = null,
107zig_rodata_section_index: ?u16 = null,105zig_rodata_section_index: ?u16 = null,
108zig_data_section_index: ?u16 = null,106zig_data_section_index: ?u16 = null,
...@@ -181,50 +179,16 @@ debug_line_header_dirty: bool = false,...@@ -181,50 +179,16 @@ debug_line_header_dirty: bool = false,
181error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},179error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
182misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},180misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
183181
184/// Table of tracked LazySymbols.
185lazy_syms: LazySymbolTable = .{},
186
187/// Table of tracked Decls.
188decls: DeclTable = .{},
189
190/// List of atoms that are owned directly by the linker.182/// List of atoms that are owned directly by the linker.
191atoms: std.ArrayListUnmanaged(Atom) = .{},183atoms: std.ArrayListUnmanaged(Atom) = .{},
184
192/// Table of last atom index in a section and matching atom free list if any.185/// Table of last atom index in a section and matching atom free list if any.
193last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},186last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
194187
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`
197/// needs updating or is freed.
198///
199/// For example,
200///
201/// ```zig
202/// const Foo = struct{
203/// a: u8,
204/// };
205///
206/// pub fn main() void {
207/// var foo = Foo{ .a = 1 };
208/// _ = foo;
209/// }
210/// ```
211///
212/// value assigned to label `foo` is an unnamed constant belonging/associated
213/// with `Decl` `main`, and lives as long as that `Decl`.
214unnamed_consts: UnnamedConstTable = .{},
215anon_decls: AnonDeclTable = .{},
216
217comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},188comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
218comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},189comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
219comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},190comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
220191
221const AtomList = std.ArrayListUnmanaged(Atom.Index);
222const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
223const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
224const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
225const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
226const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
227
228/// When allocating, the ideal_capacity is calculated by192/// When allocating, the ideal_capacity is calculated by
229/// actual_capacity + (actual_capacity / ideal_factor)193/// actual_capacity + (actual_capacity / ideal_factor)
230const ideal_factor = 3;194const ideal_factor = 3;
...@@ -322,10 +286,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -322,10 +286,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
322 }286 }
323287
324 if (options.module != null and !options.use_llvm) {288 if (options.module != null and !options.use_llvm) {
325 if (!options.strip) {
326 self.dwarf = Dwarf.init(allocator, &self.base, .dwarf32);
327 }
328
329 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));289 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));
330 self.files.set(index, .{ .zig_object = .{290 self.files.set(index, .{ .zig_object = .{
331 .index = index,291 .index = index,
...@@ -350,6 +310,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -350,6 +310,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
350 esym.st_shndx = elf.SHN_ABS;310 esym.st_shndx = elf.SHN_ABS;
351 symbol_ptr.esym_index = esym_index;311 symbol_ptr.esym_index = esym_index;
352312
313 if (!options.strip) {
314 zig_object.dwarf = Dwarf.init(allocator, &self.base, .dwarf32);
315 }
316
353 try self.initMetadata();317 try self.initMetadata();
354 }318 }
355319
...@@ -425,40 +389,11 @@ pub fn deinit(self: *Elf) void {...@@ -425,40 +389,11 @@ pub fn deinit(self: *Elf) void {
425 self.resolver.deinit(gpa);389 self.resolver.deinit(gpa);
426 self.start_stop_indexes.deinit(gpa);390 self.start_stop_indexes.deinit(gpa);
427391
428 {
429 var it = self.decls.iterator();
430 while (it.next()) |entry| {
431 entry.value_ptr.exports.deinit(gpa);
432 }
433 self.decls.deinit(gpa);
434 }
435
436 self.atoms.deinit(gpa);392 self.atoms.deinit(gpa);
437 for (self.last_atom_and_free_list_table.values()) |*value| {393 for (self.last_atom_and_free_list_table.values()) |*value| {
438 value.free_list.deinit(gpa);394 value.free_list.deinit(gpa);
439 }395 }
440 self.last_atom_and_free_list_table.deinit(gpa);396 self.last_atom_and_free_list_table.deinit(gpa);
441 self.lazy_syms.deinit(gpa);
442
443 {
444 var it = self.unnamed_consts.valueIterator();
445 while (it.next()) |syms| {
446 syms.deinit(gpa);
447 }
448 self.unnamed_consts.deinit(gpa);
449 }
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 }
458
459 if (self.dwarf) |*dw| {
460 dw.deinit();
461 }
462397
463 self.misc_errors.deinit(gpa);398 self.misc_errors.deinit(gpa);
464 self.comdat_groups.deinit(gpa);399 self.comdat_groups.deinit(gpa);
...@@ -481,16 +416,7 @@ pub fn deinit(self: *Elf) void {...@@ -481,16 +416,7 @@ pub fn deinit(self: *Elf) void {
481416
482pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {417pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
483 assert(self.llvm_object == null);418 assert(self.llvm_object == null);
484 const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index);419 return self.zigObjectPtr().?.getDeclVAddr(self, decl_index, reloc_info);
485 const this_sym = self.symbol(this_sym_index);
486 const vaddr = this_sym.value;
487 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
488 try parent_atom.addReloc(self, .{
489 .r_offset = reloc_info.offset,
490 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64,
491 .r_addend = reloc_info.addend,
492 });
493 return vaddr;
494}420}
495421
496pub fn lowerAnonDecl(422pub fn lowerAnonDecl(
...@@ -499,60 +425,12 @@ pub fn lowerAnonDecl(...@@ -499,60 +425,12 @@ pub fn lowerAnonDecl(
499 explicit_alignment: InternPool.Alignment,425 explicit_alignment: InternPool.Alignment,
500 src_loc: Module.SrcLoc,426 src_loc: Module.SrcLoc,
501) !codegen.Result {427) !codegen.Result {
502 const gpa = self.base.allocator;428 return self.zigObjectPtr().?.lowerAnonDecl(self, decl_val, explicit_alignment, src_loc);
503 const mod = self.base.options.module.?;
504 const ty = mod.intern_pool.typeOf(decl_val).toType();
505 const decl_alignment = switch (explicit_alignment) {
506 .none => ty.abiAlignment(mod),
507 else => explicit_alignment,
508 };
509 if (self.anon_decls.get(decl_val)) |metadata| {
510 const existing_alignment = self.symbol(metadata.symbol_index).atom(self).?.alignment;
511 if (decl_alignment.order(existing_alignment).compare(.lte))
512 return .ok;
513 }
514
515 const val = decl_val.toValue();
516 const tv = TypedValue{ .ty = ty, .val = val };
517 var name_buf: [32]u8 = undefined;
518 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
519 @intFromEnum(decl_val),
520 }) catch unreachable;
521 const res = self.lowerConst(
522 name,
523 tv,
524 decl_alignment,
525 self.zig_rodata_section_index.?,
526 src_loc,
527 ) catch |err| switch (err) {
528 error.OutOfMemory => return error.OutOfMemory,
529 else => |e| return .{ .fail = try Module.ErrorMsg.create(
530 gpa,
531 src_loc,
532 "unable to lower constant value: {s}",
533 .{@errorName(e)},
534 ) },
535 };
536 const sym_index = switch (res) {
537 .ok => |sym_index| sym_index,
538 .fail => |em| return .{ .fail = em },
539 };
540 try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
541 return .ok;
542}429}
543430
544pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {431pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
545 assert(self.llvm_object == null);432 assert(self.llvm_object == null);
546 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;433 return self.zigObjectPtr().?.getAnonDeclVAddr(self, decl_val, reloc_info);
547 const sym = self.symbol(sym_index);
548 const vaddr = sym.value;
549 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
550 try parent_atom.addReloc(self, .{
551 .r_offset = reloc_info.offset,
552 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64,
553 .r_addend = reloc_info.addend,
554 });
555 return vaddr;
556}434}
557435
558/// Returns end pos of collision, if any.436/// Returns end pos of collision, if any.
...@@ -839,7 +717,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -839,7 +717,7 @@ pub fn initMetadata(self: *Elf) !void {
839 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});717 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
840 }718 }
841719
842 if (self.dwarf) |*dw| {720 if (self.zigObjectPtr().?.dwarf) |*dw| {
843 if (self.debug_str_section_index == null) {721 if (self.debug_str_section_index == null) {
844 assert(dw.strtab.buffer.items.len == 0);722 assert(dw.strtab.buffer.items.len == 0);
845 try dw.strtab.buffer.append(gpa, 0);723 try dw.strtab.buffer.append(gpa, 0);
...@@ -976,7 +854,7 @@ pub fn growNonAllocSection(...@@ -976,7 +854,7 @@ pub fn growNonAllocSection(
976}854}
977855
978pub fn markDirty(self: *Elf, shdr_index: u16) void {856pub fn markDirty(self: *Elf, shdr_index: u16) void {
979 if (self.dwarf) |_| {857 if (self.zigObjectPtr().?.dwarf) |_| {
980 if (self.debug_info_section_index.? == shdr_index) {858 if (self.debug_info_section_index.? == shdr_index) {
981 self.debug_info_header_dirty = true;859 self.debug_info_header_dirty = true;
982 } else if (self.debug_line_section_index.? == shdr_index) {860 } else if (self.debug_line_section_index.? == shdr_index) {
...@@ -1486,34 +1364,38 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1486,34 +1364,38 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1486 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1364 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1487 }1365 }
14881366
1489 // Handle any lazy symbols that were emitted by incremental compilation.1367 if (self.zigObjectPtr()) |zig_object| {
1490 if (self.lazy_syms.getPtr(.none)) |metadata| {1368 // Handle any lazy symbols that were emitted by incremental compilation.
1491 const module = self.base.options.module.?;1369 if (zig_object.lazy_syms.getPtr(.none)) |metadata| {
14921370 const module = self.base.options.module.?;
1493 // Most lazy symbols can be updated on first use, but1371
1494 // anyerror needs to wait for everything to be flushed.1372 // Most lazy symbols can be updated on first use, but
1495 if (metadata.text_state != .unused) self.updateLazySymbol(1373 // anyerror needs to wait for everything to be flushed.
1496 link.File.LazySymbol.initDecl(.code, null, module),1374 if (metadata.text_state != .unused) zig_object.updateLazySymbol(
1497 metadata.text_symbol_index,1375 self,
1498 ) catch |err| return switch (err) {1376 link.File.LazySymbol.initDecl(.code, null, module),
1499 error.CodegenFail => error.FlushFailure,1377 metadata.text_symbol_index,
1500 else => |e| e,1378 ) catch |err| return switch (err) {
1501 };1379 error.CodegenFail => error.FlushFailure,
1502 if (metadata.rodata_state != .unused) self.updateLazySymbol(1380 else => |e| e,
1503 link.File.LazySymbol.initDecl(.const_data, null, module),1381 };
1504 metadata.rodata_symbol_index,1382 if (metadata.rodata_state != .unused) zig_object.updateLazySymbol(
1505 ) catch |err| return switch (err) {1383 self,
1506 error.CodegenFail => error.FlushFailure,1384 link.File.LazySymbol.initDecl(.const_data, null, module),
1507 else => |e| e,1385 metadata.rodata_symbol_index,
1508 };1386 ) catch |err| return switch (err) {
1509 }1387 error.CodegenFail => error.FlushFailure,
1510 for (self.lazy_syms.values()) |*metadata| {1388 else => |e| e,
1511 if (metadata.text_state != .unused) metadata.text_state = .flushed;1389 };
1512 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;1390 }
1513 }1391 for (zig_object.lazy_syms.values()) |*metadata| {
1392 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1393 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
1394 }
15141395
1515 if (self.dwarf) |*dw| {1396 if (zig_object.dwarf) |*dw| {
1516 try dw.flushModule(self.base.options.module.?);1397 try dw.flushModule(self.base.options.module.?);
1398 }
1517 }1399 }
15181400
1519 // Dedup shared objects1401 // Dedup shared objects
...@@ -1576,43 +1458,45 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1576,43 +1458,45 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1576 // Scan and create missing synthetic entries such as GOT indirection.1458 // Scan and create missing synthetic entries such as GOT indirection.
1577 try self.scanRelocs();1459 try self.scanRelocs();
15781460
1579 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections1461 if (self.zigObjectPtr()) |zig_object| {
1580 // extracted from input object files correctly.1462 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
1581 if (self.dwarf) |*dw| {1463 // extracted from input object files correctly.
1582 if (self.debug_abbrev_section_dirty) {1464 if (zig_object.dwarf) |*dw| {
1583 try dw.writeDbgAbbrev();1465 if (self.debug_abbrev_section_dirty) {
1584 self.debug_abbrev_section_dirty = false;1466 try dw.writeDbgAbbrev();
1585 }1467 self.debug_abbrev_section_dirty = false;
1468 }
15861469
1587 if (self.debug_info_header_dirty) {1470 if (self.debug_info_header_dirty) {
1588 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];1471 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1589 const low_pc = text_phdr.p_vaddr;1472 const low_pc = text_phdr.p_vaddr;
1590 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;1473 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1591 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);1474 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);
1592 self.debug_info_header_dirty = false;1475 self.debug_info_header_dirty = false;
1593 }1476 }
15941477
1595 if (self.debug_aranges_section_dirty) {1478 if (self.debug_aranges_section_dirty) {
1596 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];1479 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1597 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);1480 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1598 self.debug_aranges_section_dirty = false;1481 self.debug_aranges_section_dirty = false;
1599 }1482 }
16001483
1601 if (self.debug_line_header_dirty) {1484 if (self.debug_line_header_dirty) {
1602 try dw.writeDbgLineHeader();1485 try dw.writeDbgLineHeader();
1603 self.debug_line_header_dirty = false;1486 self.debug_line_header_dirty = false;
1604 }1487 }
16051488
1606 if (self.debug_str_section_index) |shndx| {1489 if (self.debug_str_section_index) |shndx| {
1607 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) {1490 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) {
1608 try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);1491 try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
1609 const shdr = self.shdrs.items[shndx];1492 const shdr = self.shdrs.items[shndx];
1610 try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);1493 try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
1611 self.debug_strtab_dirty = false;1494 self.debug_strtab_dirty = false;
1495 }
1612 }1496 }
1613 }
16141497
1615 self.saveDebugSectionsSizes();1498 self.saveDebugSectionsSizes();
1499 }
1616 }1500 }
16171501
1618 // Generate and emit non-incremental sections.1502 // Generate and emit non-incremental sections.
...@@ -3055,206 +2939,9 @@ fn writeHeader(self: *Elf) !void {...@@ -3055,206 +2939,9 @@ fn writeHeader(self: *Elf) !void {
3055 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);2939 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
3056}2940}
30572941
3058fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
3059 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
3060 for (unnamed_consts.items) |sym_index| {
3061 self.freeDeclMetadata(sym_index);
3062 }
3063 unnamed_consts.clearAndFree(self.base.allocator);
3064}
3065
3066fn freeDeclMetadata(self: *Elf, sym_index: Symbol.Index) void {
3067 const sym = self.symbol(sym_index);
3068 sym.atom(self).?.free(self);
3069 log.debug("adding %{d} to local symbols free list", .{sym_index});
3070 self.symbols_free_list.append(self.base.allocator, sym_index) catch {};
3071 self.symbols.items[sym_index] = .{};
3072 // TODO free GOT entry here
3073}
3074
3075pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {2942pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
3076 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);2943 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
30772944 return self.zigObjectPtr().?.freeDecl(self, decl_index);
3078 const mod = self.base.options.module.?;
3079 const decl = mod.declPtr(decl_index);
3080
3081 log.debug("freeDecl {*}", .{decl});
3082
3083 if (self.decls.fetchRemove(decl_index)) |const_kv| {
3084 var kv = const_kv;
3085 const sym_index = kv.value.symbol_index;
3086 self.freeDeclMetadata(sym_index);
3087 self.freeUnnamedConsts(decl_index);
3088 kv.value.exports.deinit(self.base.allocator);
3089 }
3090
3091 if (self.dwarf) |*dw| {
3092 dw.freeDecl(decl_index);
3093 }
3094}
3095
3096pub fn getOrCreateMetadataForLazySymbol(self: *Elf, lazy_sym: link.File.LazySymbol) !Symbol.Index {
3097 const mod = self.base.options.module.?;
3098 const gop = try self.lazy_syms.getOrPut(self.base.allocator, lazy_sym.getDecl(mod));
3099 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
3100 if (!gop.found_existing) gop.value_ptr.* = .{};
3101 const metadata: struct {
3102 symbol_index: *Symbol.Index,
3103 state: *LazySymbolMetadata.State,
3104 } = switch (lazy_sym.kind) {
3105 .code => .{
3106 .symbol_index = &gop.value_ptr.text_symbol_index,
3107 .state = &gop.value_ptr.text_state,
3108 },
3109 .const_data => .{
3110 .symbol_index = &gop.value_ptr.rodata_symbol_index,
3111 .state = &gop.value_ptr.rodata_state,
3112 },
3113 };
3114 const zig_object = self.zigObjectPtr().?;
3115 switch (metadata.state.*) {
3116 .unused => metadata.symbol_index.* = try zig_object.addAtom(self),
3117 .pending_flush => return metadata.symbol_index.*,
3118 .flushed => {},
3119 }
3120 metadata.state.* = .pending_flush;
3121 const symbol_index = metadata.symbol_index.*;
3122 // anyerror needs to be deferred until flushModule
3123 if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(lazy_sym, symbol_index);
3124 return symbol_index;
3125}
3126
3127pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Symbol.Index {
3128 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
3129 if (!gop.found_existing) {
3130 const zig_object = self.zigObjectPtr().?;
3131 gop.value_ptr.* = .{ .symbol_index = try zig_object.addAtom(self) };
3132 }
3133 return gop.value_ptr.symbol_index;
3134}
3135
3136fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 {
3137 const mod = self.base.options.module.?;
3138 const decl = mod.declPtr(decl_index);
3139 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
3140 // TODO: what if this is a function pointer?
3141 .Fn => self.zig_text_section_index.?,
3142 else => blk: {
3143 if (decl.getOwnedVariable(mod)) |variable| {
3144 if (variable.is_const) break :blk self.zig_rodata_section_index.?;
3145 if (variable.init.toValue().isUndefDeep(mod)) {
3146 const mode = self.base.options.optimize_mode;
3147 if (mode == .Debug or mode == .ReleaseSafe) break :blk self.zig_data_section_index.?;
3148 break :blk self.zig_bss_section_index.?;
3149 }
3150 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
3151 // intrusive check for all zeroes than this?
3152 const is_all_zeroes = for (code) |byte| {
3153 if (byte != 0) break false;
3154 } else true;
3155 if (is_all_zeroes) break :blk self.zig_bss_section_index.?;
3156 break :blk self.zig_data_section_index.?;
3157 }
3158 break :blk self.zig_rodata_section_index.?;
3159 },
3160 };
3161 return shdr_index;
3162}
3163
3164fn updateDeclCode(
3165 self: *Elf,
3166 decl_index: Module.Decl.Index,
3167 sym_index: Symbol.Index,
3168 code: []const u8,
3169 stt_bits: u8,
3170) !void {
3171 const gpa = self.base.allocator;
3172 const mod = self.base.options.module.?;
3173 const zig_object = self.zigObjectPtr().?;
3174 const decl = mod.declPtr(decl_index);
3175
3176 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3177
3178 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
3179 const required_alignment = decl.getAlignment(mod);
3180
3181 const sym = self.symbol(sym_index);
3182 const esym = &zig_object.local_esyms.items(.elf_sym)[sym.esym_index];
3183 const atom_ptr = sym.atom(self).?;
3184
3185 const shdr_index = self.getDeclShdrIndex(decl_index, code);
3186 sym.output_section_index = shdr_index;
3187 atom_ptr.output_section_index = shdr_index;
3188
3189 sym.name_offset = try self.strtab.insert(gpa, decl_name);
3190 atom_ptr.flags.alive = true;
3191 atom_ptr.name_offset = sym.name_offset;
3192 esym.st_name = sym.name_offset;
3193 esym.st_info |= stt_bits;
3194 esym.st_size = code.len;
3195
3196 const old_size = atom_ptr.size;
3197 const old_vaddr = atom_ptr.value;
3198 atom_ptr.alignment = required_alignment;
3199 atom_ptr.size = code.len;
3200
3201 if (old_size > 0 and self.base.child_pid == null) {
3202 const capacity = atom_ptr.capacity(self);
3203 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
3204 if (need_realloc) {
3205 try atom_ptr.grow(self);
3206 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
3207 if (old_vaddr != atom_ptr.value) {
3208 sym.value = atom_ptr.value;
3209 esym.st_value = atom_ptr.value;
3210
3211 log.debug(" (writing new offset table entry)", .{});
3212 assert(sym.flags.has_zig_got);
3213 const extra = sym.extra(self).?;
3214 try self.zig_got.writeOne(self, extra.zig_got);
3215 }
3216 } else if (code.len < old_size) {
3217 atom_ptr.shrink(self);
3218 }
3219 } else {
3220 try atom_ptr.allocate(self);
3221 errdefer self.freeDeclMetadata(sym_index);
3222
3223 sym.value = atom_ptr.value;
3224 esym.st_value = atom_ptr.value;
3225
3226 const gop = try sym.getOrCreateZigGotEntry(sym_index, self);
3227 try self.zig_got.writeOne(self, gop.index);
3228 }
3229
3230 if (self.base.child_pid) |pid| {
3231 switch (builtin.os.tag) {
3232 .linux => {
3233 var code_vec: [1]std.os.iovec_const = .{.{
3234 .iov_base = code.ptr,
3235 .iov_len = code.len,
3236 }};
3237 var remote_vec: [1]std.os.iovec_const = .{.{
3238 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.value)))),
3239 .iov_len = code.len,
3240 }};
3241 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
3242 switch (std.os.errno(rc)) {
3243 .SUCCESS => assert(rc == code.len),
3244 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
3245 }
3246 },
3247 else => return error.HotSwapUnavailableOnHostOperatingSystem,
3248 }
3249 }
3250
3251 const shdr = self.shdrs.items[shdr_index];
3252 if (shdr.sh_type != elf.SHT_NOBITS) {
3253 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
3254 const section_offset = sym.value - self.phdrs.items[phdr_index].p_vaddr;
3255 const file_offset = shdr.sh_offset + section_offset;
3256 try self.base.file.?.pwriteAll(code, file_offset);
3257 }
3258}2945}
32592946
3260pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {2947pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
...@@ -3262,54 +2949,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A...@@ -3262,54 +2949,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A
3262 @panic("Attempted to compile for object format that was disabled by build configuration");2949 @panic("Attempted to compile for object format that was disabled by build configuration");
3263 }2950 }
3264 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);2951 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
32652952 return self.zigObjectPtr().?.updateFunc(self, mod, func_index, air, liveness);
3266 const tracy = trace(@src());
3267 defer tracy.end();
3268
3269 const func = mod.funcInfo(func_index);
3270 const decl_index = func.owner_decl;
3271 const decl = mod.declPtr(decl_index);
3272
3273 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);
3274 self.freeUnnamedConsts(decl_index);
3275 self.symbol(sym_index).atom(self).?.freeRelocs(self);
3276
3277 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
3278 defer code_buffer.deinit();
3279
3280 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
3281 defer if (decl_state) |*ds| ds.deinit();
3282
3283 const res = if (decl_state) |*ds|
3284 try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .{
3285 .dwarf = ds,
3286 })
3287 else
3288 try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .none);
3289
3290 const code = switch (res) {
3291 .ok => code_buffer.items,
3292 .fail => |em| {
3293 decl.analysis = .codegen_failure;
3294 try mod.failed_decls.put(mod.gpa, decl_index, em);
3295 return;
3296 },
3297 };
3298 try self.updateDeclCode(decl_index, sym_index, code, elf.STT_FUNC);
3299 if (decl_state) |*ds| {
3300 const sym = self.symbol(sym_index);
3301 try self.dwarf.?.commitDeclState(
3302 mod,
3303 decl_index,
3304 sym.value,
3305 sym.atom(self).?.size,
3306 ds,
3307 );
3308 }
3309
3310 // Since we updated the vaddr and the size, each corresponding export
3311 // symbol also needs to be updated.
3312 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
3313}2953}
33142954
3315pub fn updateDecl(2955pub fn updateDecl(
...@@ -3321,242 +2961,11 @@ pub fn updateDecl(...@@ -3321,242 +2961,11 @@ pub fn updateDecl(
3321 @panic("Attempted to compile for object format that was disabled by build configuration");2961 @panic("Attempted to compile for object format that was disabled by build configuration");
3322 }2962 }
3323 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);2963 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
33242964 return self.zigObjectPtr().?.updateDecl(self, mod, decl_index);
3325 const tracy = trace(@src());
3326 defer tracy.end();
3327
3328 const decl = mod.declPtr(decl_index);
3329
3330 if (decl.val.getExternFunc(mod)) |_| {
3331 return;
3332 }
3333
3334 if (decl.isExtern(mod)) {
3335 // Extern variable gets a .got entry only.
3336 const variable = decl.getOwnedVariable(mod).?;
3337 const name = mod.intern_pool.stringToSlice(decl.name);
3338 const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
3339 const esym_index = try self.getGlobalSymbol(name, lib_name);
3340 self.symbol(self.zigObjectPtr().?.symbol(esym_index)).flags.needs_got = true;
3341 return;
3342 }
3343
3344 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);
3345 self.symbol(sym_index).atom(self).?.freeRelocs(self);
3346
3347 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
3348 defer code_buffer.deinit();
3349
3350 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
3351 defer if (decl_state) |*ds| ds.deinit();
3352
3353 // TODO implement .debug_info for global variables
3354 const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val;
3355 const res = if (decl_state) |*ds|
3356 try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{
3357 .ty = decl.ty,
3358 .val = decl_val,
3359 }, &code_buffer, .{
3360 .dwarf = ds,
3361 }, .{
3362 .parent_atom_index = sym_index,
3363 })
3364 else
3365 try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{
3366 .ty = decl.ty,
3367 .val = decl_val,
3368 }, &code_buffer, .none, .{
3369 .parent_atom_index = sym_index,
3370 });
3371
3372 const code = switch (res) {
3373 .ok => code_buffer.items,
3374 .fail => |em| {
3375 decl.analysis = .codegen_failure;
3376 try mod.failed_decls.put(mod.gpa, decl_index, em);
3377 return;
3378 },
3379 };
3380
3381 try self.updateDeclCode(decl_index, sym_index, code, elf.STT_OBJECT);
3382 if (decl_state) |*ds| {
3383 const sym = self.symbol(sym_index);
3384 try self.dwarf.?.commitDeclState(
3385 mod,
3386 decl_index,
3387 sym.value,
3388 sym.atom(self).?.size,
3389 ds,
3390 );
3391 }
3392
3393 // Since we updated the vaddr and the size, each corresponding export
3394 // symbol also needs to be updated.
3395 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
3396}
3397
3398fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.Index) !void {
3399 const gpa = self.base.allocator;
3400 const mod = self.base.options.module.?;
3401 const zig_object = self.zigObjectPtr().?;
3402
3403 var required_alignment: InternPool.Alignment = .none;
3404 var code_buffer = std.ArrayList(u8).init(gpa);
3405 defer code_buffer.deinit();
3406
3407 const name_str_index = blk: {
3408 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
3409 @tagName(sym.kind),
3410 sym.ty.fmt(mod),
3411 });
3412 defer gpa.free(name);
3413 break :blk try self.strtab.insert(gpa, name);
3414 };
3415
3416 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
3417 mod.declPtr(owner_decl).srcLoc(mod)
3418 else
3419 Module.SrcLoc{
3420 .file_scope = undefined,
3421 .parent_decl_node = undefined,
3422 .lazy = .unneeded,
3423 };
3424 const res = try codegen.generateLazySymbol(
3425 &self.base,
3426 src,
3427 sym,
3428 &required_alignment,
3429 &code_buffer,
3430 .none,
3431 .{ .parent_atom_index = symbol_index },
3432 );
3433 const code = switch (res) {
3434 .ok => code_buffer.items,
3435 .fail => |em| {
3436 log.err("{s}", .{em.msg});
3437 return error.CodegenFail;
3438 },
3439 };
3440
3441 const output_section_index = switch (sym.kind) {
3442 .code => self.zig_text_section_index.?,
3443 .const_data => self.zig_rodata_section_index.?,
3444 };
3445 const local_sym = self.symbol(symbol_index);
3446 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
3447 local_sym.name_offset = name_str_index;
3448 local_sym.output_section_index = output_section_index;
3449 const local_esym = &zig_object.local_esyms.items(.elf_sym)[local_sym.esym_index];
3450 local_esym.st_name = name_str_index;
3451 local_esym.st_info |= elf.STT_OBJECT;
3452 local_esym.st_size = code.len;
3453 const atom_ptr = local_sym.atom(self).?;
3454 atom_ptr.flags.alive = true;
3455 atom_ptr.name_offset = name_str_index;
3456 atom_ptr.alignment = required_alignment;
3457 atom_ptr.size = code.len;
3458 atom_ptr.output_section_index = output_section_index;
3459
3460 try atom_ptr.allocate(self);
3461 errdefer self.freeDeclMetadata(symbol_index);
3462
3463 local_sym.value = atom_ptr.value;
3464 local_esym.st_value = atom_ptr.value;
3465
3466 const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, self);
3467 try self.zig_got.writeOne(self, gop.index);
3468
3469 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
3470 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
3471 try self.base.file.?.pwriteAll(code, file_offset);
3472}2965}
34732966
3474pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {2967pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
3475 const gpa = self.base.allocator;2968 return self.zigObjectPtr().?.lowerUnnamedConst(self, typed_value, decl_index);
3476 const mod = self.base.options.module.?;
3477 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
3478 if (!gop.found_existing) {
3479 gop.value_ptr.* = .{};
3480 }
3481 const unnamed_consts = gop.value_ptr;
3482 const decl = mod.declPtr(decl_index);
3483 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3484 const index = unnamed_consts.items.len;
3485 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
3486 defer gpa.free(name);
3487 const sym_index = switch (try self.lowerConst(name, typed_value, typed_value.ty.abiAlignment(mod), self.zig_rodata_section_index.?, decl.srcLoc(mod))) {
3488 .ok => |sym_index| sym_index,
3489 .fail => |em| {
3490 decl.analysis = .codegen_failure;
3491 try mod.failed_decls.put(mod.gpa, decl_index, em);
3492 log.err("{s}", .{em.msg});
3493 return error.CodegenFail;
3494 },
3495 };
3496 const sym = self.symbol(sym_index);
3497 try unnamed_consts.append(gpa, sym.atom_index);
3498 return sym_index;
3499}
3500
3501const LowerConstResult = union(enum) {
3502 ok: Symbol.Index,
3503 fail: *Module.ErrorMsg,
3504};
3505
3506fn lowerConst(
3507 self: *Elf,
3508 name: []const u8,
3509 tv: TypedValue,
3510 required_alignment: InternPool.Alignment,
3511 output_section_index: u16,
3512 src_loc: Module.SrcLoc,
3513) !LowerConstResult {
3514 const gpa = self.base.allocator;
3515
3516 var code_buffer = std.ArrayList(u8).init(gpa);
3517 defer code_buffer.deinit();
3518
3519 const zig_object = self.zigObjectPtr().?;
3520 const sym_index = try zig_object.addAtom(self);
3521
3522 const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{
3523 .none = {},
3524 }, .{
3525 .parent_atom_index = sym_index,
3526 });
3527 const code = switch (res) {
3528 .ok => code_buffer.items,
3529 .fail => |em| return .{ .fail = em },
3530 };
3531
3532 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
3533 const local_sym = self.symbol(sym_index);
3534 const name_str_index = try self.strtab.insert(gpa, name);
3535 local_sym.name_offset = name_str_index;
3536 local_sym.output_section_index = output_section_index;
3537 const local_esym = &zig_object.local_esyms.items(.elf_sym)[local_sym.esym_index];
3538 local_esym.st_name = name_str_index;
3539 local_esym.st_info |= elf.STT_OBJECT;
3540 local_esym.st_size = code.len;
3541 const atom_ptr = local_sym.atom(self).?;
3542 atom_ptr.flags.alive = true;
3543 atom_ptr.name_offset = name_str_index;
3544 atom_ptr.alignment = required_alignment;
3545 atom_ptr.size = code.len;
3546 atom_ptr.output_section_index = output_section_index;
3547
3548 try atom_ptr.allocate(self);
3549 // TODO rename and re-audit this method
3550 errdefer self.freeDeclMetadata(sym_index);
3551
3552 local_sym.value = atom_ptr.value;
3553 local_esym.st_value = atom_ptr.value;
3554
3555 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
3556 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
3557 try self.base.file.?.pwriteAll(code, file_offset);
3558
3559 return .{ .ok = sym_index };
3560}2969}
35612970
3562pub fn updateExports(2971pub fn updateExports(
...@@ -3569,107 +2978,13 @@ pub fn updateExports(...@@ -3569,107 +2978,13 @@ pub fn updateExports(
3569 @panic("Attempted to compile for object format that was disabled by build configuration");2978 @panic("Attempted to compile for object format that was disabled by build configuration");
3570 }2979 }
3571 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);2980 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3572
3573 if (self.base.options.emit == null) return;2981 if (self.base.options.emit == null) return;
35742982 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
3575 const tracy = trace(@src());
3576 defer tracy.end();
3577
3578 const gpa = self.base.allocator;
3579 const zig_object = self.zigObjectPtr().?;
3580 const metadata = switch (exported) {
3581 .decl_index => |decl_index| blk: {
3582 _ = try self.getOrCreateMetadataForDecl(decl_index);
3583 break :blk self.decls.getPtr(decl_index).?;
3584 },
3585 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
3586 const first_exp = exports[0];
3587 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
3588 switch (res) {
3589 .ok => {},
3590 .fail => |em| {
3591 // TODO maybe it's enough to return an error here and let Module.processExportsInner
3592 // handle the error?
3593 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3594 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
3595 return;
3596 },
3597 }
3598 break :blk self.anon_decls.getPtr(value).?;
3599 },
3600 };
3601 const sym_index = metadata.symbol_index;
3602 const esym_index = self.symbol(sym_index).esym_index;
3603 const esym = zig_object.local_esyms.items(.elf_sym)[esym_index];
3604 const esym_shndx = zig_object.local_esyms.items(.shndx)[esym_index];
3605
3606 for (exports) |exp| {
3607 if (exp.opts.section.unwrap()) |section_name| {
3608 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
3609 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3610 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3611 gpa,
3612 exp.getSrcLoc(mod),
3613 "Unimplemented: ExportOptions.section",
3614 .{},
3615 ));
3616 continue;
3617 }
3618 }
3619 const stb_bits: u8 = switch (exp.opts.linkage) {
3620 .Internal => elf.STB_LOCAL,
3621 .Strong => elf.STB_GLOBAL,
3622 .Weak => elf.STB_WEAK,
3623 .LinkOnce => {
3624 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3625 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3626 gpa,
3627 exp.getSrcLoc(mod),
3628 "Unimplemented: GlobalLinkage.LinkOnce",
3629 .{},
3630 ));
3631 continue;
3632 },
3633 };
3634 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
3635 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
3636 const name_off = try self.strtab.insert(gpa, exp_name);
3637 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
3638 const global_esym_index = try zig_object.addGlobalEsym(gpa);
3639 const lookup_gop = try zig_object.globals_lookup.getOrPut(gpa, name_off);
3640 const global_esym = zig_object.elfSym(global_esym_index);
3641 global_esym.st_name = name_off;
3642 lookup_gop.value_ptr.* = global_esym_index;
3643 try metadata.exports.append(gpa, global_esym_index);
3644 const gop = try self.getOrPutGlobal(name_off);
3645 try zig_object.global_symbols.append(gpa, gop.index);
3646 break :blk global_esym_index;
3647 };
3648
3649 const actual_esym_index = global_esym_index & ZigObject.symbol_mask;
3650 const global_esym = &zig_object.global_esyms.items(.elf_sym)[actual_esym_index];
3651 global_esym.st_value = self.symbol(sym_index).value;
3652 global_esym.st_shndx = esym.st_shndx;
3653 global_esym.st_info = (stb_bits << 4) | stt_bits;
3654 global_esym.st_name = name_off;
3655 zig_object.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
3656 }
3657}2983}
36582984
3659/// Must be called only after a successful call to `updateDecl`.
3660pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void {2985pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void {
3661 const tracy = trace(@src());
3662 defer tracy.end();
3663
3664 const decl = mod.declPtr(decl_index);
3665 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3666
3667 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
3668
3669 if (self.llvm_object) |_| return;2986 if (self.llvm_object) |_| return;
3670 if (self.dwarf) |*dw| {2987 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
3671 try dw.updateDeclLineNumber(mod, decl_index);
3672 }
3673}2988}
36742989
3675pub fn deleteDeclExport(2990pub fn deleteDeclExport(
...@@ -3678,22 +2993,7 @@ pub fn deleteDeclExport(...@@ -3678,22 +2993,7 @@ pub fn deleteDeclExport(
3678 name: InternPool.NullTerminatedString,2993 name: InternPool.NullTerminatedString,
3679) void {2994) void {
3680 if (self.llvm_object) |_| return;2995 if (self.llvm_object) |_| return;
3681 const metadata = self.decls.getPtr(decl_index) orelse return;2996 return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
3682 const mod = self.base.options.module.?;
3683 const zig_object = self.zigObjectPtr().?;
3684 const exp_name = mod.intern_pool.stringToSlice(name);
3685 const esym_index = metadata.@"export"(self, exp_name) orelse return;
3686 log.debug("deleting export '{s}'", .{exp_name});
3687 const esym = &zig_object.global_esyms.items(.elf_sym)[esym_index.*];
3688 _ = zig_object.globals_lookup.remove(esym.st_name);
3689 const sym_index = self.resolver.get(esym.st_name).?;
3690 const sym = self.symbol(sym_index);
3691 if (sym.file_index == zig_object.index) {
3692 _ = self.resolver.swapRemove(esym.st_name);
3693 sym.* = .{};
3694 }
3695 esym.* = null_sym;
3696 zig_object.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
3697}2997}
36982998
3699fn addLinkerDefinedSymbols(self: *Elf) !void {2999fn addLinkerDefinedSymbols(self: *Elf) !void {
...@@ -5955,20 +5255,7 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {...@@ -5955,20 +5255,7 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
5955}5255}
59565256
5957pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {5257pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
5958 _ = lib_name;5258 return self.zigObjectPtr().?.getGlobalSymbol(self, name, lib_name);
5959 const gpa = self.base.allocator;
5960 const off = try self.strtab.insert(gpa, name);
5961 const zig_object = self.zigObjectPtr().?;
5962 const lookup_gop = try zig_object.globals_lookup.getOrPut(gpa, off);
5963 if (!lookup_gop.found_existing) {
5964 const esym_index = try zig_object.addGlobalEsym(gpa);
5965 const esym = zig_object.elfSym(esym_index);
5966 esym.st_name = off;
5967 lookup_gop.value_ptr.* = esym_index;
5968 const gop = try self.getOrPutGlobal(off);
5969 try zig_object.global_symbols.append(gpa, gop.index);
5970 }
5971 return lookup_gop.value_ptr.*;
5972}5259}
59735260
5974pub fn zigObjectPtr(self: *Elf) ?*ZigObject {5261pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
...@@ -6335,51 +5622,6 @@ const default_entry_addr = 0x8000000;...@@ -6335,51 +5622,6 @@ const default_entry_addr = 0x8000000;
63355622
6336pub const base_tag: link.File.Tag = .elf;5623pub const base_tag: link.File.Tag = .elf;
63375624
6338const LastAtomAndFreeList = struct {
6339 /// Index of the last allocated atom in this section.
6340 last_atom_index: Atom.Index = 0,
6341
6342 /// A list of atoms that have surplus capacity. This list can have false
6343 /// positives, as functions grow and shrink over time, only sometimes being added
6344 /// or removed from the freelist.
6345 ///
6346 /// An atom has surplus capacity when its overcapacity value is greater than
6347 /// padToIdeal(minimum_atom_size). That is, when it has so
6348 /// much extra capacity, that we could fit a small new symbol in it, itself with
6349 /// ideal_capacity or more.
6350 ///
6351 /// Ideal capacity is defined by size + (size / ideal_factor)
6352 ///
6353 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
6354 /// overcapacity can be negative. A simple way to have negative overcapacity is to
6355 /// allocate a fresh text block, which will have ideal capacity, and then grow it
6356 /// by 1 byte. It will then have -1 overcapacity.
6357 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6358};
6359
6360const LazySymbolMetadata = struct {
6361 const State = enum { unused, pending_flush, flushed };
6362 text_symbol_index: Symbol.Index = undefined,
6363 rodata_symbol_index: Symbol.Index = undefined,
6364 text_state: State = .unused,
6365 rodata_state: State = .unused,
6366};
6367
6368const DeclMetadata = struct {
6369 symbol_index: Symbol.Index,
6370 /// A list of all exports aliases of this Decl.
6371 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
6372
6373 fn @"export"(m: DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 {
6374 const zig_object = elf_file.zigObjectPtr().?;
6375 for (m.exports.items) |*exp| {
6376 const exp_name = elf_file.strtab.getAssumeExists(zig_object.elfSym(exp.*).st_name);
6377 if (mem.eql(u8, name, exp_name)) return exp;
6378 }
6379 return null;
6380 }
6381};
6382
6383const ComdatGroupOwner = struct {5625const ComdatGroupOwner = struct {
6384 file: File.Index = 0,5626 file: File.Index = 0,
6385 const Index = u32;5627 const Index = u32;
...@@ -6423,6 +5665,30 @@ pub const SystemLib = struct {...@@ -6423,6 +5665,30 @@ pub const SystemLib = struct {
6423 path: []const u8,5665 path: []const u8,
6424};5666};
64255667
5668const LastAtomAndFreeList = struct {
5669 /// Index of the last allocated atom in this section.
5670 last_atom_index: Atom.Index = 0,
5671
5672 /// A list of atoms that have surplus capacity. This list can have false
5673 /// positives, as functions grow and shrink over time, only sometimes being added
5674 /// or removed from the freelist.
5675 ///
5676 /// An atom has surplus capacity when its overcapacity value is greater than
5677 /// padToIdeal(minimum_atom_size). That is, when it has so
5678 /// much extra capacity, that we could fit a small new symbol in it, itself with
5679 /// ideal_capacity or more.
5680 ///
5681 /// Ideal capacity is defined by size + (size / ideal_factor)
5682 ///
5683 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
5684 /// overcapacity can be negative. A simple way to have negative overcapacity is to
5685 /// allocate a fresh text block, which will have ideal capacity, and then grow it
5686 /// by 1 byte. It will then have -1 overcapacity.
5687 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
5688};
5689
5690const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
5691
6426pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;5692pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
6427pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;5693pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
64285694
...@@ -6471,16 +5737,12 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;...@@ -6471,16 +5737,12 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;
6471const Module = @import("../Module.zig");5737const Module = @import("../Module.zig");
6472const Object = @import("Elf/Object.zig");5738const Object = @import("Elf/Object.zig");
6473const InternPool = @import("../InternPool.zig");5739const InternPool = @import("../InternPool.zig");
6474const Package = @import("../Package.zig");
6475const PltSection = synthetic_sections.PltSection;5740const PltSection = synthetic_sections.PltSection;
6476const PltGotSection = synthetic_sections.PltGotSection;5741const PltGotSection = synthetic_sections.PltGotSection;
6477const SharedObject = @import("Elf/SharedObject.zig");5742const SharedObject = @import("Elf/SharedObject.zig");
6478const Symbol = @import("Elf/Symbol.zig");5743const Symbol = @import("Elf/Symbol.zig");
6479const StringTable = @import("strtab.zig").StringTable;5744const StringTable = @import("strtab.zig").StringTable;
6480const TableSection = @import("table_section.zig").TableSection;
6481const Type = @import("../type.zig").Type;
6482const TypedValue = @import("../TypedValue.zig");5745const TypedValue = @import("../TypedValue.zig");
6483const Value = @import("../value.zig").Value;
6484const VerneedSection = synthetic_sections.VerneedSection;5746const VerneedSection = synthetic_sections.VerneedSection;
6485const ZigGotSection = synthetic_sections.ZigGotSection;5747const ZigGotSection = synthetic_sections.ZigGotSection;
6486const ZigObject = @import("Elf/ZigObject.zig");5748const ZigObject = @import("Elf/ZigObject.zig");
src/link/Elf/Atom.zig+1-1
...@@ -166,7 +166,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -166,7 +166,7 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
166 try elf_file.growAllocSection(self.outputShndx().?, needed_size);166 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
167 last_atom_index.* = self.atom_index;167 last_atom_index.* = self.atom_index;
168168
169 if (elf_file.dwarf) |_| {169 if (elf_file.zigObjectPtr().?.dwarf) |_| {
170 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address170 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
171 // range of the compilation unit. When we expand the text section, this range changes,171 // range of the compilation unit. When we expand the text section, this range changes,
172 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.172 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
src/link/Elf/ZigObject.zig+899-24
...@@ -1,4 +1,4 @@...@@ -1,4 +1,4 @@
1//! ZigModule encapsulates the state of the incrementally compiled Zig module.1//! ZigObject encapsulates the state of the incrementally compiled Zig module.
2//! It stores the associated input local and global symbols, allocated atoms,2//! It stores the associated input local and global symbols, allocated atoms,
3//! and any relocations that may have been emitted.3//! and any relocations that may have been emitted.
4//! Think about this as fake in-memory Object file for the Zig module.4//! Think about this as fake in-memory Object file for the Zig module.
...@@ -20,11 +20,43 @@ num_dynrelocs: u32 = 0,...@@ -20,11 +20,43 @@ num_dynrelocs: u32 = 0,
2020
21output_symtab_size: Elf.SymtabSize = .{},21output_symtab_size: Elf.SymtabSize = .{},
2222
23dwarf: ?Dwarf = null,
24
25/// Table of tracked LazySymbols.
26lazy_syms: LazySymbolTable = .{},
27
28/// Table of tracked Decls.
29decls: DeclTable = .{},
30
31/// Table of unnamed constants associated with a parent `Decl`.
32/// We store them here so that we can free the constants whenever the `Decl`
33/// needs updating or is freed.
34///
35/// For example,
36///
37/// ```zig
38/// const Foo = struct{
39/// a: u8,
40/// };
41///
42/// pub fn main() void {
43/// var foo = Foo{ .a = 1 };
44/// _ = foo;
45/// }
46/// ```
47///
48/// value assigned to label `foo` is an unnamed constant belonging/associated
49/// with `Decl` `main`, and lives as long as that `Decl`.
50unnamed_consts: UnnamedConstTable = .{},
51
52/// Table of tracked AnonDecls.
53anon_decls: AnonDeclTable = .{},
54
23pub const global_symbol_bit: u32 = 0x80000000;55pub const global_symbol_bit: u32 = 0x80000000;
24pub const symbol_mask: u32 = 0x7fffffff;56pub const symbol_mask: u32 = 0x7fffffff;
25pub const SHN_ATOM: u16 = 0x100;57pub const SHN_ATOM: u16 = 0x100;
2658
27pub fn deinit(self: *ZigModule, allocator: Allocator) void {59pub fn deinit(self: *ZigObject, allocator: Allocator) void {
28 self.local_esyms.deinit(allocator);60 self.local_esyms.deinit(allocator);
29 self.global_esyms.deinit(allocator);61 self.global_esyms.deinit(allocator);
30 self.local_symbols.deinit(allocator);62 self.local_symbols.deinit(allocator);
...@@ -35,9 +67,39 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void {...@@ -35,9 +67,39 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void {
35 list.deinit(allocator);67 list.deinit(allocator);
36 }68 }
37 self.relocs.deinit(allocator);69 self.relocs.deinit(allocator);
70
71 {
72 var it = self.decls.iterator();
73 while (it.next()) |entry| {
74 entry.value_ptr.exports.deinit(allocator);
75 }
76 self.decls.deinit(allocator);
77 }
78
79 self.lazy_syms.deinit(allocator);
80
81 {
82 var it = self.unnamed_consts.valueIterator();
83 while (it.next()) |syms| {
84 syms.deinit(allocator);
85 }
86 self.unnamed_consts.deinit(allocator);
87 }
88
89 {
90 var it = self.anon_decls.iterator();
91 while (it.next()) |entry| {
92 entry.value_ptr.exports.deinit(allocator);
93 }
94 self.anon_decls.deinit(allocator);
95 }
96
97 if (self.dwarf) |*dw| {
98 dw.deinit();
99 }
38}100}
39101
40pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {102pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
41 try self.local_esyms.ensureUnusedCapacity(allocator, 1);103 try self.local_esyms.ensureUnusedCapacity(allocator, 1);
42 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));104 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
43 var esym = ElfSym{ .elf_sym = Elf.null_sym };105 var esym = ElfSym{ .elf_sym = Elf.null_sym };
...@@ -46,7 +108,7 @@ pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {...@@ -46,7 +108,7 @@ pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
46 return index;108 return index;
47}109}
48110
49pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {111pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
50 try self.global_esyms.ensureUnusedCapacity(allocator, 1);112 try self.global_esyms.ensureUnusedCapacity(allocator, 1);
51 const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));113 const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));
52 var esym = ElfSym{ .elf_sym = Elf.null_sym };114 var esym = ElfSym{ .elf_sym = Elf.null_sym };
...@@ -55,7 +117,7 @@ pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {...@@ -55,7 +117,7 @@ pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
55 return index | global_symbol_bit;117 return index | global_symbol_bit;
56}118}
57119
58pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {120pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
59 const gpa = elf_file.base.allocator;121 const gpa = elf_file.base.allocator;
60122
61 const atom_index = try elf_file.addAtom();123 const atom_index = try elf_file.addAtom();
...@@ -86,7 +148,7 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {...@@ -86,7 +148,7 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
86}148}
87149
88/// TODO actually create fake input shdrs and return that instead.150/// TODO actually create fake input shdrs and return that instead.
89pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {151pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
90 _ = self;152 _ = self;
91 const shdr = shdr: {153 const shdr = shdr: {
92 const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;154 const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;
...@@ -101,7 +163,7 @@ pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object...@@ -101,7 +163,7 @@ pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object
101 return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;163 return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
102}164}
103165
104pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {166pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
105 for (self.globals(), 0..) |index, i| {167 for (self.globals(), 0..) |index, i| {
106 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;168 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
107 const esym = self.global_esyms.items(.elf_sym)[i];169 const esym = self.global_esyms.items(.elf_sym)[i];
...@@ -138,7 +200,7 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {...@@ -138,7 +200,7 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
138 }200 }
139}201}
140202
141pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {203pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
142 for (self.globals(), 0..) |index, i| {204 for (self.globals(), 0..) |index, i| {
143 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;205 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
144 const esym = self.global_esyms.items(.elf_sym)[i];206 const esym = self.global_esyms.items(.elf_sym)[i];
...@@ -166,7 +228,7 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {...@@ -166,7 +228,7 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
166 }228 }
167}229}
168230
169pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {231pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
170 for (self.atoms.items) |atom_index| {232 for (self.atoms.items) |atom_index| {
171 const atom = elf_file.atom(atom_index) orelse continue;233 const atom = elf_file.atom(atom_index) orelse continue;
172 if (!atom.flags.alive) continue;234 if (!atom.flags.alive) continue;
...@@ -183,7 +245,7 @@ pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {...@@ -183,7 +245,7 @@ pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
183 }245 }
184}246}
185247
186pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {248pub fn resetGlobals(self: *ZigObject, elf_file: *Elf) void {
187 for (self.globals()) |index| {249 for (self.globals()) |index| {
188 const global = elf_file.symbol(index);250 const global = elf_file.symbol(index);
189 const off = global.name_offset;251 const off = global.name_offset;
...@@ -192,7 +254,7 @@ pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {...@@ -192,7 +254,7 @@ pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {
192 }254 }
193}255}
194256
195pub fn markLive(self: *ZigModule, elf_file: *Elf) void {257pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
196 for (self.globals(), 0..) |index, i| {258 for (self.globals(), 0..) |index, i| {
197 const esym = self.global_esyms.items(.elf_sym)[i];259 const esym = self.global_esyms.items(.elf_sym)[i];
198 if (esym.st_bind() == elf.STB_WEAK) continue;260 if (esym.st_bind() == elf.STB_WEAK) continue;
...@@ -208,7 +270,7 @@ pub fn markLive(self: *ZigModule, elf_file: *Elf) void {...@@ -208,7 +270,7 @@ pub fn markLive(self: *ZigModule, elf_file: *Elf) void {
208 }270 }
209}271}
210272
211pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {273pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) void {
212 for (self.locals()) |local_index| {274 for (self.locals()) |local_index| {
213 const local = elf_file.symbol(local_index);275 const local = elf_file.symbol(local_index);
214 const esym = local.elfSym(elf_file);276 const esym = local.elfSym(elf_file);
...@@ -238,7 +300,7 @@ pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {...@@ -238,7 +300,7 @@ pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
238 }300 }
239}301}
240302
241pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {303pub fn writeSymtab(self: *ZigObject, elf_file: *Elf, ctx: anytype) void {
242 var ilocal = ctx.ilocal;304 var ilocal = ctx.ilocal;
243 for (self.locals()) |local_index| {305 for (self.locals()) |local_index| {
244 const local = elf_file.symbol(local_index);306 const local = elf_file.symbol(local_index);
...@@ -262,35 +324,35 @@ pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {...@@ -262,35 +324,35 @@ pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {
262 }324 }
263}325}
264326
265pub fn symbol(self: *ZigModule, index: Symbol.Index) Symbol.Index {327pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
266 const is_global = index & global_symbol_bit != 0;328 const is_global = index & global_symbol_bit != 0;
267 const actual_index = index & symbol_mask;329 const actual_index = index & symbol_mask;
268 if (is_global) return self.global_symbols.items[actual_index];330 if (is_global) return self.global_symbols.items[actual_index];
269 return self.local_symbols.items[actual_index];331 return self.local_symbols.items[actual_index];
270}332}
271333
272pub fn elfSym(self: *ZigModule, index: Symbol.Index) *elf.Elf64_Sym {334pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
273 const is_global = index & global_symbol_bit != 0;335 const is_global = index & global_symbol_bit != 0;
274 const actual_index = index & symbol_mask;336 const actual_index = index & symbol_mask;
275 if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index];337 if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index];
276 return &self.local_esyms.items(.elf_sym)[actual_index];338 return &self.local_esyms.items(.elf_sym)[actual_index];
277}339}
278340
279pub fn locals(self: *ZigModule) []const Symbol.Index {341pub fn locals(self: *ZigObject) []const Symbol.Index {
280 return self.local_symbols.items;342 return self.local_symbols.items;
281}343}
282344
283pub fn globals(self: *ZigModule) []const Symbol.Index {345pub fn globals(self: *ZigObject) []const Symbol.Index {
284 return self.global_symbols.items;346 return self.global_symbols.items;
285}347}
286348
287pub fn asFile(self: *ZigModule) File {349pub fn asFile(self: *ZigObject) File {
288 return .{ .zig_object = self };350 return .{ .zig_object = self };
289}351}
290352
291/// Returns atom's code.353/// Returns atom's code.
292/// Caller owns the memory.354/// Caller owns the memory.
293pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {355pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
294 const gpa = elf_file.base.allocator;356 const gpa = elf_file.base.allocator;
295 const atom = elf_file.atom(atom_index).?;357 const atom = elf_file.atom(atom_index).?;
296 assert(atom.file_index == self.index);358 assert(atom.file_index == self.index);
...@@ -307,7 +369,782 @@ pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8...@@ -307,7 +369,782 @@ pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8
307 return code;369 return code;
308}370}
309371
310pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {372pub fn getDeclVAddr(
373 self: *ZigObject,
374 elf_file: *Elf,
375 decl_index: Module.Decl.Index,
376 reloc_info: link.File.RelocInfo,
377) !u64 {
378 const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
379 const this_sym = elf_file.symbol(this_sym_index);
380 const vaddr = this_sym.value;
381 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
382 try parent_atom.addReloc(elf_file, .{
383 .r_offset = reloc_info.offset,
384 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64,
385 .r_addend = reloc_info.addend,
386 });
387 return vaddr;
388}
389
390pub fn getAnonDeclVAddr(
391 self: *ZigObject,
392 elf_file: *Elf,
393 decl_val: InternPool.Index,
394 reloc_info: link.File.RelocInfo,
395) !u64 {
396 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
397 const sym = elf_file.symbol(sym_index);
398 const vaddr = sym.value;
399 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
400 try parent_atom.addReloc(elf_file, .{
401 .r_offset = reloc_info.offset,
402 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64,
403 .r_addend = reloc_info.addend,
404 });
405 return vaddr;
406}
407
408pub fn lowerAnonDecl(
409 self: *ZigObject,
410 elf_file: *Elf,
411 decl_val: InternPool.Index,
412 explicit_alignment: InternPool.Alignment,
413 src_loc: Module.SrcLoc,
414) !codegen.Result {
415 const gpa = elf_file.base.allocator;
416 const mod = elf_file.base.options.module.?;
417 const ty = mod.intern_pool.typeOf(decl_val).toType();
418 const decl_alignment = switch (explicit_alignment) {
419 .none => ty.abiAlignment(mod),
420 else => explicit_alignment,
421 };
422 if (self.anon_decls.get(decl_val)) |metadata| {
423 const existing_alignment = elf_file.symbol(metadata.symbol_index).atom(elf_file).?.alignment;
424 if (decl_alignment.order(existing_alignment).compare(.lte))
425 return .ok;
426 }
427
428 const val = decl_val.toValue();
429 const tv = TypedValue{ .ty = ty, .val = val };
430 var name_buf: [32]u8 = undefined;
431 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
432 @intFromEnum(decl_val),
433 }) catch unreachable;
434 const res = self.lowerConst(
435 elf_file,
436 name,
437 tv,
438 decl_alignment,
439 elf_file.zig_rodata_section_index.?,
440 src_loc,
441 ) catch |err| switch (err) {
442 error.OutOfMemory => return error.OutOfMemory,
443 else => |e| return .{ .fail = try Module.ErrorMsg.create(
444 gpa,
445 src_loc,
446 "unable to lower constant value: {s}",
447 .{@errorName(e)},
448 ) },
449 };
450 const sym_index = switch (res) {
451 .ok => |sym_index| sym_index,
452 .fail => |em| return .{ .fail = em },
453 };
454 try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
455 return .ok;
456}
457
458pub fn getOrCreateMetadataForLazySymbol(
459 self: *ZigObject,
460 elf_file: *Elf,
461 lazy_sym: link.File.LazySymbol,
462) !Symbol.Index {
463 const gpa = elf_file.base.allocator;
464 const mod = elf_file.base.options.module.?;
465 const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));
466 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
467 if (!gop.found_existing) gop.value_ptr.* = .{};
468 const metadata: struct {
469 symbol_index: *Symbol.Index,
470 state: *LazySymbolMetadata.State,
471 } = switch (lazy_sym.kind) {
472 .code => .{
473 .symbol_index = &gop.value_ptr.text_symbol_index,
474 .state = &gop.value_ptr.text_state,
475 },
476 .const_data => .{
477 .symbol_index = &gop.value_ptr.rodata_symbol_index,
478 .state = &gop.value_ptr.rodata_state,
479 },
480 };
481 switch (metadata.state.*) {
482 .unused => metadata.symbol_index.* = try self.addAtom(elf_file),
483 .pending_flush => return metadata.symbol_index.*,
484 .flushed => {},
485 }
486 metadata.state.* = .pending_flush;
487 const symbol_index = metadata.symbol_index.*;
488 // anyerror needs to be deferred until flushModule
489 if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(elf_file, lazy_sym, symbol_index);
490 return symbol_index;
491}
492
493fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.Index) void {
494 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
495 for (unnamed_consts.items) |sym_index| {
496 self.freeDeclMetadata(elf_file, sym_index);
497 }
498 unnamed_consts.clearAndFree(elf_file.base.allocator);
499}
500
501fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
502 _ = self;
503 const sym = elf_file.symbol(sym_index);
504 sym.atom(elf_file).?.free(elf_file);
505 log.debug("adding %{d} to local symbols free list", .{sym_index});
506 elf_file.symbols_free_list.append(elf_file.base.allocator, sym_index) catch {};
507 elf_file.symbols.items[sym_index] = .{};
508 // TODO free GOT entry here
509}
510
511pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.Index) void {
512 const mod = elf_file.base.options.module.?;
513 const decl = mod.declPtr(decl_index);
514
515 log.debug("freeDecl {*}", .{decl});
516
517 if (self.decls.fetchRemove(decl_index)) |const_kv| {
518 var kv = const_kv;
519 const sym_index = kv.value.symbol_index;
520 self.freeDeclMetadata(elf_file, sym_index);
521 self.freeUnnamedConsts(elf_file, decl_index);
522 kv.value.exports.deinit(elf_file.base.allocator);
523 }
524
525 if (self.dwarf) |*dw| {
526 dw.freeDecl(decl_index);
527 }
528}
529
530pub fn getOrCreateMetadataForDecl(
531 self: *ZigObject,
532 elf_file: *Elf,
533 decl_index: Module.Decl.Index,
534) !Symbol.Index {
535 const gop = try self.decls.getOrPut(elf_file.base.allocator, decl_index);
536 if (!gop.found_existing) {
537 gop.value_ptr.* = .{ .symbol_index = try self.addAtom(elf_file) };
538 }
539 return gop.value_ptr.symbol_index;
540}
541
542fn getDeclShdrIndex(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 {
543 _ = self;
544 const mod = elf_file.base.options.module.?;
545 const decl = mod.declPtr(decl_index);
546 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
547 // TODO: what if this is a function pointer?
548 .Fn => elf_file.zig_text_section_index.?,
549 else => blk: {
550 if (decl.getOwnedVariable(mod)) |variable| {
551 if (variable.is_const) break :blk elf_file.zig_rodata_section_index.?;
552 if (variable.init.toValue().isUndefDeep(mod)) {
553 const mode = elf_file.base.options.optimize_mode;
554 if (mode == .Debug or mode == .ReleaseSafe) break :blk elf_file.zig_data_section_index.?;
555 break :blk elf_file.zig_bss_section_index.?;
556 }
557 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
558 // intrusive check for all zeroes than this?
559 const is_all_zeroes = for (code) |byte| {
560 if (byte != 0) break false;
561 } else true;
562 if (is_all_zeroes) break :blk elf_file.zig_bss_section_index.?;
563 break :blk elf_file.zig_data_section_index.?;
564 }
565 break :blk elf_file.zig_rodata_section_index.?;
566 },
567 };
568 return shdr_index;
569}
570
571fn updateDeclCode(
572 self: *ZigObject,
573 elf_file: *Elf,
574 decl_index: Module.Decl.Index,
575 sym_index: Symbol.Index,
576 code: []const u8,
577 stt_bits: u8,
578) !void {
579 const gpa = elf_file.base.allocator;
580 const mod = elf_file.base.options.module.?;
581 const decl = mod.declPtr(decl_index);
582 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
583
584 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
585
586 const required_alignment = decl.getAlignment(mod);
587
588 const sym = elf_file.symbol(sym_index);
589 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
590 const atom_ptr = sym.atom(elf_file).?;
591
592 const shdr_index = self.getDeclShdrIndex(elf_file, decl_index, code);
593 sym.output_section_index = shdr_index;
594 atom_ptr.output_section_index = shdr_index;
595
596 sym.name_offset = try elf_file.strtab.insert(gpa, decl_name);
597 atom_ptr.flags.alive = true;
598 atom_ptr.name_offset = sym.name_offset;
599 esym.st_name = sym.name_offset;
600 esym.st_info |= stt_bits;
601 esym.st_size = code.len;
602
603 const old_size = atom_ptr.size;
604 const old_vaddr = atom_ptr.value;
605 atom_ptr.alignment = required_alignment;
606 atom_ptr.size = code.len;
607
608 if (old_size > 0 and elf_file.base.child_pid == null) {
609 const capacity = atom_ptr.capacity(elf_file);
610 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
611 if (need_realloc) {
612 try atom_ptr.grow(elf_file);
613 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
614 if (old_vaddr != atom_ptr.value) {
615 sym.value = atom_ptr.value;
616 esym.st_value = atom_ptr.value;
617
618 log.debug(" (writing new offset table entry)", .{});
619 assert(sym.flags.has_zig_got);
620 const extra = sym.extra(elf_file).?;
621 try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
622 }
623 } else if (code.len < old_size) {
624 atom_ptr.shrink(elf_file);
625 }
626 } else {
627 try atom_ptr.allocate(elf_file);
628 errdefer self.freeDeclMetadata(elf_file, sym_index);
629
630 sym.value = atom_ptr.value;
631 esym.st_value = atom_ptr.value;
632
633 const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
634 try elf_file.zig_got.writeOne(elf_file, gop.index);
635 }
636
637 if (elf_file.base.child_pid) |pid| {
638 switch (builtin.os.tag) {
639 .linux => {
640 var code_vec: [1]std.os.iovec_const = .{.{
641 .iov_base = code.ptr,
642 .iov_len = code.len,
643 }};
644 var remote_vec: [1]std.os.iovec_const = .{.{
645 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.value)))),
646 .iov_len = code.len,
647 }};
648 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
649 switch (std.os.errno(rc)) {
650 .SUCCESS => assert(rc == code.len),
651 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
652 }
653 },
654 else => return error.HotSwapUnavailableOnHostOperatingSystem,
655 }
656 }
657
658 const shdr = elf_file.shdrs.items[shdr_index];
659 if (shdr.sh_type != elf.SHT_NOBITS) {
660 const phdr_index = elf_file.phdr_to_shdr_table.get(shdr_index).?;
661 const section_offset = sym.value - elf_file.phdrs.items[phdr_index].p_vaddr;
662 const file_offset = shdr.sh_offset + section_offset;
663 try elf_file.base.file.?.pwriteAll(code, file_offset);
664 }
665}
666
667pub fn updateFunc(
668 self: *ZigObject,
669 elf_file: *Elf,
670 mod: *Module,
671 func_index: InternPool.Index,
672 air: Air,
673 liveness: Liveness,
674) !void {
675 const tracy = trace(@src());
676 defer tracy.end();
677
678 const func = mod.funcInfo(func_index);
679 const decl_index = func.owner_decl;
680 const decl = mod.declPtr(decl_index);
681
682 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
683 self.freeUnnamedConsts(elf_file, decl_index);
684 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
685
686 var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator);
687 defer code_buffer.deinit();
688
689 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
690 defer if (decl_state) |*ds| ds.deinit();
691
692 const res = if (decl_state) |*ds|
693 try codegen.generateFunction(
694 &elf_file.base,
695 decl.srcLoc(mod),
696 func_index,
697 air,
698 liveness,
699 &code_buffer,
700 .{ .dwarf = ds },
701 )
702 else
703 try codegen.generateFunction(
704 &elf_file.base,
705 decl.srcLoc(mod),
706 func_index,
707 air,
708 liveness,
709 &code_buffer,
710 .none,
711 );
712
713 const code = switch (res) {
714 .ok => code_buffer.items,
715 .fail => |em| {
716 decl.analysis = .codegen_failure;
717 try mod.failed_decls.put(mod.gpa, decl_index, em);
718 return;
719 },
720 };
721 try self.updateDeclCode(elf_file, decl_index, sym_index, code, elf.STT_FUNC);
722 if (decl_state) |*ds| {
723 const sym = elf_file.symbol(sym_index);
724 try self.dwarf.?.commitDeclState(
725 mod,
726 decl_index,
727 sym.value,
728 sym.atom(elf_file).?.size,
729 ds,
730 );
731 }
732
733 // Since we updated the vaddr and the size, each corresponding export
734 // symbol also needs to be updated.
735 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
736}
737
738pub fn updateDecl(
739 self: *ZigObject,
740 elf_file: *Elf,
741 mod: *Module,
742 decl_index: Module.Decl.Index,
743) link.File.UpdateDeclError!void {
744 const tracy = trace(@src());
745 defer tracy.end();
746
747 const decl = mod.declPtr(decl_index);
748
749 if (decl.val.getExternFunc(mod)) |_| {
750 return;
751 }
752
753 if (decl.isExtern(mod)) {
754 // Extern variable gets a .got entry only.
755 const variable = decl.getOwnedVariable(mod).?;
756 const name = mod.intern_pool.stringToSlice(decl.name);
757 const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
758 const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
759 elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true;
760 return;
761 }
762
763 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
764 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
765
766 var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator);
767 defer code_buffer.deinit();
768
769 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
770 defer if (decl_state) |*ds| ds.deinit();
771
772 // TODO implement .debug_info for global variables
773 const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val;
774 const res = if (decl_state) |*ds|
775 try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{
776 .ty = decl.ty,
777 .val = decl_val,
778 }, &code_buffer, .{
779 .dwarf = ds,
780 }, .{
781 .parent_atom_index = sym_index,
782 })
783 else
784 try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{
785 .ty = decl.ty,
786 .val = decl_val,
787 }, &code_buffer, .none, .{
788 .parent_atom_index = sym_index,
789 });
790
791 const code = switch (res) {
792 .ok => code_buffer.items,
793 .fail => |em| {
794 decl.analysis = .codegen_failure;
795 try mod.failed_decls.put(mod.gpa, decl_index, em);
796 return;
797 },
798 };
799
800 try self.updateDeclCode(elf_file, decl_index, sym_index, code, elf.STT_OBJECT);
801 if (decl_state) |*ds| {
802 const sym = elf_file.symbol(sym_index);
803 try self.dwarf.?.commitDeclState(
804 mod,
805 decl_index,
806 sym.value,
807 sym.atom(elf_file).?.size,
808 ds,
809 );
810 }
811
812 // Since we updated the vaddr and the size, each corresponding export
813 // symbol also needs to be updated.
814 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
815}
816
817pub fn updateLazySymbol(
818 self: *ZigObject,
819 elf_file: *Elf,
820 sym: link.File.LazySymbol,
821 symbol_index: Symbol.Index,
822) !void {
823 const gpa = elf_file.base.allocator;
824 const mod = elf_file.base.options.module.?;
825
826 var required_alignment: InternPool.Alignment = .none;
827 var code_buffer = std.ArrayList(u8).init(gpa);
828 defer code_buffer.deinit();
829
830 const name_str_index = blk: {
831 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
832 @tagName(sym.kind),
833 sym.ty.fmt(mod),
834 });
835 defer gpa.free(name);
836 break :blk try elf_file.strtab.insert(gpa, name);
837 };
838
839 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
840 mod.declPtr(owner_decl).srcLoc(mod)
841 else
842 Module.SrcLoc{
843 .file_scope = undefined,
844 .parent_decl_node = undefined,
845 .lazy = .unneeded,
846 };
847 const res = try codegen.generateLazySymbol(
848 &elf_file.base,
849 src,
850 sym,
851 &required_alignment,
852 &code_buffer,
853 .none,
854 .{ .parent_atom_index = symbol_index },
855 );
856 const code = switch (res) {
857 .ok => code_buffer.items,
858 .fail => |em| {
859 log.err("{s}", .{em.msg});
860 return error.CodegenFail;
861 },
862 };
863
864 const output_section_index = switch (sym.kind) {
865 .code => elf_file.zig_text_section_index.?,
866 .const_data => elf_file.zig_rodata_section_index.?,
867 };
868 const local_sym = elf_file.symbol(symbol_index);
869 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
870 local_sym.name_offset = name_str_index;
871 local_sym.output_section_index = output_section_index;
872 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
873 local_esym.st_name = name_str_index;
874 local_esym.st_info |= elf.STT_OBJECT;
875 local_esym.st_size = code.len;
876 const atom_ptr = local_sym.atom(elf_file).?;
877 atom_ptr.flags.alive = true;
878 atom_ptr.name_offset = name_str_index;
879 atom_ptr.alignment = required_alignment;
880 atom_ptr.size = code.len;
881 atom_ptr.output_section_index = output_section_index;
882
883 try atom_ptr.allocate(elf_file);
884 errdefer self.freeDeclMetadata(elf_file, symbol_index);
885
886 local_sym.value = atom_ptr.value;
887 local_esym.st_value = atom_ptr.value;
888
889 const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);
890 try elf_file.zig_got.writeOne(elf_file, gop.index);
891
892 const section_offset = atom_ptr.value - elf_file.phdrs.items[phdr_index].p_vaddr;
893 const file_offset = elf_file.shdrs.items[output_section_index].sh_offset + section_offset;
894 try elf_file.base.file.?.pwriteAll(code, file_offset);
895}
896
897pub fn lowerUnnamedConst(
898 self: *ZigObject,
899 elf_file: *Elf,
900 typed_value: TypedValue,
901 decl_index: Module.Decl.Index,
902) !u32 {
903 const gpa = elf_file.base.allocator;
904 const mod = elf_file.base.options.module.?;
905 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
906 if (!gop.found_existing) {
907 gop.value_ptr.* = .{};
908 }
909 const unnamed_consts = gop.value_ptr;
910 const decl = mod.declPtr(decl_index);
911 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
912 const index = unnamed_consts.items.len;
913 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
914 defer gpa.free(name);
915 const sym_index = switch (try self.lowerConst(
916 elf_file,
917 name,
918 typed_value,
919 typed_value.ty.abiAlignment(mod),
920 elf_file.zig_rodata_section_index.?,
921 decl.srcLoc(mod),
922 )) {
923 .ok => |sym_index| sym_index,
924 .fail => |em| {
925 decl.analysis = .codegen_failure;
926 try mod.failed_decls.put(mod.gpa, decl_index, em);
927 log.err("{s}", .{em.msg});
928 return error.CodegenFail;
929 },
930 };
931 const sym = elf_file.symbol(sym_index);
932 try unnamed_consts.append(gpa, sym.atom_index);
933 return sym_index;
934}
935
936const LowerConstResult = union(enum) {
937 ok: Symbol.Index,
938 fail: *Module.ErrorMsg,
939};
940
941fn lowerConst(
942 self: *ZigObject,
943 elf_file: *Elf,
944 name: []const u8,
945 tv: TypedValue,
946 required_alignment: InternPool.Alignment,
947 output_section_index: u16,
948 src_loc: Module.SrcLoc,
949) !LowerConstResult {
950 const gpa = elf_file.base.allocator;
951
952 var code_buffer = std.ArrayList(u8).init(gpa);
953 defer code_buffer.deinit();
954
955 const sym_index = try self.addAtom(elf_file);
956
957 const res = try codegen.generateSymbol(&elf_file.base, src_loc, tv, &code_buffer, .{
958 .none = {},
959 }, .{
960 .parent_atom_index = sym_index,
961 });
962 const code = switch (res) {
963 .ok => code_buffer.items,
964 .fail => |em| return .{ .fail = em },
965 };
966
967 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
968 const local_sym = elf_file.symbol(sym_index);
969 const name_str_index = try elf_file.strtab.insert(gpa, name);
970 local_sym.name_offset = name_str_index;
971 local_sym.output_section_index = output_section_index;
972 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
973 local_esym.st_name = name_str_index;
974 local_esym.st_info |= elf.STT_OBJECT;
975 local_esym.st_size = code.len;
976 const atom_ptr = local_sym.atom(elf_file).?;
977 atom_ptr.flags.alive = true;
978 atom_ptr.name_offset = name_str_index;
979 atom_ptr.alignment = required_alignment;
980 atom_ptr.size = code.len;
981 atom_ptr.output_section_index = output_section_index;
982
983 try atom_ptr.allocate(elf_file);
984 // TODO rename and re-audit this method
985 errdefer self.freeDeclMetadata(elf_file, sym_index);
986
987 local_sym.value = atom_ptr.value;
988 local_esym.st_value = atom_ptr.value;
989
990 const section_offset = atom_ptr.value - elf_file.phdrs.items[phdr_index].p_vaddr;
991 const file_offset = elf_file.shdrs.items[output_section_index].sh_offset + section_offset;
992 try elf_file.base.file.?.pwriteAll(code, file_offset);
993
994 return .{ .ok = sym_index };
995}
996
997pub fn updateExports(
998 self: *ZigObject,
999 elf_file: *Elf,
1000 mod: *Module,
1001 exported: Module.Exported,
1002 exports: []const *Module.Export,
1003) link.File.UpdateExportsError!void {
1004 const tracy = trace(@src());
1005 defer tracy.end();
1006
1007 const gpa = elf_file.base.allocator;
1008 const metadata = switch (exported) {
1009 .decl_index => |decl_index| blk: {
1010 _ = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
1011 break :blk self.decls.getPtr(decl_index).?;
1012 },
1013 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1014 const first_exp = exports[0];
1015 const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod));
1016 switch (res) {
1017 .ok => {},
1018 .fail => |em| {
1019 // TODO maybe it's enough to return an error here and let Module.processExportsInner
1020 // handle the error?
1021 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1022 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1023 return;
1024 },
1025 }
1026 break :blk self.anon_decls.getPtr(value).?;
1027 },
1028 };
1029 const sym_index = metadata.symbol_index;
1030 const esym_index = elf_file.symbol(sym_index).esym_index;
1031 const esym = self.local_esyms.items(.elf_sym)[esym_index];
1032 const esym_shndx = self.local_esyms.items(.shndx)[esym_index];
1033
1034 for (exports) |exp| {
1035 if (exp.opts.section.unwrap()) |section_name| {
1036 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
1037 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1038 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1039 gpa,
1040 exp.getSrcLoc(mod),
1041 "Unimplemented: ExportOptions.section",
1042 .{},
1043 ));
1044 continue;
1045 }
1046 }
1047 const stb_bits: u8 = switch (exp.opts.linkage) {
1048 .Internal => elf.STB_LOCAL,
1049 .Strong => elf.STB_GLOBAL,
1050 .Weak => elf.STB_WEAK,
1051 .LinkOnce => {
1052 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1053 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1054 gpa,
1055 exp.getSrcLoc(mod),
1056 "Unimplemented: GlobalLinkage.LinkOnce",
1057 .{},
1058 ));
1059 continue;
1060 },
1061 };
1062 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
1063 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1064 const name_off = try elf_file.strtab.insert(gpa, exp_name);
1065 const global_esym_index = if (metadata.@"export"(self, elf_file, exp_name)) |exp_index|
1066 exp_index.*
1067 else blk: {
1068 const global_esym_index = try self.addGlobalEsym(gpa);
1069 const lookup_gop = try self.globals_lookup.getOrPut(gpa, name_off);
1070 const global_esym = self.elfSym(global_esym_index);
1071 global_esym.st_name = name_off;
1072 lookup_gop.value_ptr.* = global_esym_index;
1073 try metadata.exports.append(gpa, global_esym_index);
1074 const gop = try elf_file.getOrPutGlobal(name_off);
1075 try self.global_symbols.append(gpa, gop.index);
1076 break :blk global_esym_index;
1077 };
1078
1079 const actual_esym_index = global_esym_index & symbol_mask;
1080 const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];
1081 global_esym.st_value = elf_file.symbol(sym_index).value;
1082 global_esym.st_shndx = esym.st_shndx;
1083 global_esym.st_info = (stb_bits << 4) | stt_bits;
1084 global_esym.st_name = name_off;
1085 self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
1086 }
1087}
1088
1089/// Must be called only after a successful call to `updateDecl`.
1090pub fn updateDeclLineNumber(
1091 self: *ZigObject,
1092 mod: *Module,
1093 decl_index: Module.Decl.Index,
1094) !void {
1095 const tracy = trace(@src());
1096 defer tracy.end();
1097
1098 const decl = mod.declPtr(decl_index);
1099 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1100
1101 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
1102
1103 if (self.dwarf) |*dw| {
1104 try dw.updateDeclLineNumber(mod, decl_index);
1105 }
1106}
1107
1108pub fn deleteDeclExport(
1109 self: *ZigObject,
1110 elf_file: *Elf,
1111 decl_index: Module.Decl.Index,
1112 name: InternPool.NullTerminatedString,
1113) void {
1114 const metadata = self.decls.getPtr(decl_index) orelse return;
1115 const mod = elf_file.base.options.module.?;
1116 const exp_name = mod.intern_pool.stringToSlice(name);
1117 const esym_index = metadata.@"export"(self, elf_file, exp_name) orelse return;
1118 log.debug("deleting export '{s}'", .{exp_name});
1119 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
1120 _ = self.globals_lookup.remove(esym.st_name);
1121 const sym_index = elf_file.resolver.get(esym.st_name).?;
1122 const sym = elf_file.symbol(sym_index);
1123 if (sym.file_index == self.index) {
1124 _ = elf_file.resolver.swapRemove(esym.st_name);
1125 sym.* = .{};
1126 }
1127 esym.* = Elf.null_sym;
1128 self.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
1129}
1130
1131pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
1132 _ = lib_name;
1133 const gpa = elf_file.base.allocator;
1134 const off = try elf_file.strtab.insert(gpa, name);
1135 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1136 if (!lookup_gop.found_existing) {
1137 const esym_index = try self.addGlobalEsym(gpa);
1138 const esym = self.elfSym(esym_index);
1139 esym.st_name = off;
1140 lookup_gop.value_ptr.* = esym_index;
1141 const gop = try elf_file.getOrPutGlobal(off);
1142 try self.global_symbols.append(gpa, gop.index);
1143 }
1144 return lookup_gop.value_ptr.*;
1145}
1146
1147pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
311 return .{ .data = .{1148 return .{ .data = .{
312 .self = self,1149 .self = self,
313 .elf_file = elf_file,1150 .elf_file = elf_file,
...@@ -315,7 +1152,7 @@ pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymta...@@ -315,7 +1152,7 @@ pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymta
315}1152}
3161153
317const FormatContext = struct {1154const FormatContext = struct {
318 self: *ZigModule,1155 self: *ZigObject,
319 elf_file: *Elf,1156 elf_file: *Elf,
320};1157};
3211158
...@@ -339,7 +1176,7 @@ fn formatSymtab(...@@ -339,7 +1176,7 @@ fn formatSymtab(
339 }1176 }
340}1177}
3411178
342pub fn fmtAtoms(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {1179pub fn fmtAtoms(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {
343 return .{ .data = .{1180 return .{ .data = .{
344 .self = self,1181 .self = self,
345 .elf_file = elf_file,1182 .elf_file = elf_file,
...@@ -366,16 +1203,54 @@ const ElfSym = struct {...@@ -366,16 +1203,54 @@ const ElfSym = struct {
366 shndx: u32 = elf.SHN_UNDEF,1203 shndx: u32 = elf.SHN_UNDEF,
367};1204};
3681205
1206const LazySymbolMetadata = struct {
1207 const State = enum { unused, pending_flush, flushed };
1208 text_symbol_index: Symbol.Index = undefined,
1209 rodata_symbol_index: Symbol.Index = undefined,
1210 text_state: State = .unused,
1211 rodata_state: State = .unused,
1212};
1213
1214const DeclMetadata = struct {
1215 symbol_index: Symbol.Index,
1216 /// A list of all exports aliases of this Decl.
1217 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
1218
1219 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, elf_file: *Elf, name: []const u8) ?*u32 {
1220 for (m.exports.items) |*exp| {
1221 const exp_name = elf_file.strtab.getAssumeExists(zig_object.elfSym(exp.*).st_name);
1222 if (mem.eql(u8, name, exp_name)) return exp;
1223 }
1224 return null;
1225 }
1226};
1227
1228const AtomList = std.ArrayListUnmanaged(Atom.Index);
1229const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
1230const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
1231const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
1232const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
1233
369const assert = std.debug.assert;1234const assert = std.debug.assert;
370const std = @import("std");1235const builtin = @import("builtin");
1236const codegen = @import("../../codegen.zig");
371const elf = std.elf;1237const elf = std.elf;
1238const link = @import("../../link.zig");
372const log = std.log.scoped(.link);1239const log = std.log.scoped(.link);
1240const mem = std.mem;
1241const trace = @import("../../tracy.zig").trace;
1242const std = @import("std");
3731243
1244const Air = @import("../../Air.zig");
374const Allocator = std.mem.Allocator;1245const Allocator = std.mem.Allocator;
375const Atom = @import("Atom.zig");1246const Atom = @import("Atom.zig");
1247const Dwarf = @import("../Dwarf.zig");
376const Elf = @import("../Elf.zig");1248const Elf = @import("../Elf.zig");
377const File = @import("file.zig").File;1249const File = @import("file.zig").File;
1250const InternPool = @import("../../InternPool.zig");
1251const Liveness = @import("../../Liveness.zig");
378const Module = @import("../../Module.zig");1252const Module = @import("../../Module.zig");
379const Object = @import("Object.zig");1253const Object = @import("Object.zig");
380const Symbol = @import("Symbol.zig");1254const Symbol = @import("Symbol.zig");
381const ZigModule = @This();1255const TypedValue = @import("../../TypedValue.zig");
1256const ZigObject = @This();