authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2023-10-31 07:51:26+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-31 07:51:26+01:00
loga09ba455c2b8334f790fc3ebca9a12c8bd06f1db
tree837e373b4396939cf850f4606f285cc77ff11d3e
parent34aac2bae145ae19fcbe36f794ee7054ea4de11f
parentea95c74948b6cbc615452c661180874213cb5f9c
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17791 from ziglang/elf-object

elf: rename ZigModule to ZigObject and move all codegen hooks into it

14 files changed, 1549 insertions(+), 1406 deletions(-)

CMakeLists.txt+1-1
......@@ -594,7 +594,7 @@ set(ZIG_STAGE2_SOURCES
594594 "${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig"
595595 "${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig"
596596 "${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig"
597 "${CMAKE_SOURCE_DIR}/src/link/Elf/ZigModule.zig"
597 "${CMAKE_SOURCE_DIR}/src/link/Elf/ZigObject.zig"
598598 "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig"
599599 "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig"
600600 "${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig"
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/arch/x86_64/Emit.zig+1-1
......@@ -86,7 +86,7 @@ pub fn emitMir(emit: *Emit) Error!void {
8686 }),
8787 .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
8888 const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;
89 const sym = elf_file.symbol(elf_file.zigModulePtr().symbol(data.sym_index));
89 const sym = elf_file.symbol(elf_file.zigObjectPtr().?.symbol(data.sym_index));
9090 if (emit.lower.bin_file.options.pic) {
9191 const r_type: u32 = if (sym.flags.has_zig_got)
9292 link.File.Elf.R_X86_64_ZIG_GOTPCREL
src/codegen.zig+2-2
......@@ -904,10 +904,10 @@ fn genDeclRef(
904904 else
905905 null;
906906 const sym_index = try elf_file.getGlobalSymbol(name, lib_name);
907 elf_file.symbol(elf_file.zigModulePtr().symbol(sym_index)).flags.needs_got = true;
907 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+121-987
......@@ -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.
......@@ -11,7 +9,7 @@ llvm_object: ?*LlvmObject = null,
119/// Index of each input file also encodes the priority or precedence of one input file
1210/// over another.
1311files: std.MultiArrayList(File.Entry) = .{},
14zig_module_index: ?File.Index = null,
12zig_object_index: ?File.Index = null,
1513linker_defined_index: ?File.Index = null,
1614objects: std.ArrayListUnmanaged(File.Index) = .{},
1715shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
......@@ -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,
......@@ -115,14 +113,6 @@ debug_str_section_index: ?u16 = null,
115113debug_aranges_section_index: ?u16 = null,
116114debug_line_section_index: ?u16 = null,
117115
118/// Size contribution of Zig's metadata to each debug section.
119/// Used to track start of metadata from input object files.
120debug_info_section_zig_size: u64 = 0,
121debug_abbrev_section_zig_size: u64 = 0,
122debug_str_section_zig_size: u64 = 0,
123debug_aranges_section_zig_size: u64 = 0,
124debug_line_section_zig_size: u64 = 0,
125
126116copy_rel_section_index: ?u16 = null,
127117dynamic_section_index: ?u16 = null,
128118dynstrtab_section_index: ?u16 = null,
......@@ -172,59 +162,19 @@ symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
172162has_text_reloc: bool = false,
173163num_ifunc_dynrelocs: usize = 0,
174164
175debug_strtab_dirty: bool = false,
176debug_abbrev_section_dirty: bool = false,
177debug_aranges_section_dirty: bool = false,
178debug_info_header_dirty: bool = false,
179debug_line_header_dirty: bool = false,
180
181165error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
182166misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
183167
184/// Table of tracked LazySymbols.
185lazy_syms: LazySymbolTable = .{},
186
187/// Table of tracked Decls.
188decls: DeclTable = .{},
189
190168/// List of atoms that are owned directly by the linker.
191169atoms: std.ArrayListUnmanaged(Atom) = .{},
170
192171/// Table of last atom index in a section and matching atom free list if any.
193172last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
194173
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
217174comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
218175comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
219176comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
220177
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
228178/// When allocating, the ideal_capacity is calculated by
229179/// actual_capacity + (actual_capacity / ideal_factor)
230180const ideal_factor = 3;
......@@ -322,34 +272,13 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
322272 }
323273
324274 if (options.module != null and !options.use_llvm) {
325 if (!options.strip) {
326 self.dwarf = Dwarf.init(allocator, &self.base, .dwarf32);
327 }
328
329275 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));
330 self.files.set(index, .{ .zig_module = .{
276 self.files.set(index, .{ .zig_object = .{
331277 .index = index,
332278 .path = options.module.?.main_mod.root_src_path,
333279 } });
334 self.zig_module_index = index;
335 const zig_module = self.file(index).?.zig_module;
336
337 try zig_module.atoms.append(allocator, 0); // null input section
338
339 const name_off = try self.strtab.insert(allocator, std.fs.path.stem(options.module.?.main_mod.root_src_path));
340 const symbol_index = try self.addSymbol();
341 try zig_module.local_symbols.append(allocator, symbol_index);
342 const symbol_ptr = self.symbol(symbol_index);
343 symbol_ptr.file_index = zig_module.index;
344 symbol_ptr.name_offset = name_off;
345
346 const esym_index = try zig_module.addLocalEsym(allocator);
347 const esym = &zig_module.local_esyms.items(.elf_sym)[esym_index];
348 esym.st_name = name_off;
349 esym.st_info |= elf.STT_FILE;
350 esym.st_shndx = elf.SHN_ABS;
351 symbol_ptr.esym_index = esym_index;
352
280 self.zig_object_index = index;
281 try self.zigObjectPtr().?.init(self);
353282 try self.initMetadata();
354283 }
355284
......@@ -401,7 +330,7 @@ pub fn deinit(self: *Elf) void {
401330
402331 for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
403332 .null => {},
404 .zig_module => data.zig_module.deinit(gpa),
333 .zig_object => data.zig_object.deinit(gpa),
405334 .linker_defined => data.linker_defined.deinit(gpa),
406335 .object => data.object.deinit(gpa),
407336 .shared_object => data.shared_object.deinit(gpa),
......@@ -425,40 +354,11 @@ pub fn deinit(self: *Elf) void {
425354 self.resolver.deinit(gpa);
426355 self.start_stop_indexes.deinit(gpa);
427356
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
436357 self.atoms.deinit(gpa);
437358 for (self.last_atom_and_free_list_table.values()) |*value| {
438359 value.free_list.deinit(gpa);
439360 }
440361 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 }
462362
463363 self.misc_errors.deinit(gpa);
464364 self.comdat_groups.deinit(gpa);
......@@ -481,16 +381,7 @@ pub fn deinit(self: *Elf) void {
481381
482382pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
483383 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;
384 return self.zigObjectPtr().?.getDeclVAddr(self, decl_index, reloc_info);
494385}
495386
496387pub fn lowerAnonDecl(
......@@ -499,60 +390,12 @@ pub fn lowerAnonDecl(
499390 explicit_alignment: InternPool.Alignment,
500391 src_loc: Module.SrcLoc,
501392) !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;
393 return self.zigObjectPtr().?.lowerAnonDecl(self, decl_val, explicit_alignment, src_loc);
542394}
543395
544396pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
545397 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;
398 return self.zigObjectPtr().?.getAnonDeclVAddr(self, decl_val, reloc_info);
556399}
557400
558401/// Returns end pos of collision, if any.
......@@ -726,7 +569,7 @@ fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{
726569 return index;
727570}
728571
729/// TODO move to ZigModule
572/// TODO move to ZigObject
730573pub fn initMetadata(self: *Elf) !void {
731574 const gpa = self.base.allocator;
732575 const ptr_size = self.ptrWidthBytes();
......@@ -839,7 +682,8 @@ pub fn initMetadata(self: *Elf) !void {
839682 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
840683 }
841684
842 if (self.dwarf) |*dw| {
685 const zig_object = self.zigObjectPtr().?;
686 if (zig_object.dwarf) |*dw| {
843687 if (self.debug_str_section_index == null) {
844688 assert(dw.strtab.buffer.items.len == 0);
845689 try dw.strtab.buffer.append(gpa, 0);
......@@ -849,7 +693,7 @@ pub fn initMetadata(self: *Elf) !void {
849693 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
850694 .entsize = 1,
851695 });
852 self.debug_strtab_dirty = true;
696 zig_object.debug_strtab_dirty = true;
853697 }
854698
855699 if (self.debug_info_section_index == null) {
......@@ -858,7 +702,7 @@ pub fn initMetadata(self: *Elf) !void {
858702 .size = 200,
859703 .alignment = 1,
860704 });
861 self.debug_info_header_dirty = true;
705 zig_object.debug_info_header_dirty = true;
862706 }
863707
864708 if (self.debug_abbrev_section_index == null) {
......@@ -867,7 +711,7 @@ pub fn initMetadata(self: *Elf) !void {
867711 .size = 128,
868712 .alignment = 1,
869713 });
870 self.debug_abbrev_section_dirty = true;
714 zig_object.debug_abbrev_section_dirty = true;
871715 }
872716
873717 if (self.debug_aranges_section_index == null) {
......@@ -876,7 +720,7 @@ pub fn initMetadata(self: *Elf) !void {
876720 .size = 160,
877721 .alignment = 16,
878722 });
879 self.debug_aranges_section_dirty = true;
723 zig_object.debug_aranges_section_dirty = true;
880724 }
881725
882726 if (self.debug_line_section_index == null) {
......@@ -885,7 +729,7 @@ pub fn initMetadata(self: *Elf) !void {
885729 .size = 250,
886730 .alignment = 1,
887731 });
888 self.debug_line_header_dirty = true;
732 zig_object.debug_line_header_dirty = true;
889733 }
890734 }
891735}
......@@ -976,17 +820,18 @@ pub fn growNonAllocSection(
976820}
977821
978822pub fn markDirty(self: *Elf, shdr_index: u16) void {
979 if (self.dwarf) |_| {
823 const zig_object = self.zigObjectPtr().?;
824 if (zig_object.dwarf) |_| {
980825 if (self.debug_info_section_index.? == shdr_index) {
981 self.debug_info_header_dirty = true;
826 zig_object.debug_info_header_dirty = true;
982827 } else if (self.debug_line_section_index.? == shdr_index) {
983 self.debug_line_header_dirty = true;
828 zig_object.debug_line_header_dirty = true;
984829 } else if (self.debug_abbrev_section_index.? == shdr_index) {
985 self.debug_abbrev_section_dirty = true;
830 zig_object.debug_abbrev_section_dirty = true;
986831 } else if (self.debug_str_section_index.? == shdr_index) {
987 self.debug_strtab_dirty = true;
832 zig_object.debug_strtab_dirty = true;
988833 } else if (self.debug_aranges_section_index.? == shdr_index) {
989 self.debug_aranges_section_dirty = true;
834 zig_object.debug_aranges_section_dirty = true;
990835 }
991836 }
992837}
......@@ -1041,7 +886,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1041886 } else null;
1042887 const gc_sections = self.base.options.gc_sections orelse false;
1043888
1044 if (self.base.options.output_mode == .Obj and self.zig_module_index == null) {
889 if (self.base.options.output_mode == .Obj and self.zig_object_index == null) {
1045890 // TODO this will become -r route I guess. For now, just copy the object file.
1046891 assert(self.base.file == null); // TODO uncomment once we implement -r
1047892 const the_object_path = blk: {
......@@ -1486,35 +1331,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
14861331 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
14871332 }
14881333
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 }
1514
1515 if (self.dwarf) |*dw| {
1516 try dw.flushModule(self.base.options.module.?);
1517 }
1334 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
15181335
15191336 // Dedup shared objects
15201337 {
......@@ -1543,7 +1360,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15431360 }
15441361
15451362 // Now, we are ready to resolve the symbols across all input files.
1546 // We will first resolve the files in the ZigModule, next in the parsed
1363 // We will first resolve the files in the ZigObject, next in the parsed
15471364 // input Object files.
15481365 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
15491366 // symbol for potential resolution at load-time.
......@@ -1576,45 +1393,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
15761393 // Scan and create missing synthetic entries such as GOT indirection.
15771394 try self.scanRelocs();
15781395
1579 // TODO I need to re-think how to handle ZigModule'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 }
1586
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 }
1594
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 }
1600
1601 if (self.debug_line_header_dirty) {
1602 try dw.writeDbgLineHeader();
1603 self.debug_line_header_dirty = false;
1604 }
1605
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;
1612 }
1613 }
1614
1615 self.saveDebugSectionsSizes();
1616 }
1617
16181396 // Generate and emit non-incremental sections.
16191397 try self.initSections();
16201398 try self.initSpecialPhdrs();
......@@ -1645,15 +1423,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
16451423
16461424 // Beyond this point, everything has been allocated a virtual address and we can resolve
16471425 // the relocations, and commit objects to file.
1648 if (self.zig_module_index) |index| {
1649 const zig_module = self.file(index).?.zig_module;
1650 for (zig_module.atoms.items) |atom_index| {
1426 if (self.zigObjectPtr()) |zig_object| {
1427 for (zig_object.atoms.items) |atom_index| {
16511428 const atom_ptr = self.atom(atom_index) orelse continue;
16521429 if (!atom_ptr.flags.alive) continue;
16531430 const out_shndx = atom_ptr.outputShndx() orelse continue;
16541431 const shdr = &self.shdrs.items[out_shndx];
16551432 if (shdr.sh_type == elf.SHT_NOBITS) continue;
1656 const code = try zig_module.codeAlloc(self, atom_index);
1433 const code = try zig_object.codeAlloc(self, atom_index);
16571434 defer gpa.free(code);
16581435 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
16591436 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
......@@ -1680,14 +1457,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
16801457 self.error_flags.no_entry_point_found = false;
16811458 try self.writeHeader();
16821459 }
1683
1684 // The point of flush() is to commit changes, so in theory, nothing should
1685 // be dirty after this. However, it is possible for some things to remain
1686 // dirty because they fail to be written in the event of compile errors,
1687 // such as debug_line_header_dirty and debug_info_header_dirty.
1688 assert(!self.debug_abbrev_section_dirty);
1689 assert(!self.debug_aranges_section_dirty);
1690 assert(!self.debug_strtab_dirty);
16911460}
16921461
16931462const ParseError = error{
......@@ -1926,8 +1695,8 @@ fn accessLibPath(
19261695/// 5. Remove references to dead objects/shared objects
19271696/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
19281697fn resolveSymbols(self: *Elf) void {
1929 // Resolve symbols in the ZigModule. For now, we assume that it's always live.
1930 if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);
1698 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1699 if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);
19311700 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
19321701 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
19331702 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
......@@ -1936,7 +1705,7 @@ fn resolveSymbols(self: *Elf) void {
19361705 self.markLive();
19371706
19381707 // Reset state of all globals after marking live objects.
1939 if (self.zig_module_index) |index| self.file(index).?.resetGlobals(self);
1708 if (self.zigObjectPtr()) |zig_object| zig_object.resetGlobals(self);
19401709 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
19411710 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
19421711
......@@ -1988,7 +1757,7 @@ fn resolveSymbols(self: *Elf) void {
19881757 }
19891758
19901759 // Re-resolve the symbols.
1991 if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);
1760 if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);
19921761 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
19931762 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
19941763}
......@@ -1998,7 +1767,7 @@ fn resolveSymbols(self: *Elf) void {
19981767/// This routine will prune unneeded objects extracted from archives and
19991768/// unneeded shared objects.
20001769fn markLive(self: *Elf) void {
2001 if (self.zig_module_index) |index| self.file(index).?.markLive(self);
1770 if (self.zigObjectPtr()) |zig_object| zig_object.markLive(self);
20021771 for (self.objects.items) |index| {
20031772 const file_ptr = self.file(index).?;
20041773 if (file_ptr.isAlive()) file_ptr.markLive(self);
......@@ -2057,7 +1826,7 @@ fn markImportsExports(self: *Elf) void {
20571826 }
20581827 }
20591828
2060 if (self.zig_module_index) |index| {
1829 if (self.zig_object_index) |index| {
20611830 mark(self, index);
20621831 }
20631832
......@@ -2067,9 +1836,8 @@ fn markImportsExports(self: *Elf) void {
20671836}
20681837
20691838fn claimUnresolved(self: *Elf) void {
2070 if (self.zig_module_index) |index| {
2071 const zig_module = self.file(index).?.zig_module;
2072 zig_module.claimUnresolved(self);
1839 if (self.zigObjectPtr()) |zig_object| {
1840 zig_object.claimUnresolved(self);
20731841 }
20741842 for (self.objects.items) |index| {
20751843 const object = self.file(index).?.object;
......@@ -2093,9 +1861,8 @@ fn scanRelocs(self: *Elf) !void {
20931861 undefs.deinit();
20941862 }
20951863
2096 if (self.zig_module_index) |index| {
2097 const zig_module = self.file(index).?.zig_module;
2098 try zig_module.scanRelocs(self, &undefs);
1864 if (self.zigObjectPtr()) |zig_object| {
1865 try zig_object.scanRelocs(self, &undefs);
20991866 }
21001867 for (self.objects.items) |index| {
21011868 const object = self.file(index).?.object;
......@@ -3058,206 +2825,9 @@ fn writeHeader(self: *Elf) !void {
30582825 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
30592826}
30602827
3061fn freeUnnamedConsts(self: *Elf, decl_index: Module.Decl.Index) void {
3062 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
3063 for (unnamed_consts.items) |sym_index| {
3064 self.freeDeclMetadata(sym_index);
3065 }
3066 unnamed_consts.clearAndFree(self.base.allocator);
3067}
3068
3069fn freeDeclMetadata(self: *Elf, sym_index: Symbol.Index) void {
3070 const sym = self.symbol(sym_index);
3071 sym.atom(self).?.free(self);
3072 log.debug("adding %{d} to local symbols free list", .{sym_index});
3073 self.symbols_free_list.append(self.base.allocator, sym_index) catch {};
3074 self.symbols.items[sym_index] = .{};
3075 // TODO free GOT entry here
3076}
3077
30782828pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
30792829 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
3080
3081 const mod = self.base.options.module.?;
3082 const decl = mod.declPtr(decl_index);
3083
3084 log.debug("freeDecl {*}", .{decl});
3085
3086 if (self.decls.fetchRemove(decl_index)) |const_kv| {
3087 var kv = const_kv;
3088 const sym_index = kv.value.symbol_index;
3089 self.freeDeclMetadata(sym_index);
3090 self.freeUnnamedConsts(decl_index);
3091 kv.value.exports.deinit(self.base.allocator);
3092 }
3093
3094 if (self.dwarf) |*dw| {
3095 dw.freeDecl(decl_index);
3096 }
3097}
3098
3099pub fn getOrCreateMetadataForLazySymbol(self: *Elf, lazy_sym: link.File.LazySymbol) !Symbol.Index {
3100 const mod = self.base.options.module.?;
3101 const gop = try self.lazy_syms.getOrPut(self.base.allocator, lazy_sym.getDecl(mod));
3102 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
3103 if (!gop.found_existing) gop.value_ptr.* = .{};
3104 const metadata: struct {
3105 symbol_index: *Symbol.Index,
3106 state: *LazySymbolMetadata.State,
3107 } = switch (lazy_sym.kind) {
3108 .code => .{
3109 .symbol_index = &gop.value_ptr.text_symbol_index,
3110 .state = &gop.value_ptr.text_state,
3111 },
3112 .const_data => .{
3113 .symbol_index = &gop.value_ptr.rodata_symbol_index,
3114 .state = &gop.value_ptr.rodata_state,
3115 },
3116 };
3117 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3118 switch (metadata.state.*) {
3119 .unused => metadata.symbol_index.* = try zig_module.addAtom(self),
3120 .pending_flush => return metadata.symbol_index.*,
3121 .flushed => {},
3122 }
3123 metadata.state.* = .pending_flush;
3124 const symbol_index = metadata.symbol_index.*;
3125 // anyerror needs to be deferred until flushModule
3126 if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(lazy_sym, symbol_index);
3127 return symbol_index;
3128}
3129
3130pub fn getOrCreateMetadataForDecl(self: *Elf, decl_index: Module.Decl.Index) !Symbol.Index {
3131 const gop = try self.decls.getOrPut(self.base.allocator, decl_index);
3132 if (!gop.found_existing) {
3133 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3134 gop.value_ptr.* = .{ .symbol_index = try zig_module.addAtom(self) };
3135 }
3136 return gop.value_ptr.symbol_index;
3137}
3138
3139fn getDeclShdrIndex(self: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 {
3140 const mod = self.base.options.module.?;
3141 const decl = mod.declPtr(decl_index);
3142 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
3143 // TODO: what if this is a function pointer?
3144 .Fn => self.zig_text_section_index.?,
3145 else => blk: {
3146 if (decl.getOwnedVariable(mod)) |variable| {
3147 if (variable.is_const) break :blk self.zig_rodata_section_index.?;
3148 if (variable.init.toValue().isUndefDeep(mod)) {
3149 const mode = self.base.options.optimize_mode;
3150 if (mode == .Debug or mode == .ReleaseSafe) break :blk self.zig_data_section_index.?;
3151 break :blk self.zig_bss_section_index.?;
3152 }
3153 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
3154 // intrusive check for all zeroes than this?
3155 const is_all_zeroes = for (code) |byte| {
3156 if (byte != 0) break false;
3157 } else true;
3158 if (is_all_zeroes) break :blk self.zig_bss_section_index.?;
3159 break :blk self.zig_data_section_index.?;
3160 }
3161 break :blk self.zig_rodata_section_index.?;
3162 },
3163 };
3164 return shdr_index;
3165}
3166
3167fn updateDeclCode(
3168 self: *Elf,
3169 decl_index: Module.Decl.Index,
3170 sym_index: Symbol.Index,
3171 code: []const u8,
3172 stt_bits: u8,
3173) !void {
3174 const gpa = self.base.allocator;
3175 const mod = self.base.options.module.?;
3176 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3177 const decl = mod.declPtr(decl_index);
3178
3179 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3180
3181 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
3182 const required_alignment = decl.getAlignment(mod);
3183
3184 const sym = self.symbol(sym_index);
3185 const esym = &zig_module.local_esyms.items(.elf_sym)[sym.esym_index];
3186 const atom_ptr = sym.atom(self).?;
3187
3188 const shdr_index = self.getDeclShdrIndex(decl_index, code);
3189 sym.output_section_index = shdr_index;
3190 atom_ptr.output_section_index = shdr_index;
3191
3192 sym.name_offset = try self.strtab.insert(gpa, decl_name);
3193 atom_ptr.flags.alive = true;
3194 atom_ptr.name_offset = sym.name_offset;
3195 esym.st_name = sym.name_offset;
3196 esym.st_info |= stt_bits;
3197 esym.st_size = code.len;
3198
3199 const old_size = atom_ptr.size;
3200 const old_vaddr = atom_ptr.value;
3201 atom_ptr.alignment = required_alignment;
3202 atom_ptr.size = code.len;
3203
3204 if (old_size > 0 and self.base.child_pid == null) {
3205 const capacity = atom_ptr.capacity(self);
3206 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
3207 if (need_realloc) {
3208 try atom_ptr.grow(self);
3209 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
3210 if (old_vaddr != atom_ptr.value) {
3211 sym.value = atom_ptr.value;
3212 esym.st_value = atom_ptr.value;
3213
3214 log.debug(" (writing new offset table entry)", .{});
3215 assert(sym.flags.has_zig_got);
3216 const extra = sym.extra(self).?;
3217 try self.zig_got.writeOne(self, extra.zig_got);
3218 }
3219 } else if (code.len < old_size) {
3220 atom_ptr.shrink(self);
3221 }
3222 } else {
3223 try atom_ptr.allocate(self);
3224 errdefer self.freeDeclMetadata(sym_index);
3225
3226 sym.value = atom_ptr.value;
3227 esym.st_value = atom_ptr.value;
3228
3229 const gop = try sym.getOrCreateZigGotEntry(sym_index, self);
3230 try self.zig_got.writeOne(self, gop.index);
3231 }
3232
3233 if (self.base.child_pid) |pid| {
3234 switch (builtin.os.tag) {
3235 .linux => {
3236 var code_vec: [1]std.os.iovec_const = .{.{
3237 .iov_base = code.ptr,
3238 .iov_len = code.len,
3239 }};
3240 var remote_vec: [1]std.os.iovec_const = .{.{
3241 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.value)))),
3242 .iov_len = code.len,
3243 }};
3244 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
3245 switch (std.os.errno(rc)) {
3246 .SUCCESS => assert(rc == code.len),
3247 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
3248 }
3249 },
3250 else => return error.HotSwapUnavailableOnHostOperatingSystem,
3251 }
3252 }
3253
3254 const shdr = self.shdrs.items[shdr_index];
3255 if (shdr.sh_type != elf.SHT_NOBITS) {
3256 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
3257 const section_offset = sym.value - self.phdrs.items[phdr_index].p_vaddr;
3258 const file_offset = shdr.sh_offset + section_offset;
3259 try self.base.file.?.pwriteAll(code, file_offset);
3260 }
2830 return self.zigObjectPtr().?.freeDecl(self, decl_index);
32612831}
32622832
32632833pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
......@@ -3265,54 +2835,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A
32652835 @panic("Attempted to compile for object format that was disabled by build configuration");
32662836 }
32672837 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
3268
3269 const tracy = trace(@src());
3270 defer tracy.end();
3271
3272 const func = mod.funcInfo(func_index);
3273 const decl_index = func.owner_decl;
3274 const decl = mod.declPtr(decl_index);
3275
3276 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);
3277 self.freeUnnamedConsts(decl_index);
3278 self.symbol(sym_index).atom(self).?.freeRelocs(self);
3279
3280 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
3281 defer code_buffer.deinit();
3282
3283 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
3284 defer if (decl_state) |*ds| ds.deinit();
3285
3286 const res = if (decl_state) |*ds|
3287 try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .{
3288 .dwarf = ds,
3289 })
3290 else
3291 try codegen.generateFunction(&self.base, decl.srcLoc(mod), func_index, air, liveness, &code_buffer, .none);
3292
3293 const code = switch (res) {
3294 .ok => code_buffer.items,
3295 .fail => |em| {
3296 decl.analysis = .codegen_failure;
3297 try mod.failed_decls.put(mod.gpa, decl_index, em);
3298 return;
3299 },
3300 };
3301 try self.updateDeclCode(decl_index, sym_index, code, elf.STT_FUNC);
3302 if (decl_state) |*ds| {
3303 const sym = self.symbol(sym_index);
3304 try self.dwarf.?.commitDeclState(
3305 mod,
3306 decl_index,
3307 sym.value,
3308 sym.atom(self).?.size,
3309 ds,
3310 );
3311 }
3312
3313 // Since we updated the vaddr and the size, each corresponding export
3314 // symbol also needs to be updated.
3315 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
2838 return self.zigObjectPtr().?.updateFunc(self, mod, func_index, air, liveness);
33162839}
33172840
33182841pub fn updateDecl(
......@@ -3324,242 +2847,11 @@ pub fn updateDecl(
33242847 @panic("Attempted to compile for object format that was disabled by build configuration");
33252848 }
33262849 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
3327
3328 const tracy = trace(@src());
3329 defer tracy.end();
3330
3331 const decl = mod.declPtr(decl_index);
3332
3333 if (decl.val.getExternFunc(mod)) |_| {
3334 return;
3335 }
3336
3337 if (decl.isExtern(mod)) {
3338 // Extern variable gets a .got entry only.
3339 const variable = decl.getOwnedVariable(mod).?;
3340 const name = mod.intern_pool.stringToSlice(decl.name);
3341 const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
3342 const esym_index = try self.getGlobalSymbol(name, lib_name);
3343 self.symbol(self.zigModulePtr().symbol(esym_index)).flags.needs_got = true;
3344 return;
3345 }
3346
3347 const sym_index = try self.getOrCreateMetadataForDecl(decl_index);
3348 self.symbol(sym_index).atom(self).?.freeRelocs(self);
3349
3350 var code_buffer = std.ArrayList(u8).init(self.base.allocator);
3351 defer code_buffer.deinit();
3352
3353 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
3354 defer if (decl_state) |*ds| ds.deinit();
3355
3356 // TODO implement .debug_info for global variables
3357 const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val;
3358 const res = if (decl_state) |*ds|
3359 try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{
3360 .ty = decl.ty,
3361 .val = decl_val,
3362 }, &code_buffer, .{
3363 .dwarf = ds,
3364 }, .{
3365 .parent_atom_index = sym_index,
3366 })
3367 else
3368 try codegen.generateSymbol(&self.base, decl.srcLoc(mod), .{
3369 .ty = decl.ty,
3370 .val = decl_val,
3371 }, &code_buffer, .none, .{
3372 .parent_atom_index = sym_index,
3373 });
3374
3375 const code = switch (res) {
3376 .ok => code_buffer.items,
3377 .fail => |em| {
3378 decl.analysis = .codegen_failure;
3379 try mod.failed_decls.put(mod.gpa, decl_index, em);
3380 return;
3381 },
3382 };
3383
3384 try self.updateDeclCode(decl_index, sym_index, code, elf.STT_OBJECT);
3385 if (decl_state) |*ds| {
3386 const sym = self.symbol(sym_index);
3387 try self.dwarf.?.commitDeclState(
3388 mod,
3389 decl_index,
3390 sym.value,
3391 sym.atom(self).?.size,
3392 ds,
3393 );
3394 }
3395
3396 // Since we updated the vaddr and the size, each corresponding export
3397 // symbol also needs to be updated.
3398 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
3399}
3400
3401fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.Index) !void {
3402 const gpa = self.base.allocator;
3403 const mod = self.base.options.module.?;
3404 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3405
3406 var required_alignment: InternPool.Alignment = .none;
3407 var code_buffer = std.ArrayList(u8).init(gpa);
3408 defer code_buffer.deinit();
3409
3410 const name_str_index = blk: {
3411 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
3412 @tagName(sym.kind),
3413 sym.ty.fmt(mod),
3414 });
3415 defer gpa.free(name);
3416 break :blk try self.strtab.insert(gpa, name);
3417 };
3418
3419 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
3420 mod.declPtr(owner_decl).srcLoc(mod)
3421 else
3422 Module.SrcLoc{
3423 .file_scope = undefined,
3424 .parent_decl_node = undefined,
3425 .lazy = .unneeded,
3426 };
3427 const res = try codegen.generateLazySymbol(
3428 &self.base,
3429 src,
3430 sym,
3431 &required_alignment,
3432 &code_buffer,
3433 .none,
3434 .{ .parent_atom_index = symbol_index },
3435 );
3436 const code = switch (res) {
3437 .ok => code_buffer.items,
3438 .fail => |em| {
3439 log.err("{s}", .{em.msg});
3440 return error.CodegenFail;
3441 },
3442 };
3443
3444 const output_section_index = switch (sym.kind) {
3445 .code => self.zig_text_section_index.?,
3446 .const_data => self.zig_rodata_section_index.?,
3447 };
3448 const local_sym = self.symbol(symbol_index);
3449 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
3450 local_sym.name_offset = name_str_index;
3451 local_sym.output_section_index = output_section_index;
3452 const local_esym = &zig_module.local_esyms.items(.elf_sym)[local_sym.esym_index];
3453 local_esym.st_name = name_str_index;
3454 local_esym.st_info |= elf.STT_OBJECT;
3455 local_esym.st_size = code.len;
3456 const atom_ptr = local_sym.atom(self).?;
3457 atom_ptr.flags.alive = true;
3458 atom_ptr.name_offset = name_str_index;
3459 atom_ptr.alignment = required_alignment;
3460 atom_ptr.size = code.len;
3461 atom_ptr.output_section_index = output_section_index;
3462
3463 try atom_ptr.allocate(self);
3464 errdefer self.freeDeclMetadata(symbol_index);
3465
3466 local_sym.value = atom_ptr.value;
3467 local_esym.st_value = atom_ptr.value;
3468
3469 const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, self);
3470 try self.zig_got.writeOne(self, gop.index);
3471
3472 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
3473 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
3474 try self.base.file.?.pwriteAll(code, file_offset);
2850 return self.zigObjectPtr().?.updateDecl(self, mod, decl_index);
34752851}
34762852
34772853pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
3478 const gpa = self.base.allocator;
3479 const mod = self.base.options.module.?;
3480 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
3481 if (!gop.found_existing) {
3482 gop.value_ptr.* = .{};
3483 }
3484 const unnamed_consts = gop.value_ptr;
3485 const decl = mod.declPtr(decl_index);
3486 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3487 const index = unnamed_consts.items.len;
3488 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
3489 defer gpa.free(name);
3490 const sym_index = switch (try self.lowerConst(name, typed_value, typed_value.ty.abiAlignment(mod), self.zig_rodata_section_index.?, decl.srcLoc(mod))) {
3491 .ok => |sym_index| sym_index,
3492 .fail => |em| {
3493 decl.analysis = .codegen_failure;
3494 try mod.failed_decls.put(mod.gpa, decl_index, em);
3495 log.err("{s}", .{em.msg});
3496 return error.CodegenFail;
3497 },
3498 };
3499 const sym = self.symbol(sym_index);
3500 try unnamed_consts.append(gpa, sym.atom_index);
3501 return sym_index;
3502}
3503
3504const LowerConstResult = union(enum) {
3505 ok: Symbol.Index,
3506 fail: *Module.ErrorMsg,
3507};
3508
3509fn lowerConst(
3510 self: *Elf,
3511 name: []const u8,
3512 tv: TypedValue,
3513 required_alignment: InternPool.Alignment,
3514 output_section_index: u16,
3515 src_loc: Module.SrcLoc,
3516) !LowerConstResult {
3517 const gpa = self.base.allocator;
3518
3519 var code_buffer = std.ArrayList(u8).init(gpa);
3520 defer code_buffer.deinit();
3521
3522 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3523 const sym_index = try zig_module.addAtom(self);
3524
3525 const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{
3526 .none = {},
3527 }, .{
3528 .parent_atom_index = sym_index,
3529 });
3530 const code = switch (res) {
3531 .ok => code_buffer.items,
3532 .fail => |em| return .{ .fail = em },
3533 };
3534
3535 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
3536 const local_sym = self.symbol(sym_index);
3537 const name_str_index = try self.strtab.insert(gpa, name);
3538 local_sym.name_offset = name_str_index;
3539 local_sym.output_section_index = output_section_index;
3540 const local_esym = &zig_module.local_esyms.items(.elf_sym)[local_sym.esym_index];
3541 local_esym.st_name = name_str_index;
3542 local_esym.st_info |= elf.STT_OBJECT;
3543 local_esym.st_size = code.len;
3544 const atom_ptr = local_sym.atom(self).?;
3545 atom_ptr.flags.alive = true;
3546 atom_ptr.name_offset = name_str_index;
3547 atom_ptr.alignment = required_alignment;
3548 atom_ptr.size = code.len;
3549 atom_ptr.output_section_index = output_section_index;
3550
3551 try atom_ptr.allocate(self);
3552 // TODO rename and re-audit this method
3553 errdefer self.freeDeclMetadata(sym_index);
3554
3555 local_sym.value = atom_ptr.value;
3556 local_esym.st_value = atom_ptr.value;
3557
3558 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
3559 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
3560 try self.base.file.?.pwriteAll(code, file_offset);
3561
3562 return .{ .ok = sym_index };
2854 return self.zigObjectPtr().?.lowerUnnamedConst(self, typed_value, decl_index);
35632855}
35642856
35652857pub fn updateExports(
......@@ -3572,107 +2864,13 @@ pub fn updateExports(
35722864 @panic("Attempted to compile for object format that was disabled by build configuration");
35732865 }
35742866 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3575
35762867 if (self.base.options.emit == null) return;
3577
3578 const tracy = trace(@src());
3579 defer tracy.end();
3580
3581 const gpa = self.base.allocator;
3582 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3583 const metadata = switch (exported) {
3584 .decl_index => |decl_index| blk: {
3585 _ = try self.getOrCreateMetadataForDecl(decl_index);
3586 break :blk self.decls.getPtr(decl_index).?;
3587 },
3588 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
3589 const first_exp = exports[0];
3590 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
3591 switch (res) {
3592 .ok => {},
3593 .fail => |em| {
3594 // TODO maybe it's enough to return an error here and let Module.processExportsInner
3595 // handle the error?
3596 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3597 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
3598 return;
3599 },
3600 }
3601 break :blk self.anon_decls.getPtr(value).?;
3602 },
3603 };
3604 const sym_index = metadata.symbol_index;
3605 const esym_index = self.symbol(sym_index).esym_index;
3606 const esym = zig_module.local_esyms.items(.elf_sym)[esym_index];
3607 const esym_shndx = zig_module.local_esyms.items(.shndx)[esym_index];
3608
3609 for (exports) |exp| {
3610 if (exp.opts.section.unwrap()) |section_name| {
3611 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
3612 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3613 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3614 gpa,
3615 exp.getSrcLoc(mod),
3616 "Unimplemented: ExportOptions.section",
3617 .{},
3618 ));
3619 continue;
3620 }
3621 }
3622 const stb_bits: u8 = switch (exp.opts.linkage) {
3623 .Internal => elf.STB_LOCAL,
3624 .Strong => elf.STB_GLOBAL,
3625 .Weak => elf.STB_WEAK,
3626 .LinkOnce => {
3627 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
3628 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
3629 gpa,
3630 exp.getSrcLoc(mod),
3631 "Unimplemented: GlobalLinkage.LinkOnce",
3632 .{},
3633 ));
3634 continue;
3635 },
3636 };
3637 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
3638 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
3639 const name_off = try self.strtab.insert(gpa, exp_name);
3640 const global_esym_index = if (metadata.@"export"(self, exp_name)) |exp_index| exp_index.* else blk: {
3641 const global_esym_index = try zig_module.addGlobalEsym(gpa);
3642 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, name_off);
3643 const global_esym = zig_module.elfSym(global_esym_index);
3644 global_esym.st_name = name_off;
3645 lookup_gop.value_ptr.* = global_esym_index;
3646 try metadata.exports.append(gpa, global_esym_index);
3647 const gop = try self.getOrPutGlobal(name_off);
3648 try zig_module.global_symbols.append(gpa, gop.index);
3649 break :blk global_esym_index;
3650 };
3651
3652 const actual_esym_index = global_esym_index & ZigModule.symbol_mask;
3653 const global_esym = &zig_module.global_esyms.items(.elf_sym)[actual_esym_index];
3654 global_esym.st_value = self.symbol(sym_index).value;
3655 global_esym.st_shndx = esym.st_shndx;
3656 global_esym.st_info = (stb_bits << 4) | stt_bits;
3657 global_esym.st_name = name_off;
3658 zig_module.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
3659 }
2868 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
36602869}
36612870
3662/// Must be called only after a successful call to `updateDecl`.
36632871pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void {
3664 const tracy = trace(@src());
3665 defer tracy.end();
3666
3667 const decl = mod.declPtr(decl_index);
3668 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3669
3670 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
3671
36722872 if (self.llvm_object) |_| return;
3673 if (self.dwarf) |*dw| {
3674 try dw.updateDeclLineNumber(mod, decl_index);
3675 }
2873 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
36762874}
36772875
36782876pub fn deleteDeclExport(
......@@ -3681,22 +2879,7 @@ pub fn deleteDeclExport(
36812879 name: InternPool.NullTerminatedString,
36822880) void {
36832881 if (self.llvm_object) |_| return;
3684 const metadata = self.decls.getPtr(decl_index) orelse return;
3685 const mod = self.base.options.module.?;
3686 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3687 const exp_name = mod.intern_pool.stringToSlice(name);
3688 const esym_index = metadata.@"export"(self, exp_name) orelse return;
3689 log.debug("deleting export '{s}'", .{exp_name});
3690 const esym = &zig_module.global_esyms.items(.elf_sym)[esym_index.*];
3691 _ = zig_module.globals_lookup.remove(esym.st_name);
3692 const sym_index = self.resolver.get(esym.st_name).?;
3693 const sym = self.symbol(sym_index);
3694 if (sym.file_index == zig_module.index) {
3695 _ = self.resolver.swapRemove(esym.st_name);
3696 sym.* = .{};
3697 }
3698 esym.* = null_sym;
3699 zig_module.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
2882 return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
37002883}
37012884
37022885fn addLinkerDefinedSymbols(self: *Elf) !void {
......@@ -3917,8 +3100,8 @@ fn initSections(self: *Elf) !void {
39173100 const needs_rela_dyn = blk: {
39183101 if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or
39193102 self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true;
3920 if (self.zig_module_index) |index| {
3921 if (self.file(index).?.zig_module.num_dynrelocs > 0) break :blk true;
3103 if (self.zigObjectPtr()) |zig_object| {
3104 if (zig_object.num_dynrelocs > 0) break :blk true;
39223105 }
39233106 for (self.objects.items) |index| {
39243107 if (self.file(index).?.object.num_dynrelocs > 0) break :blk true;
......@@ -4512,16 +3695,15 @@ fn sortShdrs(self: *Elf) !void {
45123695 }
45133696 }
45143697
4515 if (self.zig_module_index) |index| {
4516 const zig_module = self.file(index).?.zig_module;
4517 for (zig_module.atoms.items) |atom_index| {
3698 if (self.zigObjectPtr()) |zig_object| {
3699 for (zig_object.atoms.items) |atom_index| {
45183700 const atom_ptr = self.atom(atom_index) orelse continue;
45193701 if (!atom_ptr.flags.alive) continue;
45203702 const out_shndx = atom_ptr.outputShndx() orelse continue;
45213703 atom_ptr.output_section_index = backlinks[out_shndx];
45223704 }
45233705
4524 for (zig_module.locals()) |local_index| {
3706 for (zig_object.locals()) |local_index| {
45253707 const local = self.symbol(local_index);
45263708 const atom_ptr = local.atom(self) orelse continue;
45273709 if (!atom_ptr.flags.alive) continue;
......@@ -4529,35 +3711,17 @@ fn sortShdrs(self: *Elf) !void {
45293711 local.output_section_index = backlinks[out_shndx];
45303712 }
45313713
4532 for (zig_module.globals()) |global_index| {
3714 for (zig_object.globals()) |global_index| {
45333715 const global = self.symbol(global_index);
45343716 const atom_ptr = global.atom(self) orelse continue;
45353717 if (!atom_ptr.flags.alive) continue;
4536 if (global.file(self).?.index() != index) continue;
3718 if (global.file(self).?.index() != zig_object.index) continue;
45373719 const out_shndx = global.outputShndx() orelse continue;
45383720 global.output_section_index = backlinks[out_shndx];
45393721 }
45403722 }
45413723}
45423724
4543fn saveDebugSectionsSizes(self: *Elf) void {
4544 if (self.debug_info_section_index) |shndx| {
4545 self.debug_info_section_zig_size = self.shdrs.items[shndx].sh_size;
4546 }
4547 if (self.debug_abbrev_section_index) |shndx| {
4548 self.debug_abbrev_section_zig_size = self.shdrs.items[shndx].sh_size;
4549 }
4550 if (self.debug_str_section_index) |shndx| {
4551 self.debug_str_section_zig_size = self.shdrs.items[shndx].sh_size;
4552 }
4553 if (self.debug_aranges_section_index) |shndx| {
4554 self.debug_aranges_section_zig_size = self.shdrs.items[shndx].sh_size;
4555 }
4556 if (self.debug_line_section_index) |shndx| {
4557 self.debug_line_section_zig_size = self.shdrs.items[shndx].sh_size;
4558 }
4559}
4560
45613725fn updateSectionSizes(self: *Elf) !void {
45623726 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
45633727 if (atom_list.items.len == 0) continue;
......@@ -4599,8 +3763,8 @@ fn updateSectionSizes(self: *Elf) !void {
45993763
46003764 if (self.rela_dyn_section_index) |shndx| {
46013765 var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela();
4602 if (self.zig_module_index) |index| {
4603 num += self.file(index).?.zig_module.num_dynrelocs;
3766 if (self.zigObjectPtr()) |zig_object| {
3767 num += zig_object.num_dynrelocs;
46043768 }
46053769 for (self.objects.items) |index| {
46063770 num += self.file(index).?.object.num_dynrelocs;
......@@ -4914,12 +4078,18 @@ fn allocateNonAllocSections(self: *Elf) !void {
49144078 shdr.sh_offset,
49154079 new_offset,
49164080 });
4081 const zig_object = self.zigObjectPtr().?;
49174082 const existing_size = blk: {
4918 if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
4919 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
4920 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
4921 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
4922 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
4083 if (shndx == self.debug_info_section_index.?)
4084 break :blk zig_object.debug_info_section_zig_size;
4085 if (shndx == self.debug_abbrev_section_index.?)
4086 break :blk zig_object.debug_abbrev_section_zig_size;
4087 if (shndx == self.debug_str_section_index.?)
4088 break :blk zig_object.debug_str_section_zig_size;
4089 if (shndx == self.debug_aranges_section_index.?)
4090 break :blk zig_object.debug_aranges_section_zig_size;
4091 if (shndx == self.debug_line_section_index.?)
4092 break :blk zig_object.debug_line_section_zig_size;
49234093 unreachable;
49244094 };
49254095 const amt = try self.base.file.?.copyRangeAll(
......@@ -5021,11 +4191,17 @@ fn writeAtoms(self: *Elf) !void {
50214191
50224192 // TODO really, really handle debug section separately
50234193 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
5024 if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;
5025 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;
5026 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;
5027 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;
5028 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;
4194 const zig_object = self.zigObjectPtr().?;
4195 if (shndx == self.debug_info_section_index.?)
4196 break :blk zig_object.debug_info_section_zig_size;
4197 if (shndx == self.debug_abbrev_section_index.?)
4198 break :blk zig_object.debug_abbrev_section_zig_size;
4199 if (shndx == self.debug_str_section_index.?)
4200 break :blk zig_object.debug_str_section_zig_size;
4201 if (shndx == self.debug_aranges_section_index.?)
4202 break :blk zig_object.debug_aranges_section_zig_size;
4203 if (shndx == self.debug_line_section_index.?)
4204 break :blk zig_object.debug_line_section_zig_size;
50294205 unreachable;
50304206 } else 0;
50314207 const sh_offset = shdr.sh_offset + base_offset;
......@@ -5079,11 +4255,10 @@ fn writeAtoms(self: *Elf) !void {
50794255fn updateSymtabSize(self: *Elf) !void {
50804256 var sizes = SymtabSize{};
50814257
5082 if (self.zig_module_index) |index| {
5083 const zig_module = self.file(index).?.zig_module;
5084 zig_module.updateSymtabSize(self);
5085 sizes.nlocals += zig_module.output_symtab_size.nlocals;
5086 sizes.nglobals += zig_module.output_symtab_size.nglobals;
4258 if (self.zigObjectPtr()) |zig_object| {
4259 zig_object.updateSymtabSize(self);
4260 sizes.nlocals += zig_object.output_symtab_size.nlocals;
4261 sizes.nglobals += zig_object.output_symtab_size.nglobals;
50874262 }
50884263
50894264 for (self.objects.items) |index| {
......@@ -5299,11 +4474,10 @@ fn writeSymtab(self: *Elf) !void {
52994474 .symtab = symtab,
53004475 };
53014476
5302 if (self.zig_module_index) |index| {
5303 const zig_module = self.file(index).?.zig_module;
5304 zig_module.writeSymtab(self, ctx);
5305 ctx.ilocal += zig_module.output_symtab_size.nlocals;
5306 ctx.iglobal += zig_module.output_symtab_size.nglobals;
4477 if (self.zigObjectPtr()) |zig_object| {
4478 zig_object.writeSymtab(self, ctx);
4479 ctx.ilocal += zig_object.output_symtab_size.nlocals;
4480 ctx.iglobal += zig_object.output_symtab_size.nglobals;
53074481 }
53084482
53094483 for (self.objects.items) |index| {
......@@ -5863,7 +5037,7 @@ pub fn file(self: *Elf, index: File.Index) ?File {
58635037 return switch (tag) {
58645038 .null => null,
58655039 .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined },
5866 .zig_module => .{ .zig_module = &self.files.items(.data)[index].zig_module },
5040 .zig_object => .{ .zig_object = &self.files.items(.data)[index].zig_object },
58675041 .object => .{ .object = &self.files.items(.data)[index].object },
58685042 .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object },
58695043 };
......@@ -5961,26 +5135,12 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
59615135}
59625136
59635137pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
5964 _ = lib_name;
5965 const gpa = self.base.allocator;
5966 const off = try self.strtab.insert(gpa, name);
5967 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
5968 const lookup_gop = try zig_module.globals_lookup.getOrPut(gpa, off);
5969 if (!lookup_gop.found_existing) {
5970 const esym_index = try zig_module.addGlobalEsym(gpa);
5971 const esym = zig_module.elfSym(esym_index);
5972 esym.st_name = off;
5973 lookup_gop.value_ptr.* = esym_index;
5974 const gop = try self.getOrPutGlobal(off);
5975 try zig_module.global_symbols.append(gpa, gop.index);
5976 }
5977 return lookup_gop.value_ptr.*;
5138 return self.zigObjectPtr().?.getGlobalSymbol(self, name, lib_name);
59785139}
59795140
5980pub fn zigModulePtr(self: *Elf) *ZigModule {
5981 assert(self.zig_module_index != null);
5982 const file_ptr = self.file(self.zig_module_index.?).?;
5983 return file_ptr.zig_module;
5141pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
5142 const index = self.zig_object_index orelse return null;
5143 return self.file(index).?.zig_object;
59845144}
59855145
59865146const GetOrCreateComdatGroupOwnerResult = struct {
......@@ -6245,12 +5405,11 @@ fn fmtDumpState(
62455405 _ = unused_fmt_string;
62465406 _ = options;
62475407
6248 if (self.zig_module_index) |index| {
6249 const zig_module = self.file(index).?.zig_module;
6250 try writer.print("zig_module({d}) : {s}\n", .{ index, zig_module.path });
5408 if (self.zigObjectPtr()) |zig_object| {
5409 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });
62515410 try writer.print("{}{}\n", .{
6252 zig_module.fmtAtoms(self),
6253 zig_module.fmtSymtab(self),
5411 zig_object.fmtAtoms(self),
5412 zig_object.fmtSymtab(self),
62545413 });
62555414 }
62565415
......@@ -6343,51 +5502,6 @@ const default_entry_addr = 0x8000000;
63435502
63445503pub const base_tag: link.File.Tag = .elf;
63455504
6346const LastAtomAndFreeList = struct {
6347 /// Index of the last allocated atom in this section.
6348 last_atom_index: Atom.Index = 0,
6349
6350 /// A list of atoms that have surplus capacity. This list can have false
6351 /// positives, as functions grow and shrink over time, only sometimes being added
6352 /// or removed from the freelist.
6353 ///
6354 /// An atom has surplus capacity when its overcapacity value is greater than
6355 /// padToIdeal(minimum_atom_size). That is, when it has so
6356 /// much extra capacity, that we could fit a small new symbol in it, itself with
6357 /// ideal_capacity or more.
6358 ///
6359 /// Ideal capacity is defined by size + (size / ideal_factor)
6360 ///
6361 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
6362 /// overcapacity can be negative. A simple way to have negative overcapacity is to
6363 /// allocate a fresh text block, which will have ideal capacity, and then grow it
6364 /// by 1 byte. It will then have -1 overcapacity.
6365 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
6366};
6367
6368const LazySymbolMetadata = struct {
6369 const State = enum { unused, pending_flush, flushed };
6370 text_symbol_index: Symbol.Index = undefined,
6371 rodata_symbol_index: Symbol.Index = undefined,
6372 text_state: State = .unused,
6373 rodata_state: State = .unused,
6374};
6375
6376const DeclMetadata = struct {
6377 symbol_index: Symbol.Index,
6378 /// A list of all exports aliases of this Decl.
6379 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
6380
6381 fn @"export"(m: DeclMetadata, elf_file: *Elf, name: []const u8) ?*u32 {
6382 const zig_module = elf_file.file(elf_file.zig_module_index.?).?.zig_module;
6383 for (m.exports.items) |*exp| {
6384 const exp_name = elf_file.strtab.getAssumeExists(zig_module.elfSym(exp.*).st_name);
6385 if (mem.eql(u8, name, exp_name)) return exp;
6386 }
6387 return null;
6388 }
6389};
6390
63915505const ComdatGroupOwner = struct {
63925506 file: File.Index = 0,
63935507 const Index = u32;
......@@ -6431,6 +5545,30 @@ pub const SystemLib = struct {
64315545 path: []const u8,
64325546};
64335547
5548const LastAtomAndFreeList = struct {
5549 /// Index of the last allocated atom in this section.
5550 last_atom_index: Atom.Index = 0,
5551
5552 /// A list of atoms that have surplus capacity. This list can have false
5553 /// positives, as functions grow and shrink over time, only sometimes being added
5554 /// or removed from the freelist.
5555 ///
5556 /// An atom has surplus capacity when its overcapacity value is greater than
5557 /// padToIdeal(minimum_atom_size). That is, when it has so
5558 /// much extra capacity, that we could fit a small new symbol in it, itself with
5559 /// ideal_capacity or more.
5560 ///
5561 /// Ideal capacity is defined by size + (size / ideal_factor)
5562 ///
5563 /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
5564 /// overcapacity can be negative. A simple way to have negative overcapacity is to
5565 /// allocate a fresh text block, which will have ideal capacity, and then grow it
5566 /// by 1 byte. It will then have -1 overcapacity.
5567 free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
5568};
5569
5570const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
5571
64345572pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
64355573pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
64365574
......@@ -6479,16 +5617,12 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;
64795617const Module = @import("../Module.zig");
64805618const Object = @import("Elf/Object.zig");
64815619const InternPool = @import("../InternPool.zig");
6482const Package = @import("../Package.zig");
64835620const PltSection = synthetic_sections.PltSection;
64845621const PltGotSection = synthetic_sections.PltGotSection;
64855622const SharedObject = @import("Elf/SharedObject.zig");
64865623const Symbol = @import("Elf/Symbol.zig");
64875624const StringTable = @import("strtab.zig").StringTable;
6488const TableSection = @import("table_section.zig").TableSection;
6489const Type = @import("../type.zig").Type;
64905625const TypedValue = @import("../TypedValue.zig");
6491const Value = @import("../value.zig").Value;
64925626const VerneedSection = synthetic_sections.VerneedSection;
64935627const ZigGotSection = synthetic_sections.ZigGotSection;
6494const ZigModule = @import("Elf/ZigModule.zig");
5628const ZigObject = @import("Elf/ZigObject.zig");
src/link/Elf/Atom.zig+18-17
......@@ -52,7 +52,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
5252pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
5353 return switch (self.file(elf_file).?) {
5454 .object => |x| x.shdrs.items[self.input_section_index],
55 .zig_module => |x| x.inputShdr(self.atom_index, elf_file),
55 .zig_object => |x| x.inputShdr(self.atom_index, elf_file),
5656 else => unreachable,
5757 };
5858}
......@@ -166,15 +166,16 @@ 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 const zig_object = elf_file.zigObjectPtr().?;
170 if (zig_object.dwarf) |_| {
170171 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
171172 // range of the compilation unit. When we expand the text section, this range changes,
172173 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.
173 elf_file.debug_info_header_dirty = true;
174 zig_object.debug_info_header_dirty = true;
174175 // This becomes dirty for the same reason. We could potentially make this more
175176 // fine-grained with the addition of support for more compilation units. It is planned to
176177 // model each package as a different compilation unit.
177 elf_file.debug_aranges_section_dirty = true;
178 zig_object.debug_aranges_section_dirty = true;
178179 }
179180 }
180181 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
......@@ -270,14 +271,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
270271 // TODO create relocs free list
271272 self.freeRelocs(elf_file);
272273 // TODO figure out how to free input section mappind in ZigModule
273 // const zig_module = self.file(elf_file).?.zig_module;
274 // assert(zig_module.atoms.swapRemove(self.atom_index));
274 // const zig_object = elf_file.zigObjectPtr().?
275 // assert(zig_object.atoms.swapRemove(self.atom_index));
275276 self.* = .{};
276277}
277278
278279pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
279280 return switch (self.file(elf_file).?) {
280 .zig_module => |x| x.relocs.items[self.relocs_section_index].items,
281 .zig_object => |x| x.relocs.items[self.relocs_section_index].items,
281282 .object => |x| x.getRelocs(self.relocs_section_index),
282283 else => unreachable,
283284 };
......@@ -298,17 +299,17 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
298299pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {
299300 const gpa = elf_file.base.allocator;
300301 const file_ptr = self.file(elf_file).?;
301 assert(file_ptr == .zig_module);
302 const zig_module = file_ptr.zig_module;
303 const rels = &zig_module.relocs.items[self.relocs_section_index];
302 assert(file_ptr == .zig_object);
303 const zig_object = file_ptr.zig_object;
304 const rels = &zig_object.relocs.items[self.relocs_section_index];
304305 try rels.append(gpa, reloc);
305306}
306307
307308pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
308309 const file_ptr = self.file(elf_file).?;
309 assert(file_ptr == .zig_module);
310 const zig_module = file_ptr.zig_module;
311 zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();
310 assert(file_ptr == .zig_object);
311 const zig_object = file_ptr.zig_object;
312 zig_object.relocs.items[self.relocs_section_index].clearRetainingCapacity();
312313}
313314
314315pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {
......@@ -332,7 +333,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
332333 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
333334
334335 const symbol_index = switch (file_ptr) {
335 .zig_module => |x| x.symbol(rel.r_sym()),
336 .zig_object => |x| x.symbol(rel.r_sym()),
336337 .object => |x| x.symbols.items[rel.r_sym()],
337338 else => unreachable,
338339 };
......@@ -690,7 +691,7 @@ fn reportUndefined(
690691 undefs: anytype,
691692) !void {
692693 const rel_esym = switch (self.file(elf_file).?) {
693 .zig_module => |x| x.elfSym(rel.r_sym()).*,
694 .zig_object => |x| x.elfSym(rel.r_sym()).*,
694695 .object => |x| x.symtab[rel.r_sym()],
695696 else => unreachable,
696697 };
......@@ -724,7 +725,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
724725 if (r_type == elf.R_X86_64_NONE) continue;
725726
726727 const target = switch (file_ptr) {
727 .zig_module => |x| elf_file.symbol(x.symbol(rel.r_sym())),
728 .zig_object => |x| elf_file.symbol(x.symbol(rel.r_sym())),
728729 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
729730 else => unreachable,
730731 };
......@@ -1004,7 +1005,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
10041005 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
10051006
10061007 const target_index = switch (file_ptr) {
1007 .zig_module => |x| x.symbol(rel.r_sym()),
1008 .zig_object => |x| x.symbol(rel.r_sym()),
10081009 .object => |x| x.symbols.items[rel.r_sym()],
10091010 else => unreachable,
10101011 };
src/link/Elf/Symbol.zig+1-2
......@@ -72,7 +72,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
7272pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
7373 const file_ptr = symbol.file(elf_file).?;
7474 switch (file_ptr) {
75 .zig_module => |x| return x.elfSym(symbol.esym_index).*,
75 .zig_object => |x| return x.elfSym(symbol.esym_index).*,
7676 .linker_defined => |x| return x.symtab.items[symbol.esym_index],
7777 inline else => |x| return x.symtab[symbol.esym_index],
7878 }
......@@ -406,4 +406,3 @@ const PltSection = synthetic_sections.PltSection;
406406const SharedObject = @import("SharedObject.zig");
407407const Symbol = @This();
408408const ZigGotSection = synthetic_sections.ZigGotSection;
409const ZigModule = @import("ZigModule.zig");
src/link/Elf/ZigModule.zig deleted-381
......@@ -1,381 +0,0 @@
1//! ZigModule encapsulates the state of the incrementally compiled Zig module.
2//! It stores the associated input local and global symbols, allocated atoms,
3//! and any relocations that may have been emitted.
4//! Think about this as fake in-memory Object file for the Zig module.
5
6/// Path is owned by Module and lives as long as *Module.
7path: []const u8,
8index: File.Index,
9
10local_esyms: std.MultiArrayList(ElfSym) = .{},
11global_esyms: std.MultiArrayList(ElfSym) = .{},
12local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
15
16atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
17relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
18
19num_dynrelocs: u32 = 0,
20
21output_symtab_size: Elf.SymtabSize = .{},
22
23pub const global_symbol_bit: u32 = 0x80000000;
24pub const symbol_mask: u32 = 0x7fffffff;
25pub const SHN_ATOM: u16 = 0x100;
26
27pub fn deinit(self: *ZigModule, allocator: Allocator) void {
28 self.local_esyms.deinit(allocator);
29 self.global_esyms.deinit(allocator);
30 self.local_symbols.deinit(allocator);
31 self.global_symbols.deinit(allocator);
32 self.globals_lookup.deinit(allocator);
33 self.atoms.deinit(allocator);
34 for (self.relocs.items) |*list| {
35 list.deinit(allocator);
36 }
37 self.relocs.deinit(allocator);
38}
39
40pub fn addLocalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
41 try self.local_esyms.ensureUnusedCapacity(allocator, 1);
42 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
43 var esym = ElfSym{ .elf_sym = Elf.null_sym };
44 esym.elf_sym.st_info = elf.STB_LOCAL << 4;
45 self.local_esyms.set(index, esym);
46 return index;
47}
48
49pub fn addGlobalEsym(self: *ZigModule, allocator: Allocator) !Symbol.Index {
50 try self.global_esyms.ensureUnusedCapacity(allocator, 1);
51 const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));
52 var esym = ElfSym{ .elf_sym = Elf.null_sym };
53 esym.elf_sym.st_info = elf.STB_GLOBAL << 4;
54 self.global_esyms.set(index, esym);
55 return index | global_symbol_bit;
56}
57
58pub fn addAtom(self: *ZigModule, elf_file: *Elf) !Symbol.Index {
59 const gpa = elf_file.base.allocator;
60
61 const atom_index = try elf_file.addAtom();
62 const symbol_index = try elf_file.addSymbol();
63 const esym_index = try self.addLocalEsym(gpa);
64
65 const shndx = @as(u32, @intCast(self.atoms.items.len));
66 try self.atoms.append(gpa, atom_index);
67 try self.local_symbols.append(gpa, symbol_index);
68
69 const atom_ptr = elf_file.atom(atom_index).?;
70 atom_ptr.file_index = self.index;
71
72 const symbol_ptr = elf_file.symbol(symbol_index);
73 symbol_ptr.file_index = self.index;
74 symbol_ptr.atom_index = atom_index;
75
76 self.local_esyms.items(.shndx)[esym_index] = shndx;
77 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
78 symbol_ptr.esym_index = esym_index;
79
80 const relocs_index = @as(u32, @intCast(self.relocs.items.len));
81 const relocs = try self.relocs.addOne(gpa);
82 relocs.* = .{};
83 atom_ptr.relocs_section_index = relocs_index;
84
85 return symbol_index;
86}
87
88/// TODO actually create fake input shdrs and return that instead.
89pub fn inputShdr(self: ZigModule, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
90 _ = self;
91 const shdr = shdr: {
92 const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;
93 const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr;
94 var shdr = elf_file.shdrs.items[shndx];
95 shdr.sh_addr = 0;
96 shdr.sh_offset = 0;
97 shdr.sh_size = atom.size;
98 shdr.sh_addralign = atom.alignment.toByteUnits(1);
99 break :shdr shdr;
100 };
101 return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
102}
103
104pub fn resolveSymbols(self: *ZigModule, elf_file: *Elf) void {
105 for (self.globals(), 0..) |index, i| {
106 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
107 const esym = self.global_esyms.items(.elf_sym)[i];
108 const shndx = self.global_esyms.items(.shndx)[i];
109
110 if (esym.st_shndx == elf.SHN_UNDEF) continue;
111
112 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
113 assert(esym.st_shndx == SHN_ATOM);
114 const atom_index = self.atoms.items[shndx];
115 const atom = elf_file.atom(atom_index) orelse continue;
116 if (!atom.flags.alive) continue;
117 }
118
119 const global = elf_file.symbol(index);
120 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
121 const atom_index = switch (esym.st_shndx) {
122 elf.SHN_ABS, elf.SHN_COMMON => 0,
123 SHN_ATOM => self.atoms.items[shndx],
124 else => unreachable,
125 };
126 const output_section_index = if (elf_file.atom(atom_index)) |atom|
127 atom.outputShndx().?
128 else
129 elf.SHN_UNDEF;
130 global.value = esym.st_value;
131 global.atom_index = atom_index;
132 global.esym_index = esym_index;
133 global.file_index = self.index;
134 global.output_section_index = output_section_index;
135 global.version_index = elf_file.default_sym_version;
136 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
137 }
138 }
139}
140
141pub fn claimUnresolved(self: *ZigModule, elf_file: *Elf) void {
142 for (self.globals(), 0..) |index, i| {
143 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
144 const esym = self.global_esyms.items(.elf_sym)[i];
145
146 if (esym.st_shndx != elf.SHN_UNDEF) continue;
147
148 const global = elf_file.symbol(index);
149 if (global.file(elf_file)) |_| {
150 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
151 }
152
153 const is_import = blk: {
154 if (!elf_file.isDynLib()) break :blk false;
155 const vis = @as(elf.STV, @enumFromInt(esym.st_other));
156 if (vis == .HIDDEN) break :blk false;
157 break :blk true;
158 };
159
160 global.value = 0;
161 global.atom_index = 0;
162 global.esym_index = esym_index;
163 global.file_index = self.index;
164 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
165 global.flags.import = is_import;
166 }
167}
168
169pub fn scanRelocs(self: *ZigModule, elf_file: *Elf, undefs: anytype) !void {
170 for (self.atoms.items) |atom_index| {
171 const atom = elf_file.atom(atom_index) orelse continue;
172 if (!atom.flags.alive) continue;
173 const shdr = atom.inputShdr(elf_file);
174 if (shdr.sh_type == elf.SHT_NOBITS) continue;
175 if (atom.scanRelocsRequiresCode(elf_file)) {
176 // TODO ideally we don't have to fetch the code here.
177 // Perhaps it would make sense to save the code until flushModule where we
178 // would free all of generated code?
179 const code = try self.codeAlloc(elf_file, atom_index);
180 defer elf_file.base.allocator.free(code);
181 try atom.scanRelocs(elf_file, code, undefs);
182 } else try atom.scanRelocs(elf_file, null, undefs);
183 }
184}
185
186pub fn resetGlobals(self: *ZigModule, elf_file: *Elf) void {
187 for (self.globals()) |index| {
188 const global = elf_file.symbol(index);
189 const off = global.name_offset;
190 global.* = .{};
191 global.name_offset = off;
192 }
193}
194
195pub fn markLive(self: *ZigModule, elf_file: *Elf) void {
196 for (self.globals(), 0..) |index, i| {
197 const esym = self.global_esyms.items(.elf_sym)[i];
198 if (esym.st_bind() == elf.STB_WEAK) continue;
199
200 const global = elf_file.symbol(index);
201 const file = global.file(elf_file) orelse continue;
202 const should_keep = esym.st_shndx == elf.SHN_UNDEF or
203 (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
204 if (should_keep and !file.isAlive()) {
205 file.setAlive();
206 file.markLive(elf_file);
207 }
208 }
209}
210
211pub fn updateSymtabSize(self: *ZigModule, elf_file: *Elf) void {
212 for (self.locals()) |local_index| {
213 const local = elf_file.symbol(local_index);
214 const esym = local.elfSym(elf_file);
215 switch (esym.st_type()) {
216 elf.STT_SECTION, elf.STT_NOTYPE => {
217 local.flags.output_symtab = false;
218 continue;
219 },
220 else => {},
221 }
222 local.flags.output_symtab = true;
223 self.output_symtab_size.nlocals += 1;
224 }
225
226 for (self.globals()) |global_index| {
227 const global = elf_file.symbol(global_index);
228 if (global.file(elf_file)) |file| if (file.index() != self.index) {
229 global.flags.output_symtab = false;
230 continue;
231 };
232 global.flags.output_symtab = true;
233 if (global.isLocal()) {
234 self.output_symtab_size.nlocals += 1;
235 } else {
236 self.output_symtab_size.nglobals += 1;
237 }
238 }
239}
240
241pub fn writeSymtab(self: *ZigModule, elf_file: *Elf, ctx: anytype) void {
242 var ilocal = ctx.ilocal;
243 for (self.locals()) |local_index| {
244 const local = elf_file.symbol(local_index);
245 if (!local.flags.output_symtab) continue;
246 local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
247 ilocal += 1;
248 }
249
250 var iglobal = ctx.iglobal;
251 for (self.globals()) |global_index| {
252 const global = elf_file.symbol(global_index);
253 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
254 if (!global.flags.output_symtab) continue;
255 if (global.isLocal()) {
256 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
257 ilocal += 1;
258 } else {
259 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
260 iglobal += 1;
261 }
262 }
263}
264
265pub fn symbol(self: *ZigModule, index: Symbol.Index) Symbol.Index {
266 const is_global = index & global_symbol_bit != 0;
267 const actual_index = index & symbol_mask;
268 if (is_global) return self.global_symbols.items[actual_index];
269 return self.local_symbols.items[actual_index];
270}
271
272pub fn elfSym(self: *ZigModule, index: Symbol.Index) *elf.Elf64_Sym {
273 const is_global = index & global_symbol_bit != 0;
274 const actual_index = index & symbol_mask;
275 if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index];
276 return &self.local_esyms.items(.elf_sym)[actual_index];
277}
278
279pub fn locals(self: *ZigModule) []const Symbol.Index {
280 return self.local_symbols.items;
281}
282
283pub fn globals(self: *ZigModule) []const Symbol.Index {
284 return self.global_symbols.items;
285}
286
287pub fn asFile(self: *ZigModule) File {
288 return .{ .zig_module = self };
289}
290
291/// Returns atom's code.
292/// Caller owns the memory.
293pub fn codeAlloc(self: ZigModule, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
294 const gpa = elf_file.base.allocator;
295 const atom = elf_file.atom(atom_index).?;
296 assert(atom.file_index == self.index);
297 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
298 const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr;
299 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
300 const code = try gpa.alloc(u8, size);
301 errdefer gpa.free(code);
302 const amt = try elf_file.base.file.?.preadAll(code, file_offset);
303 if (amt != code.len) {
304 log.err("fetching code for {s} failed", .{atom.name(elf_file)});
305 return error.InputOutput;
306 }
307 return code;
308}
309
310pub fn fmtSymtab(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
311 return .{ .data = .{
312 .self = self,
313 .elf_file = elf_file,
314 } };
315}
316
317const FormatContext = struct {
318 self: *ZigModule,
319 elf_file: *Elf,
320};
321
322fn formatSymtab(
323 ctx: FormatContext,
324 comptime unused_fmt_string: []const u8,
325 options: std.fmt.FormatOptions,
326 writer: anytype,
327) !void {
328 _ = unused_fmt_string;
329 _ = options;
330 try writer.writeAll(" locals\n");
331 for (ctx.self.locals()) |index| {
332 const local = ctx.elf_file.symbol(index);
333 try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});
334 }
335 try writer.writeAll(" globals\n");
336 for (ctx.self.globals()) |index| {
337 const global = ctx.elf_file.symbol(index);
338 try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
339 }
340}
341
342pub fn fmtAtoms(self: *ZigModule, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {
343 return .{ .data = .{
344 .self = self,
345 .elf_file = elf_file,
346 } };
347}
348
349fn formatAtoms(
350 ctx: FormatContext,
351 comptime unused_fmt_string: []const u8,
352 options: std.fmt.FormatOptions,
353 writer: anytype,
354) !void {
355 _ = unused_fmt_string;
356 _ = options;
357 try writer.writeAll(" atoms\n");
358 for (ctx.self.atoms.items) |atom_index| {
359 const atom = ctx.elf_file.atom(atom_index) orelse continue;
360 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
361 }
362}
363
364const ElfSym = struct {
365 elf_sym: elf.Elf64_Sym,
366 shndx: u32 = elf.SHN_UNDEF,
367};
368
369const assert = std.debug.assert;
370const std = @import("std");
371const elf = std.elf;
372const log = std.log.scoped(.link);
373
374const Allocator = std.mem.Allocator;
375const Atom = @import("Atom.zig");
376const Elf = @import("../Elf.zig");
377const File = @import("file.zig").File;
378const Module = @import("../../Module.zig");
379const Object = @import("Object.zig");
380const Symbol = @import("Symbol.zig");
381const ZigModule = @This();
src/link/Elf/ZigObject.zig created+1390
......@@ -0,0 +1,1390 @@
1//! ZigObject encapsulates the state of the incrementally compiled Zig module.
2//! It stores the associated input local and global symbols, allocated atoms,
3//! and any relocations that may have been emitted.
4//! Think about this as fake in-memory Object file for the Zig module.
5
6/// Path is owned by Module and lives as long as *Module.
7path: []const u8,
8index: File.Index,
9
10local_esyms: std.MultiArrayList(ElfSym) = .{},
11global_esyms: std.MultiArrayList(ElfSym) = .{},
12local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
13global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
14globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
15
16atoms: std.ArrayListUnmanaged(Atom.Index) = .{},
17relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
18
19num_dynrelocs: u32 = 0,
20
21output_symtab_size: Elf.SymtabSize = .{},
22
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
55debug_strtab_dirty: bool = false,
56debug_abbrev_section_dirty: bool = false,
57debug_aranges_section_dirty: bool = false,
58debug_info_header_dirty: bool = false,
59debug_line_header_dirty: bool = false,
60
61/// Size contribution of Zig's metadata to each debug section.
62/// Used to track start of metadata from input object files.
63debug_info_section_zig_size: u64 = 0,
64debug_abbrev_section_zig_size: u64 = 0,
65debug_str_section_zig_size: u64 = 0,
66debug_aranges_section_zig_size: u64 = 0,
67debug_line_section_zig_size: u64 = 0,
68
69pub const global_symbol_bit: u32 = 0x80000000;
70pub const symbol_mask: u32 = 0x7fffffff;
71pub const SHN_ATOM: u16 = 0x100;
72
73pub fn init(self: *ZigObject, elf_file: *Elf) !void {
74 const gpa = elf_file.base.allocator;
75
76 try self.atoms.append(gpa, 0); // null input section
77
78 const name_off = try elf_file.strtab.insert(gpa, std.fs.path.stem(self.path));
79 const symbol_index = try elf_file.addSymbol();
80 try self.local_symbols.append(gpa, symbol_index);
81 const symbol_ptr = elf_file.symbol(symbol_index);
82 symbol_ptr.file_index = self.index;
83 symbol_ptr.name_offset = name_off;
84
85 const esym_index = try self.addLocalEsym(gpa);
86 const esym = &self.local_esyms.items(.elf_sym)[esym_index];
87 esym.st_name = name_off;
88 esym.st_info |= elf.STT_FILE;
89 esym.st_shndx = elf.SHN_ABS;
90 symbol_ptr.esym_index = esym_index;
91
92 if (!elf_file.base.options.strip) {
93 self.dwarf = Dwarf.init(gpa, &elf_file.base, .dwarf32);
94 }
95}
96
97pub fn deinit(self: *ZigObject, allocator: Allocator) void {
98 self.local_esyms.deinit(allocator);
99 self.global_esyms.deinit(allocator);
100 self.local_symbols.deinit(allocator);
101 self.global_symbols.deinit(allocator);
102 self.globals_lookup.deinit(allocator);
103 self.atoms.deinit(allocator);
104 for (self.relocs.items) |*list| {
105 list.deinit(allocator);
106 }
107 self.relocs.deinit(allocator);
108
109 {
110 var it = self.decls.iterator();
111 while (it.next()) |entry| {
112 entry.value_ptr.exports.deinit(allocator);
113 }
114 self.decls.deinit(allocator);
115 }
116
117 self.lazy_syms.deinit(allocator);
118
119 {
120 var it = self.unnamed_consts.valueIterator();
121 while (it.next()) |syms| {
122 syms.deinit(allocator);
123 }
124 self.unnamed_consts.deinit(allocator);
125 }
126
127 {
128 var it = self.anon_decls.iterator();
129 while (it.next()) |entry| {
130 entry.value_ptr.exports.deinit(allocator);
131 }
132 self.anon_decls.deinit(allocator);
133 }
134
135 if (self.dwarf) |*dw| {
136 dw.deinit();
137 }
138}
139
140pub fn flushModule(self: *ZigObject, elf_file: *Elf) !void {
141 // Handle any lazy symbols that were emitted by incremental compilation.
142 if (self.lazy_syms.getPtr(.none)) |metadata| {
143 const module = elf_file.base.options.module.?;
144
145 // Most lazy symbols can be updated on first use, but
146 // anyerror needs to wait for everything to be flushed.
147 if (metadata.text_state != .unused) self.updateLazySymbol(
148 elf_file,
149 link.File.LazySymbol.initDecl(.code, null, module),
150 metadata.text_symbol_index,
151 ) catch |err| return switch (err) {
152 error.CodegenFail => error.FlushFailure,
153 else => |e| e,
154 };
155 if (metadata.rodata_state != .unused) self.updateLazySymbol(
156 elf_file,
157 link.File.LazySymbol.initDecl(.const_data, null, module),
158 metadata.rodata_symbol_index,
159 ) catch |err| return switch (err) {
160 error.CodegenFail => error.FlushFailure,
161 else => |e| e,
162 };
163 }
164 for (self.lazy_syms.values()) |*metadata| {
165 if (metadata.text_state != .unused) metadata.text_state = .flushed;
166 if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
167 }
168
169 if (self.dwarf) |*dw| {
170 try dw.flushModule(elf_file.base.options.module.?);
171
172 // TODO I need to re-think how to handle ZigObject's debug sections AND debug sections
173 // extracted from input object files correctly.
174 if (self.debug_abbrev_section_dirty) {
175 try dw.writeDbgAbbrev();
176 self.debug_abbrev_section_dirty = false;
177 }
178
179 if (self.debug_info_header_dirty) {
180 const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];
181 const low_pc = text_phdr.p_vaddr;
182 const high_pc = text_phdr.p_vaddr + text_phdr.p_memsz;
183 try dw.writeDbgInfoHeader(elf_file.base.options.module.?, low_pc, high_pc);
184 self.debug_info_header_dirty = false;
185 }
186
187 if (self.debug_aranges_section_dirty) {
188 const text_phdr = &elf_file.phdrs.items[elf_file.phdr_zig_load_re_index.?];
189 try dw.writeDbgAranges(text_phdr.p_vaddr, text_phdr.p_memsz);
190 self.debug_aranges_section_dirty = false;
191 }
192
193 if (self.debug_line_header_dirty) {
194 try dw.writeDbgLineHeader();
195 self.debug_line_header_dirty = false;
196 }
197
198 if (elf_file.debug_str_section_index) |shndx| {
199 if (self.debug_strtab_dirty or dw.strtab.buffer.items.len != elf_file.shdrs.items[shndx].sh_size) {
200 try elf_file.growNonAllocSection(shndx, dw.strtab.buffer.items.len, 1, false);
201 const shdr = elf_file.shdrs.items[shndx];
202 try elf_file.base.file.?.pwriteAll(dw.strtab.buffer.items, shdr.sh_offset);
203 self.debug_strtab_dirty = false;
204 }
205 }
206
207 self.saveDebugSectionsSizes(elf_file);
208 }
209
210 // The point of flushModule() is to commit changes, so in theory, nothing should
211 // be dirty after this. However, it is possible for some things to remain
212 // dirty because they fail to be written in the event of compile errors,
213 // such as debug_line_header_dirty and debug_info_header_dirty.
214 assert(!self.debug_abbrev_section_dirty);
215 assert(!self.debug_aranges_section_dirty);
216 assert(!self.debug_strtab_dirty);
217}
218
219fn saveDebugSectionsSizes(self: *ZigObject, elf_file: *Elf) void {
220 if (elf_file.debug_info_section_index) |shndx| {
221 self.debug_info_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
222 }
223 if (elf_file.debug_abbrev_section_index) |shndx| {
224 self.debug_abbrev_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
225 }
226 if (elf_file.debug_str_section_index) |shndx| {
227 self.debug_str_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
228 }
229 if (elf_file.debug_aranges_section_index) |shndx| {
230 self.debug_aranges_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
231 }
232 if (elf_file.debug_line_section_index) |shndx| {
233 self.debug_line_section_zig_size = elf_file.shdrs.items[shndx].sh_size;
234 }
235}
236
237pub fn addLocalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
238 try self.local_esyms.ensureUnusedCapacity(allocator, 1);
239 const index = @as(Symbol.Index, @intCast(self.local_esyms.addOneAssumeCapacity()));
240 var esym = ElfSym{ .elf_sym = Elf.null_sym };
241 esym.elf_sym.st_info = elf.STB_LOCAL << 4;
242 self.local_esyms.set(index, esym);
243 return index;
244}
245
246pub fn addGlobalEsym(self: *ZigObject, allocator: Allocator) !Symbol.Index {
247 try self.global_esyms.ensureUnusedCapacity(allocator, 1);
248 const index = @as(Symbol.Index, @intCast(self.global_esyms.addOneAssumeCapacity()));
249 var esym = ElfSym{ .elf_sym = Elf.null_sym };
250 esym.elf_sym.st_info = elf.STB_GLOBAL << 4;
251 self.global_esyms.set(index, esym);
252 return index | global_symbol_bit;
253}
254
255pub fn addAtom(self: *ZigObject, elf_file: *Elf) !Symbol.Index {
256 const gpa = elf_file.base.allocator;
257 const atom_index = try elf_file.addAtom();
258 const symbol_index = try elf_file.addSymbol();
259 const esym_index = try self.addLocalEsym(gpa);
260
261 const shndx = @as(u32, @intCast(self.atoms.items.len));
262 try self.atoms.append(gpa, atom_index);
263 try self.local_symbols.append(gpa, symbol_index);
264
265 const atom_ptr = elf_file.atom(atom_index).?;
266 atom_ptr.file_index = self.index;
267
268 const symbol_ptr = elf_file.symbol(symbol_index);
269 symbol_ptr.file_index = self.index;
270 symbol_ptr.atom_index = atom_index;
271
272 self.local_esyms.items(.shndx)[esym_index] = shndx;
273 self.local_esyms.items(.elf_sym)[esym_index].st_shndx = SHN_ATOM;
274 symbol_ptr.esym_index = esym_index;
275
276 const relocs_index = @as(u32, @intCast(self.relocs.items.len));
277 const relocs = try self.relocs.addOne(gpa);
278 relocs.* = .{};
279 atom_ptr.relocs_section_index = relocs_index;
280
281 return symbol_index;
282}
283
284/// TODO actually create fake input shdrs and return that instead.
285pub fn inputShdr(self: ZigObject, atom_index: Atom.Index, elf_file: *Elf) Object.ElfShdr {
286 _ = self;
287 const shdr = shdr: {
288 const atom = elf_file.atom(atom_index) orelse break :shdr Elf.null_shdr;
289 const shndx = atom.outputShndx() orelse break :shdr Elf.null_shdr;
290 var shdr = elf_file.shdrs.items[shndx];
291 shdr.sh_addr = 0;
292 shdr.sh_offset = 0;
293 shdr.sh_size = atom.size;
294 shdr.sh_addralign = atom.alignment.toByteUnits(1);
295 break :shdr shdr;
296 };
297 return Object.ElfShdr.fromElf64Shdr(shdr) catch unreachable;
298}
299
300pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) void {
301 for (self.globals(), 0..) |index, i| {
302 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
303 const esym = self.global_esyms.items(.elf_sym)[i];
304 const shndx = self.global_esyms.items(.shndx)[i];
305
306 if (esym.st_shndx == elf.SHN_UNDEF) continue;
307
308 if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON) {
309 assert(esym.st_shndx == SHN_ATOM);
310 const atom_index = self.atoms.items[shndx];
311 const atom = elf_file.atom(atom_index) orelse continue;
312 if (!atom.flags.alive) continue;
313 }
314
315 const global = elf_file.symbol(index);
316 if (self.asFile().symbolRank(esym, false) < global.symbolRank(elf_file)) {
317 const atom_index = switch (esym.st_shndx) {
318 elf.SHN_ABS, elf.SHN_COMMON => 0,
319 SHN_ATOM => self.atoms.items[shndx],
320 else => unreachable,
321 };
322 const output_section_index = if (elf_file.atom(atom_index)) |atom|
323 atom.outputShndx().?
324 else
325 elf.SHN_UNDEF;
326 global.value = esym.st_value;
327 global.atom_index = atom_index;
328 global.esym_index = esym_index;
329 global.file_index = self.index;
330 global.output_section_index = output_section_index;
331 global.version_index = elf_file.default_sym_version;
332 if (esym.st_bind() == elf.STB_WEAK) global.flags.weak = true;
333 }
334 }
335}
336
337pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
338 for (self.globals(), 0..) |index, i| {
339 const esym_index = @as(Symbol.Index, @intCast(i)) | global_symbol_bit;
340 const esym = self.global_esyms.items(.elf_sym)[i];
341
342 if (esym.st_shndx != elf.SHN_UNDEF) continue;
343
344 const global = elf_file.symbol(index);
345 if (global.file(elf_file)) |_| {
346 if (global.elfSym(elf_file).st_shndx != elf.SHN_UNDEF) continue;
347 }
348
349 const is_import = blk: {
350 if (!elf_file.isDynLib()) break :blk false;
351 const vis = @as(elf.STV, @enumFromInt(esym.st_other));
352 if (vis == .HIDDEN) break :blk false;
353 break :blk true;
354 };
355
356 global.value = 0;
357 global.atom_index = 0;
358 global.esym_index = esym_index;
359 global.file_index = self.index;
360 global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
361 global.flags.import = is_import;
362 }
363}
364
365pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
366 for (self.atoms.items) |atom_index| {
367 const atom = elf_file.atom(atom_index) orelse continue;
368 if (!atom.flags.alive) continue;
369 const shdr = atom.inputShdr(elf_file);
370 if (shdr.sh_type == elf.SHT_NOBITS) continue;
371 if (atom.scanRelocsRequiresCode(elf_file)) {
372 // TODO ideally we don't have to fetch the code here.
373 // Perhaps it would make sense to save the code until flushModule where we
374 // would free all of generated code?
375 const code = try self.codeAlloc(elf_file, atom_index);
376 defer elf_file.base.allocator.free(code);
377 try atom.scanRelocs(elf_file, code, undefs);
378 } else try atom.scanRelocs(elf_file, null, undefs);
379 }
380}
381
382pub fn resetGlobals(self: *ZigObject, elf_file: *Elf) void {
383 for (self.globals()) |index| {
384 const global = elf_file.symbol(index);
385 const off = global.name_offset;
386 global.* = .{};
387 global.name_offset = off;
388 }
389}
390
391pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
392 for (self.globals(), 0..) |index, i| {
393 const esym = self.global_esyms.items(.elf_sym)[i];
394 if (esym.st_bind() == elf.STB_WEAK) continue;
395
396 const global = elf_file.symbol(index);
397 const file = global.file(elf_file) orelse continue;
398 const should_keep = esym.st_shndx == elf.SHN_UNDEF or
399 (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
400 if (should_keep and !file.isAlive()) {
401 file.setAlive();
402 file.markLive(elf_file);
403 }
404 }
405}
406
407pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) void {
408 for (self.locals()) |local_index| {
409 const local = elf_file.symbol(local_index);
410 const esym = local.elfSym(elf_file);
411 switch (esym.st_type()) {
412 elf.STT_SECTION, elf.STT_NOTYPE => {
413 local.flags.output_symtab = false;
414 continue;
415 },
416 else => {},
417 }
418 local.flags.output_symtab = true;
419 self.output_symtab_size.nlocals += 1;
420 }
421
422 for (self.globals()) |global_index| {
423 const global = elf_file.symbol(global_index);
424 if (global.file(elf_file)) |file| if (file.index() != self.index) {
425 global.flags.output_symtab = false;
426 continue;
427 };
428 global.flags.output_symtab = true;
429 if (global.isLocal()) {
430 self.output_symtab_size.nlocals += 1;
431 } else {
432 self.output_symtab_size.nglobals += 1;
433 }
434 }
435}
436
437pub fn writeSymtab(self: *ZigObject, elf_file: *Elf, ctx: anytype) void {
438 var ilocal = ctx.ilocal;
439 for (self.locals()) |local_index| {
440 const local = elf_file.symbol(local_index);
441 if (!local.flags.output_symtab) continue;
442 local.setOutputSym(elf_file, &ctx.symtab[ilocal]);
443 ilocal += 1;
444 }
445
446 var iglobal = ctx.iglobal;
447 for (self.globals()) |global_index| {
448 const global = elf_file.symbol(global_index);
449 if (global.file(elf_file)) |file| if (file.index() != self.index) continue;
450 if (!global.flags.output_symtab) continue;
451 if (global.isLocal()) {
452 global.setOutputSym(elf_file, &ctx.symtab[ilocal]);
453 ilocal += 1;
454 } else {
455 global.setOutputSym(elf_file, &ctx.symtab[iglobal]);
456 iglobal += 1;
457 }
458 }
459}
460
461pub fn symbol(self: *ZigObject, index: Symbol.Index) Symbol.Index {
462 const is_global = index & global_symbol_bit != 0;
463 const actual_index = index & symbol_mask;
464 if (is_global) return self.global_symbols.items[actual_index];
465 return self.local_symbols.items[actual_index];
466}
467
468pub fn elfSym(self: *ZigObject, index: Symbol.Index) *elf.Elf64_Sym {
469 const is_global = index & global_symbol_bit != 0;
470 const actual_index = index & symbol_mask;
471 if (is_global) return &self.global_esyms.items(.elf_sym)[actual_index];
472 return &self.local_esyms.items(.elf_sym)[actual_index];
473}
474
475pub fn locals(self: *ZigObject) []const Symbol.Index {
476 return self.local_symbols.items;
477}
478
479pub fn globals(self: *ZigObject) []const Symbol.Index {
480 return self.global_symbols.items;
481}
482
483pub fn asFile(self: *ZigObject) File {
484 return .{ .zig_object = self };
485}
486
487/// Returns atom's code.
488/// Caller owns the memory.
489pub fn codeAlloc(self: ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
490 const gpa = elf_file.base.allocator;
491 const atom = elf_file.atom(atom_index).?;
492 assert(atom.file_index == self.index);
493 const shdr = &elf_file.shdrs.items[atom.outputShndx().?];
494 const file_offset = shdr.sh_offset + atom.value - shdr.sh_addr;
495 const size = std.math.cast(usize, atom.size) orelse return error.Overflow;
496 const code = try gpa.alloc(u8, size);
497 errdefer gpa.free(code);
498 const amt = try elf_file.base.file.?.preadAll(code, file_offset);
499 if (amt != code.len) {
500 log.err("fetching code for {s} failed", .{atom.name(elf_file)});
501 return error.InputOutput;
502 }
503 return code;
504}
505
506pub fn getDeclVAddr(
507 self: *ZigObject,
508 elf_file: *Elf,
509 decl_index: Module.Decl.Index,
510 reloc_info: link.File.RelocInfo,
511) !u64 {
512 const this_sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
513 const this_sym = elf_file.symbol(this_sym_index);
514 const vaddr = this_sym.value;
515 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
516 try parent_atom.addReloc(elf_file, .{
517 .r_offset = reloc_info.offset,
518 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64,
519 .r_addend = reloc_info.addend,
520 });
521 return vaddr;
522}
523
524pub fn getAnonDeclVAddr(
525 self: *ZigObject,
526 elf_file: *Elf,
527 decl_val: InternPool.Index,
528 reloc_info: link.File.RelocInfo,
529) !u64 {
530 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;
531 const sym = elf_file.symbol(sym_index);
532 const vaddr = sym.value;
533 const parent_atom = elf_file.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
534 try parent_atom.addReloc(elf_file, .{
535 .r_offset = reloc_info.offset,
536 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64,
537 .r_addend = reloc_info.addend,
538 });
539 return vaddr;
540}
541
542pub fn lowerAnonDecl(
543 self: *ZigObject,
544 elf_file: *Elf,
545 decl_val: InternPool.Index,
546 explicit_alignment: InternPool.Alignment,
547 src_loc: Module.SrcLoc,
548) !codegen.Result {
549 const gpa = elf_file.base.allocator;
550 const mod = elf_file.base.options.module.?;
551 const ty = mod.intern_pool.typeOf(decl_val).toType();
552 const decl_alignment = switch (explicit_alignment) {
553 .none => ty.abiAlignment(mod),
554 else => explicit_alignment,
555 };
556 if (self.anon_decls.get(decl_val)) |metadata| {
557 const existing_alignment = elf_file.symbol(metadata.symbol_index).atom(elf_file).?.alignment;
558 if (decl_alignment.order(existing_alignment).compare(.lte))
559 return .ok;
560 }
561
562 const val = decl_val.toValue();
563 const tv = TypedValue{ .ty = ty, .val = val };
564 var name_buf: [32]u8 = undefined;
565 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
566 @intFromEnum(decl_val),
567 }) catch unreachable;
568 const res = self.lowerConst(
569 elf_file,
570 name,
571 tv,
572 decl_alignment,
573 elf_file.zig_rodata_section_index.?,
574 src_loc,
575 ) catch |err| switch (err) {
576 error.OutOfMemory => return error.OutOfMemory,
577 else => |e| return .{ .fail = try Module.ErrorMsg.create(
578 gpa,
579 src_loc,
580 "unable to lower constant value: {s}",
581 .{@errorName(e)},
582 ) },
583 };
584 const sym_index = switch (res) {
585 .ok => |sym_index| sym_index,
586 .fail => |em| return .{ .fail = em },
587 };
588 try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
589 return .ok;
590}
591
592pub fn getOrCreateMetadataForLazySymbol(
593 self: *ZigObject,
594 elf_file: *Elf,
595 lazy_sym: link.File.LazySymbol,
596) !Symbol.Index {
597 const gpa = elf_file.base.allocator;
598 const mod = elf_file.base.options.module.?;
599 const gop = try self.lazy_syms.getOrPut(gpa, lazy_sym.getDecl(mod));
600 errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
601 if (!gop.found_existing) gop.value_ptr.* = .{};
602 const metadata: struct {
603 symbol_index: *Symbol.Index,
604 state: *LazySymbolMetadata.State,
605 } = switch (lazy_sym.kind) {
606 .code => .{
607 .symbol_index = &gop.value_ptr.text_symbol_index,
608 .state = &gop.value_ptr.text_state,
609 },
610 .const_data => .{
611 .symbol_index = &gop.value_ptr.rodata_symbol_index,
612 .state = &gop.value_ptr.rodata_state,
613 },
614 };
615 switch (metadata.state.*) {
616 .unused => metadata.symbol_index.* = try self.addAtom(elf_file),
617 .pending_flush => return metadata.symbol_index.*,
618 .flushed => {},
619 }
620 metadata.state.* = .pending_flush;
621 const symbol_index = metadata.symbol_index.*;
622 // anyerror needs to be deferred until flushModule
623 if (lazy_sym.getDecl(mod) != .none) try self.updateLazySymbol(elf_file, lazy_sym, symbol_index);
624 return symbol_index;
625}
626
627fn freeUnnamedConsts(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.Index) void {
628 const unnamed_consts = self.unnamed_consts.getPtr(decl_index) orelse return;
629 for (unnamed_consts.items) |sym_index| {
630 self.freeDeclMetadata(elf_file, sym_index);
631 }
632 unnamed_consts.clearAndFree(elf_file.base.allocator);
633}
634
635fn freeDeclMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
636 _ = self;
637 const sym = elf_file.symbol(sym_index);
638 sym.atom(elf_file).?.free(elf_file);
639 log.debug("adding %{d} to local symbols free list", .{sym_index});
640 elf_file.symbols_free_list.append(elf_file.base.allocator, sym_index) catch {};
641 elf_file.symbols.items[sym_index] = .{};
642 // TODO free GOT entry here
643}
644
645pub fn freeDecl(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.Index) void {
646 const mod = elf_file.base.options.module.?;
647 const decl = mod.declPtr(decl_index);
648
649 log.debug("freeDecl {*}", .{decl});
650
651 if (self.decls.fetchRemove(decl_index)) |const_kv| {
652 var kv = const_kv;
653 const sym_index = kv.value.symbol_index;
654 self.freeDeclMetadata(elf_file, sym_index);
655 self.freeUnnamedConsts(elf_file, decl_index);
656 kv.value.exports.deinit(elf_file.base.allocator);
657 }
658
659 if (self.dwarf) |*dw| {
660 dw.freeDecl(decl_index);
661 }
662}
663
664pub fn getOrCreateMetadataForDecl(
665 self: *ZigObject,
666 elf_file: *Elf,
667 decl_index: Module.Decl.Index,
668) !Symbol.Index {
669 const gop = try self.decls.getOrPut(elf_file.base.allocator, decl_index);
670 if (!gop.found_existing) {
671 gop.value_ptr.* = .{ .symbol_index = try self.addAtom(elf_file) };
672 }
673 return gop.value_ptr.symbol_index;
674}
675
676fn getDeclShdrIndex(self: *ZigObject, elf_file: *Elf, decl_index: Module.Decl.Index, code: []const u8) u16 {
677 _ = self;
678 const mod = elf_file.base.options.module.?;
679 const decl = mod.declPtr(decl_index);
680 const shdr_index = switch (decl.ty.zigTypeTag(mod)) {
681 // TODO: what if this is a function pointer?
682 .Fn => elf_file.zig_text_section_index.?,
683 else => blk: {
684 if (decl.getOwnedVariable(mod)) |variable| {
685 if (variable.is_const) break :blk elf_file.zig_rodata_section_index.?;
686 if (variable.init.toValue().isUndefDeep(mod)) {
687 const mode = elf_file.base.options.optimize_mode;
688 if (mode == .Debug or mode == .ReleaseSafe) break :blk elf_file.zig_data_section_index.?;
689 break :blk elf_file.zig_bss_section_index.?;
690 }
691 // TODO I blatantly copied the logic from the Wasm linker, but is there a less
692 // intrusive check for all zeroes than this?
693 const is_all_zeroes = for (code) |byte| {
694 if (byte != 0) break false;
695 } else true;
696 if (is_all_zeroes) break :blk elf_file.zig_bss_section_index.?;
697 break :blk elf_file.zig_data_section_index.?;
698 }
699 break :blk elf_file.zig_rodata_section_index.?;
700 },
701 };
702 return shdr_index;
703}
704
705fn updateDeclCode(
706 self: *ZigObject,
707 elf_file: *Elf,
708 decl_index: Module.Decl.Index,
709 sym_index: Symbol.Index,
710 code: []const u8,
711 stt_bits: u8,
712) !void {
713 const gpa = elf_file.base.allocator;
714 const mod = elf_file.base.options.module.?;
715 const decl = mod.declPtr(decl_index);
716 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
717
718 log.debug("updateDeclCode {s}{*}", .{ decl_name, decl });
719
720 const required_alignment = decl.getAlignment(mod);
721
722 const sym = elf_file.symbol(sym_index);
723 const esym = &self.local_esyms.items(.elf_sym)[sym.esym_index];
724 const atom_ptr = sym.atom(elf_file).?;
725
726 const shdr_index = self.getDeclShdrIndex(elf_file, decl_index, code);
727 sym.output_section_index = shdr_index;
728 atom_ptr.output_section_index = shdr_index;
729
730 sym.name_offset = try elf_file.strtab.insert(gpa, decl_name);
731 atom_ptr.flags.alive = true;
732 atom_ptr.name_offset = sym.name_offset;
733 esym.st_name = sym.name_offset;
734 esym.st_info |= stt_bits;
735 esym.st_size = code.len;
736
737 const old_size = atom_ptr.size;
738 const old_vaddr = atom_ptr.value;
739 atom_ptr.alignment = required_alignment;
740 atom_ptr.size = code.len;
741
742 if (old_size > 0 and elf_file.base.child_pid == null) {
743 const capacity = atom_ptr.capacity(elf_file);
744 const need_realloc = code.len > capacity or !required_alignment.check(sym.value);
745 if (need_realloc) {
746 try atom_ptr.grow(elf_file);
747 log.debug("growing {s} from 0x{x} to 0x{x}", .{ decl_name, old_vaddr, atom_ptr.value });
748 if (old_vaddr != atom_ptr.value) {
749 sym.value = atom_ptr.value;
750 esym.st_value = atom_ptr.value;
751
752 log.debug(" (writing new offset table entry)", .{});
753 assert(sym.flags.has_zig_got);
754 const extra = sym.extra(elf_file).?;
755 try elf_file.zig_got.writeOne(elf_file, extra.zig_got);
756 }
757 } else if (code.len < old_size) {
758 atom_ptr.shrink(elf_file);
759 }
760 } else {
761 try atom_ptr.allocate(elf_file);
762 errdefer self.freeDeclMetadata(elf_file, sym_index);
763
764 sym.value = atom_ptr.value;
765 esym.st_value = atom_ptr.value;
766
767 const gop = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
768 try elf_file.zig_got.writeOne(elf_file, gop.index);
769 }
770
771 if (elf_file.base.child_pid) |pid| {
772 switch (builtin.os.tag) {
773 .linux => {
774 var code_vec: [1]std.os.iovec_const = .{.{
775 .iov_base = code.ptr,
776 .iov_len = code.len,
777 }};
778 var remote_vec: [1]std.os.iovec_const = .{.{
779 .iov_base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.value)))),
780 .iov_len = code.len,
781 }};
782 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
783 switch (std.os.errno(rc)) {
784 .SUCCESS => assert(rc == code.len),
785 else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
786 }
787 },
788 else => return error.HotSwapUnavailableOnHostOperatingSystem,
789 }
790 }
791
792 const shdr = elf_file.shdrs.items[shdr_index];
793 if (shdr.sh_type != elf.SHT_NOBITS) {
794 const phdr_index = elf_file.phdr_to_shdr_table.get(shdr_index).?;
795 const section_offset = sym.value - elf_file.phdrs.items[phdr_index].p_vaddr;
796 const file_offset = shdr.sh_offset + section_offset;
797 try elf_file.base.file.?.pwriteAll(code, file_offset);
798 }
799}
800
801pub fn updateFunc(
802 self: *ZigObject,
803 elf_file: *Elf,
804 mod: *Module,
805 func_index: InternPool.Index,
806 air: Air,
807 liveness: Liveness,
808) !void {
809 const tracy = trace(@src());
810 defer tracy.end();
811
812 const func = mod.funcInfo(func_index);
813 const decl_index = func.owner_decl;
814 const decl = mod.declPtr(decl_index);
815
816 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
817 self.freeUnnamedConsts(elf_file, decl_index);
818 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
819
820 var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator);
821 defer code_buffer.deinit();
822
823 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
824 defer if (decl_state) |*ds| ds.deinit();
825
826 const res = if (decl_state) |*ds|
827 try codegen.generateFunction(
828 &elf_file.base,
829 decl.srcLoc(mod),
830 func_index,
831 air,
832 liveness,
833 &code_buffer,
834 .{ .dwarf = ds },
835 )
836 else
837 try codegen.generateFunction(
838 &elf_file.base,
839 decl.srcLoc(mod),
840 func_index,
841 air,
842 liveness,
843 &code_buffer,
844 .none,
845 );
846
847 const code = switch (res) {
848 .ok => code_buffer.items,
849 .fail => |em| {
850 decl.analysis = .codegen_failure;
851 try mod.failed_decls.put(mod.gpa, decl_index, em);
852 return;
853 },
854 };
855 try self.updateDeclCode(elf_file, decl_index, sym_index, code, elf.STT_FUNC);
856 if (decl_state) |*ds| {
857 const sym = elf_file.symbol(sym_index);
858 try self.dwarf.?.commitDeclState(
859 mod,
860 decl_index,
861 sym.value,
862 sym.atom(elf_file).?.size,
863 ds,
864 );
865 }
866
867 // Since we updated the vaddr and the size, each corresponding export
868 // symbol also needs to be updated.
869 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
870}
871
872pub fn updateDecl(
873 self: *ZigObject,
874 elf_file: *Elf,
875 mod: *Module,
876 decl_index: Module.Decl.Index,
877) link.File.UpdateDeclError!void {
878 const tracy = trace(@src());
879 defer tracy.end();
880
881 const decl = mod.declPtr(decl_index);
882
883 if (decl.val.getExternFunc(mod)) |_| {
884 return;
885 }
886
887 if (decl.isExtern(mod)) {
888 // Extern variable gets a .got entry only.
889 const variable = decl.getOwnedVariable(mod).?;
890 const name = mod.intern_pool.stringToSlice(decl.name);
891 const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name);
892 const esym_index = try self.getGlobalSymbol(elf_file, name, lib_name);
893 elf_file.symbol(self.symbol(esym_index)).flags.needs_got = true;
894 return;
895 }
896
897 const sym_index = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
898 elf_file.symbol(sym_index).atom(elf_file).?.freeRelocs(elf_file);
899
900 var code_buffer = std.ArrayList(u8).init(elf_file.base.allocator);
901 defer code_buffer.deinit();
902
903 var decl_state: ?Dwarf.DeclState = if (self.dwarf) |*dw| try dw.initDeclState(mod, decl_index) else null;
904 defer if (decl_state) |*ds| ds.deinit();
905
906 // TODO implement .debug_info for global variables
907 const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val;
908 const res = if (decl_state) |*ds|
909 try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{
910 .ty = decl.ty,
911 .val = decl_val,
912 }, &code_buffer, .{
913 .dwarf = ds,
914 }, .{
915 .parent_atom_index = sym_index,
916 })
917 else
918 try codegen.generateSymbol(&elf_file.base, decl.srcLoc(mod), .{
919 .ty = decl.ty,
920 .val = decl_val,
921 }, &code_buffer, .none, .{
922 .parent_atom_index = sym_index,
923 });
924
925 const code = switch (res) {
926 .ok => code_buffer.items,
927 .fail => |em| {
928 decl.analysis = .codegen_failure;
929 try mod.failed_decls.put(mod.gpa, decl_index, em);
930 return;
931 },
932 };
933
934 try self.updateDeclCode(elf_file, decl_index, sym_index, code, elf.STT_OBJECT);
935 if (decl_state) |*ds| {
936 const sym = elf_file.symbol(sym_index);
937 try self.dwarf.?.commitDeclState(
938 mod,
939 decl_index,
940 sym.value,
941 sym.atom(elf_file).?.size,
942 ds,
943 );
944 }
945
946 // Since we updated the vaddr and the size, each corresponding export
947 // symbol also needs to be updated.
948 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
949}
950
951fn updateLazySymbol(
952 self: *ZigObject,
953 elf_file: *Elf,
954 sym: link.File.LazySymbol,
955 symbol_index: Symbol.Index,
956) !void {
957 const gpa = elf_file.base.allocator;
958 const mod = elf_file.base.options.module.?;
959
960 var required_alignment: InternPool.Alignment = .none;
961 var code_buffer = std.ArrayList(u8).init(gpa);
962 defer code_buffer.deinit();
963
964 const name_str_index = blk: {
965 const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
966 @tagName(sym.kind),
967 sym.ty.fmt(mod),
968 });
969 defer gpa.free(name);
970 break :blk try elf_file.strtab.insert(gpa, name);
971 };
972
973 const src = if (sym.ty.getOwnerDeclOrNull(mod)) |owner_decl|
974 mod.declPtr(owner_decl).srcLoc(mod)
975 else
976 Module.SrcLoc{
977 .file_scope = undefined,
978 .parent_decl_node = undefined,
979 .lazy = .unneeded,
980 };
981 const res = try codegen.generateLazySymbol(
982 &elf_file.base,
983 src,
984 sym,
985 &required_alignment,
986 &code_buffer,
987 .none,
988 .{ .parent_atom_index = symbol_index },
989 );
990 const code = switch (res) {
991 .ok => code_buffer.items,
992 .fail => |em| {
993 log.err("{s}", .{em.msg});
994 return error.CodegenFail;
995 },
996 };
997
998 const output_section_index = switch (sym.kind) {
999 .code => elf_file.zig_text_section_index.?,
1000 .const_data => elf_file.zig_rodata_section_index.?,
1001 };
1002 const local_sym = elf_file.symbol(symbol_index);
1003 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
1004 local_sym.name_offset = name_str_index;
1005 local_sym.output_section_index = output_section_index;
1006 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
1007 local_esym.st_name = name_str_index;
1008 local_esym.st_info |= elf.STT_OBJECT;
1009 local_esym.st_size = code.len;
1010 const atom_ptr = local_sym.atom(elf_file).?;
1011 atom_ptr.flags.alive = true;
1012 atom_ptr.name_offset = name_str_index;
1013 atom_ptr.alignment = required_alignment;
1014 atom_ptr.size = code.len;
1015 atom_ptr.output_section_index = output_section_index;
1016
1017 try atom_ptr.allocate(elf_file);
1018 errdefer self.freeDeclMetadata(elf_file, symbol_index);
1019
1020 local_sym.value = atom_ptr.value;
1021 local_esym.st_value = atom_ptr.value;
1022
1023 const gop = try local_sym.getOrCreateZigGotEntry(symbol_index, elf_file);
1024 try elf_file.zig_got.writeOne(elf_file, gop.index);
1025
1026 const section_offset = atom_ptr.value - elf_file.phdrs.items[phdr_index].p_vaddr;
1027 const file_offset = elf_file.shdrs.items[output_section_index].sh_offset + section_offset;
1028 try elf_file.base.file.?.pwriteAll(code, file_offset);
1029}
1030
1031pub fn lowerUnnamedConst(
1032 self: *ZigObject,
1033 elf_file: *Elf,
1034 typed_value: TypedValue,
1035 decl_index: Module.Decl.Index,
1036) !u32 {
1037 const gpa = elf_file.base.allocator;
1038 const mod = elf_file.base.options.module.?;
1039 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
1040 if (!gop.found_existing) {
1041 gop.value_ptr.* = .{};
1042 }
1043 const unnamed_consts = gop.value_ptr;
1044 const decl = mod.declPtr(decl_index);
1045 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1046 const index = unnamed_consts.items.len;
1047 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
1048 defer gpa.free(name);
1049 const sym_index = switch (try self.lowerConst(
1050 elf_file,
1051 name,
1052 typed_value,
1053 typed_value.ty.abiAlignment(mod),
1054 elf_file.zig_rodata_section_index.?,
1055 decl.srcLoc(mod),
1056 )) {
1057 .ok => |sym_index| sym_index,
1058 .fail => |em| {
1059 decl.analysis = .codegen_failure;
1060 try mod.failed_decls.put(mod.gpa, decl_index, em);
1061 log.err("{s}", .{em.msg});
1062 return error.CodegenFail;
1063 },
1064 };
1065 const sym = elf_file.symbol(sym_index);
1066 try unnamed_consts.append(gpa, sym.atom_index);
1067 return sym_index;
1068}
1069
1070const LowerConstResult = union(enum) {
1071 ok: Symbol.Index,
1072 fail: *Module.ErrorMsg,
1073};
1074
1075fn lowerConst(
1076 self: *ZigObject,
1077 elf_file: *Elf,
1078 name: []const u8,
1079 tv: TypedValue,
1080 required_alignment: InternPool.Alignment,
1081 output_section_index: u16,
1082 src_loc: Module.SrcLoc,
1083) !LowerConstResult {
1084 const gpa = elf_file.base.allocator;
1085
1086 var code_buffer = std.ArrayList(u8).init(gpa);
1087 defer code_buffer.deinit();
1088
1089 const sym_index = try self.addAtom(elf_file);
1090
1091 const res = try codegen.generateSymbol(&elf_file.base, src_loc, tv, &code_buffer, .{
1092 .none = {},
1093 }, .{
1094 .parent_atom_index = sym_index,
1095 });
1096 const code = switch (res) {
1097 .ok => code_buffer.items,
1098 .fail => |em| return .{ .fail = em },
1099 };
1100
1101 const phdr_index = elf_file.phdr_to_shdr_table.get(output_section_index).?;
1102 const local_sym = elf_file.symbol(sym_index);
1103 const name_str_index = try elf_file.strtab.insert(gpa, name);
1104 local_sym.name_offset = name_str_index;
1105 local_sym.output_section_index = output_section_index;
1106 const local_esym = &self.local_esyms.items(.elf_sym)[local_sym.esym_index];
1107 local_esym.st_name = name_str_index;
1108 local_esym.st_info |= elf.STT_OBJECT;
1109 local_esym.st_size = code.len;
1110 const atom_ptr = local_sym.atom(elf_file).?;
1111 atom_ptr.flags.alive = true;
1112 atom_ptr.name_offset = name_str_index;
1113 atom_ptr.alignment = required_alignment;
1114 atom_ptr.size = code.len;
1115 atom_ptr.output_section_index = output_section_index;
1116
1117 try atom_ptr.allocate(elf_file);
1118 // TODO rename and re-audit this method
1119 errdefer self.freeDeclMetadata(elf_file, sym_index);
1120
1121 local_sym.value = atom_ptr.value;
1122 local_esym.st_value = atom_ptr.value;
1123
1124 const section_offset = atom_ptr.value - elf_file.phdrs.items[phdr_index].p_vaddr;
1125 const file_offset = elf_file.shdrs.items[output_section_index].sh_offset + section_offset;
1126 try elf_file.base.file.?.pwriteAll(code, file_offset);
1127
1128 return .{ .ok = sym_index };
1129}
1130
1131pub fn updateExports(
1132 self: *ZigObject,
1133 elf_file: *Elf,
1134 mod: *Module,
1135 exported: Module.Exported,
1136 exports: []const *Module.Export,
1137) link.File.UpdateExportsError!void {
1138 const tracy = trace(@src());
1139 defer tracy.end();
1140
1141 const gpa = elf_file.base.allocator;
1142 const metadata = switch (exported) {
1143 .decl_index => |decl_index| blk: {
1144 _ = try self.getOrCreateMetadataForDecl(elf_file, decl_index);
1145 break :blk self.decls.getPtr(decl_index).?;
1146 },
1147 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1148 const first_exp = exports[0];
1149 const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod));
1150 switch (res) {
1151 .ok => {},
1152 .fail => |em| {
1153 // TODO maybe it's enough to return an error here and let Module.processExportsInner
1154 // handle the error?
1155 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1156 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1157 return;
1158 },
1159 }
1160 break :blk self.anon_decls.getPtr(value).?;
1161 },
1162 };
1163 const sym_index = metadata.symbol_index;
1164 const esym_index = elf_file.symbol(sym_index).esym_index;
1165 const esym = self.local_esyms.items(.elf_sym)[esym_index];
1166 const esym_shndx = self.local_esyms.items(.shndx)[esym_index];
1167
1168 for (exports) |exp| {
1169 if (exp.opts.section.unwrap()) |section_name| {
1170 if (!mod.intern_pool.stringEqlSlice(section_name, ".text")) {
1171 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1172 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1173 gpa,
1174 exp.getSrcLoc(mod),
1175 "Unimplemented: ExportOptions.section",
1176 .{},
1177 ));
1178 continue;
1179 }
1180 }
1181 const stb_bits: u8 = switch (exp.opts.linkage) {
1182 .Internal => elf.STB_LOCAL,
1183 .Strong => elf.STB_GLOBAL,
1184 .Weak => elf.STB_WEAK,
1185 .LinkOnce => {
1186 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1187 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1188 gpa,
1189 exp.getSrcLoc(mod),
1190 "Unimplemented: GlobalLinkage.LinkOnce",
1191 .{},
1192 ));
1193 continue;
1194 },
1195 };
1196 const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
1197 const exp_name = mod.intern_pool.stringToSlice(exp.opts.name);
1198 const name_off = try elf_file.strtab.insert(gpa, exp_name);
1199 const global_esym_index = if (metadata.@"export"(self, elf_file, exp_name)) |exp_index|
1200 exp_index.*
1201 else blk: {
1202 const global_esym_index = try self.addGlobalEsym(gpa);
1203 const lookup_gop = try self.globals_lookup.getOrPut(gpa, name_off);
1204 const global_esym = self.elfSym(global_esym_index);
1205 global_esym.st_name = name_off;
1206 lookup_gop.value_ptr.* = global_esym_index;
1207 try metadata.exports.append(gpa, global_esym_index);
1208 const gop = try elf_file.getOrPutGlobal(name_off);
1209 try self.global_symbols.append(gpa, gop.index);
1210 break :blk global_esym_index;
1211 };
1212
1213 const actual_esym_index = global_esym_index & symbol_mask;
1214 const global_esym = &self.global_esyms.items(.elf_sym)[actual_esym_index];
1215 global_esym.st_value = elf_file.symbol(sym_index).value;
1216 global_esym.st_shndx = esym.st_shndx;
1217 global_esym.st_info = (stb_bits << 4) | stt_bits;
1218 global_esym.st_name = name_off;
1219 self.global_esyms.items(.shndx)[actual_esym_index] = esym_shndx;
1220 }
1221}
1222
1223/// Must be called only after a successful call to `updateDecl`.
1224pub fn updateDeclLineNumber(
1225 self: *ZigObject,
1226 mod: *Module,
1227 decl_index: Module.Decl.Index,
1228) !void {
1229 const tracy = trace(@src());
1230 defer tracy.end();
1231
1232 const decl = mod.declPtr(decl_index);
1233 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1234
1235 log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl });
1236
1237 if (self.dwarf) |*dw| {
1238 try dw.updateDeclLineNumber(mod, decl_index);
1239 }
1240}
1241
1242pub fn deleteDeclExport(
1243 self: *ZigObject,
1244 elf_file: *Elf,
1245 decl_index: Module.Decl.Index,
1246 name: InternPool.NullTerminatedString,
1247) void {
1248 const metadata = self.decls.getPtr(decl_index) orelse return;
1249 const mod = elf_file.base.options.module.?;
1250 const exp_name = mod.intern_pool.stringToSlice(name);
1251 const esym_index = metadata.@"export"(self, elf_file, exp_name) orelse return;
1252 log.debug("deleting export '{s}'", .{exp_name});
1253 const esym = &self.global_esyms.items(.elf_sym)[esym_index.*];
1254 _ = self.globals_lookup.remove(esym.st_name);
1255 const sym_index = elf_file.resolver.get(esym.st_name).?;
1256 const sym = elf_file.symbol(sym_index);
1257 if (sym.file_index == self.index) {
1258 _ = elf_file.resolver.swapRemove(esym.st_name);
1259 sym.* = .{};
1260 }
1261 esym.* = Elf.null_sym;
1262 self.global_esyms.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
1263}
1264
1265pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
1266 _ = lib_name;
1267 const gpa = elf_file.base.allocator;
1268 const off = try elf_file.strtab.insert(gpa, name);
1269 const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
1270 if (!lookup_gop.found_existing) {
1271 const esym_index = try self.addGlobalEsym(gpa);
1272 const esym = self.elfSym(esym_index);
1273 esym.st_name = off;
1274 lookup_gop.value_ptr.* = esym_index;
1275 const gop = try elf_file.getOrPutGlobal(off);
1276 try self.global_symbols.append(gpa, gop.index);
1277 }
1278 return lookup_gop.value_ptr.*;
1279}
1280
1281pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
1282 return .{ .data = .{
1283 .self = self,
1284 .elf_file = elf_file,
1285 } };
1286}
1287
1288const FormatContext = struct {
1289 self: *ZigObject,
1290 elf_file: *Elf,
1291};
1292
1293fn formatSymtab(
1294 ctx: FormatContext,
1295 comptime unused_fmt_string: []const u8,
1296 options: std.fmt.FormatOptions,
1297 writer: anytype,
1298) !void {
1299 _ = unused_fmt_string;
1300 _ = options;
1301 try writer.writeAll(" locals\n");
1302 for (ctx.self.locals()) |index| {
1303 const local = ctx.elf_file.symbol(index);
1304 try writer.print(" {}\n", .{local.fmt(ctx.elf_file)});
1305 }
1306 try writer.writeAll(" globals\n");
1307 for (ctx.self.globals()) |index| {
1308 const global = ctx.elf_file.symbol(index);
1309 try writer.print(" {}\n", .{global.fmt(ctx.elf_file)});
1310 }
1311}
1312
1313pub fn fmtAtoms(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {
1314 return .{ .data = .{
1315 .self = self,
1316 .elf_file = elf_file,
1317 } };
1318}
1319
1320fn formatAtoms(
1321 ctx: FormatContext,
1322 comptime unused_fmt_string: []const u8,
1323 options: std.fmt.FormatOptions,
1324 writer: anytype,
1325) !void {
1326 _ = unused_fmt_string;
1327 _ = options;
1328 try writer.writeAll(" atoms\n");
1329 for (ctx.self.atoms.items) |atom_index| {
1330 const atom = ctx.elf_file.atom(atom_index) orelse continue;
1331 try writer.print(" {}\n", .{atom.fmt(ctx.elf_file)});
1332 }
1333}
1334
1335const ElfSym = struct {
1336 elf_sym: elf.Elf64_Sym,
1337 shndx: u32 = elf.SHN_UNDEF,
1338};
1339
1340const LazySymbolMetadata = struct {
1341 const State = enum { unused, pending_flush, flushed };
1342 text_symbol_index: Symbol.Index = undefined,
1343 rodata_symbol_index: Symbol.Index = undefined,
1344 text_state: State = .unused,
1345 rodata_state: State = .unused,
1346};
1347
1348const DeclMetadata = struct {
1349 symbol_index: Symbol.Index,
1350 /// A list of all exports aliases of this Decl.
1351 exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
1352
1353 fn @"export"(m: DeclMetadata, zig_object: *ZigObject, elf_file: *Elf, name: []const u8) ?*u32 {
1354 for (m.exports.items) |*exp| {
1355 const exp_name = elf_file.strtab.getAssumeExists(zig_object.elfSym(exp.*).st_name);
1356 if (mem.eql(u8, name, exp_name)) return exp;
1357 }
1358 return null;
1359 }
1360};
1361
1362const AtomList = std.ArrayListUnmanaged(Atom.Index);
1363const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
1364const DeclTable = std.AutoHashMapUnmanaged(Module.Decl.Index, DeclMetadata);
1365const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, DeclMetadata);
1366const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
1367
1368const assert = std.debug.assert;
1369const builtin = @import("builtin");
1370const codegen = @import("../../codegen.zig");
1371const elf = std.elf;
1372const link = @import("../../link.zig");
1373const log = std.log.scoped(.link);
1374const mem = std.mem;
1375const trace = @import("../../tracy.zig").trace;
1376const std = @import("std");
1377
1378const Air = @import("../../Air.zig");
1379const Allocator = std.mem.Allocator;
1380const Atom = @import("Atom.zig");
1381const Dwarf = @import("../Dwarf.zig");
1382const Elf = @import("../Elf.zig");
1383const File = @import("file.zig").File;
1384const InternPool = @import("../../InternPool.zig");
1385const Liveness = @import("../../Liveness.zig");
1386const Module = @import("../../Module.zig");
1387const Object = @import("Object.zig");
1388const Symbol = @import("Symbol.zig");
1389const TypedValue = @import("../../TypedValue.zig");
1390const ZigObject = @This();
src/link/Elf/file.zig+7-7
......@@ -1,5 +1,5 @@
11pub const File = union(enum) {
2 zig_module: *ZigModule,
2 zig_object: *ZigObject,
33 linker_defined: *LinkerDefined,
44 object: *Object,
55 shared_object: *SharedObject,
......@@ -23,7 +23,7 @@ pub const File = union(enum) {
2323 _ = unused_fmt_string;
2424 _ = options;
2525 switch (file) {
26 .zig_module => |x| try writer.print("{s}", .{x.path}),
26 .zig_object => |x| try writer.print("{s}", .{x.path}),
2727 .linker_defined => try writer.writeAll("(linker defined)"),
2828 .object => |x| try writer.print("{}", .{x.fmtPath()}),
2929 .shared_object => |x| try writer.writeAll(x.path),
......@@ -32,7 +32,7 @@ pub const File = union(enum) {
3232
3333 pub fn isAlive(file: File) bool {
3434 return switch (file) {
35 .zig_module => true,
35 .zig_object => true,
3636 .linker_defined => true,
3737 inline else => |x| x.alive,
3838 };
......@@ -76,7 +76,7 @@ pub const File = union(enum) {
7676
7777 pub fn setAlive(file: File) void {
7878 switch (file) {
79 .zig_module, .linker_defined => {},
79 .zig_object, .linker_defined => {},
8080 inline else => |x| x.alive = true,
8181 }
8282 }
......@@ -92,7 +92,7 @@ pub const File = union(enum) {
9292 return switch (file) {
9393 .linker_defined => unreachable,
9494 .shared_object => unreachable,
95 .zig_module => |x| x.atoms.items,
95 .zig_object => |x| x.atoms.items,
9696 .object => |x| x.atoms.items,
9797 };
9898 }
......@@ -115,7 +115,7 @@ pub const File = union(enum) {
115115
116116 pub const Entry = union(enum) {
117117 null: void,
118 zig_module: ZigModule,
118 zig_object: ZigObject,
119119 linker_defined: LinkerDefined,
120120 object: Object,
121121 shared_object: SharedObject,
......@@ -132,4 +132,4 @@ const LinkerDefined = @import("LinkerDefined.zig");
132132const Object = @import("Object.zig");
133133const SharedObject = @import("SharedObject.zig");
134134const Symbol = @import("Symbol.zig");
135const ZigModule = @import("ZigModule.zig");
135const ZigObject = @import("ZigObject.zig");