zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 9cd7577d (91244B) - Raw


      1 //! ZigObject encapsulates the state of the incrementally compiled Zig module.
      2 //! It stores the associated input local and global symbols, allocated atoms,
      3 //! and any relocations that may have been emitted.
      4 //! Think about this as fake in-memory Object file for the Zig module.
      5 
      6 data: std.ArrayListUnmanaged(u8) = .{},
      7 /// Externally owned memory.
      8 path: []const u8,
      9 index: File.Index,
     10 
     11 symtab: std.MultiArrayList(ElfSym) = .{},
     12 strtab: StringTable = .{},
     13 symbols: std.ArrayListUnmanaged(Symbol) = .{},
     14 symbols_extra: std.ArrayListUnmanaged(u32) = .{},
     15 symbols_resolver: std.ArrayListUnmanaged(Elf.SymbolResolver.Index) = .{},
     16 local_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
     17 global_symbols: std.ArrayListUnmanaged(Symbol.Index) = .{},
     18 globals_lookup: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .{},
     19 
     20 atoms: std.ArrayListUnmanaged(Atom) = .{},
     21 atoms_indexes: std.ArrayListUnmanaged(Atom.Index) = .{},
     22 atoms_extra: std.ArrayListUnmanaged(u32) = .{},
     23 relocs: std.ArrayListUnmanaged(std.ArrayListUnmanaged(elf.Elf64_Rela)) = .{},
     24 
     25 num_dynrelocs: u32 = 0,
     26 
     27 output_symtab_ctx: Elf.SymtabCtx = .{},
     28 output_ar_state: Archive.ArState = .{},
     29 
     30 dwarf: ?Dwarf = null,
     31 
     32 /// Table of tracked LazySymbols.
     33 lazy_syms: LazySymbolTable = .{},
     34 
     35 /// Table of tracked `Nav`s.
     36 navs: NavTable = .{},
     37 
     38 /// TLS variables indexed by Atom.Index.
     39 tls_variables: TlsTable = .{},
     40 
     41 /// Table of tracked `Uav`s.
     42 uavs: UavTable = .{},
     43 
     44 debug_info_section_dirty: bool = false,
     45 debug_abbrev_section_dirty: bool = false,
     46 debug_aranges_section_dirty: bool = false,
     47 debug_str_section_dirty: bool = false,
     48 debug_line_section_dirty: bool = false,
     49 debug_line_str_section_dirty: bool = false,
     50 debug_loclists_section_dirty: bool = false,
     51 debug_rnglists_section_dirty: bool = false,
     52 
     53 debug_info_index: ?Symbol.Index = null,
     54 debug_abbrev_index: ?Symbol.Index = null,
     55 debug_aranges_index: ?Symbol.Index = null,
     56 debug_str_index: ?Symbol.Index = null,
     57 debug_line_index: ?Symbol.Index = null,
     58 debug_line_str_index: ?Symbol.Index = null,
     59 debug_loclists_index: ?Symbol.Index = null,
     60 debug_rnglists_index: ?Symbol.Index = null,
     61 
     62 pub const global_symbol_bit: u32 = 0x80000000;
     63 pub const symbol_mask: u32 = 0x7fffffff;
     64 pub const SHN_ATOM: u16 = 0x100;
     65 
     66 const InitOptions = struct {
     67     symbol_count_hint: u64,
     68     program_code_size_hint: u64,
     69 };
     70 
     71 pub fn init(self: *ZigObject, elf_file: *Elf, options: InitOptions) !void {
     72     const comp = elf_file.base.comp;
     73     const gpa = comp.gpa;
     74     const ptr_size = elf_file.ptrWidthBytes();
     75     const target = elf_file.getTarget();
     76     const ptr_bit_width = target.ptrBitWidth();
     77 
     78     try self.atoms.append(gpa, .{ .extra_index = try self.addAtomExtra(gpa, .{}) }); // null input section
     79     try self.relocs.append(gpa, .{}); // null relocs section
     80     try self.strtab.buffer.append(gpa, 0);
     81 
     82     {
     83         const name_off = try self.strtab.insert(gpa, self.path);
     84         const symbol_index = try self.newLocalSymbol(gpa, name_off);
     85         const sym = self.symbol(symbol_index);
     86         const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
     87         esym.st_info = elf.STT_FILE;
     88         esym.st_shndx = elf.SHN_ABS;
     89     }
     90 
     91     const fillSection = struct {
     92         fn fillSection(ef: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) !void {
     93             if (ef.base.isRelocatable()) {
     94                 const off = try ef.findFreeSpace(size, shdr.sh_addralign);
     95                 shdr.sh_offset = off;
     96                 shdr.sh_size = size;
     97             } else {
     98                 const phdr = ef.phdrs.items[phndx.?];
     99                 shdr.sh_addr = phdr.p_vaddr;
    100                 shdr.sh_offset = phdr.p_offset;
    101                 shdr.sh_size = phdr.p_memsz;
    102             }
    103         }
    104     }.fillSection;
    105 
    106     comptime assert(Elf.number_of_zig_segments == 4);
    107 
    108     if (!elf_file.base.isRelocatable()) {
    109         if (elf_file.phdr_zig_load_re_index == null) {
    110             const filesz = options.program_code_size_hint;
    111             const off = try elf_file.findFreeSpace(filesz, elf_file.page_size);
    112             elf_file.phdr_zig_load_re_index = try elf_file.addPhdr(.{
    113                 .type = elf.PT_LOAD,
    114                 .offset = off,
    115                 .filesz = filesz,
    116                 .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
    117                 .memsz = filesz,
    118                 .@"align" = elf_file.page_size,
    119                 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
    120             });
    121         }
    122 
    123         if (elf_file.phdr_zig_load_ro_index == null) {
    124             const alignment = elf_file.page_size;
    125             const filesz: u64 = 1024;
    126             const off = try elf_file.findFreeSpace(filesz, alignment);
    127             elf_file.phdr_zig_load_ro_index = try elf_file.addPhdr(.{
    128                 .type = elf.PT_LOAD,
    129                 .offset = off,
    130                 .filesz = filesz,
    131                 .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000,
    132                 .memsz = filesz,
    133                 .@"align" = alignment,
    134                 .flags = elf.PF_R | elf.PF_W,
    135             });
    136         }
    137 
    138         if (elf_file.phdr_zig_load_rw_index == null) {
    139             const alignment = elf_file.page_size;
    140             const filesz: u64 = 1024;
    141             const off = try elf_file.findFreeSpace(filesz, alignment);
    142             elf_file.phdr_zig_load_rw_index = try elf_file.addPhdr(.{
    143                 .type = elf.PT_LOAD,
    144                 .offset = off,
    145                 .filesz = filesz,
    146                 .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000,
    147                 .memsz = filesz,
    148                 .@"align" = alignment,
    149                 .flags = elf.PF_R | elf.PF_W,
    150             });
    151         }
    152 
    153         if (elf_file.phdr_zig_load_zerofill_index == null) {
    154             const alignment = elf_file.page_size;
    155             elf_file.phdr_zig_load_zerofill_index = try elf_file.addPhdr(.{
    156                 .type = elf.PT_LOAD,
    157                 .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000,
    158                 .memsz = 1024,
    159                 .@"align" = alignment,
    160                 .flags = elf.PF_R | elf.PF_W,
    161             });
    162         }
    163     }
    164 
    165     if (elf_file.zig_text_section_index == null) {
    166         elf_file.zig_text_section_index = try elf_file.addSection(.{
    167             .name = try elf_file.insertShString(".text.zig"),
    168             .type = elf.SHT_PROGBITS,
    169             .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
    170             .addralign = 1,
    171             .offset = std.math.maxInt(u64),
    172         });
    173         const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_text_section_index.?];
    174         const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_text_section_index.?];
    175         try fillSection(elf_file, shdr, options.program_code_size_hint, elf_file.phdr_zig_load_re_index);
    176         if (elf_file.base.isRelocatable()) {
    177             _ = try elf_file.addRelaShdr(
    178                 try elf_file.insertShString(".rela.text.zig"),
    179                 elf_file.zig_text_section_index.?,
    180             );
    181         } else {
    182             phndx.* = elf_file.phdr_zig_load_re_index.?;
    183         }
    184     }
    185 
    186     if (elf_file.zig_data_rel_ro_section_index == null) {
    187         elf_file.zig_data_rel_ro_section_index = try elf_file.addSection(.{
    188             .name = try elf_file.insertShString(".data.rel.ro.zig"),
    189             .type = elf.SHT_PROGBITS,
    190             .addralign = 1,
    191             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
    192             .offset = std.math.maxInt(u64),
    193         });
    194         const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_rel_ro_section_index.?];
    195         const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_rel_ro_section_index.?];
    196         try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_ro_index);
    197         if (elf_file.base.isRelocatable()) {
    198             _ = try elf_file.addRelaShdr(
    199                 try elf_file.insertShString(".rela.data.rel.ro.zig"),
    200                 elf_file.zig_data_rel_ro_section_index.?,
    201             );
    202         } else {
    203             phndx.* = elf_file.phdr_zig_load_ro_index.?;
    204         }
    205     }
    206 
    207     if (elf_file.zig_data_section_index == null) {
    208         elf_file.zig_data_section_index = try elf_file.addSection(.{
    209             .name = try elf_file.insertShString(".data.zig"),
    210             .type = elf.SHT_PROGBITS,
    211             .addralign = ptr_size,
    212             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
    213             .offset = std.math.maxInt(u64),
    214         });
    215         const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_data_section_index.?];
    216         const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_data_section_index.?];
    217         try fillSection(elf_file, shdr, 1024, elf_file.phdr_zig_load_rw_index);
    218         if (elf_file.base.isRelocatable()) {
    219             _ = try elf_file.addRelaShdr(
    220                 try elf_file.insertShString(".rela.data.zig"),
    221                 elf_file.zig_data_section_index.?,
    222             );
    223         } else {
    224             phndx.* = elf_file.phdr_zig_load_rw_index.?;
    225         }
    226     }
    227 
    228     if (elf_file.zig_bss_section_index == null) {
    229         elf_file.zig_bss_section_index = try elf_file.addSection(.{
    230             .name = try elf_file.insertShString(".bss.zig"),
    231             .type = elf.SHT_NOBITS,
    232             .addralign = ptr_size,
    233             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
    234             .offset = 0,
    235         });
    236         const shdr = &elf_file.sections.items(.shdr)[elf_file.zig_bss_section_index.?];
    237         const phndx = &elf_file.sections.items(.phndx)[elf_file.zig_bss_section_index.?];
    238         if (elf_file.base.isRelocatable()) {
    239             shdr.sh_size = 1024;
    240         } else {
    241             phndx.* = elf_file.phdr_zig_load_zerofill_index.?;
    242             const phdr = elf_file.phdrs.items[phndx.*.?];
    243             shdr.sh_addr = phdr.p_vaddr;
    244             shdr.sh_size = phdr.p_memsz;
    245         }
    246     }
    247 
    248     switch (comp.config.debug_format) {
    249         .strip => {},
    250         .dwarf => |v| {
    251             var dwarf = Dwarf.init(&elf_file.base, v);
    252 
    253             const addSectionSymbol = struct {
    254                 fn addSectionSymbol(
    255                     zig_object: *ZigObject,
    256                     alloc: Allocator,
    257                     name: [:0]const u8,
    258                     alignment: Atom.Alignment,
    259                     shndx: u32,
    260                 ) !Symbol.Index {
    261                     const name_off = try zig_object.addString(alloc, name);
    262                     const index = try zig_object.newSymbolWithAtom(alloc, name_off);
    263                     const sym = zig_object.symbol(index);
    264                     const esym = &zig_object.symtab.items(.elf_sym)[sym.esym_index];
    265                     esym.st_info |= elf.STT_SECTION;
    266                     const atom_ptr = zig_object.atom(sym.ref.index).?;
    267                     atom_ptr.alignment = alignment;
    268                     atom_ptr.output_section_index = shndx;
    269                     return index;
    270                 }
    271             }.addSectionSymbol;
    272 
    273             if (elf_file.debug_str_section_index == null) {
    274                 elf_file.debug_str_section_index = try elf_file.addSection(.{
    275                     .name = try elf_file.insertShString(".debug_str"),
    276                     .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
    277                     .entsize = 1,
    278                     .type = elf.SHT_PROGBITS,
    279                     .addralign = 1,
    280                 });
    281                 self.debug_str_section_dirty = true;
    282                 self.debug_str_index = try addSectionSymbol(self, gpa, ".debug_str", .@"1", elf_file.debug_str_section_index.?);
    283             }
    284 
    285             if (elf_file.debug_info_section_index == null) {
    286                 elf_file.debug_info_section_index = try elf_file.addSection(.{
    287                     .name = try elf_file.insertShString(".debug_info"),
    288                     .type = elf.SHT_PROGBITS,
    289                     .addralign = 1,
    290                 });
    291                 self.debug_info_section_dirty = true;
    292                 self.debug_info_index = try addSectionSymbol(self, gpa, ".debug_info", .@"1", elf_file.debug_info_section_index.?);
    293             }
    294 
    295             if (elf_file.debug_abbrev_section_index == null) {
    296                 elf_file.debug_abbrev_section_index = try elf_file.addSection(.{
    297                     .name = try elf_file.insertShString(".debug_abbrev"),
    298                     .type = elf.SHT_PROGBITS,
    299                     .addralign = 1,
    300                 });
    301                 self.debug_abbrev_section_dirty = true;
    302                 self.debug_abbrev_index = try addSectionSymbol(self, gpa, ".debug_abbrev", .@"1", elf_file.debug_abbrev_section_index.?);
    303             }
    304 
    305             if (elf_file.debug_aranges_section_index == null) {
    306                 elf_file.debug_aranges_section_index = try elf_file.addSection(.{
    307                     .name = try elf_file.insertShString(".debug_aranges"),
    308                     .type = elf.SHT_PROGBITS,
    309                     .addralign = 16,
    310                 });
    311                 self.debug_aranges_section_dirty = true;
    312                 self.debug_aranges_index = try addSectionSymbol(self, gpa, ".debug_aranges", .@"16", elf_file.debug_aranges_section_index.?);
    313             }
    314 
    315             if (elf_file.debug_line_section_index == null) {
    316                 elf_file.debug_line_section_index = try elf_file.addSection(.{
    317                     .name = try elf_file.insertShString(".debug_line"),
    318                     .type = elf.SHT_PROGBITS,
    319                     .addralign = 1,
    320                 });
    321                 self.debug_line_section_dirty = true;
    322                 self.debug_line_index = try addSectionSymbol(self, gpa, ".debug_line", .@"1", elf_file.debug_line_section_index.?);
    323             }
    324 
    325             if (elf_file.debug_line_str_section_index == null) {
    326                 elf_file.debug_line_str_section_index = try elf_file.addSection(.{
    327                     .name = try elf_file.insertShString(".debug_line_str"),
    328                     .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
    329                     .entsize = 1,
    330                     .type = elf.SHT_PROGBITS,
    331                     .addralign = 1,
    332                 });
    333                 self.debug_line_str_section_dirty = true;
    334                 self.debug_line_str_index = try addSectionSymbol(self, gpa, ".debug_line_str", .@"1", elf_file.debug_line_str_section_index.?);
    335             }
    336 
    337             if (elf_file.debug_loclists_section_index == null) {
    338                 elf_file.debug_loclists_section_index = try elf_file.addSection(.{
    339                     .name = try elf_file.insertShString(".debug_loclists"),
    340                     .type = elf.SHT_PROGBITS,
    341                     .addralign = 1,
    342                 });
    343                 self.debug_loclists_section_dirty = true;
    344                 self.debug_loclists_index = try addSectionSymbol(self, gpa, ".debug_loclists", .@"1", elf_file.debug_loclists_section_index.?);
    345             }
    346 
    347             if (elf_file.debug_rnglists_section_index == null) {
    348                 elf_file.debug_rnglists_section_index = try elf_file.addSection(.{
    349                     .name = try elf_file.insertShString(".debug_rnglists"),
    350                     .type = elf.SHT_PROGBITS,
    351                     .addralign = 1,
    352                 });
    353                 self.debug_rnglists_section_dirty = true;
    354                 self.debug_rnglists_index = try addSectionSymbol(self, gpa, ".debug_rnglists", .@"1", elf_file.debug_rnglists_section_index.?);
    355             }
    356 
    357             try dwarf.initMetadata();
    358             self.dwarf = dwarf;
    359         },
    360         .code_view => unreachable,
    361     }
    362 }
    363 
    364 pub fn deinit(self: *ZigObject, allocator: Allocator) void {
    365     self.data.deinit(allocator);
    366     self.symtab.deinit(allocator);
    367     self.strtab.deinit(allocator);
    368     self.symbols.deinit(allocator);
    369     self.symbols_extra.deinit(allocator);
    370     self.symbols_resolver.deinit(allocator);
    371     self.local_symbols.deinit(allocator);
    372     self.global_symbols.deinit(allocator);
    373     self.globals_lookup.deinit(allocator);
    374     self.atoms.deinit(allocator);
    375     self.atoms_indexes.deinit(allocator);
    376     self.atoms_extra.deinit(allocator);
    377     for (self.relocs.items) |*list| {
    378         list.deinit(allocator);
    379     }
    380     self.relocs.deinit(allocator);
    381 
    382     for (self.navs.values()) |*meta| {
    383         meta.exports.deinit(allocator);
    384     }
    385     self.navs.deinit(allocator);
    386 
    387     self.lazy_syms.deinit(allocator);
    388 
    389     for (self.uavs.values()) |*meta| {
    390         meta.exports.deinit(allocator);
    391     }
    392     self.uavs.deinit(allocator);
    393 
    394     for (self.tls_variables.values()) |*tlv| {
    395         tlv.deinit(allocator);
    396     }
    397     self.tls_variables.deinit(allocator);
    398 
    399     if (self.dwarf) |*dwarf| {
    400         dwarf.deinit();
    401     }
    402 }
    403 
    404 pub fn flushModule(self: *ZigObject, elf_file: *Elf, tid: Zcu.PerThread.Id) !void {
    405     // Handle any lazy symbols that were emitted by incremental compilation.
    406     if (self.lazy_syms.getPtr(.anyerror_type)) |metadata| {
    407         const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
    408 
    409         // Most lazy symbols can be updated on first use, but
    410         // anyerror needs to wait for everything to be flushed.
    411         if (metadata.text_state != .unused) self.updateLazySymbol(
    412             elf_file,
    413             pt,
    414             .{ .kind = .code, .ty = .anyerror_type },
    415             metadata.text_symbol_index,
    416         ) catch |err| return switch (err) {
    417             error.CodegenFail => error.FlushFailure,
    418             else => |e| e,
    419         };
    420         if (metadata.rodata_state != .unused) self.updateLazySymbol(
    421             elf_file,
    422             pt,
    423             .{ .kind = .const_data, .ty = .anyerror_type },
    424             metadata.rodata_symbol_index,
    425         ) catch |err| return switch (err) {
    426             error.CodegenFail => error.FlushFailure,
    427             else => |e| e,
    428         };
    429     }
    430     for (self.lazy_syms.values()) |*metadata| {
    431         if (metadata.text_state != .unused) metadata.text_state = .flushed;
    432         if (metadata.rodata_state != .unused) metadata.rodata_state = .flushed;
    433     }
    434 
    435     if (build_options.enable_logging) {
    436         const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
    437         for (self.navs.keys(), self.navs.values()) |nav_index, meta| {
    438             checkNavAllocated(pt, nav_index, meta);
    439         }
    440         for (self.uavs.keys(), self.uavs.values()) |uav_index, meta| {
    441             checkUavAllocated(pt, uav_index, meta);
    442         }
    443     }
    444 
    445     if (self.dwarf) |*dwarf| {
    446         const pt: Zcu.PerThread = .{ .zcu = elf_file.base.comp.module.?, .tid = tid };
    447         try dwarf.flushModule(pt);
    448 
    449         const gpa = elf_file.base.comp.gpa;
    450         const cpu_arch = elf_file.getTarget().cpu.arch;
    451 
    452         // TODO invert this logic so that we manage the output section with the atom, not the
    453         // other way around
    454         for ([_]u32{
    455             self.debug_info_index.?,
    456             self.debug_abbrev_index.?,
    457             self.debug_str_index.?,
    458             self.debug_aranges_index.?,
    459             self.debug_line_index.?,
    460             self.debug_line_str_index.?,
    461             self.debug_loclists_index.?,
    462             self.debug_rnglists_index.?,
    463         }, [_]*Dwarf.Section{
    464             &dwarf.debug_info.section,
    465             &dwarf.debug_abbrev.section,
    466             &dwarf.debug_str.section,
    467             &dwarf.debug_aranges.section,
    468             &dwarf.debug_line.section,
    469             &dwarf.debug_line_str.section,
    470             &dwarf.debug_loclists.section,
    471             &dwarf.debug_rnglists.section,
    472         }) |sym_index, sect| {
    473             const sym = self.symbol(sym_index);
    474             const atom_ptr = self.atom(sym.ref.index).?;
    475             if (!atom_ptr.alive) continue;
    476             const shndx = sym.outputShndx(elf_file).?;
    477             const shdr = elf_file.sections.items(.shdr)[shndx];
    478             const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
    479             esym.st_size = shdr.sh_size;
    480             atom_ptr.size = shdr.sh_size;
    481             atom_ptr.alignment = Atom.Alignment.fromNonzeroByteUnits(shdr.sh_addralign);
    482 
    483             log.debug("parsing relocs in {s}", .{sym.name(elf_file)});
    484 
    485             const relocs = &self.relocs.items[atom_ptr.relocsShndx().?];
    486             for (sect.units.items) |*unit| {
    487                 try relocs.ensureUnusedCapacity(gpa, unit.cross_unit_relocs.items.len +
    488                     unit.cross_section_relocs.items.len);
    489                 for (unit.cross_unit_relocs.items) |reloc| {
    490                     const target_unit = sect.getUnit(reloc.target_unit);
    491                     const r_offset = unit.off + reloc.source_off;
    492                     const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
    493                         target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
    494                     else
    495                         0));
    496                     const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
    497                     log.debug("  {s} <- r_off={x}, r_add={x}, r_type={}", .{
    498                         self.symbol(sym_index).name(elf_file),
    499                         r_offset,
    500                         r_addend,
    501                         relocation.fmtRelocType(r_type, cpu_arch),
    502                     });
    503                     atom_ptr.addRelocAssumeCapacity(.{
    504                         .r_offset = r_offset,
    505                         .r_addend = r_addend,
    506                         .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
    507                     }, self);
    508                 }
    509                 for (unit.cross_section_relocs.items) |reloc| {
    510                     const target_sym_index = switch (reloc.target_sec) {
    511                         .debug_abbrev => self.debug_abbrev_index.?,
    512                         .debug_info => self.debug_info_index.?,
    513                         .debug_line => self.debug_line_index.?,
    514                         .debug_line_str => self.debug_line_str_index.?,
    515                         .debug_loclists => self.debug_loclists_index.?,
    516                         .debug_rnglists => self.debug_rnglists_index.?,
    517                         .debug_str => self.debug_str_index.?,
    518                     };
    519                     const target_sec = switch (reloc.target_sec) {
    520                         inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
    521                     };
    522                     const target_unit = target_sec.getUnit(reloc.target_unit);
    523                     const r_offset = unit.off + reloc.source_off;
    524                     const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
    525                         target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
    526                     else
    527                         0));
    528                     const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
    529                     log.debug("  {s} <- r_off={x}, r_add={x}, r_type={}", .{
    530                         self.symbol(target_sym_index).name(elf_file),
    531                         r_offset,
    532                         r_addend,
    533                         relocation.fmtRelocType(r_type, cpu_arch),
    534                     });
    535                     atom_ptr.addRelocAssumeCapacity(.{
    536                         .r_offset = r_offset,
    537                         .r_addend = r_addend,
    538                         .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | r_type,
    539                     }, self);
    540                 }
    541 
    542                 for (unit.entries.items) |*entry| {
    543                     const entry_off = unit.off + unit.header_len + entry.off;
    544 
    545                     try relocs.ensureUnusedCapacity(gpa, entry.cross_entry_relocs.items.len +
    546                         entry.cross_unit_relocs.items.len + entry.cross_section_relocs.items.len +
    547                         entry.external_relocs.items.len);
    548                     for (entry.cross_entry_relocs.items) |reloc| {
    549                         const r_offset = entry_off + reloc.source_off;
    550                         const r_addend: i64 = @intCast(unit.off + reloc.target_off + unit.header_len + unit.getEntry(reloc.target_entry).assertNonEmpty(unit, sect, dwarf).off);
    551                         const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
    552                         log.debug("  {s} <- r_off={x}, r_add={x}, r_type={}", .{
    553                             self.symbol(sym_index).name(elf_file),
    554                             r_offset,
    555                             r_addend,
    556                             relocation.fmtRelocType(r_type, cpu_arch),
    557                         });
    558                         atom_ptr.addRelocAssumeCapacity(.{
    559                             .r_offset = r_offset,
    560                             .r_addend = r_addend,
    561                             .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
    562                         }, self);
    563                     }
    564                     for (entry.cross_unit_relocs.items) |reloc| {
    565                         const target_unit = sect.getUnit(reloc.target_unit);
    566                         const r_offset = entry_off + reloc.source_off;
    567                         const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
    568                             target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
    569                         else
    570                             0));
    571                         const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
    572                         log.debug("  {s} <- r_off={x}, r_add={x}, r_type={}", .{
    573                             self.symbol(sym_index).name(elf_file),
    574                             r_offset,
    575                             r_addend,
    576                             relocation.fmtRelocType(r_type, cpu_arch),
    577                         });
    578                         atom_ptr.addRelocAssumeCapacity(.{
    579                             .r_offset = r_offset,
    580                             .r_addend = r_addend,
    581                             .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
    582                         }, self);
    583                     }
    584                     for (entry.cross_section_relocs.items) |reloc| {
    585                         const target_sym_index = switch (reloc.target_sec) {
    586                             .debug_abbrev => self.debug_abbrev_index.?,
    587                             .debug_info => self.debug_info_index.?,
    588                             .debug_line => self.debug_line_index.?,
    589                             .debug_line_str => self.debug_line_str_index.?,
    590                             .debug_loclists => self.debug_loclists_index.?,
    591                             .debug_rnglists => self.debug_rnglists_index.?,
    592                             .debug_str => self.debug_str_index.?,
    593                         };
    594                         const target_sec = switch (reloc.target_sec) {
    595                             inline else => |target_sec| &@field(dwarf, @tagName(target_sec)).section,
    596                         };
    597                         const target_unit = target_sec.getUnit(reloc.target_unit);
    598                         const r_offset = entry_off + reloc.source_off;
    599                         const r_addend: i64 = @intCast(target_unit.off + reloc.target_off + (if (reloc.target_entry.unwrap()) |target_entry|
    600                             target_unit.header_len + target_unit.getEntry(target_entry).assertNonEmpty(unit, sect, dwarf).off
    601                         else
    602                             0));
    603                         const r_type = relocation.dwarf.crossSectionRelocType(dwarf.format, cpu_arch);
    604                         log.debug("  {s} <- r_off={x}, r_add={x}, r_type={}", .{
    605                             self.symbol(target_sym_index).name(elf_file),
    606                             r_offset,
    607                             r_addend,
    608                             relocation.fmtRelocType(r_type, cpu_arch),
    609                         });
    610                         atom_ptr.addRelocAssumeCapacity(.{
    611                             .r_offset = r_offset,
    612                             .r_addend = r_addend,
    613                             .r_info = (@as(u64, @intCast(target_sym_index)) << 32) | r_type,
    614                         }, self);
    615                     }
    616                     for (entry.external_relocs.items) |reloc| {
    617                         const target_sym = self.symbol(reloc.target_sym);
    618                         const r_offset = entry_off + reloc.source_off;
    619                         const r_addend: i64 = @intCast(reloc.target_off);
    620                         const r_type = relocation.dwarf.externalRelocType(target_sym.*, dwarf.address_size, cpu_arch);
    621                         log.debug("  {s} <- r_off={x}, r_add={x}, r_type={}", .{
    622                             target_sym.name(elf_file),
    623                             r_offset,
    624                             r_addend,
    625                             relocation.fmtRelocType(r_type, cpu_arch),
    626                         });
    627                         atom_ptr.addRelocAssumeCapacity(.{
    628                             .r_offset = r_offset,
    629                             .r_addend = r_addend,
    630                             .r_info = (@as(u64, @intCast(reloc.target_sym)) << 32) | r_type,
    631                         }, self);
    632                     }
    633                 }
    634             }
    635 
    636             if (elf_file.base.isRelocatable() and relocs.items.len > 0) {
    637                 const rela_sect_name = try std.fmt.allocPrintZ(gpa, ".rela{s}", .{elf_file.getShString(shdr.sh_name)});
    638                 defer gpa.free(rela_sect_name);
    639                 if (elf_file.sectionByName(rela_sect_name) == null) {
    640                     _ = try elf_file.addRelaShdr(try elf_file.insertShString(rela_sect_name), shndx);
    641                 }
    642             }
    643         }
    644 
    645         self.debug_abbrev_section_dirty = false;
    646         self.debug_aranges_section_dirty = false;
    647         self.debug_rnglists_section_dirty = false;
    648         self.debug_str_section_dirty = false;
    649     }
    650 
    651     // The point of flushModule() is to commit changes, so in theory, nothing should
    652     // be dirty after this. However, it is possible for some things to remain
    653     // dirty because they fail to be written in the event of compile errors,
    654     // such as debug_line_header_dirty and debug_info_header_dirty.
    655     assert(!self.debug_abbrev_section_dirty);
    656     assert(!self.debug_aranges_section_dirty);
    657     assert(!self.debug_rnglists_section_dirty);
    658     assert(!self.debug_str_section_dirty);
    659 }
    660 
    661 fn newSymbol(self: *ZigObject, allocator: Allocator, name_off: u32, st_bind: u4) !Symbol.Index {
    662     try self.symtab.ensureUnusedCapacity(allocator, 1);
    663     try self.symbols.ensureUnusedCapacity(allocator, 1);
    664     try self.symbols_extra.ensureUnusedCapacity(allocator, @sizeOf(Symbol.Extra));
    665 
    666     const index = self.addSymbolAssumeCapacity();
    667     const sym = &self.symbols.items[index];
    668     sym.name_offset = name_off;
    669     sym.extra_index = self.addSymbolExtraAssumeCapacity(.{});
    670 
    671     const esym_idx: u32 = @intCast(self.symtab.addOneAssumeCapacity());
    672     const esym = ElfSym{ .elf_sym = .{
    673         .st_value = 0,
    674         .st_name = name_off,
    675         .st_info = @as(u8, @intCast(st_bind)) << 4,
    676         .st_other = 0,
    677         .st_size = 0,
    678         .st_shndx = 0,
    679     } };
    680     self.symtab.set(index, esym);
    681     sym.esym_index = esym_idx;
    682 
    683     return index;
    684 }
    685 
    686 fn newLocalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
    687     try self.local_symbols.ensureUnusedCapacity(allocator, 1);
    688     const fake_index: Symbol.Index = @intCast(self.local_symbols.items.len);
    689     const index = try self.newSymbol(allocator, name_off, elf.STB_LOCAL);
    690     self.local_symbols.appendAssumeCapacity(index);
    691     return fake_index;
    692 }
    693 
    694 fn newGlobalSymbol(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
    695     try self.global_symbols.ensureUnusedCapacity(allocator, 1);
    696     try self.symbols_resolver.ensureUnusedCapacity(allocator, 1);
    697     const fake_index: Symbol.Index = @intCast(self.global_symbols.items.len);
    698     const index = try self.newSymbol(allocator, name_off, elf.STB_GLOBAL);
    699     self.global_symbols.appendAssumeCapacity(index);
    700     self.symbols_resolver.addOneAssumeCapacity().* = 0;
    701     return fake_index | global_symbol_bit;
    702 }
    703 
    704 fn newAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Atom.Index {
    705     try self.atoms.ensureUnusedCapacity(allocator, 1);
    706     try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
    707     try self.atoms_indexes.ensureUnusedCapacity(allocator, 1);
    708     try self.relocs.ensureUnusedCapacity(allocator, 1);
    709 
    710     const index = self.addAtomAssumeCapacity();
    711     self.atoms_indexes.appendAssumeCapacity(index);
    712     const atom_ptr = self.atom(index).?;
    713     atom_ptr.name_offset = name_off;
    714 
    715     const relocs_index: u32 = @intCast(self.relocs.items.len);
    716     self.relocs.addOneAssumeCapacity().* = .{};
    717     atom_ptr.relocs_section_index = relocs_index;
    718 
    719     return index;
    720 }
    721 
    722 fn newSymbolWithAtom(self: *ZigObject, allocator: Allocator, name_off: u32) !Symbol.Index {
    723     const atom_index = try self.newAtom(allocator, name_off);
    724     const sym_index = try self.newLocalSymbol(allocator, name_off);
    725     const sym = self.symbol(sym_index);
    726     sym.ref = .{ .index = atom_index, .file = self.index };
    727     self.symtab.items(.shndx)[sym.esym_index] = atom_index;
    728     self.symtab.items(.elf_sym)[sym.esym_index].st_shndx = SHN_ATOM;
    729     return sym_index;
    730 }
    731 
    732 /// TODO actually create fake input shdrs and return that instead.
    733 pub fn inputShdr(self: *ZigObject, atom_index: Atom.Index, elf_file: *Elf) elf.Elf64_Shdr {
    734     const atom_ptr = self.atom(atom_index) orelse return Elf.null_shdr;
    735     const shndx = atom_ptr.output_section_index;
    736     var shdr = elf_file.sections.items(.shdr)[shndx];
    737     shdr.sh_addr = 0;
    738     shdr.sh_offset = 0;
    739     shdr.sh_size = atom_ptr.size;
    740     shdr.sh_addralign = atom_ptr.alignment.toByteUnits() orelse 1;
    741     return shdr;
    742 }
    743 
    744 pub fn resolveSymbols(self: *ZigObject, elf_file: *Elf) !void {
    745     const gpa = elf_file.base.comp.gpa;
    746 
    747     for (self.global_symbols.items, 0..) |index, i| {
    748         const global = &self.symbols.items[index];
    749         const esym = global.elfSym(elf_file);
    750         const shndx = self.symtab.items(.shndx)[global.esym_index];
    751         if (esym.st_shndx != elf.SHN_ABS and esym.st_shndx != elf.SHN_COMMON and esym.st_shndx != elf.SHN_UNDEF) {
    752             assert(esym.st_shndx == SHN_ATOM);
    753             const atom_ptr = self.atom(shndx) orelse continue;
    754             if (!atom_ptr.alive) continue;
    755         }
    756 
    757         const resolv = &self.symbols_resolver.items[i];
    758         const gop = try elf_file.resolver.getOrPut(gpa, .{
    759             .index = @intCast(i | global_symbol_bit),
    760             .file = self.index,
    761         }, elf_file);
    762         if (!gop.found_existing) {
    763             gop.ref.* = .{ .index = 0, .file = 0 };
    764         }
    765         resolv.* = gop.index;
    766 
    767         if (esym.st_shndx == elf.SHN_UNDEF) continue;
    768         if (elf_file.symbol(gop.ref.*) == null) {
    769             gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
    770             continue;
    771         }
    772 
    773         if (self.asFile().symbolRank(esym, false) < elf_file.symbol(gop.ref.*).?.symbolRank(elf_file)) {
    774             gop.ref.* = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
    775         }
    776     }
    777 }
    778 
    779 pub fn claimUnresolved(self: *ZigObject, elf_file: *Elf) void {
    780     for (self.global_symbols.items, 0..) |index, i| {
    781         const global = &self.symbols.items[index];
    782         const esym = self.symtab.items(.elf_sym)[index];
    783         if (esym.st_shndx != elf.SHN_UNDEF) continue;
    784         if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
    785 
    786         const is_import = blk: {
    787             if (!elf_file.isEffectivelyDynLib()) break :blk false;
    788             const vis = @as(elf.STV, @enumFromInt(esym.st_other));
    789             if (vis == .HIDDEN) break :blk false;
    790             break :blk true;
    791         };
    792 
    793         global.value = 0;
    794         global.ref = .{ .index = 0, .file = 0 };
    795         global.esym_index = @intCast(index);
    796         global.file_index = self.index;
    797         global.version_index = if (is_import) elf.VER_NDX_LOCAL else elf_file.default_sym_version;
    798         global.flags.import = is_import;
    799 
    800         const idx = self.symbols_resolver.items[i];
    801         elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
    802     }
    803 }
    804 
    805 pub fn claimUnresolvedObject(self: ZigObject, elf_file: *Elf) void {
    806     for (self.global_symbols.items, 0..) |index, i| {
    807         const global = &self.symbols.items[index];
    808         const esym = self.symtab.items(.elf_sym)[index];
    809         if (esym.st_shndx != elf.SHN_UNDEF) continue;
    810         if (elf_file.symbol(self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file)) != null) continue;
    811 
    812         global.value = 0;
    813         global.ref = .{ .index = 0, .file = 0 };
    814         global.esym_index = @intCast(index);
    815         global.file_index = self.index;
    816 
    817         const idx = self.symbols_resolver.items[i];
    818         elf_file.resolver.values.items[idx - 1] = .{ .index = @intCast(i | global_symbol_bit), .file = self.index };
    819     }
    820 }
    821 
    822 pub fn scanRelocs(self: *ZigObject, elf_file: *Elf, undefs: anytype) !void {
    823     const gpa = elf_file.base.comp.gpa;
    824     for (self.atoms_indexes.items) |atom_index| {
    825         const atom_ptr = self.atom(atom_index) orelse continue;
    826         if (!atom_ptr.alive) continue;
    827         const shdr = atom_ptr.inputShdr(elf_file);
    828         if (shdr.sh_type == elf.SHT_NOBITS) continue;
    829         if (atom_ptr.scanRelocsRequiresCode(elf_file)) {
    830             // TODO ideally we don't have to fetch the code here.
    831             // Perhaps it would make sense to save the code until flushModule where we
    832             // would free all of generated code?
    833             const code = try self.codeAlloc(elf_file, atom_index);
    834             defer gpa.free(code);
    835             try atom_ptr.scanRelocs(elf_file, code, undefs);
    836         } else try atom_ptr.scanRelocs(elf_file, null, undefs);
    837     }
    838 }
    839 
    840 pub fn markLive(self: *ZigObject, elf_file: *Elf) void {
    841     for (self.global_symbols.items, 0..) |index, i| {
    842         const global = self.symbols.items[index];
    843         const esym = self.symtab.items(.elf_sym)[index];
    844         if (esym.st_bind() == elf.STB_WEAK) continue;
    845 
    846         const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
    847         const sym = elf_file.symbol(ref) orelse continue;
    848         const file = sym.file(elf_file).?;
    849         const should_keep = esym.st_shndx == elf.SHN_UNDEF or
    850             (esym.st_shndx == elf.SHN_COMMON and global.elfSym(elf_file).st_shndx != elf.SHN_COMMON);
    851         if (should_keep and !file.isAlive()) {
    852             file.setAlive();
    853             file.markLive(elf_file);
    854         }
    855     }
    856 }
    857 
    858 pub fn markImportsExports(self: *ZigObject, elf_file: *Elf) void {
    859     for (0..self.global_symbols.items.len) |i| {
    860         const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
    861         const sym = elf_file.symbol(ref) orelse continue;
    862         const file = sym.file(elf_file).?;
    863         if (sym.version_index == elf.VER_NDX_LOCAL) continue;
    864         const vis = @as(elf.STV, @enumFromInt(sym.elfSym(elf_file).st_other));
    865         if (vis == .HIDDEN) continue;
    866         if (file == .shared_object and !sym.isAbs(elf_file)) {
    867             sym.flags.import = true;
    868             continue;
    869         }
    870         if (file.index() == self.index) {
    871             sym.flags.@"export" = true;
    872             if (elf_file.isEffectivelyDynLib() and vis != .PROTECTED) {
    873                 sym.flags.import = true;
    874             }
    875         }
    876     }
    877 }
    878 
    879 pub fn checkDuplicates(self: *ZigObject, dupes: anytype, elf_file: *Elf) error{OutOfMemory}!void {
    880     for (self.global_symbols.items, 0..) |index, i| {
    881         const esym = self.symtab.items(.elf_sym)[index];
    882         const shndx = self.symtab.items(.shndx)[index];
    883         const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
    884         const ref_sym = elf_file.symbol(ref) orelse continue;
    885         const ref_file = ref_sym.file(elf_file).?;
    886 
    887         if (self.index == ref_file.index() or
    888             esym.st_shndx == elf.SHN_UNDEF or
    889             esym.st_bind() == elf.STB_WEAK or
    890             esym.st_shndx == elf.SHN_COMMON) continue;
    891 
    892         if (esym.st_shndx == SHN_ATOM) {
    893             const atom_ptr = self.atom(shndx) orelse continue;
    894             if (!atom_ptr.alive) continue;
    895         }
    896 
    897         const gop = try dupes.getOrPut(self.symbols_resolver.items[i]);
    898         if (!gop.found_existing) {
    899             gop.value_ptr.* = .{};
    900         }
    901         try gop.value_ptr.append(elf_file.base.comp.gpa, self.index);
    902     }
    903 }
    904 
    905 /// This is just a temporary helper function that allows us to re-read what we wrote to file into a buffer.
    906 /// We need this so that we can write to an archive.
    907 /// TODO implement writing ZigObject data directly to a buffer instead.
    908 pub fn readFileContents(self: *ZigObject, elf_file: *Elf) !void {
    909     const gpa = elf_file.base.comp.gpa;
    910     const shsize: u64 = switch (elf_file.ptr_width) {
    911         .p32 => @sizeOf(elf.Elf32_Shdr),
    912         .p64 => @sizeOf(elf.Elf64_Shdr),
    913     };
    914     var end_pos: u64 = elf_file.shdr_table_offset.? + elf_file.sections.items(.shdr).len * shsize;
    915     for (elf_file.sections.items(.shdr)) |shdr| {
    916         if (shdr.sh_type == elf.SHT_NOBITS) continue;
    917         end_pos = @max(end_pos, shdr.sh_offset + shdr.sh_size);
    918     }
    919     const size = std.math.cast(usize, end_pos) orelse return error.Overflow;
    920     try self.data.resize(gpa, size);
    921 
    922     const amt = try elf_file.base.file.?.preadAll(self.data.items, 0);
    923     if (amt != size) return error.InputOutput;
    924 }
    925 
    926 pub fn updateArSymtab(self: ZigObject, ar_symtab: *Archive.ArSymtab, elf_file: *Elf) error{OutOfMemory}!void {
    927     const gpa = elf_file.base.comp.gpa;
    928 
    929     try ar_symtab.symtab.ensureUnusedCapacity(gpa, self.global_symbols.items.len);
    930 
    931     for (self.global_symbols.items, 0..) |index, i| {
    932         const global = self.symbols.items[index];
    933         const ref = self.resolveSymbol(@intCast(i | global_symbol_bit), elf_file);
    934         const sym = elf_file.symbol(ref).?;
    935         assert(sym.file(elf_file).?.index() == self.index);
    936         if (global.outputShndx(elf_file) == null) continue;
    937 
    938         const off = try ar_symtab.strtab.insert(gpa, global.name(elf_file));
    939         ar_symtab.symtab.appendAssumeCapacity(.{ .off = off, .file_index = self.index });
    940     }
    941 }
    942 
    943 pub fn updateArSize(self: *ZigObject) void {
    944     self.output_ar_state.size = self.data.items.len;
    945 }
    946 
    947 pub fn writeAr(self: ZigObject, writer: anytype) !void {
    948     const name = self.path;
    949     const hdr = Archive.setArHdr(.{
    950         .name = if (name.len <= Archive.max_member_name_len)
    951             .{ .name = name }
    952         else
    953             .{ .name_off = self.output_ar_state.name_off },
    954         .size = self.data.items.len,
    955     });
    956     try writer.writeAll(mem.asBytes(&hdr));
    957     try writer.writeAll(self.data.items);
    958 }
    959 
    960 pub fn addAtomsToRelaSections(self: *ZigObject, elf_file: *Elf) !void {
    961     for (self.atoms_indexes.items) |atom_index| {
    962         const atom_ptr = self.atom(atom_index) orelse continue;
    963         if (!atom_ptr.alive) continue;
    964         const rela_shndx = atom_ptr.relocsShndx() orelse continue;
    965         // TODO this check will become obsolete when we rework our relocs mechanism at the ZigObject level
    966         if (self.relocs.items[rela_shndx].items.len == 0) continue;
    967         const out_shndx = atom_ptr.output_section_index;
    968         const out_shdr = elf_file.sections.items(.shdr)[out_shndx];
    969         if (out_shdr.sh_type == elf.SHT_NOBITS) continue;
    970         const out_rela_shndx = for (elf_file.sections.items(.shdr), 0..) |out_rela_shdr, out_rela_shndx| {
    971             if (out_rela_shdr.sh_type == elf.SHT_RELA and out_rela_shdr.sh_info == out_shndx) break out_rela_shndx;
    972         } else unreachable;
    973         const atom_list = &elf_file.sections.items(.atom_list)[out_rela_shndx];
    974         const gpa = elf_file.base.comp.gpa;
    975         try atom_list.append(gpa, .{ .index = atom_index, .file = self.index });
    976     }
    977 }
    978 
    979 pub fn updateSymtabSize(self: *ZigObject, elf_file: *Elf) !void {
    980     for (self.local_symbols.items) |index| {
    981         const local = &self.symbols.items[index];
    982         if (local.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
    983         const name = local.name(elf_file);
    984         assert(name.len > 0);
    985         const esym = local.elfSym(elf_file);
    986         switch (esym.st_type()) {
    987             elf.STT_SECTION, elf.STT_NOTYPE => continue,
    988             else => {},
    989         }
    990         local.flags.output_symtab = true;
    991         local.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
    992         self.output_symtab_ctx.nlocals += 1;
    993         self.output_symtab_ctx.strsize += @as(u32, @intCast(name.len)) + 1;
    994     }
    995 
    996     for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
    997         const global = &self.symbols.items[index];
    998         const ref = elf_file.resolver.values.items[resolv - 1];
    999         const ref_sym = elf_file.symbol(ref) orelse continue;
   1000         if (ref_sym.file(elf_file).?.index() != self.index) continue;
   1001         if (global.atom(elf_file)) |atom_ptr| if (!atom_ptr.alive) continue;
   1002         global.flags.output_symtab = true;
   1003         if (global.isLocal(elf_file)) {
   1004             global.addExtra(.{ .symtab = self.output_symtab_ctx.nlocals }, elf_file);
   1005             self.output_symtab_ctx.nlocals += 1;
   1006         } else {
   1007             global.addExtra(.{ .symtab = self.output_symtab_ctx.nglobals }, elf_file);
   1008             self.output_symtab_ctx.nglobals += 1;
   1009         }
   1010         self.output_symtab_ctx.strsize += @as(u32, @intCast(global.name(elf_file).len)) + 1;
   1011     }
   1012 }
   1013 
   1014 pub fn writeSymtab(self: ZigObject, elf_file: *Elf) void {
   1015     for (self.local_symbols.items) |index| {
   1016         const local = &self.symbols.items[index];
   1017         const idx = local.outputSymtabIndex(elf_file) orelse continue;
   1018         const out_sym = &elf_file.symtab.items[idx];
   1019         out_sym.st_name = @intCast(elf_file.strtab.items.len);
   1020         elf_file.strtab.appendSliceAssumeCapacity(local.name(elf_file));
   1021         elf_file.strtab.appendAssumeCapacity(0);
   1022         local.setOutputSym(elf_file, out_sym);
   1023     }
   1024 
   1025     for (self.global_symbols.items, self.symbols_resolver.items) |index, resolv| {
   1026         const global = self.symbols.items[index];
   1027         const ref = elf_file.resolver.values.items[resolv - 1];
   1028         const ref_sym = elf_file.symbol(ref) orelse continue;
   1029         if (ref_sym.file(elf_file).?.index() != self.index) continue;
   1030         const idx = global.outputSymtabIndex(elf_file) orelse continue;
   1031         const st_name = @as(u32, @intCast(elf_file.strtab.items.len));
   1032         elf_file.strtab.appendSliceAssumeCapacity(global.name(elf_file));
   1033         elf_file.strtab.appendAssumeCapacity(0);
   1034         const out_sym = &elf_file.symtab.items[idx];
   1035         out_sym.st_name = st_name;
   1036         global.setOutputSym(elf_file, out_sym);
   1037     }
   1038 }
   1039 
   1040 /// Returns atom's code.
   1041 /// Caller owns the memory.
   1042 pub fn codeAlloc(self: *ZigObject, elf_file: *Elf, atom_index: Atom.Index) ![]u8 {
   1043     const gpa = elf_file.base.comp.gpa;
   1044     const atom_ptr = self.atom(atom_index).?;
   1045     const shdr = &elf_file.sections.items(.shdr)[atom_ptr.output_section_index];
   1046 
   1047     if (shdr.sh_flags & elf.SHF_TLS != 0) {
   1048         const tlv = self.tls_variables.get(atom_index).?;
   1049         const code = try gpa.dupe(u8, tlv.code);
   1050         return code;
   1051     }
   1052 
   1053     const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
   1054     const size = std.math.cast(usize, atom_ptr.size) orelse return error.Overflow;
   1055     const code = try gpa.alloc(u8, size);
   1056     errdefer gpa.free(code);
   1057     const amt = try elf_file.base.file.?.preadAll(code, file_offset);
   1058     if (amt != code.len) {
   1059         log.err("fetching code for {s} failed", .{atom_ptr.name(elf_file)});
   1060         return error.InputOutput;
   1061     }
   1062     return code;
   1063 }
   1064 
   1065 pub fn getNavVAddr(
   1066     self: *ZigObject,
   1067     elf_file: *Elf,
   1068     pt: Zcu.PerThread,
   1069     nav_index: InternPool.Nav.Index,
   1070     reloc_info: link.File.RelocInfo,
   1071 ) !u64 {
   1072     const zcu = pt.zcu;
   1073     const ip = &zcu.intern_pool;
   1074     const nav = ip.getNav(nav_index);
   1075     log.debug("getNavVAddr {}({d})", .{ nav.fqn.fmt(ip), nav_index });
   1076     const this_sym_index = switch (ip.indexToKey(nav.status.resolved.val)) {
   1077         .@"extern" => |@"extern"| try self.getGlobalSymbol(
   1078             elf_file,
   1079             nav.name.toSlice(ip),
   1080             @"extern".lib_name.toSlice(ip),
   1081         ),
   1082         else => try self.getOrCreateMetadataForNav(elf_file, nav_index),
   1083     };
   1084     const this_sym = self.symbol(this_sym_index);
   1085     const vaddr = this_sym.address(.{}, elf_file);
   1086     const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
   1087     const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
   1088     try parent_atom.addReloc(elf_file.base.comp.gpa, .{
   1089         .r_offset = reloc_info.offset,
   1090         .r_info = (@as(u64, @intCast(this_sym_index)) << 32) | r_type,
   1091         .r_addend = reloc_info.addend,
   1092     }, self);
   1093     return @intCast(vaddr);
   1094 }
   1095 
   1096 pub fn getUavVAddr(
   1097     self: *ZigObject,
   1098     elf_file: *Elf,
   1099     uav: InternPool.Index,
   1100     reloc_info: link.File.RelocInfo,
   1101 ) !u64 {
   1102     const sym_index = self.uavs.get(uav).?.symbol_index;
   1103     const sym = self.symbol(sym_index);
   1104     const vaddr = sym.address(.{}, elf_file);
   1105     const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(elf_file).?;
   1106     const r_type = relocation.encode(.abs, elf_file.getTarget().cpu.arch);
   1107     try parent_atom.addReloc(elf_file.base.comp.gpa, .{
   1108         .r_offset = reloc_info.offset,
   1109         .r_info = (@as(u64, @intCast(sym_index)) << 32) | r_type,
   1110         .r_addend = reloc_info.addend,
   1111     }, self);
   1112     return @intCast(vaddr);
   1113 }
   1114 
   1115 pub fn lowerUav(
   1116     self: *ZigObject,
   1117     elf_file: *Elf,
   1118     pt: Zcu.PerThread,
   1119     uav: InternPool.Index,
   1120     explicit_alignment: InternPool.Alignment,
   1121     src_loc: Zcu.LazySrcLoc,
   1122 ) !codegen.GenResult {
   1123     const zcu = pt.zcu;
   1124     const gpa = zcu.gpa;
   1125     const val = Value.fromInterned(uav);
   1126     const uav_alignment = switch (explicit_alignment) {
   1127         .none => val.typeOf(zcu).abiAlignment(pt),
   1128         else => explicit_alignment,
   1129     };
   1130     if (self.uavs.get(uav)) |metadata| {
   1131         assert(metadata.allocated);
   1132         const sym = self.symbol(metadata.symbol_index);
   1133         const existing_alignment = sym.atom(elf_file).?.alignment;
   1134         if (uav_alignment.order(existing_alignment).compare(.lte))
   1135             return .{ .mcv = .{ .load_symbol = metadata.symbol_index } };
   1136     }
   1137 
   1138     var name_buf: [32]u8 = undefined;
   1139     const name = std.fmt.bufPrint(&name_buf, "__anon_{d}", .{
   1140         @intFromEnum(uav),
   1141     }) catch unreachable;
   1142     const res = self.lowerConst(
   1143         elf_file,
   1144         pt,
   1145         name,
   1146         val,
   1147         uav_alignment,
   1148         elf_file.zig_data_rel_ro_section_index.?,
   1149         src_loc,
   1150     ) catch |err| switch (err) {
   1151         error.OutOfMemory => return error.OutOfMemory,
   1152         else => |e| return .{ .fail = try Zcu.ErrorMsg.create(
   1153             gpa,
   1154             src_loc,
   1155             "unable to lower constant value: {s}",
   1156             .{@errorName(e)},
   1157         ) },
   1158     };
   1159     const sym_index = switch (res) {
   1160         .ok => |sym_index| sym_index,
   1161         .fail => |em| return .{ .fail = em },
   1162     };
   1163     try self.uavs.put(gpa, uav, .{ .symbol_index = sym_index, .allocated = true });
   1164     return .{ .mcv = .{ .load_symbol = sym_index } };
   1165 }
   1166 
   1167 pub fn getOrCreateMetadataForLazySymbol(
   1168     self: *ZigObject,
   1169     elf_file: *Elf,
   1170     pt: Zcu.PerThread,
   1171     lazy_sym: link.File.LazySymbol,
   1172 ) !Symbol.Index {
   1173     const gop = try self.lazy_syms.getOrPut(pt.zcu.gpa, lazy_sym.ty);
   1174     errdefer _ = if (!gop.found_existing) self.lazy_syms.pop();
   1175     if (!gop.found_existing) gop.value_ptr.* = .{};
   1176     const symbol_index_ptr, const state_ptr = switch (lazy_sym.kind) {
   1177         .code => .{ &gop.value_ptr.text_symbol_index, &gop.value_ptr.text_state },
   1178         .const_data => .{ &gop.value_ptr.rodata_symbol_index, &gop.value_ptr.rodata_state },
   1179     };
   1180     switch (state_ptr.*) {
   1181         .unused => symbol_index_ptr.* = try self.newSymbolWithAtom(pt.zcu.gpa, 0),
   1182         .pending_flush => return symbol_index_ptr.*,
   1183         .flushed => {},
   1184     }
   1185     state_ptr.* = .pending_flush;
   1186     const symbol_index = symbol_index_ptr.*;
   1187     // anyerror needs to be deferred until flushModule
   1188     if (lazy_sym.ty != .anyerror_type) try self.updateLazySymbol(elf_file, pt, lazy_sym, symbol_index);
   1189     return symbol_index;
   1190 }
   1191 
   1192 fn freeNavMetadata(self: *ZigObject, elf_file: *Elf, sym_index: Symbol.Index) void {
   1193     const sym = self.symbol(sym_index);
   1194     sym.atom(elf_file).?.free(elf_file);
   1195     log.debug("adding %{d} to local symbols free list", .{sym_index});
   1196     self.symbols.items[sym_index] = .{};
   1197     // TODO free GOT entry here
   1198 }
   1199 
   1200 pub fn freeNav(self: *ZigObject, elf_file: *Elf, nav_index: InternPool.Nav.Index) void {
   1201     const gpa = elf_file.base.comp.gpa;
   1202 
   1203     log.debug("freeNav ({d})", .{nav_index});
   1204 
   1205     if (self.navs.fetchRemove(nav_index)) |const_kv| {
   1206         var kv = const_kv;
   1207         const sym_index = kv.value.symbol_index;
   1208         self.freeNavMetadata(elf_file, sym_index);
   1209         kv.value.exports.deinit(gpa);
   1210     }
   1211 
   1212     if (self.dwarf) |*dwarf| {
   1213         dwarf.freeNav(nav_index);
   1214     }
   1215 }
   1216 
   1217 pub fn getOrCreateMetadataForNav(
   1218     self: *ZigObject,
   1219     elf_file: *Elf,
   1220     nav_index: InternPool.Nav.Index,
   1221 ) !Symbol.Index {
   1222     const gpa = elf_file.base.comp.gpa;
   1223     const gop = try self.navs.getOrPut(gpa, nav_index);
   1224     if (!gop.found_existing) {
   1225         const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
   1226         const symbol_index = try self.newSymbolWithAtom(gpa, 0);
   1227         const zcu = elf_file.base.comp.module.?;
   1228         const nav_val = Value.fromInterned(zcu.intern_pool.getNav(nav_index).status.resolved.val);
   1229         const sym = self.symbol(symbol_index);
   1230         if (nav_val.getVariable(zcu)) |variable| {
   1231             if (variable.is_threadlocal and any_non_single_threaded) {
   1232                 sym.flags.is_tls = true;
   1233             }
   1234         }
   1235         gop.value_ptr.* = .{ .symbol_index = symbol_index };
   1236     }
   1237     return gop.value_ptr.symbol_index;
   1238 }
   1239 
   1240 fn getNavShdrIndex(
   1241     self: *ZigObject,
   1242     elf_file: *Elf,
   1243     zcu: *Zcu,
   1244     nav_index: InternPool.Nav.Index,
   1245     sym_index: Symbol.Index,
   1246     code: []const u8,
   1247 ) error{OutOfMemory}!u32 {
   1248     const ip = &zcu.intern_pool;
   1249     const any_non_single_threaded = elf_file.base.comp.config.any_non_single_threaded;
   1250     const nav_val = zcu.navValue(nav_index);
   1251     if (ip.isFunctionType(nav_val.typeOf(zcu).toIntern())) return elf_file.zig_text_section_index.?;
   1252     const is_const, const is_threadlocal, const nav_init = switch (ip.indexToKey(nav_val.toIntern())) {
   1253         .variable => |variable| .{ false, variable.is_threadlocal, variable.init },
   1254         .@"extern" => |@"extern"| .{ @"extern".is_const, @"extern".is_threadlocal, .none },
   1255         else => .{ true, false, nav_val.toIntern() },
   1256     };
   1257     const has_relocs = self.symbol(sym_index).atom(elf_file).?.relocs(elf_file).len > 0;
   1258     if (any_non_single_threaded and is_threadlocal) {
   1259         const is_bss = !has_relocs and for (code) |byte| {
   1260             if (byte != 0) break false;
   1261         } else true;
   1262         if (is_bss) return elf_file.sectionByName(".tbss") orelse try elf_file.addSection(.{
   1263             .type = elf.SHT_NOBITS,
   1264             .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
   1265             .name = try elf_file.insertShString(".tbss"),
   1266             .offset = std.math.maxInt(u64),
   1267         });
   1268         return elf_file.sectionByName(".tdata") orelse try elf_file.addSection(.{
   1269             .type = elf.SHT_PROGBITS,
   1270             .flags = elf.SHF_ALLOC | elf.SHF_WRITE | elf.SHF_TLS,
   1271             .name = try elf_file.insertShString(".tdata"),
   1272             .offset = std.math.maxInt(u64),
   1273         });
   1274     }
   1275     if (is_const) return elf_file.zig_data_rel_ro_section_index.?;
   1276     if (nav_init != .none and Value.fromInterned(nav_init).isUndefDeep(zcu))
   1277         return switch (zcu.navFileScope(nav_index).mod.optimize_mode) {
   1278             .Debug, .ReleaseSafe => elf_file.zig_data_section_index.?,
   1279             .ReleaseFast, .ReleaseSmall => elf_file.zig_bss_section_index.?,
   1280         };
   1281     const is_bss = !has_relocs and for (code) |byte| {
   1282         if (byte != 0) break false;
   1283     } else true;
   1284     if (is_bss) return elf_file.zig_bss_section_index.?;
   1285     return elf_file.zig_data_section_index.?;
   1286 }
   1287 
   1288 fn updateNavCode(
   1289     self: *ZigObject,
   1290     elf_file: *Elf,
   1291     pt: Zcu.PerThread,
   1292     nav_index: InternPool.Nav.Index,
   1293     sym_index: Symbol.Index,
   1294     shdr_index: u32,
   1295     code: []const u8,
   1296     stt_bits: u8,
   1297 ) !void {
   1298     const zcu = pt.zcu;
   1299     const gpa = zcu.gpa;
   1300     const ip = &zcu.intern_pool;
   1301     const nav = ip.getNav(nav_index);
   1302 
   1303     log.debug("updateNavCode {}({d})", .{ nav.fqn.fmt(ip), nav_index });
   1304 
   1305     const required_alignment = pt.navAlignment(nav_index).max(
   1306         target_util.minFunctionAlignment(zcu.navFileScope(nav_index).mod.resolved_target.result),
   1307     );
   1308 
   1309     const sym = self.symbol(sym_index);
   1310     const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
   1311     const atom_ptr = sym.atom(elf_file).?;
   1312     const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip));
   1313 
   1314     atom_ptr.alive = true;
   1315     atom_ptr.name_offset = name_offset;
   1316     atom_ptr.output_section_index = shdr_index;
   1317 
   1318     sym.name_offset = name_offset;
   1319     esym.st_name = name_offset;
   1320     esym.st_info |= stt_bits;
   1321     esym.st_size = code.len;
   1322 
   1323     const old_size = atom_ptr.size;
   1324     const old_vaddr = atom_ptr.value;
   1325     atom_ptr.alignment = required_alignment;
   1326     atom_ptr.size = code.len;
   1327 
   1328     if (old_size > 0 and elf_file.base.child_pid == null) {
   1329         const capacity = atom_ptr.capacity(elf_file);
   1330         const need_realloc = code.len > capacity or !required_alignment.check(@intCast(atom_ptr.value));
   1331         if (need_realloc) {
   1332             try atom_ptr.grow(elf_file);
   1333             log.debug("growing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), old_vaddr, atom_ptr.value });
   1334             if (old_vaddr != atom_ptr.value) {
   1335                 sym.value = 0;
   1336                 esym.st_value = 0;
   1337             }
   1338         } else if (code.len < old_size) {
   1339             atom_ptr.shrink(elf_file);
   1340         }
   1341     } else {
   1342         try atom_ptr.allocate(elf_file);
   1343         errdefer self.freeNavMetadata(elf_file, sym_index);
   1344 
   1345         sym.value = 0;
   1346         esym.st_value = 0;
   1347     }
   1348 
   1349     self.navs.getPtr(nav_index).?.allocated = true;
   1350 
   1351     if (elf_file.base.child_pid) |pid| {
   1352         switch (builtin.os.tag) {
   1353             .linux => {
   1354                 var code_vec: [1]std.posix.iovec_const = .{.{
   1355                     .base = code.ptr,
   1356                     .len = code.len,
   1357                 }};
   1358                 var remote_vec: [1]std.posix.iovec_const = .{.{
   1359                     .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(sym.address(.{}, elf_file))))),
   1360                     .len = code.len,
   1361                 }};
   1362                 const rc = std.os.linux.process_vm_writev(pid, &code_vec, &remote_vec, 0);
   1363                 switch (std.os.linux.E.init(rc)) {
   1364                     .SUCCESS => assert(rc == code.len),
   1365                     else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
   1366                 }
   1367             },
   1368             else => return error.HotSwapUnavailableOnHostOperatingSystem,
   1369         }
   1370     }
   1371 
   1372     const shdr = elf_file.sections.items(.shdr)[shdr_index];
   1373     if (shdr.sh_type != elf.SHT_NOBITS) {
   1374         const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
   1375         try elf_file.base.file.?.pwriteAll(code, file_offset);
   1376         log.debug("writing {} from 0x{x} to 0x{x}", .{ nav.fqn.fmt(ip), file_offset, file_offset + code.len });
   1377     }
   1378 }
   1379 
   1380 fn updateTlv(
   1381     self: *ZigObject,
   1382     elf_file: *Elf,
   1383     pt: Zcu.PerThread,
   1384     nav_index: InternPool.Nav.Index,
   1385     sym_index: Symbol.Index,
   1386     shndx: u32,
   1387     code: []const u8,
   1388 ) !void {
   1389     const zcu = pt.zcu;
   1390     const ip = &zcu.intern_pool;
   1391     const gpa = zcu.gpa;
   1392     const nav = ip.getNav(nav_index);
   1393 
   1394     log.debug("updateTlv {}({d})", .{ nav.fqn.fmt(ip), nav_index });
   1395 
   1396     const required_alignment = pt.navAlignment(nav_index);
   1397 
   1398     const sym = self.symbol(sym_index);
   1399     const esym = &self.symtab.items(.elf_sym)[sym.esym_index];
   1400     const atom_ptr = sym.atom(elf_file).?;
   1401     const name_offset = try self.strtab.insert(gpa, nav.fqn.toSlice(ip));
   1402 
   1403     sym.value = 0;
   1404     sym.name_offset = name_offset;
   1405 
   1406     atom_ptr.output_section_index = shndx;
   1407     atom_ptr.alive = true;
   1408     atom_ptr.name_offset = name_offset;
   1409 
   1410     sym.name_offset = name_offset;
   1411     esym.st_value = 0;
   1412     esym.st_name = name_offset;
   1413     esym.st_info = elf.STT_TLS;
   1414     esym.st_size = code.len;
   1415 
   1416     atom_ptr.alignment = required_alignment;
   1417     atom_ptr.size = code.len;
   1418 
   1419     self.navs.getPtr(nav_index).?.allocated = true;
   1420 
   1421     {
   1422         const gop = try self.tls_variables.getOrPut(gpa, atom_ptr.atom_index);
   1423         assert(!gop.found_existing); // TODO incremental updates
   1424         gop.value_ptr.* = .{ .symbol_index = sym_index };
   1425 
   1426         // We only store the data for the TLV if it's non-zerofill.
   1427         if (elf_file.sections.items(.shdr)[shndx].sh_type != elf.SHT_NOBITS) {
   1428             gop.value_ptr.code = try gpa.dupe(u8, code);
   1429         }
   1430     }
   1431 
   1432     const atom_list = &elf_file.sections.items(.atom_list)[atom_ptr.output_section_index];
   1433     try atom_list.append(gpa, .{ .index = atom_ptr.atom_index, .file = self.index });
   1434 }
   1435 
   1436 pub fn updateFunc(
   1437     self: *ZigObject,
   1438     elf_file: *Elf,
   1439     pt: Zcu.PerThread,
   1440     func_index: InternPool.Index,
   1441     air: Air,
   1442     liveness: Liveness,
   1443 ) !void {
   1444     const tracy = trace(@src());
   1445     defer tracy.end();
   1446 
   1447     const zcu = pt.zcu;
   1448     const ip = &zcu.intern_pool;
   1449     const gpa = elf_file.base.comp.gpa;
   1450     const func = zcu.funcInfo(func_index);
   1451 
   1452     log.debug("updateFunc {}({d})", .{ ip.getNav(func.owner_nav).fqn.fmt(ip), func.owner_nav });
   1453 
   1454     const sym_index = try self.getOrCreateMetadataForNav(elf_file, func.owner_nav);
   1455     self.symbol(sym_index).atom(elf_file).?.freeRelocs(self);
   1456 
   1457     var code_buffer = std.ArrayList(u8).init(gpa);
   1458     defer code_buffer.deinit();
   1459 
   1460     var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, func.owner_nav, sym_index) else null;
   1461     defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
   1462 
   1463     const res = try codegen.generateFunction(
   1464         &elf_file.base,
   1465         pt,
   1466         zcu.navSrcLoc(func.owner_nav),
   1467         func_index,
   1468         air,
   1469         liveness,
   1470         &code_buffer,
   1471         if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none,
   1472     );
   1473 
   1474     const code = switch (res) {
   1475         .ok => code_buffer.items,
   1476         .fail => |em| {
   1477             try zcu.failed_codegen.put(gpa, func.owner_nav, em);
   1478             return;
   1479         },
   1480     };
   1481 
   1482     const shndx = try self.getNavShdrIndex(elf_file, zcu, func.owner_nav, sym_index, code);
   1483     log.debug("setting shdr({x},{s}) for {}", .{
   1484         shndx,
   1485         elf_file.getShString(elf_file.sections.items(.shdr)[shndx].sh_name),
   1486         ip.getNav(func.owner_nav).fqn.fmt(ip),
   1487     });
   1488     const old_rva, const old_alignment = blk: {
   1489         const atom_ptr = self.symbol(sym_index).atom(elf_file).?;
   1490         break :blk .{ atom_ptr.value, atom_ptr.alignment };
   1491     };
   1492     try self.updateNavCode(elf_file, pt, func.owner_nav, sym_index, shndx, code, elf.STT_FUNC);
   1493     const new_rva, const new_alignment = blk: {
   1494         const atom_ptr = self.symbol(sym_index).atom(elf_file).?;
   1495         break :blk .{ atom_ptr.value, atom_ptr.alignment };
   1496     };
   1497 
   1498     if (debug_wip_nav) |*wip_nav| {
   1499         const sym = self.symbol(sym_index);
   1500         try self.dwarf.?.finishWipNav(
   1501             pt,
   1502             func.owner_nav,
   1503             .{
   1504                 .index = sym_index,
   1505                 .addr = @intCast(sym.address(.{}, elf_file)),
   1506                 .size = sym.atom(elf_file).?.size,
   1507             },
   1508             wip_nav,
   1509         );
   1510     }
   1511 
   1512     // Exports will be updated by `Zcu.processExports` after the update.
   1513 
   1514     if (old_rva != new_rva and old_rva > 0) {
   1515         // If we had to reallocate the function, we re-use the existing slot for a trampoline.
   1516         // In the rare case that the function has been further overaligned we skip creating a
   1517         // trampoline and update all symbols referring this function.
   1518         if (old_alignment.order(new_alignment) == .lt) {
   1519             @panic("TODO update all symbols referring this function");
   1520         }
   1521 
   1522         // Create a trampoline to the new location at `old_rva`.
   1523         if (!self.symbol(sym_index).flags.has_trampoline) {
   1524             const name = try std.fmt.allocPrint(gpa, "{s}$trampoline", .{
   1525                 self.symbol(sym_index).name(elf_file),
   1526             });
   1527             defer gpa.free(name);
   1528             const name_off = try self.addString(gpa, name);
   1529             const tr_size = trampolineSize(elf_file.getTarget().cpu.arch);
   1530             const tr_sym_index = try self.newSymbolWithAtom(gpa, name_off);
   1531             const tr_sym = self.symbol(tr_sym_index);
   1532             const tr_esym = &self.symtab.items(.elf_sym)[tr_sym.esym_index];
   1533             tr_esym.st_info |= elf.STT_OBJECT;
   1534             tr_esym.st_size = tr_size;
   1535             const tr_atom_ptr = tr_sym.atom(elf_file).?;
   1536             tr_atom_ptr.value = old_rva;
   1537             tr_atom_ptr.alive = true;
   1538             tr_atom_ptr.alignment = old_alignment;
   1539             tr_atom_ptr.output_section_index = elf_file.zig_text_section_index.?;
   1540             tr_atom_ptr.size = tr_size;
   1541             const target_sym = self.symbol(sym_index);
   1542             target_sym.addExtra(.{ .trampoline = tr_sym_index }, elf_file);
   1543             target_sym.flags.has_trampoline = true;
   1544         }
   1545         const target_sym = self.symbol(sym_index);
   1546         try writeTrampoline(self.symbol(target_sym.extra(elf_file).trampoline).*, target_sym.*, elf_file);
   1547     }
   1548 }
   1549 
   1550 pub fn updateNav(
   1551     self: *ZigObject,
   1552     elf_file: *Elf,
   1553     pt: Zcu.PerThread,
   1554     nav_index: InternPool.Nav.Index,
   1555 ) link.File.UpdateNavError!void {
   1556     const tracy = trace(@src());
   1557     defer tracy.end();
   1558 
   1559     const zcu = pt.zcu;
   1560     const ip = &zcu.intern_pool;
   1561     const nav = ip.getNav(nav_index);
   1562 
   1563     log.debug("updateNav {}({d})", .{ nav.fqn.fmt(ip), nav_index });
   1564 
   1565     const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
   1566         .func => .none,
   1567         .variable => |variable| variable.init,
   1568         .@"extern" => |@"extern"| {
   1569             if (ip.isFunctionType(@"extern".ty)) return;
   1570             const sym_index = try self.getGlobalSymbol(
   1571                 elf_file,
   1572                 nav.name.toSlice(ip),
   1573                 @"extern".lib_name.toSlice(ip),
   1574             );
   1575             self.symbol(sym_index).flags.is_extern_ptr = true;
   1576             return;
   1577         },
   1578         else => nav.status.resolved.val,
   1579     };
   1580 
   1581     if (nav_init != .none and Value.fromInterned(nav_init).typeOf(zcu).hasRuntimeBits(pt)) {
   1582         const sym_index = try self.getOrCreateMetadataForNav(elf_file, nav_index);
   1583         self.symbol(sym_index).atom(elf_file).?.freeRelocs(self);
   1584 
   1585         var code_buffer = std.ArrayList(u8).init(zcu.gpa);
   1586         defer code_buffer.deinit();
   1587 
   1588         var debug_wip_nav = if (self.dwarf) |*dwarf| try dwarf.initWipNav(pt, nav_index, sym_index) else null;
   1589         defer if (debug_wip_nav) |*wip_nav| wip_nav.deinit();
   1590 
   1591         // TODO implement .debug_info for global variables
   1592         const res = try codegen.generateSymbol(
   1593             &elf_file.base,
   1594             pt,
   1595             zcu.navSrcLoc(nav_index),
   1596             Value.fromInterned(nav_init),
   1597             &code_buffer,
   1598             if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none,
   1599             .{ .parent_atom_index = sym_index },
   1600         );
   1601 
   1602         const code = switch (res) {
   1603             .ok => code_buffer.items,
   1604             .fail => |em| {
   1605                 try zcu.failed_codegen.put(zcu.gpa, nav_index, em);
   1606                 return;
   1607             },
   1608         };
   1609 
   1610         const shndx = try self.getNavShdrIndex(elf_file, zcu, nav_index, sym_index, code);
   1611         log.debug("setting shdr({x},{s}) for {}", .{
   1612             shndx,
   1613             elf_file.getShString(elf_file.sections.items(.shdr)[shndx].sh_name),
   1614             nav.fqn.fmt(ip),
   1615         });
   1616         if (elf_file.sections.items(.shdr)[shndx].sh_flags & elf.SHF_TLS != 0)
   1617             try self.updateTlv(elf_file, pt, nav_index, sym_index, shndx, code)
   1618         else
   1619             try self.updateNavCode(elf_file, pt, nav_index, sym_index, shndx, code, elf.STT_OBJECT);
   1620 
   1621         if (debug_wip_nav) |*wip_nav| {
   1622             const sym = self.symbol(sym_index);
   1623             try self.dwarf.?.finishWipNav(
   1624                 pt,
   1625                 nav_index,
   1626                 .{
   1627                     .index = sym_index,
   1628                     .addr = @intCast(sym.address(.{}, elf_file)),
   1629                     .size = sym.atom(elf_file).?.size,
   1630                 },
   1631                 wip_nav,
   1632             );
   1633         }
   1634     } else if (self.dwarf) |*dwarf| try dwarf.updateComptimeNav(pt, nav_index);
   1635 
   1636     // Exports will be updated by `Zcu.processExports` after the update.
   1637 }
   1638 
   1639 pub fn updateContainerType(
   1640     self: *ZigObject,
   1641     pt: Zcu.PerThread,
   1642     ty: InternPool.Index,
   1643 ) link.File.UpdateNavError!void {
   1644     const tracy = trace(@src());
   1645     defer tracy.end();
   1646 
   1647     if (self.dwarf) |*dwarf| try dwarf.updateContainerType(pt, ty);
   1648 }
   1649 
   1650 fn updateLazySymbol(
   1651     self: *ZigObject,
   1652     elf_file: *Elf,
   1653     pt: Zcu.PerThread,
   1654     sym: link.File.LazySymbol,
   1655     symbol_index: Symbol.Index,
   1656 ) !void {
   1657     const mod = pt.zcu;
   1658     const gpa = mod.gpa;
   1659 
   1660     var required_alignment: InternPool.Alignment = .none;
   1661     var code_buffer = std.ArrayList(u8).init(gpa);
   1662     defer code_buffer.deinit();
   1663 
   1664     const name_str_index = blk: {
   1665         const name = try std.fmt.allocPrint(gpa, "__lazy_{s}_{}", .{
   1666             @tagName(sym.kind),
   1667             Type.fromInterned(sym.ty).fmt(pt),
   1668         });
   1669         defer gpa.free(name);
   1670         break :blk try self.strtab.insert(gpa, name);
   1671     };
   1672 
   1673     const src = Type.fromInterned(sym.ty).srcLocOrNull(mod) orelse Zcu.LazySrcLoc.unneeded;
   1674     const res = try codegen.generateLazySymbol(
   1675         &elf_file.base,
   1676         pt,
   1677         src,
   1678         sym,
   1679         &required_alignment,
   1680         &code_buffer,
   1681         .none,
   1682         .{ .parent_atom_index = symbol_index },
   1683     );
   1684     const code = switch (res) {
   1685         .ok => code_buffer.items,
   1686         .fail => |em| {
   1687             log.err("{s}", .{em.msg});
   1688             return error.CodegenFail;
   1689         },
   1690     };
   1691 
   1692     const output_section_index = switch (sym.kind) {
   1693         .code => elf_file.zig_text_section_index.?,
   1694         .const_data => elf_file.zig_data_rel_ro_section_index.?,
   1695     };
   1696     const local_sym = self.symbol(symbol_index);
   1697     local_sym.name_offset = name_str_index;
   1698     const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];
   1699     local_esym.st_name = name_str_index;
   1700     local_esym.st_info |= elf.STT_OBJECT;
   1701     local_esym.st_size = code.len;
   1702     const atom_ptr = local_sym.atom(elf_file).?;
   1703     atom_ptr.alive = true;
   1704     atom_ptr.name_offset = name_str_index;
   1705     atom_ptr.alignment = required_alignment;
   1706     atom_ptr.size = code.len;
   1707     atom_ptr.output_section_index = output_section_index;
   1708 
   1709     try atom_ptr.allocate(elf_file);
   1710     errdefer self.freeNavMetadata(elf_file, symbol_index);
   1711 
   1712     local_sym.value = 0;
   1713     local_esym.st_value = 0;
   1714 
   1715     const shdr = elf_file.sections.items(.shdr)[output_section_index];
   1716     const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
   1717     try elf_file.base.file.?.pwriteAll(code, file_offset);
   1718 }
   1719 
   1720 const LowerConstResult = union(enum) {
   1721     ok: Symbol.Index,
   1722     fail: *Zcu.ErrorMsg,
   1723 };
   1724 
   1725 fn lowerConst(
   1726     self: *ZigObject,
   1727     elf_file: *Elf,
   1728     pt: Zcu.PerThread,
   1729     name: []const u8,
   1730     val: Value,
   1731     required_alignment: InternPool.Alignment,
   1732     output_section_index: u32,
   1733     src_loc: Zcu.LazySrcLoc,
   1734 ) !LowerConstResult {
   1735     const gpa = pt.zcu.gpa;
   1736 
   1737     var code_buffer = std.ArrayList(u8).init(gpa);
   1738     defer code_buffer.deinit();
   1739 
   1740     const name_off = try self.addString(gpa, name);
   1741     const sym_index = try self.newSymbolWithAtom(gpa, name_off);
   1742 
   1743     const res = try codegen.generateSymbol(
   1744         &elf_file.base,
   1745         pt,
   1746         src_loc,
   1747         val,
   1748         &code_buffer,
   1749         .{ .none = {} },
   1750         .{ .parent_atom_index = sym_index },
   1751     );
   1752     const code = switch (res) {
   1753         .ok => code_buffer.items,
   1754         .fail => |em| return .{ .fail = em },
   1755     };
   1756 
   1757     const local_sym = self.symbol(sym_index);
   1758     const local_esym = &self.symtab.items(.elf_sym)[local_sym.esym_index];
   1759     local_esym.st_info |= elf.STT_OBJECT;
   1760     local_esym.st_size = code.len;
   1761     const atom_ptr = local_sym.atom(elf_file).?;
   1762     atom_ptr.alive = true;
   1763     atom_ptr.alignment = required_alignment;
   1764     atom_ptr.size = code.len;
   1765     atom_ptr.output_section_index = output_section_index;
   1766 
   1767     try atom_ptr.allocate(elf_file);
   1768     // TODO rename and re-audit this method
   1769     errdefer self.freeNavMetadata(elf_file, sym_index);
   1770 
   1771     const shdr = elf_file.sections.items(.shdr)[output_section_index];
   1772     const file_offset = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
   1773     try elf_file.base.file.?.pwriteAll(code, file_offset);
   1774 
   1775     return .{ .ok = sym_index };
   1776 }
   1777 
   1778 pub fn updateExports(
   1779     self: *ZigObject,
   1780     elf_file: *Elf,
   1781     pt: Zcu.PerThread,
   1782     exported: Zcu.Exported,
   1783     export_indices: []const u32,
   1784 ) link.File.UpdateExportsError!void {
   1785     const tracy = trace(@src());
   1786     defer tracy.end();
   1787 
   1788     const mod = pt.zcu;
   1789     const gpa = elf_file.base.comp.gpa;
   1790     const metadata = switch (exported) {
   1791         .nav => |nav| blk: {
   1792             _ = try self.getOrCreateMetadataForNav(elf_file, nav);
   1793             break :blk self.navs.getPtr(nav).?;
   1794         },
   1795         .uav => |uav| self.uavs.getPtr(uav) orelse blk: {
   1796             const first_exp = mod.all_exports.items[export_indices[0]];
   1797             const res = try self.lowerUav(elf_file, pt, uav, .none, first_exp.src);
   1798             switch (res) {
   1799                 .mcv => {},
   1800                 .fail => |em| {
   1801                     // TODO maybe it's enough to return an error here and let Zcu.processExportsInner
   1802                     // handle the error?
   1803                     try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
   1804                     mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
   1805                     return;
   1806                 },
   1807             }
   1808             break :blk self.uavs.getPtr(uav).?;
   1809         },
   1810     };
   1811     const sym_index = metadata.symbol_index;
   1812     const esym_index = self.symbol(sym_index).esym_index;
   1813     const esym = self.symtab.items(.elf_sym)[esym_index];
   1814     const esym_shndx = self.symtab.items(.shndx)[esym_index];
   1815 
   1816     for (export_indices) |export_idx| {
   1817         const exp = mod.all_exports.items[export_idx];
   1818         if (exp.opts.section.unwrap()) |section_name| {
   1819             if (!section_name.eqlSlice(".text", &mod.intern_pool)) {
   1820                 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
   1821                 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Zcu.ErrorMsg.create(
   1822                     gpa,
   1823                     exp.src,
   1824                     "Unimplemented: ExportOptions.section",
   1825                     .{},
   1826                 ));
   1827                 continue;
   1828             }
   1829         }
   1830         const stb_bits: u8 = switch (exp.opts.linkage) {
   1831             .internal => elf.STB_LOCAL,
   1832             .strong => elf.STB_GLOBAL,
   1833             .weak => elf.STB_WEAK,
   1834             .link_once => {
   1835                 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
   1836                 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Zcu.ErrorMsg.create(
   1837                     gpa,
   1838                     exp.src,
   1839                     "Unimplemented: GlobalLinkage.LinkOnce",
   1840                     .{},
   1841                 ));
   1842                 continue;
   1843             },
   1844         };
   1845         const stt_bits: u8 = @as(u4, @truncate(esym.st_info));
   1846         const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
   1847         const name_off = try self.strtab.insert(gpa, exp_name);
   1848         const global_sym_index = if (metadata.@"export"(self, exp_name)) |exp_index|
   1849             exp_index.*
   1850         else blk: {
   1851             const global_sym_index = try self.getGlobalSymbol(elf_file, exp_name, null);
   1852             try metadata.exports.append(gpa, global_sym_index);
   1853             break :blk global_sym_index;
   1854         };
   1855 
   1856         const value = self.symbol(sym_index).value;
   1857         const global_sym = self.symbol(global_sym_index);
   1858         global_sym.value = value;
   1859         global_sym.flags.weak = exp.opts.linkage == .weak;
   1860         global_sym.version_index = elf_file.default_sym_version;
   1861         global_sym.ref = .{ .index = esym_shndx, .file = self.index };
   1862         const global_esym = &self.symtab.items(.elf_sym)[global_sym.esym_index];
   1863         global_esym.st_value = @intCast(value);
   1864         global_esym.st_shndx = esym.st_shndx;
   1865         global_esym.st_info = (stb_bits << 4) | stt_bits;
   1866         global_esym.st_name = name_off;
   1867         global_esym.st_size = esym.st_size;
   1868         self.symtab.items(.shndx)[global_sym.esym_index] = esym_shndx;
   1869     }
   1870 }
   1871 
   1872 /// Must be called only after a successful call to `updateNav`.
   1873 pub fn updateNavLineNumber(
   1874     self: *ZigObject,
   1875     pt: Zcu.PerThread,
   1876     nav_index: InternPool.Nav.Index,
   1877 ) !void {
   1878     const tracy = trace(@src());
   1879     defer tracy.end();
   1880 
   1881     const ip = &pt.zcu.intern_pool;
   1882     const nav = ip.getNav(nav_index);
   1883 
   1884     log.debug("updateNavLineNumber {}({d})", .{ nav.fqn.fmt(ip), nav_index });
   1885 
   1886     if (self.dwarf) |*dwarf| {
   1887         try dwarf.updateNavLineNumber(pt.zcu, nav_index);
   1888     }
   1889 }
   1890 
   1891 pub fn deleteExport(
   1892     self: *ZigObject,
   1893     elf_file: *Elf,
   1894     exported: Zcu.Exported,
   1895     name: InternPool.NullTerminatedString,
   1896 ) void {
   1897     const metadata = switch (exported) {
   1898         .nav => |nav| self.navs.getPtr(nav),
   1899         .uav => |uav| self.uavs.getPtr(uav),
   1900     } orelse return;
   1901     const mod = elf_file.base.comp.module.?;
   1902     const exp_name = name.toSlice(&mod.intern_pool);
   1903     const esym_index = metadata.@"export"(self, exp_name) orelse return;
   1904     log.debug("deleting export '{s}'", .{exp_name});
   1905     const esym = &self.symtab.items(.elf_sym)[esym_index.*];
   1906     _ = self.globals_lookup.remove(esym.st_name);
   1907     esym.* = Elf.null_sym;
   1908     self.symtab.items(.shndx)[esym_index.*] = elf.SHN_UNDEF;
   1909 }
   1910 
   1911 pub fn getGlobalSymbol(self: *ZigObject, elf_file: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
   1912     _ = lib_name;
   1913     const gpa = elf_file.base.comp.gpa;
   1914     const off = try self.strtab.insert(gpa, name);
   1915     const lookup_gop = try self.globals_lookup.getOrPut(gpa, off);
   1916     if (!lookup_gop.found_existing) {
   1917         lookup_gop.value_ptr.* = try self.newGlobalSymbol(gpa, off);
   1918     }
   1919     return lookup_gop.value_ptr.*;
   1920 }
   1921 
   1922 const max_trampoline_len = 12;
   1923 
   1924 fn trampolineSize(cpu_arch: std.Target.Cpu.Arch) u64 {
   1925     const len = switch (cpu_arch) {
   1926         .x86_64 => 5, // jmp rel32
   1927         else => @panic("TODO implement trampoline size for this CPU arch"),
   1928     };
   1929     comptime assert(len <= max_trampoline_len);
   1930     return len;
   1931 }
   1932 
   1933 fn writeTrampoline(tr_sym: Symbol, target: Symbol, elf_file: *Elf) !void {
   1934     const atom_ptr = tr_sym.atom(elf_file).?;
   1935     const shdr = elf_file.sections.items(.shdr)[atom_ptr.output_section_index];
   1936     const fileoff = shdr.sh_offset + @as(u64, @intCast(atom_ptr.value));
   1937     const source_addr = tr_sym.address(.{}, elf_file);
   1938     const target_addr = target.address(.{ .trampoline = false }, elf_file);
   1939     var buf: [max_trampoline_len]u8 = undefined;
   1940     const out = switch (elf_file.getTarget().cpu.arch) {
   1941         .x86_64 => try x86_64.writeTrampolineCode(source_addr, target_addr, &buf),
   1942         else => @panic("TODO implement write trampoline for this CPU arch"),
   1943     };
   1944     try elf_file.base.file.?.pwriteAll(out, fileoff);
   1945 
   1946     if (elf_file.base.child_pid) |pid| {
   1947         switch (builtin.os.tag) {
   1948             .linux => {
   1949                 var local_vec: [1]std.posix.iovec_const = .{.{
   1950                     .base = out.ptr,
   1951                     .len = out.len,
   1952                 }};
   1953                 var remote_vec: [1]std.posix.iovec_const = .{.{
   1954                     .base = @as([*]u8, @ptrFromInt(@as(usize, @intCast(source_addr)))),
   1955                     .len = out.len,
   1956                 }};
   1957                 const rc = std.os.linux.process_vm_writev(pid, &local_vec, &remote_vec, 0);
   1958                 switch (std.os.linux.E.init(rc)) {
   1959                     .SUCCESS => assert(rc == out.len),
   1960                     else => |errno| log.warn("process_vm_writev failure: {s}", .{@tagName(errno)}),
   1961                 }
   1962             },
   1963             else => return error.HotSwapUnavailableOnHostOperatingSystem,
   1964         }
   1965     }
   1966 }
   1967 
   1968 pub fn asFile(self: *ZigObject) File {
   1969     return .{ .zig_object = self };
   1970 }
   1971 
   1972 pub fn addString(self: *ZigObject, allocator: Allocator, string: []const u8) !u32 {
   1973     return self.strtab.insert(allocator, string);
   1974 }
   1975 
   1976 pub fn getString(self: ZigObject, off: u32) [:0]const u8 {
   1977     return self.strtab.getAssumeExists(off);
   1978 }
   1979 
   1980 fn addAtom(self: *ZigObject, allocator: Allocator) !Atom.Index {
   1981     try self.atoms.ensureUnusedCapacity(allocator, 1);
   1982     try self.atoms_extra.ensureUnusedCapacity(allocator, @sizeOf(Atom.Extra));
   1983     return self.addAtomAssumeCapacity();
   1984 }
   1985 
   1986 fn addAtomAssumeCapacity(self: *ZigObject) Atom.Index {
   1987     const atom_index: Atom.Index = @intCast(self.atoms.items.len);
   1988     const atom_ptr = self.atoms.addOneAssumeCapacity();
   1989     atom_ptr.* = .{
   1990         .file_index = self.index,
   1991         .atom_index = atom_index,
   1992         .extra_index = self.addAtomExtraAssumeCapacity(.{}),
   1993     };
   1994     return atom_index;
   1995 }
   1996 
   1997 pub fn atom(self: *ZigObject, atom_index: Atom.Index) ?*Atom {
   1998     if (atom_index == 0) return null;
   1999     assert(atom_index < self.atoms.items.len);
   2000     return &self.atoms.items[atom_index];
   2001 }
   2002 
   2003 fn addAtomExtra(self: *ZigObject, allocator: Allocator, extra: Atom.Extra) !u32 {
   2004     const fields = @typeInfo(Atom.Extra).Struct.fields;
   2005     try self.atoms_extra.ensureUnusedCapacity(allocator, fields.len);
   2006     return self.addAtomExtraAssumeCapacity(extra);
   2007 }
   2008 
   2009 fn addAtomExtraAssumeCapacity(self: *ZigObject, extra: Atom.Extra) u32 {
   2010     const index = @as(u32, @intCast(self.atoms_extra.items.len));
   2011     const fields = @typeInfo(Atom.Extra).Struct.fields;
   2012     inline for (fields) |field| {
   2013         self.atoms_extra.appendAssumeCapacity(switch (field.type) {
   2014             u32 => @field(extra, field.name),
   2015             else => @compileError("bad field type"),
   2016         });
   2017     }
   2018     return index;
   2019 }
   2020 
   2021 pub fn atomExtra(self: ZigObject, index: u32) Atom.Extra {
   2022     const fields = @typeInfo(Atom.Extra).Struct.fields;
   2023     var i: usize = index;
   2024     var result: Atom.Extra = undefined;
   2025     inline for (fields) |field| {
   2026         @field(result, field.name) = switch (field.type) {
   2027             u32 => self.atoms_extra.items[i],
   2028             else => @compileError("bad field type"),
   2029         };
   2030         i += 1;
   2031     }
   2032     return result;
   2033 }
   2034 
   2035 pub fn setAtomExtra(self: *ZigObject, index: u32, extra: Atom.Extra) void {
   2036     assert(index > 0);
   2037     const fields = @typeInfo(Atom.Extra).Struct.fields;
   2038     inline for (fields, 0..) |field, i| {
   2039         self.atoms_extra.items[index + i] = switch (field.type) {
   2040             u32 => @field(extra, field.name),
   2041             else => @compileError("bad field type"),
   2042         };
   2043     }
   2044 }
   2045 
   2046 inline fn isGlobal(index: Symbol.Index) bool {
   2047     return index & global_symbol_bit != 0;
   2048 }
   2049 
   2050 pub fn symbol(self: *ZigObject, index: Symbol.Index) *Symbol {
   2051     const actual_index = index & symbol_mask;
   2052     if (isGlobal(index)) return &self.symbols.items[self.global_symbols.items[actual_index]];
   2053     return &self.symbols.items[self.local_symbols.items[actual_index]];
   2054 }
   2055 
   2056 pub fn resolveSymbol(self: ZigObject, index: Symbol.Index, elf_file: *Elf) Elf.Ref {
   2057     if (isGlobal(index)) {
   2058         const resolv = self.symbols_resolver.items[index & symbol_mask];
   2059         return elf_file.resolver.get(resolv).?;
   2060     }
   2061     return .{ .index = index, .file = self.index };
   2062 }
   2063 
   2064 fn addSymbol(self: *ZigObject, allocator: Allocator) !Symbol.Index {
   2065     try self.symbols.ensureUnusedCapacity(allocator, 1);
   2066     return self.addSymbolAssumeCapacity();
   2067 }
   2068 
   2069 fn addSymbolAssumeCapacity(self: *ZigObject) Symbol.Index {
   2070     const index: Symbol.Index = @intCast(self.symbols.items.len);
   2071     self.symbols.appendAssumeCapacity(.{ .file_index = self.index });
   2072     return index;
   2073 }
   2074 
   2075 pub fn addSymbolExtra(self: *ZigObject, allocator: Allocator, extra: Symbol.Extra) !u32 {
   2076     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   2077     try self.symbols_extra.ensureUnusedCapacity(allocator, fields.len);
   2078     return self.addSymbolExtraAssumeCapacity(extra);
   2079 }
   2080 
   2081 pub fn addSymbolExtraAssumeCapacity(self: *ZigObject, extra: Symbol.Extra) u32 {
   2082     const index = @as(u32, @intCast(self.symbols_extra.items.len));
   2083     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   2084     inline for (fields) |field| {
   2085         self.symbols_extra.appendAssumeCapacity(switch (field.type) {
   2086             u32 => @field(extra, field.name),
   2087             else => @compileError("bad field type"),
   2088         });
   2089     }
   2090     return index;
   2091 }
   2092 
   2093 pub fn symbolExtra(self: *ZigObject, index: u32) Symbol.Extra {
   2094     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   2095     var i: usize = index;
   2096     var result: Symbol.Extra = undefined;
   2097     inline for (fields) |field| {
   2098         @field(result, field.name) = switch (field.type) {
   2099             u32 => self.symbols_extra.items[i],
   2100             else => @compileError("bad field type"),
   2101         };
   2102         i += 1;
   2103     }
   2104     return result;
   2105 }
   2106 
   2107 pub fn setSymbolExtra(self: *ZigObject, index: u32, extra: Symbol.Extra) void {
   2108     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   2109     inline for (fields, 0..) |field, i| {
   2110         self.symbols_extra.items[index + i] = switch (field.type) {
   2111             u32 => @field(extra, field.name),
   2112             else => @compileError("bad field type"),
   2113         };
   2114     }
   2115 }
   2116 
   2117 pub fn fmtSymtab(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatSymtab) {
   2118     return .{ .data = .{
   2119         .self = self,
   2120         .elf_file = elf_file,
   2121     } };
   2122 }
   2123 
   2124 const FormatContext = struct {
   2125     self: *ZigObject,
   2126     elf_file: *Elf,
   2127 };
   2128 
   2129 fn formatSymtab(
   2130     ctx: FormatContext,
   2131     comptime unused_fmt_string: []const u8,
   2132     options: std.fmt.FormatOptions,
   2133     writer: anytype,
   2134 ) !void {
   2135     _ = unused_fmt_string;
   2136     _ = options;
   2137     const self = ctx.self;
   2138     const elf_file = ctx.elf_file;
   2139     try writer.writeAll("  locals\n");
   2140     for (self.local_symbols.items) |index| {
   2141         const local = self.symbols.items[index];
   2142         try writer.print("    {}\n", .{local.fmt(elf_file)});
   2143     }
   2144     try writer.writeAll("  globals\n");
   2145     for (ctx.self.global_symbols.items) |index| {
   2146         const global = self.symbols.items[index];
   2147         try writer.print("    {}\n", .{global.fmt(elf_file)});
   2148     }
   2149 }
   2150 
   2151 pub fn fmtAtoms(self: *ZigObject, elf_file: *Elf) std.fmt.Formatter(formatAtoms) {
   2152     return .{ .data = .{
   2153         .self = self,
   2154         .elf_file = elf_file,
   2155     } };
   2156 }
   2157 
   2158 fn formatAtoms(
   2159     ctx: FormatContext,
   2160     comptime unused_fmt_string: []const u8,
   2161     options: std.fmt.FormatOptions,
   2162     writer: anytype,
   2163 ) !void {
   2164     _ = unused_fmt_string;
   2165     _ = options;
   2166     try writer.writeAll("  atoms\n");
   2167     for (ctx.self.atoms_indexes.items) |atom_index| {
   2168         const atom_ptr = ctx.self.atom(atom_index) orelse continue;
   2169         try writer.print("    {}\n", .{atom_ptr.fmt(ctx.elf_file)});
   2170     }
   2171 }
   2172 
   2173 const ElfSym = struct {
   2174     elf_sym: elf.Elf64_Sym,
   2175     shndx: u32 = elf.SHN_UNDEF,
   2176 };
   2177 
   2178 const LazySymbolMetadata = struct {
   2179     const State = enum { unused, pending_flush, flushed };
   2180     text_symbol_index: Symbol.Index = undefined,
   2181     rodata_symbol_index: Symbol.Index = undefined,
   2182     text_state: State = .unused,
   2183     rodata_state: State = .unused,
   2184 };
   2185 
   2186 const AvMetadata = struct {
   2187     symbol_index: Symbol.Index,
   2188     /// A list of all exports aliases of this Av.
   2189     exports: std.ArrayListUnmanaged(Symbol.Index) = .{},
   2190     /// Set to true if the AV has been initialized and allocated.
   2191     allocated: bool = false,
   2192 
   2193     fn @"export"(m: AvMetadata, zig_object: *ZigObject, name: []const u8) ?*u32 {
   2194         for (m.exports.items) |*exp| {
   2195             const exp_name = zig_object.getString(zig_object.symbol(exp.*).name_offset);
   2196             if (mem.eql(u8, name, exp_name)) return exp;
   2197         }
   2198         return null;
   2199     }
   2200 };
   2201 
   2202 fn checkNavAllocated(pt: Zcu.PerThread, index: InternPool.Nav.Index, meta: AvMetadata) void {
   2203     if (!meta.allocated) {
   2204         const zcu = pt.zcu;
   2205         const ip = &zcu.intern_pool;
   2206         const nav = ip.getNav(index);
   2207         log.err("NAV {}({d}) assigned symbol {d} but not allocated!", .{
   2208             nav.fqn.fmt(ip),
   2209             index,
   2210             meta.symbol_index,
   2211         });
   2212     }
   2213 }
   2214 
   2215 fn checkUavAllocated(pt: Zcu.PerThread, index: InternPool.Index, meta: AvMetadata) void {
   2216     if (!meta.allocated) {
   2217         const zcu = pt.zcu;
   2218         const uav = Value.fromInterned(index);
   2219         const ty = uav.typeOf(zcu);
   2220         log.err("UAV {}({d}) assigned symbol {d} but not allocated!", .{
   2221             ty.fmt(pt),
   2222             index,
   2223             meta.symbol_index,
   2224         });
   2225     }
   2226 }
   2227 
   2228 const TlsVariable = struct {
   2229     symbol_index: Symbol.Index,
   2230     code: []const u8 = &[0]u8{},
   2231 
   2232     fn deinit(tlv: *TlsVariable, allocator: Allocator) void {
   2233         allocator.free(tlv.code);
   2234     }
   2235 };
   2236 
   2237 const AtomList = std.ArrayListUnmanaged(Atom.Index);
   2238 const NavTable = std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, AvMetadata);
   2239 const UavTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, AvMetadata);
   2240 const LazySymbolTable = std.AutoArrayHashMapUnmanaged(InternPool.Index, LazySymbolMetadata);
   2241 const TlsTable = std.AutoArrayHashMapUnmanaged(Atom.Index, TlsVariable);
   2242 
   2243 const x86_64 = struct {
   2244     fn writeTrampolineCode(source_addr: i64, target_addr: i64, buf: *[max_trampoline_len]u8) ![]u8 {
   2245         const disp = @as(i64, @intCast(target_addr)) - source_addr - 5;
   2246         var bytes = [_]u8{
   2247             0xe9, 0x00, 0x00, 0x00, 0x00, // jmp rel32
   2248         };
   2249         assert(bytes.len == trampolineSize(.x86_64));
   2250         mem.writeInt(i32, bytes[1..][0..4], @intCast(disp), .little);
   2251         @memcpy(buf[0..bytes.len], &bytes);
   2252         return buf[0..bytes.len];
   2253     }
   2254 };
   2255 
   2256 const assert = std.debug.assert;
   2257 const build_options = @import("build_options");
   2258 const builtin = @import("builtin");
   2259 const codegen = @import("../../codegen.zig");
   2260 const elf = std.elf;
   2261 const link = @import("../../link.zig");
   2262 const log = std.log.scoped(.link);
   2263 const mem = std.mem;
   2264 const relocation = @import("relocation.zig");
   2265 const target_util = @import("../../target.zig");
   2266 const trace = @import("../../tracy.zig").trace;
   2267 const std = @import("std");
   2268 
   2269 const Air = @import("../../Air.zig");
   2270 const Allocator = std.mem.Allocator;
   2271 const Archive = @import("Archive.zig");
   2272 const Atom = @import("Atom.zig");
   2273 const Dwarf = @import("../Dwarf.zig");
   2274 const Elf = @import("../Elf.zig");
   2275 const File = @import("file.zig").File;
   2276 const InternPool = @import("../../InternPool.zig");
   2277 const Liveness = @import("../../Liveness.zig");
   2278 const Zcu = @import("../../Zcu.zig");
   2279 const Object = @import("Object.zig");
   2280 const Symbol = @import("Symbol.zig");
   2281 const StringTable = @import("../StringTable.zig");
   2282 const Type = @import("../../Type.zig");
   2283 const Value = @import("../../Value.zig");
   2284 const AnalUnit = InternPool.AnalUnit;
   2285 const ZigObject = @This();