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...@@ -594,7 +594,7 @@ set(ZIG_STAGE2_SOURCES
594 "${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig"594 "${CMAKE_SOURCE_DIR}/src/link/Elf/Object.zig"
595 "${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig"595 "${CMAKE_SOURCE_DIR}/src/link/Elf/SharedObject.zig"
596 "${CMAKE_SOURCE_DIR}/src/link/Elf/Symbol.zig"596 "${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"
598 "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig"598 "${CMAKE_SOURCE_DIR}/src/link/Elf/eh_frame.zig"
599 "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig"599 "${CMAKE_SOURCE_DIR}/src/link/Elf/file.zig"
600 "${CMAKE_SOURCE_DIR}/src/link/Elf/gc.zig"600 "${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...@@ -4316,7 +4316,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4316 if (try self.air.value(callee, mod)) |func_value| {4316 if (try self.air.value(callee, mod)) |func_value| {
4317 if (func_value.getFunction(mod)) |func| {4317 if (func_value.getFunction(mod)) |func| {
4318 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4318 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4319 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);4319 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
4320 const sym = elf_file.symbol(sym_index);4320 const sym = elf_file.symbol(sym_index);
4321 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);4321 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
4322 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));4322 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/arm/CodeGen.zig+1-1
...@@ -4302,7 +4302,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -4302,7 +4302,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
4302 if (try self.air.value(callee, mod)) |func_value| {4302 if (try self.air.value(callee, mod)) |func_value| {
4303 if (func_value.getFunction(mod)) |func| {4303 if (func_value.getFunction(mod)) |func| {
4304 if (self.bin_file.cast(link.File.Elf)) |elf_file| {4304 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
4305 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);4305 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
4306 const sym = elf_file.symbol(sym_index);4306 const sym = elf_file.symbol(sym_index);
4307 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);4307 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
4308 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));4308 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/riscv64/CodeGen.zig+1-1
...@@ -1752,7 +1752,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1752,7 +1752,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1752 if (try self.air.value(callee, mod)) |func_value| {1752 if (try self.air.value(callee, mod)) |func_value| {
1753 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {1753 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
1754 .func => |func| {1754 .func => |func| {
1755 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);1755 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
1756 const sym = elf_file.symbol(sym_index);1756 const sym = elf_file.symbol(sym_index);
1757 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);1757 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
1758 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));1758 const got_addr = @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/sparc64/CodeGen.zig+1-1
...@@ -1347,7 +1347,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier...@@ -1347,7 +1347,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier
1347 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {1347 switch (mod.intern_pool.indexToKey(func_value.ip_index)) {
1348 .func => |func| {1348 .func => |func| {
1349 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {1349 const got_addr = if (self.bin_file.cast(link.File.Elf)) |elf_file| blk: {
1350 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);1350 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
1351 const sym = elf_file.symbol(sym_index);1351 const sym = elf_file.symbol(sym_index);
1352 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);1352 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
1353 break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));1353 break :blk @as(u32, @intCast(sym.zigGotAddress(elf_file)));
src/arch/x86_64/CodeGen.zig+4-4
...@@ -134,7 +134,7 @@ const Owner = union(enum) {...@@ -134,7 +134,7 @@ const Owner = union(enum) {
134 const mod = ctx.bin_file.options.module.?;134 const mod = ctx.bin_file.options.module.?;
135 const decl_index = mod.funcOwnerDeclIndex(func_index);135 const decl_index = mod.funcOwnerDeclIndex(func_index);
136 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {136 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
137 return elf_file.getOrCreateMetadataForDecl(decl_index);137 return elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
138 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {138 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
139 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);139 const atom = try macho_file.getOrCreateAtomForDecl(decl_index);
140 return macho_file.getAtom(atom).getSymbolIndex().?;140 return macho_file.getAtom(atom).getSymbolIndex().?;
...@@ -147,7 +147,7 @@ const Owner = union(enum) {...@@ -147,7 +147,7 @@ const Owner = union(enum) {
147 },147 },
148 .lazy_sym => |lazy_sym| {148 .lazy_sym => |lazy_sym| {
149 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {149 if (ctx.bin_file.cast(link.File.Elf)) |elf_file| {
150 return elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|150 return elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
151 ctx.fail("{s} creating lazy symbol", .{@errorName(err)});151 ctx.fail("{s} creating lazy symbol", .{@errorName(err)});
152 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {152 } else if (ctx.bin_file.cast(link.File.MachO)) |macho_file| {
153 const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|153 const atom = macho_file.getOrCreateAtomForLazySymbol(lazy_sym) catch |err|
...@@ -10233,7 +10233,7 @@ fn genCall(self: *Self, info: union(enum) {...@@ -10233,7 +10233,7 @@ fn genCall(self: *Self, info: union(enum) {
10233 .func => |func| {10233 .func => |func| {
10234 try mod.markDeclAlive(mod.declPtr(func.owner_decl));10234 try mod.markDeclAlive(mod.declPtr(func.owner_decl));
10235 if (self.bin_file.cast(link.File.Elf)) |elf_file| {10235 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
10236 const sym_index = try elf_file.getOrCreateMetadataForDecl(func.owner_decl);10236 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, func.owner_decl);
10237 const sym = elf_file.symbol(sym_index);10237 const sym = elf_file.symbol(sym_index);
10238 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);10238 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
10239 if (self.bin_file.options.pic) {10239 if (self.bin_file.options.pic) {
...@@ -13100,7 +13100,7 @@ fn genLazySymbolRef(...@@ -13100,7 +13100,7 @@ fn genLazySymbolRef(
13100 lazy_sym: link.File.LazySymbol,13100 lazy_sym: link.File.LazySymbol,
13101) InnerError!void {13101) InnerError!void {
13102 if (self.bin_file.cast(link.File.Elf)) |elf_file| {13102 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
13103 const sym_index = elf_file.getOrCreateMetadataForLazySymbol(lazy_sym) catch |err|13103 const sym_index = elf_file.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(elf_file, lazy_sym) catch |err|
13104 return self.fail("{s} creating lazy symbol", .{@errorName(err)});13104 return self.fail("{s} creating lazy symbol", .{@errorName(err)});
13105 const sym = elf_file.symbol(sym_index);13105 const sym = elf_file.symbol(sym_index);
13106 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);13106 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
src/arch/x86_64/Emit.zig+1-1
...@@ -86,7 +86,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -86,7 +86,7 @@ pub fn emitMir(emit: *Emit) Error!void {
86 }),86 }),
87 .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {87 .linker_reloc => |data| if (emit.lower.bin_file.cast(link.File.Elf)) |elf_file| {
88 const atom = elf_file.symbol(data.atom_index).atom(elf_file).?;88 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));
90 if (emit.lower.bin_file.options.pic) {90 if (emit.lower.bin_file.options.pic) {
91 const r_type: u32 = if (sym.flags.has_zig_got)91 const r_type: u32 = if (sym.flags.has_zig_got)
92 link.File.Elf.R_X86_64_ZIG_GOTPCREL92 link.File.Elf.R_X86_64_ZIG_GOTPCREL
src/codegen.zig+2-2
...@@ -904,10 +904,10 @@ fn genDeclRef(...@@ -904,10 +904,10 @@ fn genDeclRef(
904 else904 else
905 null;905 null;
906 const sym_index = try elf_file.getGlobalSymbol(name, lib_name);906 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;
908 return GenResult.mcv(.{ .load_symbol = sym_index });908 return GenResult.mcv(.{ .load_symbol = sym_index });
909 }909 }
910 const sym_index = try elf_file.getOrCreateMetadataForDecl(decl_index);910 const sym_index = try elf_file.zigObjectPtr().?.getOrCreateMetadataForDecl(elf_file, decl_index);
911 const sym = elf_file.symbol(sym_index);911 const sym = elf_file.symbol(sym_index);
912 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);912 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
913 return GenResult.mcv(.{ .load_symbol = sym.esym_index });913 return GenResult.mcv(.{ .load_symbol = sym.esym_index });
src/link/Elf.zig+121-987
...@@ -1,7 +1,5 @@...@@ -1,7 +1,5 @@
1base: link.File,1base: link.File,
22
3dwarf: ?Dwarf = null,
4
5ptr_width: PtrWidth,3ptr_width: PtrWidth,
64
7/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.5/// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
...@@ -11,7 +9,7 @@ llvm_object: ?*LlvmObject = null,...@@ -11,7 +9,7 @@ llvm_object: ?*LlvmObject = null,
11/// Index of each input file also encodes the priority or precedence of one input file9/// Index of each input file also encodes the priority or precedence of one input file
12/// over another.10/// over another.
13files: std.MultiArrayList(File.Entry) = .{},11files: std.MultiArrayList(File.Entry) = .{},
14zig_module_index: ?File.Index = null,12zig_object_index: ?File.Index = null,
15linker_defined_index: ?File.Index = null,13linker_defined_index: ?File.Index = null,
16objects: std.ArrayListUnmanaged(File.Index) = .{},14objects: std.ArrayListUnmanaged(File.Index) = .{},
17shared_objects: std.ArrayListUnmanaged(File.Index) = .{},15shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
...@@ -102,7 +100,7 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},...@@ -102,7 +100,7 @@ rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
102/// .zig.got section100/// .zig.got section
103zig_got: ZigGotSection = .{},101zig_got: ZigGotSection = .{},
104102
105/// Tracked section headers with incremental updates to Zig module103/// Tracked section headers with incremental updates to Zig object
106zig_text_section_index: ?u16 = null,104zig_text_section_index: ?u16 = null,
107zig_rodata_section_index: ?u16 = null,105zig_rodata_section_index: ?u16 = null,
108zig_data_section_index: ?u16 = null,106zig_data_section_index: ?u16 = null,
...@@ -115,14 +113,6 @@ debug_str_section_index: ?u16 = null,...@@ -115,14 +113,6 @@ debug_str_section_index: ?u16 = null,
115debug_aranges_section_index: ?u16 = null,113debug_aranges_section_index: ?u16 = null,
116debug_line_section_index: ?u16 = null,114debug_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
126copy_rel_section_index: ?u16 = null,116copy_rel_section_index: ?u16 = null,
127dynamic_section_index: ?u16 = null,117dynamic_section_index: ?u16 = null,
128dynstrtab_section_index: ?u16 = null,118dynstrtab_section_index: ?u16 = null,
...@@ -172,59 +162,19 @@ symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},...@@ -172,59 +162,19 @@ symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
172has_text_reloc: bool = false,162has_text_reloc: bool = false,
173num_ifunc_dynrelocs: usize = 0,163num_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
181error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},165error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
182misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},166misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
183167
184/// Table of tracked LazySymbols.
185lazy_syms: LazySymbolTable = .{},
186
187/// Table of tracked Decls.
188decls: DeclTable = .{},
189
190/// List of atoms that are owned directly by the linker.168/// List of atoms that are owned directly by the linker.
191atoms: std.ArrayListUnmanaged(Atom) = .{},169atoms: std.ArrayListUnmanaged(Atom) = .{},
170
192/// Table of last atom index in a section and matching atom free list if any.171/// Table of last atom index in a section and matching atom free list if any.
193last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},172last_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
217comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},174comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
218comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},175comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
219comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},176comdat_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
228/// When allocating, the ideal_capacity is calculated by178/// When allocating, the ideal_capacity is calculated by
229/// actual_capacity + (actual_capacity / ideal_factor)179/// actual_capacity + (actual_capacity / ideal_factor)
230const ideal_factor = 3;180const ideal_factor = 3;
...@@ -322,34 +272,13 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option...@@ -322,34 +272,13 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
322 }272 }
323273
324 if (options.module != null and !options.use_llvm) {274 if (options.module != null and !options.use_llvm) {
325 if (!options.strip) {
326 self.dwarf = Dwarf.init(allocator, &self.base, .dwarf32);
327 }
328
329 const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));275 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 = .{
331 .index = index,277 .index = index,
332 .path = options.module.?.main_mod.root_src_path,278 .path = options.module.?.main_mod.root_src_path,
333 } });279 } });
334 self.zig_module_index = index;280 self.zig_object_index = index;
335 const zig_module = self.file(index).?.zig_module;281 try self.zigObjectPtr().?.init(self);
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
353 try self.initMetadata();282 try self.initMetadata();
354 }283 }
355284
...@@ -401,7 +330,7 @@ pub fn deinit(self: *Elf) void {...@@ -401,7 +330,7 @@ pub fn deinit(self: *Elf) void {
401330
402 for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {331 for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
403 .null => {},332 .null => {},
404 .zig_module => data.zig_module.deinit(gpa),333 .zig_object => data.zig_object.deinit(gpa),
405 .linker_defined => data.linker_defined.deinit(gpa),334 .linker_defined => data.linker_defined.deinit(gpa),
406 .object => data.object.deinit(gpa),335 .object => data.object.deinit(gpa),
407 .shared_object => data.shared_object.deinit(gpa),336 .shared_object => data.shared_object.deinit(gpa),
...@@ -425,40 +354,11 @@ pub fn deinit(self: *Elf) void {...@@ -425,40 +354,11 @@ pub fn deinit(self: *Elf) void {
425 self.resolver.deinit(gpa);354 self.resolver.deinit(gpa);
426 self.start_stop_indexes.deinit(gpa);355 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
436 self.atoms.deinit(gpa);357 self.atoms.deinit(gpa);
437 for (self.last_atom_and_free_list_table.values()) |*value| {358 for (self.last_atom_and_free_list_table.values()) |*value| {
438 value.free_list.deinit(gpa);359 value.free_list.deinit(gpa);
439 }360 }
440 self.last_atom_and_free_list_table.deinit(gpa);361 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
463 self.misc_errors.deinit(gpa);363 self.misc_errors.deinit(gpa);
464 self.comdat_groups.deinit(gpa);364 self.comdat_groups.deinit(gpa);
...@@ -481,16 +381,7 @@ pub fn deinit(self: *Elf) void {...@@ -481,16 +381,7 @@ pub fn deinit(self: *Elf) void {
481381
482pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {382pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
483 assert(self.llvm_object == null);383 assert(self.llvm_object == null);
484 const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index);384 return self.zigObjectPtr().?.getDeclVAddr(self, decl_index, reloc_info);
485 const this_sym = self.symbol(this_sym_index);
486 const vaddr = this_sym.value;
487 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
488 try parent_atom.addReloc(self, .{
489 .r_offset = reloc_info.offset,
490 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64,
491 .r_addend = reloc_info.addend,
492 });
493 return vaddr;
494}385}
495386
496pub fn lowerAnonDecl(387pub fn lowerAnonDecl(
...@@ -499,60 +390,12 @@ pub fn lowerAnonDecl(...@@ -499,60 +390,12 @@ pub fn lowerAnonDecl(
499 explicit_alignment: InternPool.Alignment,390 explicit_alignment: InternPool.Alignment,
500 src_loc: Module.SrcLoc,391 src_loc: Module.SrcLoc,
501) !codegen.Result {392) !codegen.Result {
502 const gpa = self.base.allocator;393 return self.zigObjectPtr().?.lowerAnonDecl(self, decl_val, explicit_alignment, src_loc);
503 const mod = self.base.options.module.?;
504 const ty = mod.intern_pool.typeOf(decl_val).toType();
505 const decl_alignment = switch (explicit_alignment) {
506 .none => ty.abiAlignment(mod),
507 else => explicit_alignment,
508 };
509 if (self.anon_decls.get(decl_val)) |metadata| {
510 const existing_alignment = self.symbol(metadata.symbol_index).atom(self).?.alignment;
511 if (decl_alignment.order(existing_alignment).compare(.lte))
512 return .ok;
513 }
514
515 const val = decl_val.toValue();
516 const tv = TypedValue{ .ty = ty, .val = val };
517 var name_buf: [32]u8 = undefined;
518 const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
519 @intFromEnum(decl_val),
520 }) catch unreachable;
521 const res = self.lowerConst(
522 name,
523 tv,
524 decl_alignment,
525 self.zig_rodata_section_index.?,
526 src_loc,
527 ) catch |err| switch (err) {
528 error.OutOfMemory => return error.OutOfMemory,
529 else => |e| return .{ .fail = try Module.ErrorMsg.create(
530 gpa,
531 src_loc,
532 "unable to lower constant value: {s}",
533 .{@errorName(e)},
534 ) },
535 };
536 const sym_index = switch (res) {
537 .ok => |sym_index| sym_index,
538 .fail => |em| return .{ .fail = em },
539 };
540 try self.anon_decls.put(gpa, decl_val, .{ .symbol_index = sym_index });
541 return .ok;
542}394}
543395
544pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {396pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
545 assert(self.llvm_object == null);397 assert(self.llvm_object == null);
546 const sym_index = self.anon_decls.get(decl_val).?.symbol_index;398 return self.zigObjectPtr().?.getAnonDeclVAddr(self, decl_val, reloc_info);
547 const sym = self.symbol(sym_index);
548 const vaddr = sym.value;
549 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
550 try parent_atom.addReloc(self, .{
551 .r_offset = reloc_info.offset,
552 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64,
553 .r_addend = reloc_info.addend,
554 });
555 return vaddr;
556}399}
557400
558/// Returns end pos of collision, if any.401/// Returns end pos of collision, if any.
...@@ -726,7 +569,7 @@ fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{...@@ -726,7 +569,7 @@ fn allocateNonAllocSection(self: *Elf, opts: AllocateNonAllocSectionOpts) error{
726 return index;569 return index;
727}570}
728571
729/// TODO move to ZigModule572/// TODO move to ZigObject
730pub fn initMetadata(self: *Elf) !void {573pub fn initMetadata(self: *Elf) !void {
731 const gpa = self.base.allocator;574 const gpa = self.base.allocator;
732 const ptr_size = self.ptrWidthBytes();575 const ptr_size = self.ptrWidthBytes();
...@@ -839,7 +682,8 @@ pub fn initMetadata(self: *Elf) !void {...@@ -839,7 +682,8 @@ pub fn initMetadata(self: *Elf) !void {
839 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});682 try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
840 }683 }
841684
842 if (self.dwarf) |*dw| {685 const zig_object = self.zigObjectPtr().?;
686 if (zig_object.dwarf) |*dw| {
843 if (self.debug_str_section_index == null) {687 if (self.debug_str_section_index == null) {
844 assert(dw.strtab.buffer.items.len == 0);688 assert(dw.strtab.buffer.items.len == 0);
845 try dw.strtab.buffer.append(gpa, 0);689 try dw.strtab.buffer.append(gpa, 0);
...@@ -849,7 +693,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -849,7 +693,7 @@ pub fn initMetadata(self: *Elf) !void {
849 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,693 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
850 .entsize = 1,694 .entsize = 1,
851 });695 });
852 self.debug_strtab_dirty = true;696 zig_object.debug_strtab_dirty = true;
853 }697 }
854698
855 if (self.debug_info_section_index == null) {699 if (self.debug_info_section_index == null) {
...@@ -858,7 +702,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -858,7 +702,7 @@ pub fn initMetadata(self: *Elf) !void {
858 .size = 200,702 .size = 200,
859 .alignment = 1,703 .alignment = 1,
860 });704 });
861 self.debug_info_header_dirty = true;705 zig_object.debug_info_header_dirty = true;
862 }706 }
863707
864 if (self.debug_abbrev_section_index == null) {708 if (self.debug_abbrev_section_index == null) {
...@@ -867,7 +711,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -867,7 +711,7 @@ pub fn initMetadata(self: *Elf) !void {
867 .size = 128,711 .size = 128,
868 .alignment = 1,712 .alignment = 1,
869 });713 });
870 self.debug_abbrev_section_dirty = true;714 zig_object.debug_abbrev_section_dirty = true;
871 }715 }
872716
873 if (self.debug_aranges_section_index == null) {717 if (self.debug_aranges_section_index == null) {
...@@ -876,7 +720,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -876,7 +720,7 @@ pub fn initMetadata(self: *Elf) !void {
876 .size = 160,720 .size = 160,
877 .alignment = 16,721 .alignment = 16,
878 });722 });
879 self.debug_aranges_section_dirty = true;723 zig_object.debug_aranges_section_dirty = true;
880 }724 }
881725
882 if (self.debug_line_section_index == null) {726 if (self.debug_line_section_index == null) {
...@@ -885,7 +729,7 @@ pub fn initMetadata(self: *Elf) !void {...@@ -885,7 +729,7 @@ pub fn initMetadata(self: *Elf) !void {
885 .size = 250,729 .size = 250,
886 .alignment = 1,730 .alignment = 1,
887 });731 });
888 self.debug_line_header_dirty = true;732 zig_object.debug_line_header_dirty = true;
889 }733 }
890 }734 }
891}735}
...@@ -976,17 +820,18 @@ pub fn growNonAllocSection(...@@ -976,17 +820,18 @@ pub fn growNonAllocSection(
976}820}
977821
978pub fn markDirty(self: *Elf, shdr_index: u16) void {822pub fn markDirty(self: *Elf, shdr_index: u16) void {
979 if (self.dwarf) |_| {823 const zig_object = self.zigObjectPtr().?;
824 if (zig_object.dwarf) |_| {
980 if (self.debug_info_section_index.? == shdr_index) {825 if (self.debug_info_section_index.? == shdr_index) {
981 self.debug_info_header_dirty = true;826 zig_object.debug_info_header_dirty = true;
982 } else if (self.debug_line_section_index.? == shdr_index) {827 } else if (self.debug_line_section_index.? == shdr_index) {
983 self.debug_line_header_dirty = true;828 zig_object.debug_line_header_dirty = true;
984 } else if (self.debug_abbrev_section_index.? == shdr_index) {829 } else if (self.debug_abbrev_section_index.? == shdr_index) {
985 self.debug_abbrev_section_dirty = true;830 zig_object.debug_abbrev_section_dirty = true;
986 } else if (self.debug_str_section_index.? == shdr_index) {831 } else if (self.debug_str_section_index.? == shdr_index) {
987 self.debug_strtab_dirty = true;832 zig_object.debug_strtab_dirty = true;
988 } else if (self.debug_aranges_section_index.? == shdr_index) {833 } else if (self.debug_aranges_section_index.? == shdr_index) {
989 self.debug_aranges_section_dirty = true;834 zig_object.debug_aranges_section_dirty = true;
990 }835 }
991 }836 }
992}837}
...@@ -1041,7 +886,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1041,7 +886,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1041 } else null;886 } else null;
1042 const gc_sections = self.base.options.gc_sections orelse false;887 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) {
1045 // TODO this will become -r route I guess. For now, just copy the object file.890 // TODO this will become -r route I guess. For now, just copy the object file.
1046 assert(self.base.file == null); // TODO uncomment once we implement -r891 assert(self.base.file == null); // TODO uncomment once we implement -r
1047 const the_object_path = blk: {892 const the_object_path = blk: {
...@@ -1486,35 +1331,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1486,35 +1331,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1486 try self.handleAndReportParseError(obj.path, err, &parse_ctx);1331 try self.handleAndReportParseError(obj.path, err, &parse_ctx);
1487 }1332 }
14881333
1489 // Handle any lazy symbols that were emitted by incremental compilation.1334 if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
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 }
15181335
1519 // Dedup shared objects1336 // Dedup shared objects
1520 {1337 {
...@@ -1543,7 +1360,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1543,7 +1360,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1543 }1360 }
15441361
1545 // Now, we are ready to resolve the symbols across all input files.1362 // 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 parsed1363 // We will first resolve the files in the ZigObject, next in the parsed
1547 // input Object files.1364 // input Object files.
1548 // Any qualifing unresolved symbol will be upgraded to an absolute, weak1365 // Any qualifing unresolved symbol will be upgraded to an absolute, weak
1549 // symbol for potential resolution at load-time.1366 // symbol for potential resolution at load-time.
...@@ -1576,45 +1393,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1576,45 +1393,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1576 // Scan and create missing synthetic entries such as GOT indirection.1393 // Scan and create missing synthetic entries such as GOT indirection.
1577 try self.scanRelocs();1394 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
1618 // Generate and emit non-incremental sections.1396 // Generate and emit non-incremental sections.
1619 try self.initSections();1397 try self.initSections();
1620 try self.initSpecialPhdrs();1398 try self.initSpecialPhdrs();
...@@ -1645,15 +1423,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node...@@ -1645,15 +1423,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
16451423
1646 // Beyond this point, everything has been allocated a virtual address and we can resolve1424 // Beyond this point, everything has been allocated a virtual address and we can resolve
1647 // the relocations, and commit objects to file.1425 // the relocations, and commit objects to file.
1648 if (self.zig_module_index) |index| {1426 if (self.zigObjectPtr()) |zig_object| {
1649 const zig_module = self.file(index).?.zig_module;1427 for (zig_object.atoms.items) |atom_index| {
1650 for (zig_module.atoms.items) |atom_index| {
1651 const atom_ptr = self.atom(atom_index) orelse continue;1428 const atom_ptr = self.atom(atom_index) orelse continue;
1652 if (!atom_ptr.flags.alive) continue;1429 if (!atom_ptr.flags.alive) continue;
1653 const out_shndx = atom_ptr.outputShndx() orelse continue;1430 const out_shndx = atom_ptr.outputShndx() orelse continue;
1654 const shdr = &self.shdrs.items[out_shndx];1431 const shdr = &self.shdrs.items[out_shndx];
1655 if (shdr.sh_type == elf.SHT_NOBITS) continue;1432 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);
1657 defer gpa.free(code);1434 defer gpa.free(code);
1658 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;1435 const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
1659 atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {1436 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...@@ -1680,14 +1457,6 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
1680 self.error_flags.no_entry_point_found = false;1457 self.error_flags.no_entry_point_found = false;
1681 try self.writeHeader();1458 try self.writeHeader();
1682 }1459 }
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);
1691}1460}
16921461
1693const ParseError = error{1462const ParseError = error{
...@@ -1926,8 +1695,8 @@ fn accessLibPath(...@@ -1926,8 +1695,8 @@ fn accessLibPath(
1926/// 5. Remove references to dead objects/shared objects1695/// 5. Remove references to dead objects/shared objects
1927/// 6. Re-run symbol resolution on pruned objects and shared objects sets.1696/// 6. Re-run symbol resolution on pruned objects and shared objects sets.
1928fn resolveSymbols(self: *Elf) void {1697fn resolveSymbols(self: *Elf) void {
1929 // Resolve symbols in the ZigModule. For now, we assume that it's always live.1698 // Resolve symbols in the ZigObject. For now, we assume that it's always live.
1930 if (self.zig_module_index) |index| self.file(index).?.resolveSymbols(self);1699 if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);
1931 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).1700 // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
1932 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1701 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
1933 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1702 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
...@@ -1936,7 +1705,7 @@ fn resolveSymbols(self: *Elf) void {...@@ -1936,7 +1705,7 @@ fn resolveSymbols(self: *Elf) void {
1936 self.markLive();1705 self.markLive();
19371706
1938 // Reset state of all globals after marking live objects.1707 // 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);
1940 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);1709 for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
1941 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);1710 for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
19421711
...@@ -1988,7 +1757,7 @@ fn resolveSymbols(self: *Elf) void {...@@ -1988,7 +1757,7 @@ fn resolveSymbols(self: *Elf) void {
1988 }1757 }
19891758
1990 // Re-resolve the symbols.1759 // 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);
1992 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);1761 for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
1993 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);1762 for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
1994}1763}
...@@ -1998,7 +1767,7 @@ fn resolveSymbols(self: *Elf) void {...@@ -1998,7 +1767,7 @@ fn resolveSymbols(self: *Elf) void {
1998/// This routine will prune unneeded objects extracted from archives and1767/// This routine will prune unneeded objects extracted from archives and
1999/// unneeded shared objects.1768/// unneeded shared objects.
2000fn markLive(self: *Elf) void {1769fn 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);
2002 for (self.objects.items) |index| {1771 for (self.objects.items) |index| {
2003 const file_ptr = self.file(index).?;1772 const file_ptr = self.file(index).?;
2004 if (file_ptr.isAlive()) file_ptr.markLive(self);1773 if (file_ptr.isAlive()) file_ptr.markLive(self);
...@@ -2057,7 +1826,7 @@ fn markImportsExports(self: *Elf) void {...@@ -2057,7 +1826,7 @@ fn markImportsExports(self: *Elf) void {
2057 }1826 }
2058 }1827 }
20591828
2060 if (self.zig_module_index) |index| {1829 if (self.zig_object_index) |index| {
2061 mark(self, index);1830 mark(self, index);
2062 }1831 }
20631832
...@@ -2067,9 +1836,8 @@ fn markImportsExports(self: *Elf) void {...@@ -2067,9 +1836,8 @@ fn markImportsExports(self: *Elf) void {
2067}1836}
20681837
2069fn claimUnresolved(self: *Elf) void {1838fn claimUnresolved(self: *Elf) void {
2070 if (self.zig_module_index) |index| {1839 if (self.zigObjectPtr()) |zig_object| {
2071 const zig_module = self.file(index).?.zig_module;1840 zig_object.claimUnresolved(self);
2072 zig_module.claimUnresolved(self);
2073 }1841 }
2074 for (self.objects.items) |index| {1842 for (self.objects.items) |index| {
2075 const object = self.file(index).?.object;1843 const object = self.file(index).?.object;
...@@ -2093,9 +1861,8 @@ fn scanRelocs(self: *Elf) !void {...@@ -2093,9 +1861,8 @@ fn scanRelocs(self: *Elf) !void {
2093 undefs.deinit();1861 undefs.deinit();
2094 }1862 }
20951863
2096 if (self.zig_module_index) |index| {1864 if (self.zigObjectPtr()) |zig_object| {
2097 const zig_module = self.file(index).?.zig_module;1865 try zig_object.scanRelocs(self, &undefs);
2098 try zig_module.scanRelocs(self, &undefs);
2099 }1866 }
2100 for (self.objects.items) |index| {1867 for (self.objects.items) |index| {
2101 const object = self.file(index).?.object;1868 const object = self.file(index).?.object;
...@@ -3058,206 +2825,9 @@ fn writeHeader(self: *Elf) !void {...@@ -3058,206 +2825,9 @@ fn writeHeader(self: *Elf) !void {
3058 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);2825 try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
3059}2826}
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
3078pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {2828pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
3079 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);2829 if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
30802830 return self.zigObjectPtr().?.freeDecl(self, decl_index);
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 }
3261}2831}
32622832
3263pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {2833pub 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...@@ -3265,54 +2835,7 @@ pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: A
3265 @panic("Attempted to compile for object format that was disabled by build configuration");2835 @panic("Attempted to compile for object format that was disabled by build configuration");
3266 }2836 }
3267 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);2837 if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
32682838 return self.zigObjectPtr().?.updateFunc(self, mod, func_index, air, liveness);
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));
3316}2839}
33172840
3318pub fn updateDecl(2841pub fn updateDecl(
...@@ -3324,242 +2847,11 @@ pub fn updateDecl(...@@ -3324,242 +2847,11 @@ pub fn updateDecl(
3324 @panic("Attempted to compile for object format that was disabled by build configuration");2847 @panic("Attempted to compile for object format that was disabled by build configuration");
3325 }2848 }
3326 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);2849 if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
33272850 return self.zigObjectPtr().?.updateDecl(self, mod, decl_index);
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);
3475}2851}
34762852
3477pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {2853pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
3478 const gpa = self.base.allocator;2854 return self.zigObjectPtr().?.lowerUnnamedConst(self, typed_value, decl_index);
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 };
3563}2855}
35642856
3565pub fn updateExports(2857pub fn updateExports(
...@@ -3572,107 +2864,13 @@ pub fn updateExports(...@@ -3572,107 +2864,13 @@ pub fn updateExports(
3572 @panic("Attempted to compile for object format that was disabled by build configuration");2864 @panic("Attempted to compile for object format that was disabled by build configuration");
3573 }2865 }
3574 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);2866 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3575
3576 if (self.base.options.emit == null) return;2867 if (self.base.options.emit == null) return;
35772868 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
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 }
3660}2869}
36612870
3662/// Must be called only after a successful call to `updateDecl`.
3663pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void {2871pub 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
3672 if (self.llvm_object) |_| return;2872 if (self.llvm_object) |_| return;
3673 if (self.dwarf) |*dw| {2873 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
3674 try dw.updateDeclLineNumber(mod, decl_index);
3675 }
3676}2874}
36772875
3678pub fn deleteDeclExport(2876pub fn deleteDeclExport(
...@@ -3681,22 +2879,7 @@ pub fn deleteDeclExport(...@@ -3681,22 +2879,7 @@ pub fn deleteDeclExport(
3681 name: InternPool.NullTerminatedString,2879 name: InternPool.NullTerminatedString,
3682) void {2880) void {
3683 if (self.llvm_object) |_| return;2881 if (self.llvm_object) |_| return;
3684 const metadata = self.decls.getPtr(decl_index) orelse return;2882 return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
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;
3700}2883}
37012884
3702fn addLinkerDefinedSymbols(self: *Elf) !void {2885fn addLinkerDefinedSymbols(self: *Elf) !void {
...@@ -3917,8 +3100,8 @@ fn initSections(self: *Elf) !void {...@@ -3917,8 +3100,8 @@ fn initSections(self: *Elf) !void {
3917 const needs_rela_dyn = blk: {3100 const needs_rela_dyn = blk: {
3918 if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or3101 if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or
3919 self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true;3102 self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true;
3920 if (self.zig_module_index) |index| {3103 if (self.zigObjectPtr()) |zig_object| {
3921 if (self.file(index).?.zig_module.num_dynrelocs > 0) break :blk true;3104 if (zig_object.num_dynrelocs > 0) break :blk true;
3922 }3105 }
3923 for (self.objects.items) |index| {3106 for (self.objects.items) |index| {
3924 if (self.file(index).?.object.num_dynrelocs > 0) break :blk true;3107 if (self.file(index).?.object.num_dynrelocs > 0) break :blk true;
...@@ -4512,16 +3695,15 @@ fn sortShdrs(self: *Elf) !void {...@@ -4512,16 +3695,15 @@ fn sortShdrs(self: *Elf) !void {
4512 }3695 }
4513 }3696 }
45143697
4515 if (self.zig_module_index) |index| {3698 if (self.zigObjectPtr()) |zig_object| {
4516 const zig_module = self.file(index).?.zig_module;3699 for (zig_object.atoms.items) |atom_index| {
4517 for (zig_module.atoms.items) |atom_index| {
4518 const atom_ptr = self.atom(atom_index) orelse continue;3700 const atom_ptr = self.atom(atom_index) orelse continue;
4519 if (!atom_ptr.flags.alive) continue;3701 if (!atom_ptr.flags.alive) continue;
4520 const out_shndx = atom_ptr.outputShndx() orelse continue;3702 const out_shndx = atom_ptr.outputShndx() orelse continue;
4521 atom_ptr.output_section_index = backlinks[out_shndx];3703 atom_ptr.output_section_index = backlinks[out_shndx];
4522 }3704 }
45233705
4524 for (zig_module.locals()) |local_index| {3706 for (zig_object.locals()) |local_index| {
4525 const local = self.symbol(local_index);3707 const local = self.symbol(local_index);
4526 const atom_ptr = local.atom(self) orelse continue;3708 const atom_ptr = local.atom(self) orelse continue;
4527 if (!atom_ptr.flags.alive) continue;3709 if (!atom_ptr.flags.alive) continue;
...@@ -4529,35 +3711,17 @@ fn sortShdrs(self: *Elf) !void {...@@ -4529,35 +3711,17 @@ fn sortShdrs(self: *Elf) !void {
4529 local.output_section_index = backlinks[out_shndx];3711 local.output_section_index = backlinks[out_shndx];
4530 }3712 }
45313713
4532 for (zig_module.globals()) |global_index| {3714 for (zig_object.globals()) |global_index| {
4533 const global = self.symbol(global_index);3715 const global = self.symbol(global_index);
4534 const atom_ptr = global.atom(self) orelse continue;3716 const atom_ptr = global.atom(self) orelse continue;
4535 if (!atom_ptr.flags.alive) continue;3717 if (!atom_ptr.flags.alive) continue;
4536 if (global.file(self).?.index() != index) continue;3718 if (global.file(self).?.index() != zig_object.index) continue;
4537 const out_shndx = global.outputShndx() orelse continue;3719 const out_shndx = global.outputShndx() orelse continue;
4538 global.output_section_index = backlinks[out_shndx];3720 global.output_section_index = backlinks[out_shndx];
4539 }3721 }
4540 }3722 }
4541}3723}
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
4561fn updateSectionSizes(self: *Elf) !void {3725fn updateSectionSizes(self: *Elf) !void {
4562 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {3726 for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
4563 if (atom_list.items.len == 0) continue;3727 if (atom_list.items.len == 0) continue;
...@@ -4599,8 +3763,8 @@ fn updateSectionSizes(self: *Elf) !void {...@@ -4599,8 +3763,8 @@ fn updateSectionSizes(self: *Elf) !void {
45993763
4600 if (self.rela_dyn_section_index) |shndx| {3764 if (self.rela_dyn_section_index) |shndx| {
4601 var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela();3765 var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela();
4602 if (self.zig_module_index) |index| {3766 if (self.zigObjectPtr()) |zig_object| {
4603 num += self.file(index).?.zig_module.num_dynrelocs;3767 num += zig_object.num_dynrelocs;
4604 }3768 }
4605 for (self.objects.items) |index| {3769 for (self.objects.items) |index| {
4606 num += self.file(index).?.object.num_dynrelocs;3770 num += self.file(index).?.object.num_dynrelocs;
...@@ -4914,12 +4078,18 @@ fn allocateNonAllocSections(self: *Elf) !void {...@@ -4914,12 +4078,18 @@ fn allocateNonAllocSections(self: *Elf) !void {
4914 shdr.sh_offset,4078 shdr.sh_offset,
4915 new_offset,4079 new_offset,
4916 });4080 });
4081 const zig_object = self.zigObjectPtr().?;
4917 const existing_size = blk: {4082 const existing_size = blk: {
4918 if (shndx == self.debug_info_section_index.?) break :blk self.debug_info_section_zig_size;4083 if (shndx == self.debug_info_section_index.?)
4919 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;4084 break :blk zig_object.debug_info_section_zig_size;
4920 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;4085 if (shndx == self.debug_abbrev_section_index.?)
4921 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;4086 break :blk zig_object.debug_abbrev_section_zig_size;
4922 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_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;
4923 unreachable;4093 unreachable;
4924 };4094 };
4925 const amt = try self.base.file.?.copyRangeAll(4095 const amt = try self.base.file.?.copyRangeAll(
...@@ -5021,11 +4191,17 @@ fn writeAtoms(self: *Elf) !void {...@@ -5021,11 +4191,17 @@ fn writeAtoms(self: *Elf) !void {
50214191
5022 // TODO really, really handle debug section separately4192 // TODO really, really handle debug section separately
5023 const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {4193 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;4194 const zig_object = self.zigObjectPtr().?;
5025 if (shndx == self.debug_abbrev_section_index.?) break :blk self.debug_abbrev_section_zig_size;4195 if (shndx == self.debug_info_section_index.?)
5026 if (shndx == self.debug_str_section_index.?) break :blk self.debug_str_section_zig_size;4196 break :blk zig_object.debug_info_section_zig_size;
5027 if (shndx == self.debug_aranges_section_index.?) break :blk self.debug_aranges_section_zig_size;4197 if (shndx == self.debug_abbrev_section_index.?)
5028 if (shndx == self.debug_line_section_index.?) break :blk self.debug_line_section_zig_size;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;
5029 unreachable;4205 unreachable;
5030 } else 0;4206 } else 0;
5031 const sh_offset = shdr.sh_offset + base_offset;4207 const sh_offset = shdr.sh_offset + base_offset;
...@@ -5079,11 +4255,10 @@ fn writeAtoms(self: *Elf) !void {...@@ -5079,11 +4255,10 @@ fn writeAtoms(self: *Elf) !void {
5079fn updateSymtabSize(self: *Elf) !void {4255fn updateSymtabSize(self: *Elf) !void {
5080 var sizes = SymtabSize{};4256 var sizes = SymtabSize{};
50814257
5082 if (self.zig_module_index) |index| {4258 if (self.zigObjectPtr()) |zig_object| {
5083 const zig_module = self.file(index).?.zig_module;4259 zig_object.updateSymtabSize(self);
5084 zig_module.updateSymtabSize(self);4260 sizes.nlocals += zig_object.output_symtab_size.nlocals;
5085 sizes.nlocals += zig_module.output_symtab_size.nlocals;4261 sizes.nglobals += zig_object.output_symtab_size.nglobals;
5086 sizes.nglobals += zig_module.output_symtab_size.nglobals;
5087 }4262 }
50884263
5089 for (self.objects.items) |index| {4264 for (self.objects.items) |index| {
...@@ -5299,11 +4474,10 @@ fn writeSymtab(self: *Elf) !void {...@@ -5299,11 +4474,10 @@ fn writeSymtab(self: *Elf) !void {
5299 .symtab = symtab,4474 .symtab = symtab,
5300 };4475 };
53014476
5302 if (self.zig_module_index) |index| {4477 if (self.zigObjectPtr()) |zig_object| {
5303 const zig_module = self.file(index).?.zig_module;4478 zig_object.writeSymtab(self, ctx);
5304 zig_module.writeSymtab(self, ctx);4479 ctx.ilocal += zig_object.output_symtab_size.nlocals;
5305 ctx.ilocal += zig_module.output_symtab_size.nlocals;4480 ctx.iglobal += zig_object.output_symtab_size.nglobals;
5306 ctx.iglobal += zig_module.output_symtab_size.nglobals;
5307 }4481 }
53084482
5309 for (self.objects.items) |index| {4483 for (self.objects.items) |index| {
...@@ -5863,7 +5037,7 @@ pub fn file(self: *Elf, index: File.Index) ?File {...@@ -5863,7 +5037,7 @@ pub fn file(self: *Elf, index: File.Index) ?File {
5863 return switch (tag) {5037 return switch (tag) {
5864 .null => null,5038 .null => null,
5865 .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined },5039 .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 },
5867 .object => .{ .object = &self.files.items(.data)[index].object },5041 .object => .{ .object = &self.files.items(.data)[index].object },
5868 .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object },5042 .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object },
5869 };5043 };
...@@ -5961,26 +5135,12 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {...@@ -5961,26 +5135,12 @@ pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
5961}5135}
59625136
5963pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {5137pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
5964 _ = lib_name;5138 return self.zigObjectPtr().?.getGlobalSymbol(self, name, 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.*;
5978}5139}
59795140
5980pub fn zigModulePtr(self: *Elf) *ZigModule {5141pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
5981 assert(self.zig_module_index != null);5142 const index = self.zig_object_index orelse return null;
5982 const file_ptr = self.file(self.zig_module_index.?).?;5143 return self.file(index).?.zig_object;
5983 return file_ptr.zig_module;
5984}5144}
59855145
5986const GetOrCreateComdatGroupOwnerResult = struct {5146const GetOrCreateComdatGroupOwnerResult = struct {
...@@ -6245,12 +5405,11 @@ fn fmtDumpState(...@@ -6245,12 +5405,11 @@ fn fmtDumpState(
6245 _ = unused_fmt_string;5405 _ = unused_fmt_string;
6246 _ = options;5406 _ = options;
62475407
6248 if (self.zig_module_index) |index| {5408 if (self.zigObjectPtr()) |zig_object| {
6249 const zig_module = self.file(index).?.zig_module;5409 try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });
6250 try writer.print("zig_module({d}) : {s}\n", .{ index, zig_module.path });
6251 try writer.print("{}{}\n", .{5410 try writer.print("{}{}\n", .{
6252 zig_module.fmtAtoms(self),5411 zig_object.fmtAtoms(self),
6253 zig_module.fmtSymtab(self),5412 zig_object.fmtSymtab(self),
6254 });5413 });
6255 }5414 }
62565415
...@@ -6343,51 +5502,6 @@ const default_entry_addr = 0x8000000;...@@ -6343,51 +5502,6 @@ const default_entry_addr = 0x8000000;
63435502
6344pub const base_tag: link.File.Tag = .elf;5503pub 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
6391const ComdatGroupOwner = struct {5505const ComdatGroupOwner = struct {
6392 file: File.Index = 0,5506 file: File.Index = 0,
6393 const Index = u32;5507 const Index = u32;
...@@ -6431,6 +5545,30 @@ pub const SystemLib = struct {...@@ -6431,6 +5545,30 @@ pub const SystemLib = struct {
6431 path: []const u8,5545 path: []const u8,
6432};5546};
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
6434pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;5572pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
6435pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;5573pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
64365574
...@@ -6479,16 +5617,12 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;...@@ -6479,16 +5617,12 @@ const LlvmObject = @import("../codegen/llvm.zig").Object;
6479const Module = @import("../Module.zig");5617const Module = @import("../Module.zig");
6480const Object = @import("Elf/Object.zig");5618const Object = @import("Elf/Object.zig");
6481const InternPool = @import("../InternPool.zig");5619const InternPool = @import("../InternPool.zig");
6482const Package = @import("../Package.zig");
6483const PltSection = synthetic_sections.PltSection;5620const PltSection = synthetic_sections.PltSection;
6484const PltGotSection = synthetic_sections.PltGotSection;5621const PltGotSection = synthetic_sections.PltGotSection;
6485const SharedObject = @import("Elf/SharedObject.zig");5622const SharedObject = @import("Elf/SharedObject.zig");
6486const Symbol = @import("Elf/Symbol.zig");5623const Symbol = @import("Elf/Symbol.zig");
6487const StringTable = @import("strtab.zig").StringTable;5624const StringTable = @import("strtab.zig").StringTable;
6488const TableSection = @import("table_section.zig").TableSection;
6489const Type = @import("../type.zig").Type;
6490const TypedValue = @import("../TypedValue.zig");5625const TypedValue = @import("../TypedValue.zig");
6491const Value = @import("../value.zig").Value;
6492const VerneedSection = synthetic_sections.VerneedSection;5626const VerneedSection = synthetic_sections.VerneedSection;
6493const ZigGotSection = synthetic_sections.ZigGotSection;5627const 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 {...@@ -52,7 +52,7 @@ pub fn file(self: Atom, elf_file: *Elf) ?File {
52pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {52pub fn inputShdr(self: Atom, elf_file: *Elf) Object.ElfShdr {
53 return switch (self.file(elf_file).?) {53 return switch (self.file(elf_file).?) {
54 .object => |x| x.shdrs.items[self.input_section_index],54 .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),
56 else => unreachable,56 else => unreachable,
57 };57 };
58}58}
...@@ -166,15 +166,16 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {...@@ -166,15 +166,16 @@ pub fn allocate(self: *Atom, elf_file: *Elf) !void {
166 try elf_file.growAllocSection(self.outputShndx().?, needed_size);166 try elf_file.growAllocSection(self.outputShndx().?, needed_size);
167 last_atom_index.* = self.atom_index;167 last_atom_index.* = self.atom_index;
168168
169 if (elf_file.dwarf) |_| {169 const zig_object = elf_file.zigObjectPtr().?;
170 if (zig_object.dwarf) |_| {
170 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address171 // The .debug_info section has `low_pc` and `high_pc` values which is the virtual address
171 // range of the compilation unit. When we expand the text section, this range changes,172 // range of the compilation unit. When we expand the text section, this range changes,
172 // so the DW_TAG.compile_unit tag of the .debug_info section becomes dirty.173 // 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;
174 // This becomes dirty for the same reason. We could potentially make this more175 // This becomes dirty for the same reason. We could potentially make this more
175 // fine-grained with the addition of support for more compilation units. It is planned to176 // fine-grained with the addition of support for more compilation units. It is planned to
176 // model each package as a different compilation unit.177 // model each package as a different compilation unit.
177 elf_file.debug_aranges_section_dirty = true;178 zig_object.debug_aranges_section_dirty = true;
178 }179 }
179 }180 }
180 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);181 shdr.sh_addralign = @max(shdr.sh_addralign, self.alignment.toByteUnitsOptional().?);
...@@ -270,14 +271,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void {...@@ -270,14 +271,14 @@ pub fn free(self: *Atom, elf_file: *Elf) void {
270 // TODO create relocs free list271 // TODO create relocs free list
271 self.freeRelocs(elf_file);272 self.freeRelocs(elf_file);
272 // TODO figure out how to free input section mappind in ZigModule273 // TODO figure out how to free input section mappind in ZigModule
273 // const zig_module = self.file(elf_file).?.zig_module;274 // const zig_object = elf_file.zigObjectPtr().?
274 // assert(zig_module.atoms.swapRemove(self.atom_index));275 // assert(zig_object.atoms.swapRemove(self.atom_index));
275 self.* = .{};276 self.* = .{};
276}277}
277278
278pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {279pub fn relocs(self: Atom, elf_file: *Elf) []align(1) const elf.Elf64_Rela {
279 return switch (self.file(elf_file).?) {280 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,
281 .object => |x| x.getRelocs(self.relocs_section_index),282 .object => |x| x.getRelocs(self.relocs_section_index),
282 else => unreachable,283 else => unreachable,
283 };284 };
...@@ -298,17 +299,17 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void {...@@ -298,17 +299,17 @@ pub fn markFdesDead(self: Atom, elf_file: *Elf) void {
298pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {299pub fn addReloc(self: Atom, elf_file: *Elf, reloc: elf.Elf64_Rela) !void {
299 const gpa = elf_file.base.allocator;300 const gpa = elf_file.base.allocator;
300 const file_ptr = self.file(elf_file).?;301 const file_ptr = self.file(elf_file).?;
301 assert(file_ptr == .zig_module);302 assert(file_ptr == .zig_object);
302 const zig_module = file_ptr.zig_module;303 const zig_object = file_ptr.zig_object;
303 const rels = &zig_module.relocs.items[self.relocs_section_index];304 const rels = &zig_object.relocs.items[self.relocs_section_index];
304 try rels.append(gpa, reloc);305 try rels.append(gpa, reloc);
305}306}
306307
307pub fn freeRelocs(self: Atom, elf_file: *Elf) void {308pub fn freeRelocs(self: Atom, elf_file: *Elf) void {
308 const file_ptr = self.file(elf_file).?;309 const file_ptr = self.file(elf_file).?;
309 assert(file_ptr == .zig_module);310 assert(file_ptr == .zig_object);
310 const zig_module = file_ptr.zig_module;311 const zig_object = file_ptr.zig_object;
311 zig_module.relocs.items[self.relocs_section_index].clearRetainingCapacity();312 zig_object.relocs.items[self.relocs_section_index].clearRetainingCapacity();
312}313}
313314
314pub fn scanRelocsRequiresCode(self: Atom, elf_file: *Elf) bool {315pub 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...@@ -332,7 +333,7 @@ pub fn scanRelocs(self: Atom, elf_file: *Elf, code: ?[]const u8, undefs: anytype
332 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;333 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
333334
334 const symbol_index = switch (file_ptr) {335 const symbol_index = switch (file_ptr) {
335 .zig_module => |x| x.symbol(rel.r_sym()),336 .zig_object => |x| x.symbol(rel.r_sym()),
336 .object => |x| x.symbols.items[rel.r_sym()],337 .object => |x| x.symbols.items[rel.r_sym()],
337 else => unreachable,338 else => unreachable,
338 };339 };
...@@ -690,7 +691,7 @@ fn reportUndefined(...@@ -690,7 +691,7 @@ fn reportUndefined(
690 undefs: anytype,691 undefs: anytype,
691) !void {692) !void {
692 const rel_esym = switch (self.file(elf_file).?) {693 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()).*,
694 .object => |x| x.symtab[rel.r_sym()],695 .object => |x| x.symtab[rel.r_sym()],
695 else => unreachable,696 else => unreachable,
696 };697 };
...@@ -724,7 +725,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {...@@ -724,7 +725,7 @@ pub fn resolveRelocsAlloc(self: Atom, elf_file: *Elf, code: []u8) !void {
724 if (r_type == elf.R_X86_64_NONE) continue;725 if (r_type == elf.R_X86_64_NONE) continue;
725726
726 const target = switch (file_ptr) {727 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())),
728 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),729 .object => |x| elf_file.symbol(x.symbols.items[rel.r_sym()]),
729 else => unreachable,730 else => unreachable,
730 };731 };
...@@ -1004,7 +1005,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any...@@ -1004,7 +1005,7 @@ pub fn resolveRelocsNonAlloc(self: Atom, elf_file: *Elf, code: []u8, undefs: any
1004 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;1005 const r_offset = std.math.cast(usize, rel.r_offset) orelse return error.Overflow;
10051006
1006 const target_index = switch (file_ptr) {1007 const target_index = switch (file_ptr) {
1007 .zig_module => |x| x.symbol(rel.r_sym()),1008 .zig_object => |x| x.symbol(rel.r_sym()),
1008 .object => |x| x.symbols.items[rel.r_sym()],1009 .object => |x| x.symbols.items[rel.r_sym()],
1009 else => unreachable,1010 else => unreachable,
1010 };1011 };
src/link/Elf/Symbol.zig+1-2
...@@ -72,7 +72,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {...@@ -72,7 +72,7 @@ pub fn file(symbol: Symbol, elf_file: *Elf) ?File {
72pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {72pub fn elfSym(symbol: Symbol, elf_file: *Elf) elf.Elf64_Sym {
73 const file_ptr = symbol.file(elf_file).?;73 const file_ptr = symbol.file(elf_file).?;
74 switch (file_ptr) {74 switch (file_ptr) {
75 .zig_module => |x| return x.elfSym(symbol.esym_index).*,75 .zig_object => |x| return x.elfSym(symbol.esym_index).*,
76 .linker_defined => |x| return x.symtab.items[symbol.esym_index],76 .linker_defined => |x| return x.symtab.items[symbol.esym_index],
77 inline else => |x| return x.symtab[symbol.esym_index],77 inline else => |x| return x.symtab[symbol.esym_index],
78 }78 }
...@@ -406,4 +406,3 @@ const PltSection = synthetic_sections.PltSection;...@@ -406,4 +406,3 @@ const PltSection = synthetic_sections.PltSection;
406const SharedObject = @import("SharedObject.zig");406const SharedObject = @import("SharedObject.zig");
407const Symbol = @This();407const Symbol = @This();
408const ZigGotSection = synthetic_sections.ZigGotSection;408const 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 @@...@@ -1,5 +1,5 @@
1pub const File = union(enum) {1pub const File = union(enum) {
2 zig_module: *ZigModule,2 zig_object: *ZigObject,
3 linker_defined: *LinkerDefined,3 linker_defined: *LinkerDefined,
4 object: *Object,4 object: *Object,
5 shared_object: *SharedObject,5 shared_object: *SharedObject,
...@@ -23,7 +23,7 @@ pub const File = union(enum) {...@@ -23,7 +23,7 @@ pub const File = union(enum) {
23 _ = unused_fmt_string;23 _ = unused_fmt_string;
24 _ = options;24 _ = options;
25 switch (file) {25 switch (file) {
26 .zig_module => |x| try writer.print("{s}", .{x.path}),26 .zig_object => |x| try writer.print("{s}", .{x.path}),
27 .linker_defined => try writer.writeAll("(linker defined)"),27 .linker_defined => try writer.writeAll("(linker defined)"),
28 .object => |x| try writer.print("{}", .{x.fmtPath()}),28 .object => |x| try writer.print("{}", .{x.fmtPath()}),
29 .shared_object => |x| try writer.writeAll(x.path),29 .shared_object => |x| try writer.writeAll(x.path),
...@@ -32,7 +32,7 @@ pub const File = union(enum) {...@@ -32,7 +32,7 @@ pub const File = union(enum) {
3232
33 pub fn isAlive(file: File) bool {33 pub fn isAlive(file: File) bool {
34 return switch (file) {34 return switch (file) {
35 .zig_module => true,35 .zig_object => true,
36 .linker_defined => true,36 .linker_defined => true,
37 inline else => |x| x.alive,37 inline else => |x| x.alive,
38 };38 };
...@@ -76,7 +76,7 @@ pub const File = union(enum) {...@@ -76,7 +76,7 @@ pub const File = union(enum) {
7676
77 pub fn setAlive(file: File) void {77 pub fn setAlive(file: File) void {
78 switch (file) {78 switch (file) {
79 .zig_module, .linker_defined => {},79 .zig_object, .linker_defined => {},
80 inline else => |x| x.alive = true,80 inline else => |x| x.alive = true,
81 }81 }
82 }82 }
...@@ -92,7 +92,7 @@ pub const File = union(enum) {...@@ -92,7 +92,7 @@ pub const File = union(enum) {
92 return switch (file) {92 return switch (file) {
93 .linker_defined => unreachable,93 .linker_defined => unreachable,
94 .shared_object => unreachable,94 .shared_object => unreachable,
95 .zig_module => |x| x.atoms.items,95 .zig_object => |x| x.atoms.items,
96 .object => |x| x.atoms.items,96 .object => |x| x.atoms.items,
97 };97 };
98 }98 }
...@@ -115,7 +115,7 @@ pub const File = union(enum) {...@@ -115,7 +115,7 @@ pub const File = union(enum) {
115115
116 pub const Entry = union(enum) {116 pub const Entry = union(enum) {
117 null: void,117 null: void,
118 zig_module: ZigModule,118 zig_object: ZigObject,
119 linker_defined: LinkerDefined,119 linker_defined: LinkerDefined,
120 object: Object,120 object: Object,
121 shared_object: SharedObject,121 shared_object: SharedObject,
...@@ -132,4 +132,4 @@ const LinkerDefined = @import("LinkerDefined.zig");...@@ -132,4 +132,4 @@ const LinkerDefined = @import("LinkerDefined.zig");
132const Object = @import("Object.zig");132const Object = @import("Object.zig");
133const SharedObject = @import("SharedObject.zig");133const SharedObject = @import("SharedObject.zig");
134const Symbol = @import("Symbol.zig");134const Symbol = @import("Symbol.zig");
135const ZigModule = @import("ZigModule.zig");135const ZigObject = @import("ZigObject.zig");