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