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
43164316 if (try self.air.value(callee, mod)) |func_value| {
43174317 if (func_value.getFunction(mod)) |func| {
43184318 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);
43204320 const sym = elf_file.symbol(sym_index);
43214321 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
43224322 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
43024302 if (try self.air.value(callee, mod)) |func_value| {
43034303 if (func_value.getFunction(mod)) |func| {
43044304 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);
43064306 const sym = elf_file.symbol(sym_index);
43074307 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
43084308 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
17521752 if (try self.air.value(callee, mod)) |func_value| {
17531753 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
17541754 .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);
17561756 const sym = elf_file.symbol(sym_index);
17571757 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
17581758 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
13471347 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
13481348 .func => |func| {
13491349 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);
13511351 const sym = elf_file.symbol(sym_index);
13521352 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
13531353 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) {
134134 const mod = ctx.bin_file.options.module.?;
135135 const decl_index = mod.funcOwnerDeclIndex(func_index);
136136 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);
138138 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
139139 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
140140 return macho_file.getAtom(atom).getSymbolIndex().?;
......@@ -147,7 +147,7 @@ const Owner = union(enum) {
147147 },
148148 .lazy_sym => |lazy_sym| {
149149 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|
151151 ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
152152 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
153153 const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
......@@ -10233,7 +10233,7 @@ fn genCall(self: *Self, info: union(enum) {
1023310233 .func => |func| {
1023410234 try mod.markDeclAlive(mod.declPtr(func.owner_decl));
1023510235 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);
1023710237 const sym = elf_file.symbol(sym_index);
1023810238 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
1023910239 if (self.bin_file.options.pic) {
......@@ -13100,7 +13100,7 @@ fn genLazySymbolRef(
1310013100 lazy_sym: link.File.LazySymbol,
1310113101) InnerError!void {
1310213102 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|
1310413104 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
1310513105 const sym = elf_file.symbol(sym_index);
1310613106 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
src/codegen.zig+1-1
......@@ -907,7 +907,7 @@ fn genDeclRef(
907907 elf_file.symbol(elf_file.zigObjectPtr().?.symbol(sym_index)).flags.needs_got = true;
908908 return GenResult.mcv(.{ .load_symbol = sym_index });
909909 }
910 const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);
910 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
911911 const sym = elf_file.symbol(sym_index);
912912 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
913913 return GenResult.mcv(.{ .load_symbol = sym.esym_index });
src/link/Elf.zig+107-845
......@@ -1,7 +1,5 @@
11base: link.File,
22
3dwarf: ?Dwarf = null,
4
53ptr_width: PtrWidth,
64
75/// 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) = .{},
102100/// .zig.got section
103101zig_got: ZigGotSection = .{},
104102
105/// Tracked section headers with incremental updates to Zig module
103/// Tracked section headers with incremental updates to Zig object
106104zig_text_section_index: ?u16 = null,
107105zig_rodata_section_index: ?u16 = null,
108106zig_data_section_index: ?u16 = null,
......@@ -181,50 +179,16 @@ debug_line_header_dirty: bool = false,
181179error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
182180misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
183181
184/// Table of tracked LazySymbols.
185lazy_syms: LazySymbolTable = .{},
186
187/// Table of tracked Decls.
188decls: DeclTable = .{},
189
190182/// List of atoms that are owned directly by the linker.
191183atoms: std.ArrayListUnmanaged(Atom) = .{},
184
192185/// Table of last atom index in a section and matching atom free list if any.
193186last_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
217188comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
218189comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
219190comdat_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
228192/// When allocating, the ideal_capacity is calculated by
229193/// actual_capacity + (actual_capacity / ideal_factor)
230194const ideal_factor = 3;
......@@ -322,10 +286,6 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
322286 }
323287
324288 if (options.module != null and !options.use_llvm) {
325 if (!options.strip) {
326 self.dwarf = Dwarf.init(allocator, &self.base, .dwarf32);
327 }
328
329289 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));
330290 self.files.set(index, .{ .zig_object = .{
331291 .index = index,
......@@ -350,6 +310,10 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
350310 esym.st_shndx = elf.SHN_ABS;
351311 symbol_ptr.esym_index = esym_index;
352312
313 if (!options.strip) {
314 zig_object.dwarf = Dwarf.init(allocator, &self.base, .dwarf32);
315 }
316
353317 try self.initMetadata();
354318 }
355319
......@@ -425,40 +389,11 @@ pub fn deinit(self: *Elf) void {
425389 self.resolver.deinit(gpa);
426390 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
436392 self.atoms.deinit(gpa);
437393 for (self.last_atom_and_free_list_table.values()) |*value| {
438394 value.free_list.deinit(gpa);
439395 }
440396 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
463398 self.misc_errors.deinit(gpa);
464399 self.comdat_groups.deinit(gpa);
......@@ -481,16 +416,7 @@ pub fn deinit(self: *Elf) void {
481416
482417pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
483418 assert(self.llvm_object == null);
484 const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
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;
419 return self.zigObjectPtr().?.getDeclVAddr(self, decl_index, reloc_info);
494420}
495421
496422pub fn lowerAnonDecl(
......@@ -499,60 +425,12 @@ pub fn lowerAnonDecl(
499425 explicit_alignment: InternPool.Alignment,
500426 src_loc: Module.SrcLoc,
501427) !codegen.Result {
502 const gpa = self.base.allocator;
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;
428 return self.zigObjectPtr().?.lowerAnonDecl(self, decl_val, explicit_alignment, src_loc);
542429}
543430
544431pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
545432 assert(self.llvm_object == null);
546 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
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;
433 return self.zigObjectPtr().?.getAnonDeclVAddr(self, decl_val, reloc_info);
556434}
557435
558436/// Returns end pos of collision, if any.
......@@ -839,7 +717,7 @@ pub fn initMetadata(self: *Elf) !void {
839717 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
840718 }
841719
842 if (self.dwarf) |*dw| {
720 if (self.zigObjectPtr().?.dwarf) |*dw| {
843721 if (self.debug_str_section_index == null) {
844722 assert(dw.strtab.buffer.items.len == 0);
845723 try dw.strtab.buffer.append(gpa, 0);
......@@ -976,7 +854,7 @@ pub fn growNonAllocSection(
976854}
977855
978856pub fn markDirty(self: *Elf, shdr_index: u16) void {
979 if (self.dwarf) |_| {
857 if (self.zigObjectPtr().?.dwarf) |_| {
980858 if (self.debug_info_section_index.? == shdr_index) {
981859 self.debug_info_header_dirty = true;
982860 } 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
14861364 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
14871365 }
14881366
1489 // Handle any lazy symbols that were emitted by incremental compilation.
1490 if (self.lazy_syms.getPtr(.none)) |metadata| {
1491 const module = self.base.options.module.?;
1492
1493 // Most lazy symbols can be updated on first use, but
1494 // anyerror needs to wait for everything to be flushed.
1495 if (metadata.text_state != .unused) self.updateLazySymbol(
1496 link.File.LazySymbol.initDecl(.code, null, module),
1497 metadata.text_symbol_index,
1498 ) catch |err| return switch (err) {
1499 error.CodegenFail => error.FlushFailure,
1500 else => |e| e,
1501 };
1502 if (metadata.rodata_state != .unused) self.updateLazySymbol(
1503 link.File.LazySymbol.initDecl(.const_data, null, module),
1504 metadata.rodata_symbol_index,
1505 ) catch |err| return switch (err) {
1506 error.CodegenFail => error.FlushFailure,
1507 else => |e| e,
1508 };
1509 }
1510 for (self.lazy_syms.values()) |*metadata| {
1511 if (metadata.text_state != .unused) metadata.text_state = .flushed;
1512 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
1513 }
1367 if (self.zigObjectPtr()) |zig_object| {
1368 // Handle any lazy symbols that were emitted by incremental compilation.
1369 if (zig_object.lazy_syms.getPtr(.none)) |metadata| {
1370 const module = self.base.options.module.?;
1371
1372 // Most lazy symbols can be updated on first use, but
1373 // anyerror needs to wait for everything to be flushed.
1374 if (metadata.text_state != .unused) zig_object.updateLazySymbol(
1375 self,
1376 link.File.LazySymbol.initDecl(.code, null, module),
1377 metadata.text_symbol_index,
1378 ) catch |err| return switch (err) {
1379 error.CodegenFail => error.FlushFailure,
1380 else => |e| e,
1381 };
1382 if (metadata.rodata_state != .unused) zig_object.updateLazySymbol(
1383 self,
1384 link.File.LazySymbol.initDecl(.const_data, null, module),
1385 metadata.rodata_symbol_index,
1386 ) catch |err| return switch (err) {
1387 error.CodegenFail => error.FlushFailure,
1388 else => |e| e,
1389 };
1390 }
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| {
1516 try dw.flushModule(self.base.options.module.?);
1396 if (zig_object.dwarf) |*dw| {
1397 try dw.flushModule(self.base.options.module.?);
1398 }
15171399 }
15181400
15191401 // Dedup shared objects
......@@ -1576,43 +1458,45 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15761458 // Scan and create missing synthetic entries such as GOT indirection.
15771459 try self.scanRelocs();
15781460
1579 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
1580 // extracted from input object files correctly.
1581 if (self.dwarf) |*dw| {
1582 if (self.debug_abbrev_section_dirty) {
1583 try dw.writeDbgAbbrev();
1584 self.debug_abbrev_section_dirty = false;
1585 }
1461 if (self.zigObjectPtr()) |zig_object| {
1462 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
1463 // extracted from input object files correctly.
1464 if (zig_object.dwarf) |*dw| {
1465 if (self.debug_abbrev_section_dirty) {
1466 try dw.writeDbgAbbrev();
1467 self.debug_abbrev_section_dirty = false;
1468 }
15861469
1587 if (self.debug_info_header_dirty) {
1588 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1589 const low_pc = text_phdr.p_vaddr;
1590 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1591 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);
1592 self.debug_info_header_dirty = false;
1593 }
1470 if (self.debug_info_header_dirty) {
1471 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1472 const low_pc = text_phdr.p_vaddr;
1473 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
1474 try dw.writeDbgInfoHeader(self.base.options.module.?, low_pc, high_pc);
1475 self.debug_info_header_dirty = false;
1476 }
15941477
1595 if (self.debug_aranges_section_dirty) {
1596 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1597 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1598 self.debug_aranges_section_dirty = false;
1599 }
1478 if (self.debug_aranges_section_dirty) {
1479 const text_phdr = &self.phdrs.items[self.phdr_zig_load_re_index.?];
1480 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
1481 self.debug_aranges_section_dirty = false;
1482 }
16001483
1601 if (self.debug_line_header_dirty) {
1602 try dw.writeDbgLineHeader();
1603 self.debug_line_header_dirty = false;
1604 }
1484 if (self.debug_line_header_dirty) {
1485 try dw.writeDbgLineHeader();
1486 self.debug_line_header_dirty = false;
1487 }
16051488
1606 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) {
1608 try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
1609 const shdr = self.shdrs.items[shndx];
1610 try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
1611 self.debug_strtab_dirty = false;
1489 if (self.debug_str_section_index) |shndx| {
1490 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != self.shdrs.items[shndx].sh_size) {
1491 try self.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
1492 const shdr = self.shdrs.items[shndx];
1493 try self.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
1494 self.debug_strtab_dirty = false;
1495 }
16121496 }
1613 }
16141497
1615 self.saveDebugSectionsSizes();
1498 self.saveDebugSectionsSizes();
1499 }
16161500 }
16171501
16181502 // Generate and emit non-incremental sections.
......@@ -3055,206 +2939,9 @@ fn writeHeader(self: *Elf) !void {
30552939 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
30562940}
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
30752942pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
30762943 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
3077
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 }
2944 return self.zigObjectPtr().?.freeDecl(self, decl_index);
32582945}
32592946
32602947pub 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
32622949 @panic("Attempted to compile for object format that was disabled by build configuration");
32632950 }
32642951 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
3265
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));
2952 return self.zigObjectPtr().?.updateFunc(self, mod, func_index, air, liveness);
33132953}
33142954
33152955pub fn updateDecl(
......@@ -3321,242 +2961,11 @@ pub fn updateDecl(
33212961 @panic("Attempted to compile for object format that was disabled by build configuration");
33222962 }
33232963 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
3324
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);
2964 return self.zigObjectPtr().?.updateDecl(self, mod, decl_index);
34722965}
34732966
34742967pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
3475 const gpa = self.base.allocator;
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 };
2968 return self.zigObjectPtr().?.lowerUnnamedConst(self, typed_value, decl_index);
35602969}
35612970
35622971pub fn updateExports(
......@@ -3569,107 +2978,13 @@ pub fn updateExports(
35692978 @panic("Attempted to compile for object format that was disabled by build configuration");
35702979 }
35712980 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3572
35732981 if (self.base.options.emit == null) return;
3574
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 }
2982 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
36572983}
36582984
3659/// Must be called only after a successful call to `updateDecl`.
36602985pub 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
36692986 if (self.llvm_object) |_| return;
3670 if (self.dwarf) |*dw| {
3671 try dw.updateDeclLineNumber(mod, decl_index);
3672 }
2987 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
36732988}
36742989
36752990pub fn deleteDeclExport(
......@@ -3678,22 +2993,7 @@ pub fn deleteDeclExport(
36782993 name: InternPool.NullTerminatedString,
36792994) void {
36802995 if (self.llvm_object) |_| return;
3681 const metadata = self.decls.getPtr(decl_index) orelse return;
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;
2996 return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
36972997}
36982998
36992999fn addLinkerDefinedSymbols(self: *Elf) !void {
......@@ -5955,20 +5255,7 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
59555255}
59565256
59575257pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
5958 _ = 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.*;
5258 return self.zigObjectPtr().?.getGlobalSymbol(self, name, lib_name);
59725259}
59735260
59745261pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
......@@ -6335,51 +5622,6 @@ const default_entry_addr = 0x8000000;
63355622
63365623pub 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
63835625const ComdatGroupOwner = struct {
63845626 file: File.Index = 0,
63855627 const Index = u32;
......@@ -6423,6 +5665,30 @@ pub const SystemLib = struct {
64235665 path: []const u8,
64245666};
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
64265692pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
64275693pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
64285694
......@@ -6471,16 +5737,12 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;
64715737const Module = @import("../Module.zig");
64725738const Object = @import("Elf/Object.zig");
64735739const InternPool = @import("../InternPool.zig");
6474const Package = @import("../Package.zig");
64755740const PltSection = synthetic_sections.PltSection;
64765741const PltGotSection = synthetic_sections.PltGotSection;
64775742const SharedObject = @import("Elf/SharedObject.zig");
64785743const Symbol = @import("Elf/Symbol.zig");
64795744const StringTable = @import("strtab.zig").StringTable;
6480const TableSection = @import("table_section.zig").TableSection;
6481const Type = @import("../type.zig").Type;
64825745const TypedValue = @import("../TypedValue.zig");
6483const Value = @import("../value.zig").Value;
64845746const VerneedSection = synthetic_sections.VerneedSection;
64855747const ZigGotSection = synthetic_sections.ZigGotSection;
64865748const 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 {
166166 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
167167 last_atom_index.* = self.atom_index;
168168
169 if (elf_file.dwarf) |_| {
169 if (elf_file.zigObjectPtr().?.dwarf) |_| {
170170 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
171171 // range of the compilation unit. When we expand the text section, this range changes,
172172 // 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//! ZigModule encapsulates the state of the incrementally compiled Zig module.
1//! ZigObject encapsulates the state of the incrementally compiled Zig module.
22//! It stores the associated input local and global symbols, allocated atoms,
33//! and any relocations that may have been emitted.
44//! Think about this as fake in-memory Object file for the Zig module.
......@@ -20,11 +20,43 @@ num_dynrelocs: u32 = 0,
2020
2121output_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
2355pub const global_symbol_bit: u32 = 0x80000000;
2456pub const symbol_mask: u32 = 0x7fffffff;
2557pub const SHN_ATOM: u16 = 0x100;
2658
27pub fn deinit(self: *ZigModule, allocator: Allocator) void {
59pub fn deinit(self: *ZigObject, allocator: Allocator) void {
2860 self.local_esyms.deinit(allocator);
2961 self.global_esyms.deinit(allocator);
3062 self.local_symbols.deinit(allocator);
......@@ -35,9 +67,39 @@ pub fn deinit(self: *ZigModule, allocator: Allocator) void {
3567 list.deinit(allocator);
3668 }
3769 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 }
38100}
39101
40pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
102pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
41103 try self.local_esyms.ensureUnusedCapacity(allocator, 1);
42104 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
43105 var esym = ElfSym{ .elf_sym = Elf.null_sym };
......@@ -46,7 +108,7 @@ pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
46108 return index;
47109}
48110
49pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
111pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
50112 try self.global_esyms.ensureUnusedCapacity(allocator, 1);
51113 const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));
52114 var esym = ElfSym{ .elf_sym = Elf.null_sym };
......@@ -55,7 +117,7 @@ pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
55117 return index | global_symbol_bit;
56118}
57119
58pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
120pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
59121 const gpa = elf_file.base.allocator;
60122
61123 const atom_index = try elf_file.addAtom();
......@@ -86,7 +148,7 @@ pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
86148}
87149
88150/// 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 {
90152 _ = self;
91153 const shdr = shdr: {
92154 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
101163 return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
102164}
103165
104pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
166pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
105167 for (self.globals(), 0..) |index, i| {
106168 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
107169 const esym = self.global_esyms.items(.elf_sym)[i];
......@@ -138,7 +200,7 @@ pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
138200 }
139201}
140202
141pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
203pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
142204 for (self.globals(), 0..) |index, i| {
143205 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
144206 const esym = self.global_esyms.items(.elf_sym)[i];
......@@ -166,7 +228,7 @@ pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
166228 }
167229}
168230
169pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
231pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
170232 for (self.atoms.items) |atom_index| {
171233 const atom = elf_file.atom(atom_index) orelse continue;
172234 if (!atom.flags.alive) continue;
......@@ -183,7 +245,7 @@ pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
183245 }
184246}
185247
186pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {
248pub fn resetGlobals(self: *ZigObject, elf_file: *Elf) void {
187249 for (self.globals()) |index| {
188250 const global = elf_file.symbol(index);
189251 const off = global.name_offset;
......@@ -192,7 +254,7 @@ pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {
192254 }
193255}
194256
195pub fn markLive(self: *ZigModule, elf_file: *Elf) void {
257pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
196258 for (self.globals(), 0..) |index, i| {
197259 const esym = self.global_esyms.items(.elf_sym)[i];
198260 if (esym.st_bind() == elf.STB_WEAK) continue;
......@@ -208,7 +270,7 @@ pub fn markLive(self: *ZigModule, elf_file: *Elf) void {
208270 }
209271}
210272
211pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
273pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) void {
212274 for (self.locals()) |local_index| {
213275 const local = elf_file.symbol(local_index);
214276 const esym = local.elfSym(elf_file);
......@@ -238,7 +300,7 @@ pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
238300 }
239301}
240302
241pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {
303pub fn writeSymtab(self: *ZigObject, elf_file: *Elf, ctx: anytype) void {
242304 var ilocal = ctx.ilocal;
243305 for (self.locals()) |local_index| {
244306 const local = elf_file.symbol(local_index);
......@@ -262,35 +324,35 @@ pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {
262324 }
263325}
264326
265pub fn symbol(self: *ZigModule, index: Symbol.Index) Symbol.Index {
327pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
266328 const is_global = index & global_symbol_bit != 0;
267329 const actual_index = index & symbol_mask;
268330 if (is_global) return self.global_symbols.items[actual_index];
269331 return self.local_symbols.items[actual_index];
270332}
271333
272pub fn elfSym(self: *ZigModule, index: Symbol.Index) *elf.Elf64_Sym {
334pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
273335 const is_global = index & global_symbol_bit != 0;
274336 const actual_index = index & symbol_mask;
275337 if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index];
276338 return &self.local_esyms.items(.elf_sym)[actual_index];
277339}
278340
279pub fn locals(self: *ZigModule) []const Symbol.Index {
341pub fn locals(self: *ZigObject) []const Symbol.Index {
280342 return self.local_symbols.items;
281343}
282344
283pub fn globals(self: *ZigModule) []const Symbol.Index {
345pub fn globals(self: *ZigObject) []const Symbol.Index {
284346 return self.global_symbols.items;
285347}
286348
287pub fn asFile(self: *ZigModule) File {
349pub fn asFile(self: *ZigObject) File {
288350 return .{ .zig_object = self };
289351}
290352
291353/// Returns atom's code.
292354/// 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 {
294356 const gpa = elf_file.base.allocator;
295357 const atom = elf_file.atom(atom_index).?;
296358 assert(atom.file_index == self.index);
......@@ -307,7 +369,782 @@ pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8
307369 return code;
308370}
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) {
3111148 return .{ .data = .{
3121149 .self = self,
3131150 .elf_file = elf_file,
......@@ -315,7 +1152,7 @@ pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymta
3151152}
3161153
3171154const FormatContext = struct {
318 self: *ZigModule,
1155 self: *ZigObject,
3191156 elf_file: *Elf,
3201157};
3211158
......@@ -339,7 +1176,7 @@ fn formatSymtab(
3391176 }
3401177}
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) {
3431180 return .{ .data = .{
3441181 .self = self,
3451182 .elf_file = elf_file,
......@@ -366,16 +1203,54 @@ const ElfSym = struct {
3661203 shndx: u32 = elf.SHN_UNDEF,
3671204};
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
3691234const assert = std.debug.assert;
370const std = @import("std");
1235const builtin = @import("builtin");
1236const codegen = @import("../../codegen.zig");
3711237const elf = std.elf;
1238const link = @import("../../link.zig");
3721239const 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");
3741245const Allocator = std.mem.Allocator;
3751246const Atom = @import("Atom.zig");
1247const Dwarf = @import("../Dwarf.zig");
3761248const Elf = @import("../Elf.zig");
3771249const File = @import("file.zig").File;
1250const InternPool = @import("../../InternPool.zig");
1251const Liveness = @import("../../Liveness.zig");
3781252const Module = @import("../../Module.zig");
3791253const Object = @import("Object.zig");
3801254const Symbol = @import("Symbol.zig");
381const ZigModule = @This();
1255const TypedValue = @import("../../TypedValue.zig");
1256const ZigObject = @This();