zig

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

blob 786f5eac (221787B) - Raw


      1 base: link.File,
      2 
      3 ptr_width: PtrWidth,
      4 
      5 /// If this is not null, an object file is created by LLVM and linked with LLD afterwards.
      6 llvm_object: ?*LlvmObject = null,
      7 
      8 /// A list of all input files.
      9 /// Index of each input file also encodes the priority or precedence of one input file
     10 /// over another.
     11 files: std.MultiArrayList(File.Entry) = .{},
     12 zig_object_index: ?File.Index = null,
     13 linker_defined_index: ?File.Index = null,
     14 objects: std.ArrayListUnmanaged(File.Index) = .{},
     15 shared_objects: std.ArrayListUnmanaged(File.Index) = .{},
     16 
     17 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
     18 /// Same order as in the file.
     19 shdrs: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
     20 /// Given index to a section, pulls index of containing phdr if any.
     21 phdr_to_shdr_table: std.AutoHashMapUnmanaged(u16, u16) = .{},
     22 /// File offset into the shdr table.
     23 shdr_table_offset: ?u64 = null,
     24 /// Table of lists of atoms per output section.
     25 /// This table is not used to track incrementally generated atoms.
     26 output_sections: std.AutoArrayHashMapUnmanaged(u16, std.ArrayListUnmanaged(Atom.Index)) = .{},
     27 
     28 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
     29 /// Same order as in the file.
     30 phdrs: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
     31 
     32 /// Tracked loadable segments during incremental linking.
     33 /// The index into the program headers of a PT_LOAD program header with Read and Execute flags
     34 phdr_zig_load_re_index: ?u16 = null,
     35 /// The index into the program headers of the global offset table.
     36 /// It needs PT_LOAD and Read flags.
     37 phdr_zig_got_index: ?u16 = null,
     38 /// The index into the program headers of a PT_LOAD program header with Read flag
     39 phdr_zig_load_ro_index: ?u16 = null,
     40 /// The index into the program headers of a PT_LOAD program header with Write flag
     41 phdr_zig_load_rw_index: ?u16 = null,
     42 /// The index into the program headers of a PT_LOAD program header with zerofill data.
     43 phdr_zig_load_zerofill_index: ?u16 = null,
     44 
     45 /// Special program headers
     46 /// PT_PHDR
     47 phdr_table_index: ?u16 = null,
     48 /// PT_LOAD for PHDR table
     49 /// We add this special load segment to ensure the EHDR and PHDR table are always
     50 /// loaded into memory.
     51 phdr_table_load_index: ?u16 = null,
     52 /// PT_INTERP
     53 phdr_interp_index: ?u16 = null,
     54 /// PT_DYNAMIC
     55 phdr_dynamic_index: ?u16 = null,
     56 /// PT_GNU_EH_FRAME
     57 phdr_gnu_eh_frame_index: ?u16 = null,
     58 /// PT_GNU_STACK
     59 phdr_gnu_stack_index: ?u16 = null,
     60 /// PT_TLS
     61 /// TODO I think ELF permits multiple TLS segments but for now, assume one per file.
     62 phdr_tls_index: ?u16 = null,
     63 
     64 entry_index: ?Symbol.Index = null,
     65 page_size: u32,
     66 default_sym_version: elf.Elf64_Versym,
     67 
     68 /// .shstrtab buffer
     69 shstrtab: std.ArrayListUnmanaged(u8) = .{},
     70 /// .symtab buffer
     71 symtab: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
     72 /// .strtab buffer
     73 strtab: std.ArrayListUnmanaged(u8) = .{},
     74 /// Dynamic symbol table. Only populated and emitted when linking dynamically.
     75 dynsym: DynsymSection = .{},
     76 /// .dynstrtab buffer
     77 dynstrtab: std.ArrayListUnmanaged(u8) = .{},
     78 /// Version symbol table. Only populated and emitted when linking dynamically.
     79 versym: std.ArrayListUnmanaged(elf.Elf64_Versym) = .{},
     80 /// .verneed section
     81 verneed: VerneedSection = .{},
     82 /// .got section
     83 got: GotSection = .{},
     84 /// .rela.dyn section
     85 rela_dyn: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
     86 /// .dynamic section
     87 dynamic: DynamicSection = .{},
     88 /// .hash section
     89 hash: HashSection = .{},
     90 /// .gnu.hash section
     91 gnu_hash: GnuHashSection = .{},
     92 /// .plt section
     93 plt: PltSection = .{},
     94 /// .got.plt section
     95 got_plt: GotPltSection = .{},
     96 /// .plt.got section
     97 plt_got: PltGotSection = .{},
     98 /// .copyrel section
     99 copy_rel: CopyRelSection = .{},
    100 /// .rela.plt section
    101 rela_plt: std.ArrayListUnmanaged(elf.Elf64_Rela) = .{},
    102 /// .got.zig section
    103 zig_got: ZigGotSection = .{},
    104 
    105 /// Tracked section headers with incremental updates to Zig object.
    106 /// .rela.* sections are only used when emitting a relocatable object file.
    107 zig_text_section_index: ?u16 = null,
    108 zig_text_rela_section_index: ?u16 = null,
    109 zig_data_rel_ro_section_index: ?u16 = null,
    110 zig_data_rel_ro_rela_section_index: ?u16 = null,
    111 zig_data_section_index: ?u16 = null,
    112 zig_data_rela_section_index: ?u16 = null,
    113 zig_bss_section_index: ?u16 = null,
    114 zig_got_section_index: ?u16 = null,
    115 
    116 debug_info_section_index: ?u16 = null,
    117 debug_abbrev_section_index: ?u16 = null,
    118 debug_str_section_index: ?u16 = null,
    119 debug_aranges_section_index: ?u16 = null,
    120 debug_line_section_index: ?u16 = null,
    121 
    122 copy_rel_section_index: ?u16 = null,
    123 dynamic_section_index: ?u16 = null,
    124 dynstrtab_section_index: ?u16 = null,
    125 dynsymtab_section_index: ?u16 = null,
    126 eh_frame_section_index: ?u16 = null,
    127 eh_frame_hdr_section_index: ?u16 = null,
    128 hash_section_index: ?u16 = null,
    129 gnu_hash_section_index: ?u16 = null,
    130 got_section_index: ?u16 = null,
    131 got_plt_section_index: ?u16 = null,
    132 interp_section_index: ?u16 = null,
    133 plt_section_index: ?u16 = null,
    134 plt_got_section_index: ?u16 = null,
    135 rela_dyn_section_index: ?u16 = null,
    136 rela_plt_section_index: ?u16 = null,
    137 versym_section_index: ?u16 = null,
    138 verneed_section_index: ?u16 = null,
    139 
    140 shstrtab_section_index: ?u16 = null,
    141 strtab_section_index: ?u16 = null,
    142 symtab_section_index: ?u16 = null,
    143 
    144 // Linker-defined symbols
    145 dynamic_index: ?Symbol.Index = null,
    146 ehdr_start_index: ?Symbol.Index = null,
    147 init_array_start_index: ?Symbol.Index = null,
    148 init_array_end_index: ?Symbol.Index = null,
    149 fini_array_start_index: ?Symbol.Index = null,
    150 fini_array_end_index: ?Symbol.Index = null,
    151 preinit_array_start_index: ?Symbol.Index = null,
    152 preinit_array_end_index: ?Symbol.Index = null,
    153 got_index: ?Symbol.Index = null,
    154 plt_index: ?Symbol.Index = null,
    155 end_index: ?Symbol.Index = null,
    156 gnu_eh_frame_hdr_index: ?Symbol.Index = null,
    157 dso_handle_index: ?Symbol.Index = null,
    158 rela_iplt_start_index: ?Symbol.Index = null,
    159 rela_iplt_end_index: ?Symbol.Index = null,
    160 start_stop_indexes: std.ArrayListUnmanaged(u32) = .{},
    161 
    162 /// An array of symbols parsed across all input files.
    163 symbols: std.ArrayListUnmanaged(Symbol) = .{},
    164 symbols_extra: std.ArrayListUnmanaged(u32) = .{},
    165 symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .{},
    166 
    167 resolver: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index) = .{},
    168 
    169 has_text_reloc: bool = false,
    170 num_ifunc_dynrelocs: usize = 0,
    171 
    172 error_flags: link.File.ErrorFlags = link.File.ErrorFlags{},
    173 misc_errors: std.ArrayListUnmanaged(link.File.ErrorMsg) = .{},
    174 
    175 /// List of atoms that are owned directly by the linker.
    176 atoms: std.ArrayListUnmanaged(Atom) = .{},
    177 
    178 /// Table of last atom index in a section and matching atom free list if any.
    179 last_atom_and_free_list_table: LastAtomAndFreeListTable = .{},
    180 
    181 comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
    182 comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
    183 comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
    184 
    185 /// Global string table used to provide quick access to global symbol resolvers
    186 /// such as `resolver` and `comdat_groups_table`.
    187 strings: StringTable = .{},
    188 
    189 /// When allocating, the ideal_capacity is calculated by
    190 /// actual_capacity + (actual_capacity / ideal_factor)
    191 const ideal_factor = 3;
    192 
    193 /// In order for a slice of bytes to be considered eligible to keep metadata pointing at
    194 /// it as a possible place to put new symbols, it must have enough room for this many bytes
    195 /// (plus extra for reserved capacity).
    196 const minimum_atom_size = 64;
    197 pub const min_text_capacity = padToIdeal(minimum_atom_size);
    198 
    199 pub const PtrWidth = enum { p32, p64 };
    200 
    201 pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Options) !*Elf {
    202     assert(options.target.ofmt == .elf);
    203 
    204     const self = try createEmpty(allocator, options);
    205     errdefer self.base.destroy();
    206 
    207     const is_obj = options.output_mode == .Obj;
    208     const is_obj_or_ar = is_obj or (options.output_mode == .Lib and options.link_mode == .Static);
    209 
    210     if (options.use_llvm) {
    211         const use_lld = build_options.have_llvm and self.base.options.use_lld;
    212         if (use_lld) return self;
    213 
    214         if (options.module != null) {
    215             self.base.intermediary_basename = try std.fmt.allocPrint(allocator, "{s}{s}", .{
    216                 sub_path, options.target.ofmt.fileExt(options.target.cpu.arch),
    217             });
    218         }
    219         if (is_obj) {
    220             // TODO until we implement -r option, we don't want to open a file at this stage.
    221             return self;
    222         }
    223     }
    224     errdefer if (self.base.intermediary_basename) |path| allocator.free(path);
    225 
    226     self.base.file = try options.emit.?.directory.handle.createFile(sub_path, .{
    227         .truncate = false,
    228         .read = true,
    229         .mode = link.determineMode(options),
    230     });
    231 
    232     // Index 0 is always a null symbol.
    233     try self.symbols.append(allocator, .{});
    234     // Index 0 is always a null symbol.
    235     try self.symbols_extra.append(allocator, 0);
    236     // Allocate atom index 0 to null atom
    237     try self.atoms.append(allocator, .{});
    238     // Append null file at index 0
    239     try self.files.append(allocator, .null);
    240     // Append null byte to string tables
    241     try self.shstrtab.append(allocator, 0);
    242     try self.strtab.append(allocator, 0);
    243     // There must always be a null shdr in index 0
    244     _ = try self.addSection(.{ .name = "" });
    245     // Append null symbol in output symtab
    246     try self.symtab.append(allocator, null_sym);
    247 
    248     if (!is_obj_or_ar) {
    249         try self.dynstrtab.append(allocator, 0);
    250 
    251         // Initialize PT_PHDR program header
    252         const p_align: u16 = switch (self.ptr_width) {
    253             .p32 => @alignOf(elf.Elf32_Phdr),
    254             .p64 => @alignOf(elf.Elf64_Phdr),
    255         };
    256         const image_base = self.calcImageBase();
    257         const ehsize: u64 = switch (self.ptr_width) {
    258             .p32 => @sizeOf(elf.Elf32_Ehdr),
    259             .p64 => @sizeOf(elf.Elf64_Ehdr),
    260         };
    261         const phsize: u64 = switch (self.ptr_width) {
    262             .p32 => @sizeOf(elf.Elf32_Phdr),
    263             .p64 => @sizeOf(elf.Elf64_Phdr),
    264         };
    265         const max_nphdrs = comptime getMaxNumberOfPhdrs();
    266         const reserved: u64 = mem.alignForward(u64, padToIdeal(max_nphdrs * phsize), self.page_size);
    267         self.phdr_table_index = try self.addPhdr(.{
    268             .type = elf.PT_PHDR,
    269             .flags = elf.PF_R,
    270             .@"align" = p_align,
    271             .addr = image_base + ehsize,
    272             .offset = ehsize,
    273             .filesz = reserved,
    274             .memsz = reserved,
    275         });
    276         self.phdr_table_load_index = try self.addPhdr(.{
    277             .type = elf.PT_LOAD,
    278             .flags = elf.PF_R,
    279             .@"align" = self.page_size,
    280             .addr = image_base,
    281             .offset = 0,
    282             .filesz = reserved + ehsize,
    283             .memsz = reserved + ehsize,
    284         });
    285     }
    286 
    287     if (options.module != null and !options.use_llvm) {
    288         const index = @as(File.Index, @intCast(try self.files.addOne(allocator)));
    289         self.files.set(index, .{ .zig_object = .{
    290             .index = index,
    291             .path = try std.fmt.allocPrint(self.base.allocator, "{s}.o", .{std.fs.path.stem(
    292                 options.module.?.main_mod.root_src_path,
    293             )}),
    294         } });
    295         self.zig_object_index = index;
    296         try self.zigObjectPtr().?.init(self);
    297         try self.initMetadata();
    298     }
    299 
    300     return self;
    301 }
    302 
    303 pub fn createEmpty(gpa: Allocator, options: link.Options) !*Elf {
    304     const ptr_width: PtrWidth = switch (options.target.ptrBitWidth()) {
    305         0...32 => .p32,
    306         33...64 => .p64,
    307         else => return error.UnsupportedELFArchitecture,
    308     };
    309     const self = try gpa.create(Elf);
    310     errdefer gpa.destroy(self);
    311 
    312     const page_size: u32 = switch (options.target.cpu.arch) {
    313         .powerpc64le => 0x10000,
    314         .sparc64 => 0x2000,
    315         else => 0x1000,
    316     };
    317     const is_dyn_lib = options.output_mode == .Lib and options.link_mode == .Dynamic;
    318     const default_sym_version: elf.Elf64_Versym = if (is_dyn_lib or options.rdynamic)
    319         elf.VER_NDX_GLOBAL
    320     else
    321         elf.VER_NDX_LOCAL;
    322 
    323     self.* = .{
    324         .base = .{
    325             .tag = .elf,
    326             .options = options,
    327             .allocator = gpa,
    328             .file = null,
    329         },
    330         .ptr_width = ptr_width,
    331         .page_size = page_size,
    332         .default_sym_version = default_sym_version,
    333     };
    334     if (options.use_llvm and options.module != null) {
    335         self.llvm_object = try LlvmObject.create(gpa, options);
    336     }
    337 
    338     return self;
    339 }
    340 
    341 pub fn deinit(self: *Elf) void {
    342     const gpa = self.base.allocator;
    343 
    344     if (self.llvm_object) |llvm_object| llvm_object.destroy(gpa);
    345 
    346     for (self.files.items(.tags), self.files.items(.data)) |tag, *data| switch (tag) {
    347         .null => {},
    348         .zig_object => data.zig_object.deinit(gpa),
    349         .linker_defined => data.linker_defined.deinit(gpa),
    350         .object => data.object.deinit(gpa),
    351         .shared_object => data.shared_object.deinit(gpa),
    352     };
    353     self.files.deinit(gpa);
    354     self.objects.deinit(gpa);
    355     self.shared_objects.deinit(gpa);
    356 
    357     self.shdrs.deinit(gpa);
    358     self.phdr_to_shdr_table.deinit(gpa);
    359     self.phdrs.deinit(gpa);
    360     for (self.output_sections.values()) |*list| {
    361         list.deinit(gpa);
    362     }
    363     self.output_sections.deinit(gpa);
    364     self.shstrtab.deinit(gpa);
    365     self.symtab.deinit(gpa);
    366     self.strtab.deinit(gpa);
    367     self.symbols.deinit(gpa);
    368     self.symbols_extra.deinit(gpa);
    369     self.symbols_free_list.deinit(gpa);
    370     self.resolver.deinit(gpa);
    371     self.start_stop_indexes.deinit(gpa);
    372 
    373     self.atoms.deinit(gpa);
    374     for (self.last_atom_and_free_list_table.values()) |*value| {
    375         value.free_list.deinit(gpa);
    376     }
    377     self.last_atom_and_free_list_table.deinit(gpa);
    378 
    379     self.misc_errors.deinit(gpa);
    380     self.comdat_groups.deinit(gpa);
    381     self.comdat_groups_owners.deinit(gpa);
    382     self.comdat_groups_table.deinit(gpa);
    383     self.strings.deinit(gpa);
    384 
    385     self.got.deinit(gpa);
    386     self.plt.deinit(gpa);
    387     self.plt_got.deinit(gpa);
    388     self.dynsym.deinit(gpa);
    389     self.dynstrtab.deinit(gpa);
    390     self.dynamic.deinit(gpa);
    391     self.hash.deinit(gpa);
    392     self.versym.deinit(gpa);
    393     self.verneed.deinit(gpa);
    394     self.copy_rel.deinit(gpa);
    395     self.rela_dyn.deinit(gpa);
    396     self.rela_plt.deinit(gpa);
    397 }
    398 
    399 pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
    400     assert(self.llvm_object == null);
    401     return self.zigObjectPtr().?.getDeclVAddr(self, decl_index, reloc_info);
    402 }
    403 
    404 pub fn lowerAnonDecl(
    405     self: *Elf,
    406     decl_val: InternPool.Index,
    407     explicit_alignment: InternPool.Alignment,
    408     src_loc: Module.SrcLoc,
    409 ) !codegen.Result {
    410     return self.zigObjectPtr().?.lowerAnonDecl(self, decl_val, explicit_alignment, src_loc);
    411 }
    412 
    413 pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
    414     assert(self.llvm_object == null);
    415     return self.zigObjectPtr().?.getAnonDeclVAddr(self, decl_val, reloc_info);
    416 }
    417 
    418 /// Returns end pos of collision, if any.
    419 fn detectAllocCollision(self: *Elf, start: u64, size: u64) ?u64 {
    420     const small_ptr = self.ptr_width == .p32;
    421     const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);
    422     if (start < ehdr_size)
    423         return ehdr_size;
    424 
    425     const end = start + padToIdeal(size);
    426 
    427     if (self.shdr_table_offset) |off| {
    428         const shdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Shdr) else @sizeOf(elf.Elf64_Shdr);
    429         const tight_size = self.shdrs.items.len * shdr_size;
    430         const increased_size = padToIdeal(tight_size);
    431         const test_end = off +| increased_size;
    432         if (end > off and start < test_end) {
    433             return test_end;
    434         }
    435     }
    436 
    437     for (self.shdrs.items) |shdr| {
    438         if (shdr.sh_type == elf.SHT_NOBITS) continue;
    439         const increased_size = padToIdeal(shdr.sh_size);
    440         const test_end = shdr.sh_offset +| increased_size;
    441         if (end > shdr.sh_offset and start < test_end) {
    442             return test_end;
    443         }
    444     }
    445 
    446     for (self.phdrs.items) |phdr| {
    447         if (phdr.p_type != elf.PT_LOAD) continue;
    448         const increased_size = padToIdeal(phdr.p_filesz);
    449         const test_end = phdr.p_offset +| increased_size;
    450         if (end > phdr.p_offset and start < test_end) {
    451             return test_end;
    452         }
    453     }
    454 
    455     return null;
    456 }
    457 
    458 fn allocatedSize(self: *Elf, start: u64) u64 {
    459     if (start == 0) return 0;
    460     var min_pos: u64 = std.math.maxInt(u64);
    461     if (self.shdr_table_offset) |off| {
    462         if (off > start and off < min_pos) min_pos = off;
    463     }
    464     for (self.shdrs.items) |section| {
    465         if (section.sh_offset <= start) continue;
    466         if (section.sh_offset < min_pos) min_pos = section.sh_offset;
    467     }
    468     for (self.phdrs.items) |phdr| {
    469         if (phdr.p_offset <= start) continue;
    470         if (phdr.p_offset < min_pos) min_pos = phdr.p_offset;
    471     }
    472     return min_pos - start;
    473 }
    474 
    475 fn allocatedVirtualSize(self: *Elf, start: u64) u64 {
    476     if (start == 0) return 0;
    477     var min_pos: u64 = std.math.maxInt(u64);
    478     for (self.phdrs.items) |phdr| {
    479         if (phdr.p_vaddr <= start) continue;
    480         if (phdr.p_vaddr < min_pos) min_pos = phdr.p_vaddr;
    481     }
    482     return min_pos - start;
    483 }
    484 
    485 fn findFreeSpace(self: *Elf, object_size: u64, min_alignment: u64) u64 {
    486     var start: u64 = 0;
    487     while (self.detectAllocCollision(start, object_size)) |item_end| {
    488         start = mem.alignForward(u64, item_end, min_alignment);
    489     }
    490     return start;
    491 }
    492 
    493 /// TODO move to ZigObject
    494 pub fn initMetadata(self: *Elf) !void {
    495     const gpa = self.base.allocator;
    496     const ptr_size = self.ptrWidthBytes();
    497     const ptr_bit_width = self.base.options.target.ptrBitWidth();
    498     const is_linux = self.base.options.target.os.tag == .linux;
    499     const zig_object = self.zigObjectPtr().?;
    500 
    501     const fillSection = struct {
    502         fn fillSection(elf_file: *Elf, shdr: *elf.Elf64_Shdr, size: u64, phndx: ?u16) void {
    503             if (elf_file.isRelocatable()) {
    504                 const off = elf_file.findFreeSpace(size, shdr.sh_addralign);
    505                 shdr.sh_offset = off;
    506                 shdr.sh_size = size;
    507             } else {
    508                 const phdr = elf_file.phdrs.items[phndx.?];
    509                 shdr.sh_addr = phdr.p_vaddr;
    510                 shdr.sh_offset = phdr.p_offset;
    511                 shdr.sh_size = phdr.p_memsz;
    512             }
    513         }
    514     }.fillSection;
    515 
    516     comptime assert(number_of_zig_segments == 5);
    517 
    518     if (!self.isRelocatable()) {
    519         if (self.phdr_zig_load_re_index == null) {
    520             const filesz = self.base.options.program_code_size_hint;
    521             const off = self.findFreeSpace(filesz, self.page_size);
    522             self.phdr_zig_load_re_index = try self.addPhdr(.{
    523                 .type = elf.PT_LOAD,
    524                 .offset = off,
    525                 .filesz = filesz,
    526                 .addr = if (ptr_bit_width >= 32) 0x8000000 else 0x8000,
    527                 .memsz = filesz,
    528                 .@"align" = self.page_size,
    529                 .flags = elf.PF_X | elf.PF_R | elf.PF_W,
    530             });
    531         }
    532 
    533         if (self.phdr_zig_got_index == null) {
    534             // We really only need ptr alignment but since we are using PROGBITS, linux requires
    535             // page align.
    536             const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
    537             const filesz = @as(u64, ptr_size) * self.base.options.symbol_count_hint;
    538             const off = self.findFreeSpace(filesz, alignment);
    539             self.phdr_zig_got_index = try self.addPhdr(.{
    540                 .type = elf.PT_LOAD,
    541                 .offset = off,
    542                 .filesz = filesz,
    543                 .addr = if (ptr_bit_width >= 32) 0x4000000 else 0x4000,
    544                 .memsz = filesz,
    545                 .@"align" = alignment,
    546                 .flags = elf.PF_R | elf.PF_W,
    547             });
    548         }
    549 
    550         if (self.phdr_zig_load_ro_index == null) {
    551             const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
    552             const filesz: u64 = 1024;
    553             const off = self.findFreeSpace(filesz, alignment);
    554             self.phdr_zig_load_ro_index = try self.addPhdr(.{
    555                 .type = elf.PT_LOAD,
    556                 .offset = off,
    557                 .filesz = filesz,
    558                 .addr = if (ptr_bit_width >= 32) 0xc000000 else 0xa000,
    559                 .memsz = filesz,
    560                 .@"align" = alignment,
    561                 .flags = elf.PF_R | elf.PF_W,
    562             });
    563         }
    564 
    565         if (self.phdr_zig_load_rw_index == null) {
    566             const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
    567             const filesz: u64 = 1024;
    568             const off = self.findFreeSpace(filesz, alignment);
    569             self.phdr_zig_load_rw_index = try self.addPhdr(.{
    570                 .type = elf.PT_LOAD,
    571                 .offset = off,
    572                 .filesz = filesz,
    573                 .addr = if (ptr_bit_width >= 32) 0x10000000 else 0xc000,
    574                 .memsz = filesz,
    575                 .@"align" = alignment,
    576                 .flags = elf.PF_R | elf.PF_W,
    577             });
    578         }
    579 
    580         if (self.phdr_zig_load_zerofill_index == null) {
    581             const alignment = if (is_linux) self.page_size else @as(u16, ptr_size);
    582             self.phdr_zig_load_zerofill_index = try self.addPhdr(.{
    583                 .type = elf.PT_LOAD,
    584                 .addr = if (ptr_bit_width >= 32) 0x14000000 else 0xf000,
    585                 .memsz = 1024,
    586                 .@"align" = alignment,
    587                 .flags = elf.PF_R | elf.PF_W,
    588             });
    589         }
    590     }
    591 
    592     if (self.zig_text_section_index == null) {
    593         self.zig_text_section_index = try self.addSection(.{
    594             .name = ".text.zig",
    595             .type = elf.SHT_PROGBITS,
    596             .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
    597             .addralign = 1,
    598             .offset = std.math.maxInt(u64),
    599         });
    600         const shdr = &self.shdrs.items[self.zig_text_section_index.?];
    601         fillSection(self, shdr, self.base.options.program_code_size_hint, self.phdr_zig_load_re_index);
    602         if (self.isRelocatable()) {
    603             try zig_object.addSectionSymbol(self.zig_text_section_index.?, self);
    604             self.zig_text_rela_section_index = try self.addRelaShdr(
    605                 ".rela.text.zig",
    606                 self.zig_text_section_index.?,
    607             );
    608         } else {
    609             try self.phdr_to_shdr_table.putNoClobber(
    610                 gpa,
    611                 self.zig_text_section_index.?,
    612                 self.phdr_zig_load_re_index.?,
    613             );
    614         }
    615         try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_text_section_index.?, .{});
    616     }
    617 
    618     if (self.zig_got_section_index == null and !self.isRelocatable()) {
    619         self.zig_got_section_index = try self.addSection(.{
    620             .name = ".got.zig",
    621             .type = elf.SHT_PROGBITS,
    622             .addralign = ptr_size,
    623             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
    624             .offset = std.math.maxInt(u64),
    625         });
    626         const shdr = &self.shdrs.items[self.zig_got_section_index.?];
    627         const phndx = self.phdr_zig_got_index.?;
    628         const phdr = self.phdrs.items[phndx];
    629         shdr.sh_addr = phdr.p_vaddr;
    630         shdr.sh_offset = phdr.p_offset;
    631         shdr.sh_size = phdr.p_memsz;
    632         try self.phdr_to_shdr_table.putNoClobber(
    633             gpa,
    634             self.zig_got_section_index.?,
    635             self.phdr_zig_got_index.?,
    636         );
    637     }
    638 
    639     if (self.zig_data_rel_ro_section_index == null) {
    640         self.zig_data_rel_ro_section_index = try self.addSection(.{
    641             .name = ".data.rel.ro.zig",
    642             .type = elf.SHT_PROGBITS,
    643             .addralign = 1,
    644             .flags = elf.SHF_ALLOC | elf.SHF_WRITE, // TODO rename this section to .data.rel.ro
    645             .offset = std.math.maxInt(u64),
    646         });
    647         const shdr = &self.shdrs.items[self.zig_data_rel_ro_section_index.?];
    648         fillSection(self, shdr, 1024, self.phdr_zig_load_ro_index);
    649         if (self.isRelocatable()) {
    650             try zig_object.addSectionSymbol(self.zig_data_rel_ro_section_index.?, self);
    651             self.zig_data_rel_ro_rela_section_index = try self.addRelaShdr(
    652                 ".rela.data.rel.ro.zig",
    653                 self.zig_data_rel_ro_section_index.?,
    654             );
    655         } else {
    656             try self.phdr_to_shdr_table.putNoClobber(
    657                 gpa,
    658                 self.zig_data_rel_ro_section_index.?,
    659                 self.phdr_zig_load_ro_index.?,
    660             );
    661         }
    662         try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_rel_ro_section_index.?, .{});
    663     }
    664 
    665     if (self.zig_data_section_index == null) {
    666         self.zig_data_section_index = try self.addSection(.{
    667             .name = ".data.zig",
    668             .type = elf.SHT_PROGBITS,
    669             .addralign = ptr_size,
    670             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
    671             .offset = std.math.maxInt(u64),
    672         });
    673         const shdr = &self.shdrs.items[self.zig_data_section_index.?];
    674         fillSection(self, shdr, 1024, self.phdr_zig_load_rw_index);
    675         if (self.isRelocatable()) {
    676             try zig_object.addSectionSymbol(self.zig_data_section_index.?, self);
    677             self.zig_data_rela_section_index = try self.addRelaShdr(
    678                 ".rela.data.zig",
    679                 self.zig_data_section_index.?,
    680             );
    681         } else {
    682             try self.phdr_to_shdr_table.putNoClobber(
    683                 gpa,
    684                 self.zig_data_section_index.?,
    685                 self.phdr_zig_load_rw_index.?,
    686             );
    687         }
    688         try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_data_section_index.?, .{});
    689     }
    690 
    691     if (self.zig_bss_section_index == null) {
    692         self.zig_bss_section_index = try self.addSection(.{
    693             .name = ".bss.zig",
    694             .type = elf.SHT_NOBITS,
    695             .addralign = ptr_size,
    696             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
    697             .offset = 0,
    698         });
    699         const shdr = &self.shdrs.items[self.zig_bss_section_index.?];
    700         if (self.phdr_zig_load_zerofill_index) |phndx| {
    701             const phdr = self.phdrs.items[phndx];
    702             shdr.sh_addr = phdr.p_vaddr;
    703             shdr.sh_size = phdr.p_memsz;
    704             try self.phdr_to_shdr_table.putNoClobber(gpa, self.zig_bss_section_index.?, phndx);
    705         } else {
    706             try zig_object.addSectionSymbol(self.zig_bss_section_index.?, self);
    707             shdr.sh_size = 1024;
    708         }
    709         try self.last_atom_and_free_list_table.putNoClobber(gpa, self.zig_bss_section_index.?, .{});
    710     }
    711 
    712     if (zig_object.dwarf) |*dw| {
    713         if (self.debug_str_section_index == null) {
    714             assert(dw.strtab.buffer.items.len == 0);
    715             try dw.strtab.buffer.append(gpa, 0);
    716             self.debug_str_section_index = try self.addSection(.{
    717                 .name = ".debug_str",
    718                 .flags = elf.SHF_MERGE | elf.SHF_STRINGS,
    719                 .entsize = 1,
    720                 .type = elf.SHT_PROGBITS,
    721                 .addralign = 1,
    722                 .offset = std.math.maxInt(u64),
    723             });
    724             const shdr = &self.shdrs.items[self.debug_str_section_index.?];
    725             const size = @as(u64, @intCast(dw.strtab.buffer.items.len));
    726             const off = self.findFreeSpace(size, 1);
    727             shdr.sh_offset = off;
    728             shdr.sh_size = size;
    729             zig_object.debug_strtab_dirty = true;
    730         }
    731 
    732         if (self.debug_info_section_index == null) {
    733             self.debug_info_section_index = try self.addSection(.{
    734                 .name = ".debug_info",
    735                 .type = elf.SHT_PROGBITS,
    736                 .addralign = 1,
    737                 .offset = std.math.maxInt(u64),
    738             });
    739             const shdr = &self.shdrs.items[self.debug_info_section_index.?];
    740             const size: u64 = 200;
    741             const off = self.findFreeSpace(size, 1);
    742             shdr.sh_offset = off;
    743             shdr.sh_size = size;
    744             zig_object.debug_info_header_dirty = true;
    745         }
    746 
    747         if (self.debug_abbrev_section_index == null) {
    748             self.debug_abbrev_section_index = try self.addSection(.{
    749                 .name = ".debug_abbrev",
    750                 .type = elf.SHT_PROGBITS,
    751                 .addralign = 1,
    752                 .offset = std.math.maxInt(u64),
    753             });
    754             const shdr = &self.shdrs.items[self.debug_abbrev_section_index.?];
    755             const size: u64 = 128;
    756             const off = self.findFreeSpace(size, 1);
    757             shdr.sh_offset = off;
    758             shdr.sh_size = size;
    759             zig_object.debug_abbrev_section_dirty = true;
    760         }
    761 
    762         if (self.debug_aranges_section_index == null) {
    763             self.debug_aranges_section_index = try self.addSection(.{
    764                 .name = ".debug_aranges",
    765                 .type = elf.SHT_PROGBITS,
    766                 .addralign = 16,
    767                 .offset = std.math.maxInt(u64),
    768             });
    769             const shdr = &self.shdrs.items[self.debug_aranges_section_index.?];
    770             const size: u64 = 160;
    771             const off = self.findFreeSpace(size, 16);
    772             shdr.sh_offset = off;
    773             shdr.sh_size = size;
    774             zig_object.debug_aranges_section_dirty = true;
    775         }
    776 
    777         if (self.debug_line_section_index == null) {
    778             self.debug_line_section_index = try self.addSection(.{
    779                 .name = ".debug_line",
    780                 .type = elf.SHT_PROGBITS,
    781                 .addralign = 1,
    782                 .offset = std.math.maxInt(u64),
    783             });
    784             const shdr = &self.shdrs.items[self.debug_line_section_index.?];
    785             const size: u64 = 250;
    786             const off = self.findFreeSpace(size, 1);
    787             shdr.sh_offset = off;
    788             shdr.sh_size = size;
    789             zig_object.debug_line_header_dirty = true;
    790         }
    791     }
    792 }
    793 
    794 pub fn growAllocSection(self: *Elf, shdr_index: u16, needed_size: u64) !void {
    795     const shdr = &self.shdrs.items[shdr_index];
    796     const maybe_phdr = if (self.phdr_to_shdr_table.get(shdr_index)) |phndx| &self.phdrs.items[phndx] else null;
    797     const is_zerofill = shdr.sh_type == elf.SHT_NOBITS;
    798 
    799     if (needed_size > self.allocatedSize(shdr.sh_offset) and !is_zerofill) {
    800         const existing_size = shdr.sh_size;
    801         shdr.sh_size = 0;
    802         // Must move the entire section.
    803         const alignment = if (maybe_phdr) |phdr| phdr.p_align else shdr.sh_addralign;
    804         const new_offset = self.findFreeSpace(needed_size, alignment);
    805 
    806         log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
    807             self.getShString(shdr.sh_name),
    808             new_offset,
    809             new_offset + existing_size,
    810         });
    811 
    812         const amt = try self.base.file.?.copyRangeAll(shdr.sh_offset, self.base.file.?, new_offset, existing_size);
    813         // TODO figure out what to about this error condition - how to communicate it up.
    814         if (amt != existing_size) return error.InputOutput;
    815 
    816         shdr.sh_offset = new_offset;
    817         if (maybe_phdr) |phdr| phdr.p_offset = new_offset;
    818     }
    819 
    820     shdr.sh_size = needed_size;
    821     if (!is_zerofill) {
    822         if (maybe_phdr) |phdr| phdr.p_filesz = needed_size;
    823     }
    824 
    825     if (maybe_phdr) |phdr| {
    826         const mem_capacity = self.allocatedVirtualSize(phdr.p_vaddr);
    827         if (needed_size > mem_capacity) {
    828             var err = try self.addErrorWithNotes(2);
    829             try err.addMsg(self, "fatal linker error: cannot expand load segment phdr({d}) in virtual memory", .{
    830                 self.phdr_to_shdr_table.get(shdr_index).?,
    831             });
    832             try err.addNote(self, "TODO: emit relocations to memory locations in self-hosted backends", .{});
    833             try err.addNote(self, "as a workaround, try increasing pre-allocated virtual memory of each segment", .{});
    834         }
    835 
    836         phdr.p_memsz = needed_size;
    837     }
    838 
    839     self.markDirty(shdr_index);
    840 }
    841 
    842 pub fn growNonAllocSection(
    843     self: *Elf,
    844     shdr_index: u16,
    845     needed_size: u64,
    846     min_alignment: u32,
    847     requires_file_copy: bool,
    848 ) !void {
    849     const shdr = &self.shdrs.items[shdr_index];
    850 
    851     if (needed_size > self.allocatedSize(shdr.sh_offset)) {
    852         const existing_size = shdr.sh_size;
    853         shdr.sh_size = 0;
    854         // Move all the symbols to a new file location.
    855         const new_offset = self.findFreeSpace(needed_size, min_alignment);
    856 
    857         log.debug("new '{s}' file offset 0x{x} to 0x{x}", .{
    858             self.getShString(shdr.sh_name),
    859             new_offset,
    860             new_offset + existing_size,
    861         });
    862 
    863         if (requires_file_copy) {
    864             const amt = try self.base.file.?.copyRangeAll(
    865                 shdr.sh_offset,
    866                 self.base.file.?,
    867                 new_offset,
    868                 existing_size,
    869             );
    870             if (amt != existing_size) return error.InputOutput;
    871         }
    872 
    873         shdr.sh_offset = new_offset;
    874     }
    875 
    876     shdr.sh_size = needed_size;
    877 
    878     self.markDirty(shdr_index);
    879 }
    880 
    881 pub fn markDirty(self: *Elf, shdr_index: u16) void {
    882     const zig_object = self.zigObjectPtr().?;
    883     if (zig_object.dwarf) |_| {
    884         if (self.debug_info_section_index.? == shdr_index) {
    885             zig_object.debug_info_header_dirty = true;
    886         } else if (self.debug_line_section_index.? == shdr_index) {
    887             zig_object.debug_line_header_dirty = true;
    888         } else if (self.debug_abbrev_section_index.? == shdr_index) {
    889             zig_object.debug_abbrev_section_dirty = true;
    890         } else if (self.debug_str_section_index.? == shdr_index) {
    891             zig_object.debug_strtab_dirty = true;
    892         } else if (self.debug_aranges_section_index.? == shdr_index) {
    893             zig_object.debug_aranges_section_dirty = true;
    894         }
    895     }
    896 }
    897 
    898 pub fn flush(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
    899     if (self.base.options.emit == null) {
    900         if (self.llvm_object) |llvm_object| {
    901             try llvm_object.flushModule(comp, prog_node);
    902         }
    903         return;
    904     }
    905     const use_lld = build_options.have_llvm and self.base.options.use_lld;
    906     if (use_lld) {
    907         return self.linkWithLLD(comp, prog_node);
    908     }
    909     try self.flushModule(comp, prog_node);
    910 }
    911 
    912 pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
    913     const tracy = trace(@src());
    914     defer tracy.end();
    915 
    916     if (self.llvm_object) |llvm_object| {
    917         try llvm_object.flushModule(comp, prog_node);
    918 
    919         const use_lld = build_options.have_llvm and self.base.options.use_lld;
    920         if (use_lld) return;
    921     }
    922 
    923     const gpa = self.base.allocator;
    924     var sub_prog_node = prog_node.start("ELF Flush", 0);
    925     sub_prog_node.activate();
    926     defer sub_prog_node.end();
    927 
    928     var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
    929     defer arena_allocator.deinit();
    930     const arena = arena_allocator.allocator();
    931 
    932     const target = self.base.options.target;
    933     const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
    934     const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
    935     const module_obj_path: ?[]const u8 = if (self.base.intermediary_basename) |path| blk: {
    936         if (fs.path.dirname(full_out_path)) |dirname| {
    937             break :blk try fs.path.join(arena, &.{ dirname, path });
    938         } else {
    939             break :blk path;
    940         }
    941     } else null;
    942     const gc_sections = self.base.options.gc_sections orelse false;
    943 
    944     if (self.isObject() and self.zig_object_index == null) {
    945         // TODO this will become -r route I guess. For now, just copy the object file.
    946         assert(self.base.file == null); // TODO uncomment once we implement -r
    947         const the_object_path = blk: {
    948             if (self.base.options.objects.len != 0) {
    949                 break :blk self.base.options.objects[0].path;
    950             }
    951 
    952             if (comp.c_object_table.count() != 0)
    953                 break :blk comp.c_object_table.keys()[0].status.success.object_path;
    954 
    955             if (module_obj_path) |p|
    956                 break :blk p;
    957 
    958             // TODO I think this is unreachable. Audit this situation when solving the above TODO
    959             // regarding eliding redundant object -> object transformations.
    960             return error.NoObjectsToLink;
    961         };
    962         // This can happen when using --enable-cache and using the stage1 backend. In this case
    963         // we can skip the file copy.
    964         if (!mem.eql(u8, the_object_path, full_out_path)) {
    965             try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
    966         }
    967         return;
    968     }
    969 
    970     var csu = try CsuObjects.init(arena, self.base.options, comp);
    971     const compiler_rt_path: ?[]const u8 = blk: {
    972         if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
    973         if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
    974         break :blk null;
    975     };
    976 
    977     // --verbose-link
    978     if (self.base.options.verbose_link) {
    979         var argv = std.ArrayList([]const u8).init(arena);
    980 
    981         try argv.append("zig");
    982         try argv.append("ld");
    983 
    984         try argv.append("-o");
    985         try argv.append(full_out_path);
    986 
    987         if (self.base.options.entry) |entry| {
    988             try argv.append("--entry");
    989             try argv.append(entry);
    990         }
    991 
    992         if (self.base.options.dynamic_linker) |path| {
    993             try argv.append("-dynamic-linker");
    994             try argv.append(path);
    995         }
    996 
    997         if (self.base.options.soname) |name| {
    998             try argv.append("-soname");
    999             try argv.append(name);
   1000         }
   1001 
   1002         for (self.base.options.rpath_list) |rpath| {
   1003             try argv.append("-rpath");
   1004             try argv.append(rpath);
   1005         }
   1006 
   1007         if (self.base.options.each_lib_rpath) {
   1008             for (self.base.options.lib_dirs) |lib_dir_path| {
   1009                 try argv.append("-rpath");
   1010                 try argv.append(lib_dir_path);
   1011             }
   1012             for (self.base.options.objects) |obj| {
   1013                 if (Compilation.classifyFileExt(obj.path) == .shared_library) {
   1014                     const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
   1015                     if (obj.loption) continue;
   1016 
   1017                     try argv.append("-rpath");
   1018                     try argv.append(lib_dir_path);
   1019                 }
   1020             }
   1021         }
   1022 
   1023         if (self.base.options.stack_size_override) |ss| {
   1024             try argv.append("-z");
   1025             try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{ss}));
   1026         }
   1027 
   1028         if (self.base.options.image_base_override) |image_base| {
   1029             try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
   1030         }
   1031 
   1032         if (gc_sections) {
   1033             try argv.append("--gc-sections");
   1034         }
   1035 
   1036         if (self.base.options.print_gc_sections) {
   1037             try argv.append("--print-gc-sections");
   1038         }
   1039 
   1040         if (self.base.options.eh_frame_hdr) {
   1041             try argv.append("--eh-frame-hdr");
   1042         }
   1043 
   1044         if (self.base.options.rdynamic) {
   1045             try argv.append("--export-dynamic");
   1046         }
   1047 
   1048         if (self.base.options.strip) {
   1049             try argv.append("-s");
   1050         }
   1051 
   1052         if (self.base.options.z_notext) {
   1053             try argv.append("-z");
   1054             try argv.append("notext");
   1055         }
   1056 
   1057         if (self.base.options.z_nocopyreloc) {
   1058             try argv.append("-z");
   1059             try argv.append("nocopyreloc");
   1060         }
   1061 
   1062         if (self.base.options.z_now) {
   1063             try argv.append("-z");
   1064             try argv.append("now");
   1065         }
   1066 
   1067         if (self.isStatic()) {
   1068             try argv.append("-static");
   1069         } else if (self.isDynLib()) {
   1070             try argv.append("-shared");
   1071         }
   1072 
   1073         if (self.base.options.pie and self.isExe()) {
   1074             try argv.append("-pie");
   1075         }
   1076 
   1077         // csu prelude
   1078         if (csu.crt0) |v| try argv.append(v);
   1079         if (csu.crti) |v| try argv.append(v);
   1080         if (csu.crtbegin) |v| try argv.append(v);
   1081 
   1082         for (self.base.options.lib_dirs) |lib_dir| {
   1083             try argv.append("-L");
   1084             try argv.append(lib_dir);
   1085         }
   1086 
   1087         if (self.base.options.link_libc) {
   1088             if (self.base.options.libc_installation) |libc_installation| {
   1089                 try argv.append("-L");
   1090                 try argv.append(libc_installation.crt_dir.?);
   1091             }
   1092         }
   1093 
   1094         var whole_archive = false;
   1095         for (self.base.options.objects) |obj| {
   1096             if (obj.must_link and !whole_archive) {
   1097                 try argv.append("-whole-archive");
   1098                 whole_archive = true;
   1099             } else if (!obj.must_link and whole_archive) {
   1100                 try argv.append("-no-whole-archive");
   1101                 whole_archive = false;
   1102             }
   1103 
   1104             if (obj.loption) {
   1105                 assert(obj.path[0] == ':');
   1106                 try argv.append("-l");
   1107             }
   1108             try argv.append(obj.path);
   1109         }
   1110         if (whole_archive) {
   1111             try argv.append("-no-whole-archive");
   1112             whole_archive = false;
   1113         }
   1114 
   1115         for (comp.c_object_table.keys()) |key| {
   1116             try argv.append(key.status.success.object_path);
   1117         }
   1118 
   1119         if (module_obj_path) |p| {
   1120             try argv.append(p);
   1121         }
   1122 
   1123         // TSAN
   1124         if (self.base.options.tsan) {
   1125             try argv.append(comp.tsan_static_lib.?.full_object_path);
   1126         }
   1127 
   1128         // libc
   1129         if (!self.base.options.skip_linker_dependencies and
   1130             !self.base.options.link_libc)
   1131         {
   1132             if (comp.libc_static_lib) |lib| {
   1133                 try argv.append(lib.full_object_path);
   1134             }
   1135         }
   1136 
   1137         // stack-protector.
   1138         // Related: https://github.com/ziglang/zig/issues/7265
   1139         if (comp.libssp_static_lib) |ssp| {
   1140             try argv.append(ssp.full_object_path);
   1141         }
   1142 
   1143         // Shared libraries.
   1144         // Worst-case, we need an --as-needed argument for every lib, as well
   1145         // as one before and one after.
   1146         try argv.ensureUnusedCapacity(self.base.options.system_libs.keys().len * 2 + 2);
   1147         argv.appendAssumeCapacity("--as-needed");
   1148         var as_needed = true;
   1149 
   1150         for (self.base.options.system_libs.values()) |lib_info| {
   1151             const lib_as_needed = !lib_info.needed;
   1152             switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
   1153                 0b00, 0b11 => {},
   1154                 0b01 => {
   1155                     argv.appendAssumeCapacity("--no-as-needed");
   1156                     as_needed = false;
   1157                 },
   1158                 0b10 => {
   1159                     argv.appendAssumeCapacity("--as-needed");
   1160                     as_needed = true;
   1161                 },
   1162             }
   1163             argv.appendAssumeCapacity(lib_info.path.?);
   1164         }
   1165 
   1166         if (!as_needed) {
   1167             argv.appendAssumeCapacity("--as-needed");
   1168             as_needed = true;
   1169         }
   1170 
   1171         // libc++ dep
   1172         if (self.base.options.link_libcpp) {
   1173             try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
   1174             try argv.append(comp.libcxx_static_lib.?.full_object_path);
   1175         }
   1176 
   1177         // libunwind dep
   1178         if (self.base.options.link_libunwind) {
   1179             try argv.append(comp.libunwind_static_lib.?.full_object_path);
   1180         }
   1181 
   1182         // libc dep
   1183         if (self.base.options.link_libc) {
   1184             if (self.base.options.libc_installation != null) {
   1185                 const needs_grouping = self.base.options.link_mode == .Static;
   1186                 if (needs_grouping) try argv.append("--start-group");
   1187                 try argv.appendSlice(target_util.libcFullLinkFlags(target));
   1188                 if (needs_grouping) try argv.append("--end-group");
   1189             } else if (target.isGnuLibC()) {
   1190                 for (glibc.libs) |lib| {
   1191                     const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
   1192                         comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
   1193                     });
   1194                     try argv.append(lib_path);
   1195                 }
   1196                 try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
   1197             } else if (target.isMusl()) {
   1198                 try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
   1199                     .Static => "libc.a",
   1200                     .Dynamic => "libc.so",
   1201                 }));
   1202             }
   1203         }
   1204 
   1205         // compiler-rt
   1206         if (compiler_rt_path) |p| {
   1207             try argv.append(p);
   1208         }
   1209 
   1210         // crt postlude
   1211         if (csu.crtend) |v| try argv.append(v);
   1212         if (csu.crtn) |v| try argv.append(v);
   1213 
   1214         Compilation.dump_argv(argv.items);
   1215     }
   1216 
   1217     if (self.zigObjectPtr()) |zig_object| try zig_object.flushModule(self);
   1218 
   1219     // Here we will parse input positional and library files (if referenced).
   1220     // This will roughly match in any linker backend we support.
   1221     var positionals = std.ArrayList(Compilation.LinkObject).init(arena);
   1222 
   1223     // csu prelude
   1224     if (csu.crt0) |v| try positionals.append(.{ .path = v });
   1225     if (csu.crti) |v| try positionals.append(.{ .path = v });
   1226     if (csu.crtbegin) |v| try positionals.append(.{ .path = v });
   1227 
   1228     try positionals.ensureUnusedCapacity(self.base.options.objects.len);
   1229     positionals.appendSliceAssumeCapacity(self.base.options.objects);
   1230 
   1231     // This is a set of object files emitted by clang in a single `build-exe` invocation.
   1232     // For instance, the implicit `a.o` as compiled by `zig build-exe a.c` will end up
   1233     // in this set.
   1234     for (comp.c_object_table.keys()) |key| {
   1235         try positionals.append(.{ .path = key.status.success.object_path });
   1236     }
   1237 
   1238     if (module_obj_path) |path| try positionals.append(.{ .path = path });
   1239 
   1240     // rpaths
   1241     var rpath_table = std.StringArrayHashMap(void).init(self.base.allocator);
   1242     defer rpath_table.deinit();
   1243     for (self.base.options.rpath_list) |rpath| {
   1244         _ = try rpath_table.put(rpath, {});
   1245     }
   1246 
   1247     if (self.base.options.each_lib_rpath) {
   1248         var test_path = std.ArrayList(u8).init(self.base.allocator);
   1249         defer test_path.deinit();
   1250         for (self.base.options.lib_dirs) |lib_dir_path| {
   1251             for (self.base.options.system_libs.keys()) |link_lib| {
   1252                 if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
   1253                     continue;
   1254                 _ = try rpath_table.put(lib_dir_path, {});
   1255             }
   1256         }
   1257         for (self.base.options.objects) |obj| {
   1258             if (Compilation.classifyFileExt(obj.path) == .shared_library) {
   1259                 const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
   1260                 if (obj.loption) continue;
   1261                 _ = try rpath_table.put(lib_dir_path, {});
   1262             }
   1263         }
   1264     }
   1265 
   1266     // TSAN
   1267     if (self.base.options.tsan) {
   1268         try positionals.append(.{ .path = comp.tsan_static_lib.?.full_object_path });
   1269     }
   1270 
   1271     // libc
   1272     if (!self.base.options.skip_linker_dependencies and
   1273         !self.base.options.link_libc)
   1274     {
   1275         if (comp.libc_static_lib) |lib| {
   1276             try positionals.append(.{ .path = lib.full_object_path });
   1277         }
   1278     }
   1279 
   1280     // stack-protector.
   1281     // Related: https://github.com/ziglang/zig/issues/7265
   1282     if (comp.libssp_static_lib) |ssp| {
   1283         try positionals.append(.{ .path = ssp.full_object_path });
   1284     }
   1285 
   1286     for (positionals.items) |obj| {
   1287         var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
   1288         self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
   1289             try self.handleAndReportParseError(obj.path, err, &parse_ctx);
   1290     }
   1291 
   1292     var system_libs = std.ArrayList(SystemLib).init(arena);
   1293 
   1294     try system_libs.ensureUnusedCapacity(self.base.options.system_libs.values().len);
   1295     for (self.base.options.system_libs.values()) |lib_info| {
   1296         system_libs.appendAssumeCapacity(.{ .needed = lib_info.needed, .path = lib_info.path.? });
   1297     }
   1298 
   1299     // libc++ dep
   1300     if (self.base.options.link_libcpp) {
   1301         try system_libs.ensureUnusedCapacity(2);
   1302         system_libs.appendAssumeCapacity(.{ .path = comp.libcxxabi_static_lib.?.full_object_path });
   1303         system_libs.appendAssumeCapacity(.{ .path = comp.libcxx_static_lib.?.full_object_path });
   1304     }
   1305 
   1306     // libunwind dep
   1307     if (self.base.options.link_libunwind) {
   1308         try system_libs.append(.{ .path = comp.libunwind_static_lib.?.full_object_path });
   1309     }
   1310 
   1311     // libc dep
   1312     self.error_flags.missing_libc = false;
   1313     if (self.base.options.link_libc) {
   1314         if (self.base.options.libc_installation) |lc| {
   1315             const flags = target_util.libcFullLinkFlags(target);
   1316             try system_libs.ensureUnusedCapacity(flags.len);
   1317 
   1318             var test_path = std.ArrayList(u8).init(arena);
   1319             var checked_paths = std.ArrayList([]const u8).init(arena);
   1320 
   1321             for (flags) |flag| {
   1322                 checked_paths.clearRetainingCapacity();
   1323                 const lib_name = flag["-l".len..];
   1324 
   1325                 success: {
   1326                     if (!self.isStatic()) {
   1327                         if (try self.accessLibPath(&test_path, &checked_paths, lc.crt_dir.?, lib_name, .Dynamic))
   1328                             break :success;
   1329                     }
   1330                     if (try self.accessLibPath(&test_path, &checked_paths, lc.crt_dir.?, lib_name, .Static))
   1331                         break :success;
   1332 
   1333                     try self.reportMissingLibraryError(
   1334                         checked_paths.items,
   1335                         "missing system library: '{s}' was not found",
   1336                         .{lib_name},
   1337                     );
   1338 
   1339                     continue;
   1340                 }
   1341 
   1342                 const resolved_path = try arena.dupe(u8, test_path.items);
   1343                 system_libs.appendAssumeCapacity(.{ .path = resolved_path });
   1344             }
   1345         } else if (target.isGnuLibC()) {
   1346             try system_libs.ensureUnusedCapacity(glibc.libs.len + 1);
   1347             for (glibc.libs) |lib| {
   1348                 const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
   1349                     comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
   1350                 });
   1351                 system_libs.appendAssumeCapacity(.{ .path = lib_path });
   1352             }
   1353             system_libs.appendAssumeCapacity(.{
   1354                 .path = try comp.get_libc_crt_file(arena, "libc_nonshared.a"),
   1355             });
   1356         } else if (target.isMusl()) {
   1357             const path = try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
   1358                 .Static => "libc.a",
   1359                 .Dynamic => "libc.so",
   1360             });
   1361             try system_libs.append(.{ .path = path });
   1362         } else {
   1363             self.error_flags.missing_libc = true;
   1364         }
   1365     }
   1366 
   1367     for (system_libs.items) |lib| {
   1368         var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
   1369         self.parseLibrary(lib, false, &parse_ctx) catch |err|
   1370             try self.handleAndReportParseError(lib.path, err, &parse_ctx);
   1371     }
   1372 
   1373     // Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
   1374     positionals.clearRetainingCapacity();
   1375 
   1376     // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
   1377     // to be after the shared libraries, so they are picked up from the shared
   1378     // libraries, not libcompiler_rt.
   1379     if (compiler_rt_path) |path| try positionals.append(.{ .path = path });
   1380 
   1381     // csu postlude
   1382     if (csu.crtend) |v| try positionals.append(.{ .path = v });
   1383     if (csu.crtn) |v| try positionals.append(.{ .path = v });
   1384 
   1385     for (positionals.items) |obj| {
   1386         var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
   1387         self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
   1388             try self.handleAndReportParseError(obj.path, err, &parse_ctx);
   1389     }
   1390 
   1391     if (self.isStaticLib()) return self.flushStaticLib(comp);
   1392 
   1393     // Init all objects
   1394     for (self.objects.items) |index| {
   1395         try self.file(index).?.object.init(self);
   1396     }
   1397     for (self.shared_objects.items) |index| {
   1398         try self.file(index).?.shared_object.init(self);
   1399     }
   1400 
   1401     // Dedup shared objects
   1402     {
   1403         var seen_dsos = std.StringHashMap(void).init(gpa);
   1404         defer seen_dsos.deinit();
   1405         try seen_dsos.ensureTotalCapacity(@as(u32, @intCast(self.shared_objects.items.len)));
   1406 
   1407         var i: usize = 0;
   1408         while (i < self.shared_objects.items.len) {
   1409             const index = self.shared_objects.items[i];
   1410             const shared_object = self.file(index).?.shared_object;
   1411             const soname = shared_object.soname();
   1412             const gop = seen_dsos.getOrPutAssumeCapacity(soname);
   1413             if (gop.found_existing) {
   1414                 _ = self.shared_objects.orderedRemove(i);
   1415             } else i += 1;
   1416         }
   1417     }
   1418 
   1419     // If we haven't already, create a linker-generated input file comprising of
   1420     // linker-defined synthetic symbols only such as `_DYNAMIC`, etc.
   1421     if (self.linker_defined_index == null and !self.isRelocatable()) {
   1422         const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
   1423         self.files.set(index, .{ .linker_defined = .{ .index = index } });
   1424         self.linker_defined_index = index;
   1425     }
   1426 
   1427     // Now, we are ready to resolve the symbols across all input files.
   1428     // We will first resolve the files in the ZigObject, next in the parsed
   1429     // input Object files.
   1430     // Any qualifing unresolved symbol will be upgraded to an absolute, weak
   1431     // symbol for potential resolution at load-time.
   1432     self.resolveSymbols();
   1433     self.markEhFrameAtomsDead();
   1434 
   1435     if (self.isObject()) return self.flushObject(comp);
   1436 
   1437     try self.convertCommonSymbols();
   1438     self.markImportsExports();
   1439 
   1440     // Look for entry address in objects if not set by the incremental compiler.
   1441     if (self.entry_index == null) {
   1442         const entry: ?[]const u8 = entry: {
   1443             if (self.base.options.entry) |entry| break :entry entry;
   1444             if (!self.isDynLib()) break :entry "_start";
   1445             break :entry null;
   1446         };
   1447         self.entry_index = if (entry) |name| self.globalByName(name) else null;
   1448     }
   1449 
   1450     if (gc_sections) {
   1451         try gc.gcAtoms(self);
   1452 
   1453         if (self.base.options.print_gc_sections) {
   1454             try gc.dumpPrunedAtoms(self);
   1455         }
   1456     }
   1457 
   1458     try self.addLinkerDefinedSymbols();
   1459     self.claimUnresolved();
   1460 
   1461     // Scan and create missing synthetic entries such as GOT indirection.
   1462     try self.scanRelocs();
   1463 
   1464     // Generate and emit non-incremental sections.
   1465     try self.initSections();
   1466     try self.initSpecialPhdrs();
   1467     try self.sortShdrs();
   1468     for (self.objects.items) |index| {
   1469         try self.file(index).?.object.addAtomsToOutputSections(self);
   1470     }
   1471     try self.sortInitFini();
   1472     try self.setDynamicSection(rpath_table.keys());
   1473     self.sortDynamicSymtab();
   1474     try self.setHashSections();
   1475     try self.setVersionSymtab();
   1476     try self.updateSectionSizes();
   1477 
   1478     try self.allocatePhdrTable();
   1479     try self.allocateAllocSections();
   1480     try self.sortPhdrs();
   1481     try self.allocateNonAllocSections();
   1482     self.allocateSpecialPhdrs();
   1483     self.allocateAtoms();
   1484     self.allocateLinkerDefinedSymbols();
   1485 
   1486     // Dump the state for easy debugging.
   1487     // State can be dumped via `--debug-log link_state`.
   1488     if (build_options.enable_logging) {
   1489         state_log.debug("{}", .{self.dumpState()});
   1490     }
   1491 
   1492     // Beyond this point, everything has been allocated a virtual address and we can resolve
   1493     // the relocations, and commit objects to file.
   1494     if (self.zigObjectPtr()) |zig_object| {
   1495         for (zig_object.atoms.items) |atom_index| {
   1496             const atom_ptr = self.atom(atom_index) orelse continue;
   1497             if (!atom_ptr.flags.alive) continue;
   1498             const out_shndx = atom_ptr.outputShndx() orelse continue;
   1499             const shdr = &self.shdrs.items[out_shndx];
   1500             if (shdr.sh_type == elf.SHT_NOBITS) continue;
   1501             const code = try zig_object.codeAlloc(self, atom_index);
   1502             defer gpa.free(code);
   1503             const file_offset = shdr.sh_offset + atom_ptr.value - shdr.sh_addr;
   1504             atom_ptr.resolveRelocsAlloc(self, code) catch |err| switch (err) {
   1505                 // TODO
   1506                 error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
   1507                     log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{});
   1508                 },
   1509                 else => |e| return e,
   1510             };
   1511             try self.base.file.?.pwriteAll(code, file_offset);
   1512         }
   1513     }
   1514 
   1515     try self.writePhdrTable();
   1516     try self.writeShdrTable();
   1517     try self.writeAtoms();
   1518     try self.writeSyntheticSections();
   1519 
   1520     if (self.entry_index == null and self.isExe()) {
   1521         log.debug("flushing. no_entry_point_found = true", .{});
   1522         self.error_flags.no_entry_point_found = true;
   1523     } else {
   1524         log.debug("flushing. no_entry_point_found = false", .{});
   1525         self.error_flags.no_entry_point_found = false;
   1526         try self.writeElfHeader();
   1527     }
   1528 }
   1529 
   1530 pub fn flushStaticLib(self: *Elf, comp: *Compilation) link.File.FlushError!void {
   1531     _ = comp;
   1532     const gpa = self.base.allocator;
   1533 
   1534     // First, we flush relocatable object file generated with our backends.
   1535     if (self.zigObjectPtr()) |zig_object| {
   1536         zig_object.resolveSymbols(self);
   1537         zig_object.claimUnresolvedObject(self);
   1538 
   1539         try self.initSymtab();
   1540         try self.initShStrtab();
   1541         try self.sortShdrs();
   1542         zig_object.updateRelaSectionSizes(self);
   1543         try self.updateSymtabSize();
   1544         self.updateShStrtabSize();
   1545 
   1546         try self.allocateNonAllocSections();
   1547 
   1548         try self.writeShdrTable();
   1549         try zig_object.writeRelaSections(self);
   1550         try self.writeSymtab();
   1551         try self.writeShStrtab();
   1552         try self.writeElfHeader();
   1553     }
   1554 
   1555     var files = std.ArrayList(File.Index).init(gpa);
   1556     defer files.deinit();
   1557     try files.ensureTotalCapacityPrecise(self.objects.items.len + 1);
   1558     // Note to self: we currently must have ZigObject written out first as we write the object
   1559     // file into the same file descriptor and then re-read its contents.
   1560     // TODO implement writing ZigObject to a buffer instead of file.
   1561     if (self.zigObjectPtr()) |zig_object| files.appendAssumeCapacity(zig_object.index);
   1562     for (self.objects.items) |index| files.appendAssumeCapacity(index);
   1563 
   1564     // Update ar symtab from parsed objects
   1565     var ar_symtab: Archive.ArSymtab = .{};
   1566     defer ar_symtab.deinit(gpa);
   1567 
   1568     for (files.items) |index| {
   1569         try self.file(index).?.updateArSymtab(&ar_symtab, self);
   1570     }
   1571 
   1572     ar_symtab.sort();
   1573 
   1574     // Save object paths in filenames strtab.
   1575     var ar_strtab: Archive.ArStrtab = .{};
   1576     defer ar_strtab.deinit(gpa);
   1577 
   1578     for (files.items) |index| {
   1579         const file_ptr = self.file(index).?;
   1580         try file_ptr.updateArStrtab(gpa, &ar_strtab);
   1581         file_ptr.updateArSize(self);
   1582     }
   1583 
   1584     // Update file offsets of contributing objects.
   1585     const total_size: usize = blk: {
   1586         var pos: usize = Archive.ARMAG.len;
   1587         pos += @sizeOf(Archive.ar_hdr) + ar_symtab.size(.p64);
   1588 
   1589         if (ar_strtab.size() > 0) {
   1590             pos = mem.alignForward(usize, pos, 2);
   1591             pos += @sizeOf(Archive.ar_hdr) + ar_strtab.size();
   1592         }
   1593 
   1594         for (files.items) |index| {
   1595             const file_ptr = self.file(index).?;
   1596             const state = switch (file_ptr) {
   1597                 .zig_object => |x| &x.output_ar_state,
   1598                 .object => |x| &x.output_ar_state,
   1599                 else => unreachable,
   1600             };
   1601             pos = mem.alignForward(usize, pos, 2);
   1602             state.file_off = pos;
   1603             pos += @sizeOf(Archive.ar_hdr) + (math.cast(usize, state.size) orelse return error.Overflow);
   1604         }
   1605 
   1606         break :blk pos;
   1607     };
   1608 
   1609     if (build_options.enable_logging) {
   1610         state_log.debug("ar_symtab\n{}\n", .{ar_symtab.fmt(self)});
   1611         state_log.debug("ar_strtab\n{}\n", .{ar_strtab});
   1612     }
   1613 
   1614     var buffer = std.ArrayList(u8).init(gpa);
   1615     defer buffer.deinit();
   1616     try buffer.ensureTotalCapacityPrecise(total_size);
   1617 
   1618     // Write magic
   1619     try buffer.writer().writeAll(Archive.ARMAG);
   1620 
   1621     // Write symtab
   1622     try ar_symtab.write(.p64, self, buffer.writer());
   1623 
   1624     // Write strtab
   1625     if (ar_strtab.size() > 0) {
   1626         if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
   1627         try ar_strtab.write(buffer.writer());
   1628     }
   1629 
   1630     // Write object files
   1631     for (files.items) |index| {
   1632         if (!mem.isAligned(buffer.items.len, 2)) try buffer.writer().writeByte(0);
   1633         try self.file(index).?.writeAr(self, buffer.writer());
   1634     }
   1635 
   1636     assert(buffer.items.len == total_size);
   1637 
   1638     try self.base.file.?.setEndPos(total_size);
   1639     try self.base.file.?.pwriteAll(buffer.items, 0);
   1640 }
   1641 
   1642 pub fn flushObject(self: *Elf, comp: *Compilation) link.File.FlushError!void {
   1643     _ = comp;
   1644 
   1645     if (self.objects.items.len > 0) {
   1646         var err = try self.addErrorWithNotes(1);
   1647         try err.addMsg(self, "fatal linker error: too many input positionals", .{});
   1648         try err.addNote(self, "TODO implement '-r' option", .{});
   1649         return;
   1650     }
   1651 
   1652     self.claimUnresolvedObject();
   1653 
   1654     try self.initSections();
   1655     try self.sortShdrs();
   1656     try self.updateSectionSizes();
   1657 
   1658     try self.allocateNonAllocSections();
   1659 
   1660     if (build_options.enable_logging) {
   1661         state_log.debug("{}", .{self.dumpState()});
   1662     }
   1663 
   1664     try self.writeShdrTable();
   1665     try self.writeSyntheticSections();
   1666     try self.writeElfHeader();
   1667 }
   1668 
   1669 const ParseError = error{
   1670     UnknownFileType,
   1671     InvalidCpuArch,
   1672     OutOfMemory,
   1673     Overflow,
   1674     InputOutput,
   1675     EndOfStream,
   1676     FileSystem,
   1677     NotSupported,
   1678     InvalidCharacter,
   1679 } || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError;
   1680 
   1681 fn parsePositional(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {
   1682     const tracy = trace(@src());
   1683     defer tracy.end();
   1684     if (try Object.isObject(path)) {
   1685         try self.parseObject(path, ctx);
   1686     } else {
   1687         try self.parseLibrary(.{ .path = path }, must_link, ctx);
   1688     }
   1689 }
   1690 
   1691 fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {
   1692     const tracy = trace(@src());
   1693     defer tracy.end();
   1694 
   1695     if (try Archive.isArchive(lib.path)) {
   1696         try self.parseArchive(lib.path, must_link, ctx);
   1697     } else if (try SharedObject.isSharedObject(lib.path)) {
   1698         try self.parseSharedObject(lib, ctx);
   1699     } else {
   1700         // TODO if the script has a top-level comment identifying it as GNU ld script,
   1701         // then report parse errors. Otherwise return UnknownFileType.
   1702         self.parseLdScript(lib, ctx) catch |err| switch (err) {
   1703             else => return error.UnknownFileType,
   1704         };
   1705     }
   1706 }
   1707 
   1708 fn parseObject(self: *Elf, path: []const u8, ctx: *ParseErrorCtx) ParseError!void {
   1709     const tracy = trace(@src());
   1710     defer tracy.end();
   1711 
   1712     const gpa = self.base.allocator;
   1713     const in_file = try std.fs.cwd().openFile(path, .{});
   1714     defer in_file.close();
   1715     const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
   1716     const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
   1717     self.files.set(index, .{ .object = .{
   1718         .path = try gpa.dupe(u8, path),
   1719         .data = data,
   1720         .index = index,
   1721     } });
   1722     try self.objects.append(gpa, index);
   1723 
   1724     const object = self.file(index).?.object;
   1725     try object.parse(self);
   1726 
   1727     ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;
   1728     if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
   1729 }
   1730 
   1731 fn parseArchive(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {
   1732     const tracy = trace(@src());
   1733     defer tracy.end();
   1734 
   1735     const gpa = self.base.allocator;
   1736     const in_file = try std.fs.cwd().openFile(path, .{});
   1737     defer in_file.close();
   1738     const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
   1739     var archive = Archive{ .path = try gpa.dupe(u8, path), .data = data };
   1740     defer archive.deinit(gpa);
   1741     try archive.parse(self);
   1742 
   1743     const objects = try archive.objects.toOwnedSlice(gpa);
   1744     defer gpa.free(objects);
   1745 
   1746     for (objects) |extracted| {
   1747         const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
   1748         self.files.set(index, .{ .object = extracted });
   1749         const object = &self.files.items(.data)[index].object;
   1750         object.index = index;
   1751         object.alive = must_link;
   1752         try object.parse(self);
   1753         try self.objects.append(gpa, index);
   1754 
   1755         ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;
   1756         if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
   1757     }
   1758 }
   1759 
   1760 fn parseSharedObject(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!void {
   1761     const tracy = trace(@src());
   1762     defer tracy.end();
   1763 
   1764     const gpa = self.base.allocator;
   1765     const in_file = try std.fs.cwd().openFile(lib.path, .{});
   1766     defer in_file.close();
   1767     const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
   1768     const index = @as(File.Index, @intCast(try self.files.addOne(gpa)));
   1769     self.files.set(index, .{ .shared_object = .{
   1770         .path = try gpa.dupe(u8, lib.path),
   1771         .data = data,
   1772         .index = index,
   1773         .needed = lib.needed,
   1774         .alive = lib.needed,
   1775     } });
   1776     try self.shared_objects.append(gpa, index);
   1777 
   1778     const shared_object = self.file(index).?.shared_object;
   1779     try shared_object.parse(self);
   1780 
   1781     ctx.detected_cpu_arch = shared_object.header.?.e_machine.toTargetCpuArch().?;
   1782     if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
   1783 }
   1784 
   1785 fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!void {
   1786     const tracy = trace(@src());
   1787     defer tracy.end();
   1788 
   1789     const gpa = self.base.allocator;
   1790     const in_file = try std.fs.cwd().openFile(lib.path, .{});
   1791     defer in_file.close();
   1792     const data = try in_file.readToEndAlloc(gpa, std.math.maxInt(u32));
   1793     defer gpa.free(data);
   1794 
   1795     var script = LdScript{};
   1796     defer script.deinit(gpa);
   1797     try script.parse(data, self);
   1798 
   1799     if (script.cpu_arch) |cpu_arch| {
   1800         ctx.detected_cpu_arch = cpu_arch;
   1801         if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
   1802     }
   1803 
   1804     const lib_dirs = self.base.options.lib_dirs;
   1805 
   1806     var arena_allocator = std.heap.ArenaAllocator.init(gpa);
   1807     defer arena_allocator.deinit();
   1808     const arena = arena_allocator.allocator();
   1809 
   1810     var test_path = std.ArrayList(u8).init(arena);
   1811     var checked_paths = std.ArrayList([]const u8).init(arena);
   1812 
   1813     for (script.args.items) |scr_obj| {
   1814         checked_paths.clearRetainingCapacity();
   1815 
   1816         success: {
   1817             if (mem.startsWith(u8, scr_obj.path, "-l")) {
   1818                 const lib_name = scr_obj.path["-l".len..];
   1819 
   1820                 // TODO I think technically we should re-use the mechanism used by the frontend here.
   1821                 // Maybe we should hoist search-strategy all the way here?
   1822                 for (lib_dirs) |lib_dir| {
   1823                     if (!self.isStatic()) {
   1824                         if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, lib_name, .Dynamic))
   1825                             break :success;
   1826                     }
   1827                     if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, lib_name, .Static))
   1828                         break :success;
   1829                 }
   1830             } else {
   1831                 var buffer: [fs.MAX_PATH_BYTES]u8 = undefined;
   1832                 if (fs.realpath(scr_obj.path, &buffer)) |path| {
   1833                     test_path.clearRetainingCapacity();
   1834                     try test_path.writer().writeAll(path);
   1835                     break :success;
   1836                 } else |_| {}
   1837 
   1838                 try checked_paths.append(try gpa.dupe(u8, scr_obj.path));
   1839                 for (lib_dirs) |lib_dir| {
   1840                     if (try self.accessLibPath(&test_path, &checked_paths, lib_dir, scr_obj.path, null))
   1841                         break :success;
   1842                 }
   1843             }
   1844 
   1845             try self.reportMissingLibraryError(
   1846                 checked_paths.items,
   1847                 "missing library dependency: GNU ld script '{s}' requires '{s}', but file not found",
   1848                 .{
   1849                     lib.path,
   1850                     scr_obj.path,
   1851                 },
   1852             );
   1853             continue;
   1854         }
   1855 
   1856         const full_path = test_path.items;
   1857         var scr_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
   1858         self.parseLibrary(.{
   1859             .needed = scr_obj.needed,
   1860             .path = full_path,
   1861         }, false, &scr_ctx) catch |err| try self.handleAndReportParseError(full_path, err, &scr_ctx);
   1862     }
   1863 }
   1864 
   1865 fn accessLibPath(
   1866     self: *Elf,
   1867     test_path: *std.ArrayList(u8),
   1868     checked_paths: ?*std.ArrayList([]const u8),
   1869     lib_dir_path: []const u8,
   1870     lib_name: []const u8,
   1871     link_mode: ?std.builtin.LinkMode,
   1872 ) !bool {
   1873     const sep = fs.path.sep_str;
   1874     const target = self.base.options.target;
   1875     test_path.clearRetainingCapacity();
   1876     const prefix = if (link_mode != null) "lib" else "";
   1877     const suffix = if (link_mode) |mode| switch (mode) {
   1878         .Static => target.staticLibSuffix(),
   1879         .Dynamic => target.dynamicLibSuffix(),
   1880     } else "";
   1881     try test_path.writer().print("{s}" ++ sep ++ "{s}{s}{s}", .{
   1882         lib_dir_path,
   1883         prefix,
   1884         lib_name,
   1885         suffix,
   1886     });
   1887     if (checked_paths) |cpaths| {
   1888         try cpaths.append(try self.base.allocator.dupe(u8, test_path.items));
   1889     }
   1890     fs.cwd().access(test_path.items, .{}) catch |err| switch (err) {
   1891         error.FileNotFound => return false,
   1892         else => |e| return e,
   1893     };
   1894     return true;
   1895 }
   1896 
   1897 /// When resolving symbols, we approach the problem similarly to `mold`.
   1898 /// 1. Resolve symbols across all objects (including those preemptively extracted archives).
   1899 /// 2. Resolve symbols across all shared objects.
   1900 /// 3. Mark live objects (see `Elf.markLive`)
   1901 /// 4. Reset state of all resolved globals since we will redo this bit on the pruned set.
   1902 /// 5. Remove references to dead objects/shared objects
   1903 /// 6. Re-run symbol resolution on pruned objects and shared objects sets.
   1904 fn resolveSymbols(self: *Elf) void {
   1905     // Resolve symbols in the ZigObject. For now, we assume that it's always live.
   1906     if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resolveSymbols(self);
   1907     // Resolve symbols on the set of all objects and shared objects (even if some are unneeded).
   1908     for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
   1909     for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
   1910 
   1911     // Mark live objects.
   1912     self.markLive();
   1913 
   1914     // Reset state of all globals after marking live objects.
   1915     if (self.zigObjectPtr()) |zig_object| zig_object.asFile().resetGlobals(self);
   1916     for (self.objects.items) |index| self.file(index).?.resetGlobals(self);
   1917     for (self.shared_objects.items) |index| self.file(index).?.resetGlobals(self);
   1918 
   1919     // Prune dead objects and shared objects.
   1920     var i: usize = 0;
   1921     while (i < self.objects.items.len) {
   1922         const index = self.objects.items[i];
   1923         if (!self.file(index).?.isAlive()) {
   1924             _ = self.objects.orderedRemove(i);
   1925         } else i += 1;
   1926     }
   1927     i = 0;
   1928     while (i < self.shared_objects.items.len) {
   1929         const index = self.shared_objects.items[i];
   1930         if (!self.file(index).?.isAlive()) {
   1931             _ = self.shared_objects.orderedRemove(i);
   1932         } else i += 1;
   1933     }
   1934 
   1935     // Dedup comdat groups.
   1936     for (self.objects.items) |index| {
   1937         const object = self.file(index).?.object;
   1938         for (object.comdat_groups.items) |cg_index| {
   1939             const cg = self.comdatGroup(cg_index);
   1940             const cg_owner = self.comdatGroupOwner(cg.owner);
   1941             const owner_file_index = if (self.file(cg_owner.file)) |file_ptr|
   1942                 file_ptr.object.index
   1943             else
   1944                 std.math.maxInt(File.Index);
   1945             cg_owner.file = @min(owner_file_index, index);
   1946         }
   1947     }
   1948 
   1949     for (self.objects.items) |index| {
   1950         const object = self.file(index).?.object;
   1951         for (object.comdat_groups.items) |cg_index| {
   1952             const cg = self.comdatGroup(cg_index);
   1953             const cg_owner = self.comdatGroupOwner(cg.owner);
   1954             if (cg_owner.file != index) {
   1955                 for (object.comdatGroupMembers(cg.shndx)) |shndx| {
   1956                     const atom_index = object.atoms.items[shndx];
   1957                     if (self.atom(atom_index)) |atom_ptr| {
   1958                         atom_ptr.flags.alive = false;
   1959                         atom_ptr.markFdesDead(self);
   1960                     }
   1961                 }
   1962             }
   1963         }
   1964     }
   1965 
   1966     // Re-resolve the symbols.
   1967     if (self.zigObjectPtr()) |zig_object| zig_object.resolveSymbols(self);
   1968     for (self.objects.items) |index| self.file(index).?.resolveSymbols(self);
   1969     for (self.shared_objects.items) |index| self.file(index).?.resolveSymbols(self);
   1970 }
   1971 
   1972 /// Traverses all objects and shared objects marking any object referenced by
   1973 /// a live object/shared object as alive itself.
   1974 /// This routine will prune unneeded objects extracted from archives and
   1975 /// unneeded shared objects.
   1976 fn markLive(self: *Elf) void {
   1977     if (self.zigObjectPtr()) |zig_object| zig_object.asFile().markLive(self);
   1978     for (self.objects.items) |index| {
   1979         const file_ptr = self.file(index).?;
   1980         if (file_ptr.isAlive()) file_ptr.markLive(self);
   1981     }
   1982     for (self.shared_objects.items) |index| {
   1983         const file_ptr = self.file(index).?;
   1984         if (file_ptr.isAlive()) file_ptr.markLive(self);
   1985     }
   1986 }
   1987 
   1988 fn markEhFrameAtomsDead(self: *Elf) void {
   1989     for (self.objects.items) |index| {
   1990         const file_ptr = self.file(index).?;
   1991         if (!file_ptr.isAlive()) continue;
   1992         file_ptr.object.markEhFrameAtomsDead(self);
   1993     }
   1994 }
   1995 
   1996 fn convertCommonSymbols(self: *Elf) !void {
   1997     for (self.objects.items) |index| {
   1998         try self.file(index).?.object.convertCommonSymbols(self);
   1999     }
   2000 }
   2001 
   2002 fn markImportsExports(self: *Elf) void {
   2003     const mark = struct {
   2004         fn mark(elf_file: *Elf, file_index: File.Index) void {
   2005             for (elf_file.file(file_index).?.globals()) |global_index| {
   2006                 const global = elf_file.symbol(global_index);
   2007                 if (global.version_index == elf.VER_NDX_LOCAL) continue;
   2008                 const file_ptr = global.file(elf_file) orelse continue;
   2009                 const vis = @as(elf.STV, @enumFromInt(global.elfSym(elf_file).st_other));
   2010                 if (vis == .HIDDEN) continue;
   2011                 if (file_ptr == .shared_object and !global.isAbs(elf_file)) {
   2012                     global.flags.import = true;
   2013                     continue;
   2014                 }
   2015                 if (file_ptr.index() == file_index) {
   2016                     global.flags.@"export" = true;
   2017                     if (elf_file.isDynLib() and vis != .PROTECTED) {
   2018                         global.flags.import = true;
   2019                     }
   2020                 }
   2021             }
   2022         }
   2023     }.mark;
   2024 
   2025     if (!self.isDynLib()) {
   2026         for (self.shared_objects.items) |index| {
   2027             for (self.file(index).?.globals()) |global_index| {
   2028                 const global = self.symbol(global_index);
   2029                 const file_ptr = global.file(self) orelse continue;
   2030                 const vis = @as(elf.STV, @enumFromInt(global.elfSym(self).st_other));
   2031                 if (file_ptr != .shared_object and vis != .HIDDEN) global.flags.@"export" = true;
   2032             }
   2033         }
   2034     }
   2035 
   2036     if (self.zig_object_index) |index| {
   2037         mark(self, index);
   2038     }
   2039 
   2040     for (self.objects.items) |index| {
   2041         mark(self, index);
   2042     }
   2043 }
   2044 
   2045 fn claimUnresolved(self: *Elf) void {
   2046     if (self.zigObjectPtr()) |zig_object| {
   2047         zig_object.claimUnresolved(self);
   2048     }
   2049     for (self.objects.items) |index| {
   2050         const object = self.file(index).?.object;
   2051         object.claimUnresolved(self);
   2052     }
   2053 }
   2054 
   2055 fn claimUnresolvedObject(self: *Elf) void {
   2056     if (self.zigObjectPtr()) |zig_object| {
   2057         zig_object.claimUnresolvedObject(self);
   2058     }
   2059 }
   2060 
   2061 /// In scanRelocs we will go over all live atoms and scan their relocs.
   2062 /// This will help us work out what synthetics to emit, GOT indirection, etc.
   2063 /// This is also the point where we will report undefined symbols for any
   2064 /// alloc sections.
   2065 fn scanRelocs(self: *Elf) !void {
   2066     const gpa = self.base.allocator;
   2067 
   2068     var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
   2069     defer {
   2070         var it = undefs.iterator();
   2071         while (it.next()) |entry| {
   2072             entry.value_ptr.deinit();
   2073         }
   2074         undefs.deinit();
   2075     }
   2076 
   2077     if (self.zigObjectPtr()) |zig_object| {
   2078         try zig_object.scanRelocs(self, &undefs);
   2079     }
   2080     for (self.objects.items) |index| {
   2081         const object = self.file(index).?.object;
   2082         try object.scanRelocs(self, &undefs);
   2083     }
   2084 
   2085     try self.reportUndefined(&undefs);
   2086 
   2087     for (self.symbols.items, 0..) |*sym, i| {
   2088         const index = @as(u32, @intCast(i));
   2089         if (!sym.isLocal(self) and !sym.flags.has_dynamic) {
   2090             log.debug("'{s}' is non-local", .{sym.name(self)});
   2091             try self.dynsym.addSymbol(index, self);
   2092         }
   2093         if (sym.flags.needs_got) {
   2094             log.debug("'{s}' needs GOT", .{sym.name(self)});
   2095             _ = try self.got.addGotSymbol(index, self);
   2096         }
   2097         if (sym.flags.needs_plt) {
   2098             if (sym.flags.is_canonical) {
   2099                 log.debug("'{s}' needs CPLT", .{sym.name(self)});
   2100                 sym.flags.@"export" = true;
   2101                 try self.plt.addSymbol(index, self);
   2102             } else if (sym.flags.needs_got) {
   2103                 log.debug("'{s}' needs PLTGOT", .{sym.name(self)});
   2104                 try self.plt_got.addSymbol(index, self);
   2105             } else {
   2106                 log.debug("'{s}' needs PLT", .{sym.name(self)});
   2107                 try self.plt.addSymbol(index, self);
   2108             }
   2109         }
   2110         if (sym.flags.needs_copy_rel and !sym.flags.has_copy_rel) {
   2111             log.debug("'{s}' needs COPYREL", .{sym.name(self)});
   2112             try self.copy_rel.addSymbol(index, self);
   2113         }
   2114         if (sym.flags.needs_tlsgd) {
   2115             log.debug("'{s}' needs TLSGD", .{sym.name(self)});
   2116             try self.got.addTlsGdSymbol(index, self);
   2117         }
   2118         if (sym.flags.needs_gottp) {
   2119             log.debug("'{s}' needs GOTTP", .{sym.name(self)});
   2120             try self.got.addGotTpSymbol(index, self);
   2121         }
   2122         if (sym.flags.needs_tlsdesc) {
   2123             log.debug("'{s}' needs TLSDESC", .{sym.name(self)});
   2124             try self.dynsym.addSymbol(index, self);
   2125             try self.got.addTlsDescSymbol(index, self);
   2126         }
   2127     }
   2128 
   2129     if (self.got.flags.needs_tlsld) {
   2130         log.debug("program needs TLSLD", .{});
   2131         try self.got.addTlsLdSymbol(self);
   2132     }
   2133 }
   2134 
   2135 fn linkWithLLD(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node) !void {
   2136     const tracy = trace(@src());
   2137     defer tracy.end();
   2138 
   2139     var arena_allocator = std.heap.ArenaAllocator.init(self.base.allocator);
   2140     defer arena_allocator.deinit();
   2141     const arena = arena_allocator.allocator();
   2142 
   2143     const directory = self.base.options.emit.?.directory; // Just an alias to make it shorter to type.
   2144     const full_out_path = try directory.join(arena, &[_][]const u8{self.base.options.emit.?.sub_path});
   2145 
   2146     // If there is no Zig code to compile, then we should skip flushing the output file because it
   2147     // will not be part of the linker line anyway.
   2148     const module_obj_path: ?[]const u8 = if (self.base.options.module != null) blk: {
   2149         try self.flushModule(comp, prog_node);
   2150 
   2151         if (fs.path.dirname(full_out_path)) |dirname| {
   2152             break :blk try fs.path.join(arena, &.{ dirname, self.base.intermediary_basename.? });
   2153         } else {
   2154             break :blk self.base.intermediary_basename.?;
   2155         }
   2156     } else null;
   2157 
   2158     var sub_prog_node = prog_node.start("LLD Link", 0);
   2159     sub_prog_node.activate();
   2160     sub_prog_node.context.refresh();
   2161     defer sub_prog_node.end();
   2162 
   2163     const is_obj = self.base.options.output_mode == .Obj;
   2164     const is_lib = self.base.options.output_mode == .Lib;
   2165     const is_dyn_lib = self.base.options.link_mode == .Dynamic and is_lib;
   2166     const is_exe_or_dyn_lib = is_dyn_lib or self.base.options.output_mode == .Exe;
   2167     const have_dynamic_linker = self.base.options.link_libc and
   2168         self.base.options.link_mode == .Dynamic and is_exe_or_dyn_lib;
   2169     const target = self.base.options.target;
   2170     const gc_sections = self.base.options.gc_sections orelse !is_obj;
   2171     const stack_size = self.base.options.stack_size_override orelse 16777216;
   2172     const allow_shlib_undefined = self.base.options.allow_shlib_undefined orelse !self.base.options.is_native_os;
   2173     const compiler_rt_path: ?[]const u8 = blk: {
   2174         if (comp.compiler_rt_lib) |x| break :blk x.full_object_path;
   2175         if (comp.compiler_rt_obj) |x| break :blk x.full_object_path;
   2176         break :blk null;
   2177     };
   2178 
   2179     // Here we want to determine whether we can save time by not invoking LLD when the
   2180     // output is unchanged. None of the linker options or the object files that are being
   2181     // linked are in the hash that namespaces the directory we are outputting to. Therefore,
   2182     // we must hash those now, and the resulting digest will form the "id" of the linking
   2183     // job we are about to perform.
   2184     // After a successful link, we store the id in the metadata of a symlink named "lld.id" in
   2185     // the artifact directory. So, now, we check if this symlink exists, and if it matches
   2186     // our digest. If so, we can skip linking. Otherwise, we proceed with invoking LLD.
   2187     const id_symlink_basename = "lld.id";
   2188 
   2189     var man: Cache.Manifest = undefined;
   2190     defer if (!self.base.options.disable_lld_caching) man.deinit();
   2191 
   2192     var digest: [Cache.hex_digest_len]u8 = undefined;
   2193 
   2194     if (!self.base.options.disable_lld_caching) {
   2195         man = comp.cache_parent.obtain();
   2196 
   2197         // We are about to obtain this lock, so here we give other processes a chance first.
   2198         self.base.releaseLock();
   2199 
   2200         comptime assert(Compilation.link_hash_implementation_version == 10);
   2201 
   2202         try man.addOptionalFile(self.base.options.linker_script);
   2203         try man.addOptionalFile(self.base.options.version_script);
   2204         for (self.base.options.objects) |obj| {
   2205             _ = try man.addFile(obj.path, null);
   2206             man.hash.add(obj.must_link);
   2207             man.hash.add(obj.loption);
   2208         }
   2209         for (comp.c_object_table.keys()) |key| {
   2210             _ = try man.addFile(key.status.success.object_path, null);
   2211         }
   2212         try man.addOptionalFile(module_obj_path);
   2213         try man.addOptionalFile(compiler_rt_path);
   2214 
   2215         // We can skip hashing libc and libc++ components that we are in charge of building from Zig
   2216         // installation sources because they are always a product of the compiler version + target information.
   2217         man.hash.addOptionalBytes(self.base.options.entry);
   2218         man.hash.addOptional(self.base.options.image_base_override);
   2219         man.hash.add(gc_sections);
   2220         man.hash.addOptional(self.base.options.sort_section);
   2221         man.hash.add(self.base.options.eh_frame_hdr);
   2222         man.hash.add(self.base.options.emit_relocs);
   2223         man.hash.add(self.base.options.rdynamic);
   2224         man.hash.addListOfBytes(self.base.options.lib_dirs);
   2225         man.hash.addListOfBytes(self.base.options.rpath_list);
   2226         man.hash.add(self.base.options.each_lib_rpath);
   2227         if (self.base.options.output_mode == .Exe) {
   2228             man.hash.add(stack_size);
   2229             man.hash.add(self.base.options.build_id);
   2230         }
   2231         man.hash.addListOfBytes(self.base.options.symbol_wrap_set.keys());
   2232         man.hash.add(self.base.options.skip_linker_dependencies);
   2233         man.hash.add(self.base.options.z_nodelete);
   2234         man.hash.add(self.base.options.z_notext);
   2235         man.hash.add(self.base.options.z_defs);
   2236         man.hash.add(self.base.options.z_origin);
   2237         man.hash.add(self.base.options.z_nocopyreloc);
   2238         man.hash.add(self.base.options.z_now);
   2239         man.hash.add(self.base.options.z_relro);
   2240         man.hash.add(self.base.options.z_common_page_size orelse 0);
   2241         man.hash.add(self.base.options.z_max_page_size orelse 0);
   2242         man.hash.add(self.base.options.hash_style);
   2243         // strip does not need to go into the linker hash because it is part of the hash namespace
   2244         if (self.base.options.link_libc) {
   2245             man.hash.add(self.base.options.libc_installation != null);
   2246             if (self.base.options.libc_installation) |libc_installation| {
   2247                 man.hash.addBytes(libc_installation.crt_dir.?);
   2248             }
   2249             if (have_dynamic_linker) {
   2250                 man.hash.addOptionalBytes(self.base.options.dynamic_linker);
   2251             }
   2252         }
   2253         man.hash.addOptionalBytes(self.base.options.soname);
   2254         man.hash.addOptional(self.base.options.version);
   2255         try link.hashAddSystemLibs(&man, self.base.options.system_libs);
   2256         man.hash.addListOfBytes(self.base.options.force_undefined_symbols.keys());
   2257         man.hash.add(allow_shlib_undefined);
   2258         man.hash.add(self.base.options.bind_global_refs_locally);
   2259         man.hash.add(self.base.options.compress_debug_sections);
   2260         man.hash.add(self.base.options.tsan);
   2261         man.hash.addOptionalBytes(self.base.options.sysroot);
   2262         man.hash.add(self.base.options.linker_optimization);
   2263 
   2264         // We don't actually care whether it's a cache hit or miss; we just need the digest and the lock.
   2265         _ = try man.hit();
   2266         digest = man.final();
   2267 
   2268         var prev_digest_buf: [digest.len]u8 = undefined;
   2269         const prev_digest: []u8 = Cache.readSmallFile(
   2270             directory.handle,
   2271             id_symlink_basename,
   2272             &prev_digest_buf,
   2273         ) catch |err| blk: {
   2274             log.debug("ELF LLD new_digest={s} error: {s}", .{ std.fmt.fmtSliceHexLower(&digest), @errorName(err) });
   2275             // Handle this as a cache miss.
   2276             break :blk prev_digest_buf[0..0];
   2277         };
   2278         if (mem.eql(u8, prev_digest, &digest)) {
   2279             log.debug("ELF LLD digest={s} match - skipping invocation", .{std.fmt.fmtSliceHexLower(&digest)});
   2280             // Hot diggity dog! The output binary is already there.
   2281             self.base.lock = man.toOwnedLock();
   2282             return;
   2283         }
   2284         log.debug("ELF LLD prev_digest={s} new_digest={s}", .{ std.fmt.fmtSliceHexLower(prev_digest), std.fmt.fmtSliceHexLower(&digest) });
   2285 
   2286         // We are about to change the output file to be different, so we invalidate the build hash now.
   2287         directory.handle.deleteFile(id_symlink_basename) catch |err| switch (err) {
   2288             error.FileNotFound => {},
   2289             else => |e| return e,
   2290         };
   2291     }
   2292 
   2293     // Due to a deficiency in LLD, we need to special-case BPF to a simple file
   2294     // copy when generating relocatables. Normally, we would expect `lld -r` to work.
   2295     // However, because LLD wants to resolve BPF relocations which it shouldn't, it fails
   2296     // before even generating the relocatable.
   2297     if (self.base.options.output_mode == .Obj and
   2298         (self.base.options.lto or target.isBpfFreestanding()))
   2299     {
   2300         // In this case we must do a simple file copy
   2301         // here. TODO: think carefully about how we can avoid this redundant operation when doing
   2302         // build-obj. See also the corresponding TODO in linkAsArchive.
   2303         const the_object_path = blk: {
   2304             if (self.base.options.objects.len != 0)
   2305                 break :blk self.base.options.objects[0].path;
   2306 
   2307             if (comp.c_object_table.count() != 0)
   2308                 break :blk comp.c_object_table.keys()[0].status.success.object_path;
   2309 
   2310             if (module_obj_path) |p|
   2311                 break :blk p;
   2312 
   2313             // TODO I think this is unreachable. Audit this situation when solving the above TODO
   2314             // regarding eliding redundant object -> object transformations.
   2315             return error.NoObjectsToLink;
   2316         };
   2317         // This can happen when using --enable-cache and using the stage1 backend. In this case
   2318         // we can skip the file copy.
   2319         if (!mem.eql(u8, the_object_path, full_out_path)) {
   2320             try fs.cwd().copyFile(the_object_path, fs.cwd(), full_out_path, .{});
   2321         }
   2322     } else {
   2323         // Create an LLD command line and invoke it.
   2324         var argv = std.ArrayList([]const u8).init(self.base.allocator);
   2325         defer argv.deinit();
   2326         // We will invoke ourselves as a child process to gain access to LLD.
   2327         // This is necessary because LLD does not behave properly as a library -
   2328         // it calls exit() and does not reset all global data between invocations.
   2329         const linker_command = "ld.lld";
   2330         try argv.appendSlice(&[_][]const u8{ comp.self_exe_path.?, linker_command });
   2331         if (is_obj) {
   2332             try argv.append("-r");
   2333         }
   2334 
   2335         try argv.append("--error-limit=0");
   2336 
   2337         if (self.base.options.sysroot) |sysroot| {
   2338             try argv.append(try std.fmt.allocPrint(arena, "--sysroot={s}", .{sysroot}));
   2339         }
   2340 
   2341         if (self.base.options.lto) {
   2342             switch (self.base.options.optimize_mode) {
   2343                 .Debug => {},
   2344                 .ReleaseSmall => try argv.append("--lto-O2"),
   2345                 .ReleaseFast, .ReleaseSafe => try argv.append("--lto-O3"),
   2346             }
   2347         }
   2348         try argv.append(try std.fmt.allocPrint(arena, "-O{d}", .{
   2349             self.base.options.linker_optimization,
   2350         }));
   2351 
   2352         if (self.base.options.entry) |entry| {
   2353             try argv.append("--entry");
   2354             try argv.append(entry);
   2355         }
   2356 
   2357         for (self.base.options.force_undefined_symbols.keys()) |sym| {
   2358             try argv.append("-u");
   2359             try argv.append(sym);
   2360         }
   2361 
   2362         switch (self.base.options.hash_style) {
   2363             .gnu => try argv.append("--hash-style=gnu"),
   2364             .sysv => try argv.append("--hash-style=sysv"),
   2365             .both => {}, // this is the default
   2366         }
   2367 
   2368         if (self.base.options.output_mode == .Exe) {
   2369             try argv.append("-z");
   2370             try argv.append(try std.fmt.allocPrint(arena, "stack-size={d}", .{stack_size}));
   2371 
   2372             switch (self.base.options.build_id) {
   2373                 .none => {},
   2374                 .fast, .uuid, .sha1, .md5 => {
   2375                     try argv.append(try std.fmt.allocPrint(arena, "--build-id={s}", .{
   2376                         @tagName(self.base.options.build_id),
   2377                     }));
   2378                 },
   2379                 .hexstring => |hs| {
   2380                     try argv.append(try std.fmt.allocPrint(arena, "--build-id=0x{s}", .{
   2381                         std.fmt.fmtSliceHexLower(hs.toSlice()),
   2382                     }));
   2383                 },
   2384             }
   2385         }
   2386 
   2387         if (self.base.options.image_base_override) |image_base| {
   2388             try argv.append(try std.fmt.allocPrint(arena, "--image-base={d}", .{image_base}));
   2389         }
   2390 
   2391         if (self.base.options.linker_script) |linker_script| {
   2392             try argv.append("-T");
   2393             try argv.append(linker_script);
   2394         }
   2395 
   2396         if (self.base.options.sort_section) |how| {
   2397             const arg = try std.fmt.allocPrint(arena, "--sort-section={s}", .{@tagName(how)});
   2398             try argv.append(arg);
   2399         }
   2400 
   2401         if (gc_sections) {
   2402             try argv.append("--gc-sections");
   2403         }
   2404 
   2405         if (self.base.options.print_gc_sections) {
   2406             try argv.append("--print-gc-sections");
   2407         }
   2408 
   2409         if (self.base.options.print_icf_sections) {
   2410             try argv.append("--print-icf-sections");
   2411         }
   2412 
   2413         if (self.base.options.print_map) {
   2414             try argv.append("--print-map");
   2415         }
   2416 
   2417         if (self.base.options.eh_frame_hdr) {
   2418             try argv.append("--eh-frame-hdr");
   2419         }
   2420 
   2421         if (self.base.options.emit_relocs) {
   2422             try argv.append("--emit-relocs");
   2423         }
   2424 
   2425         if (self.base.options.rdynamic) {
   2426             try argv.append("--export-dynamic");
   2427         }
   2428 
   2429         if (self.base.options.strip) {
   2430             try argv.append("-s");
   2431         }
   2432 
   2433         if (self.base.options.z_nodelete) {
   2434             try argv.append("-z");
   2435             try argv.append("nodelete");
   2436         }
   2437         if (self.base.options.z_notext) {
   2438             try argv.append("-z");
   2439             try argv.append("notext");
   2440         }
   2441         if (self.base.options.z_defs) {
   2442             try argv.append("-z");
   2443             try argv.append("defs");
   2444         }
   2445         if (self.base.options.z_origin) {
   2446             try argv.append("-z");
   2447             try argv.append("origin");
   2448         }
   2449         if (self.base.options.z_nocopyreloc) {
   2450             try argv.append("-z");
   2451             try argv.append("nocopyreloc");
   2452         }
   2453         if (self.base.options.z_now) {
   2454             // LLD defaults to -zlazy
   2455             try argv.append("-znow");
   2456         }
   2457         if (!self.base.options.z_relro) {
   2458             // LLD defaults to -zrelro
   2459             try argv.append("-znorelro");
   2460         }
   2461         if (self.base.options.z_common_page_size) |size| {
   2462             try argv.append("-z");
   2463             try argv.append(try std.fmt.allocPrint(arena, "common-page-size={d}", .{size}));
   2464         }
   2465         if (self.base.options.z_max_page_size) |size| {
   2466             try argv.append("-z");
   2467             try argv.append(try std.fmt.allocPrint(arena, "max-page-size={d}", .{size}));
   2468         }
   2469 
   2470         if (getLDMOption(target)) |ldm| {
   2471             // Any target ELF will use the freebsd osabi if suffixed with "_fbsd".
   2472             const arg = if (target.os.tag == .freebsd)
   2473                 try std.fmt.allocPrint(arena, "{s}_fbsd", .{ldm})
   2474             else
   2475                 ldm;
   2476             try argv.append("-m");
   2477             try argv.append(arg);
   2478         }
   2479 
   2480         if (self.base.options.link_mode == .Static) {
   2481             if (target.cpu.arch.isArmOrThumb()) {
   2482                 try argv.append("-Bstatic");
   2483             } else {
   2484                 try argv.append("-static");
   2485             }
   2486         } else if (is_dyn_lib) {
   2487             try argv.append("-shared");
   2488         }
   2489 
   2490         if (self.base.options.pie and self.base.options.output_mode == .Exe) {
   2491             try argv.append("-pie");
   2492         }
   2493 
   2494         if (is_dyn_lib and target.os.tag == .netbsd) {
   2495             // Add options to produce shared objects with only 2 PT_LOAD segments.
   2496             // NetBSD expects 2 PT_LOAD segments in a shared object, otherwise
   2497             // ld.elf_so fails loading dynamic libraries with "not found" error.
   2498             // See https://github.com/ziglang/zig/issues/9109 .
   2499             try argv.append("--no-rosegment");
   2500             try argv.append("-znorelro");
   2501         }
   2502 
   2503         try argv.append("-o");
   2504         try argv.append(full_out_path);
   2505 
   2506         // csu prelude
   2507         var csu = try CsuObjects.init(arena, self.base.options, comp);
   2508         if (csu.crt0) |v| try argv.append(v);
   2509         if (csu.crti) |v| try argv.append(v);
   2510         if (csu.crtbegin) |v| try argv.append(v);
   2511 
   2512         // rpaths
   2513         var rpath_table = std.StringHashMap(void).init(self.base.allocator);
   2514         defer rpath_table.deinit();
   2515         for (self.base.options.rpath_list) |rpath| {
   2516             if ((try rpath_table.fetchPut(rpath, {})) == null) {
   2517                 try argv.append("-rpath");
   2518                 try argv.append(rpath);
   2519             }
   2520         }
   2521 
   2522         for (self.base.options.symbol_wrap_set.keys()) |symbol_name| {
   2523             try argv.appendSlice(&.{ "-wrap", symbol_name });
   2524         }
   2525 
   2526         if (self.base.options.each_lib_rpath) {
   2527             var test_path = std.ArrayList(u8).init(arena);
   2528             for (self.base.options.lib_dirs) |lib_dir_path| {
   2529                 for (self.base.options.system_libs.keys()) |link_lib| {
   2530                     if (!(try self.accessLibPath(&test_path, null, lib_dir_path, link_lib, .Dynamic)))
   2531                         continue;
   2532                     if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) {
   2533                         try argv.append("-rpath");
   2534                         try argv.append(lib_dir_path);
   2535                     }
   2536                 }
   2537             }
   2538             for (self.base.options.objects) |obj| {
   2539                 if (Compilation.classifyFileExt(obj.path) == .shared_library) {
   2540                     const lib_dir_path = std.fs.path.dirname(obj.path) orelse continue;
   2541                     if (obj.loption) continue;
   2542 
   2543                     if ((try rpath_table.fetchPut(lib_dir_path, {})) == null) {
   2544                         try argv.append("-rpath");
   2545                         try argv.append(lib_dir_path);
   2546                     }
   2547                 }
   2548             }
   2549         }
   2550 
   2551         for (self.base.options.lib_dirs) |lib_dir| {
   2552             try argv.append("-L");
   2553             try argv.append(lib_dir);
   2554         }
   2555 
   2556         if (self.base.options.link_libc) {
   2557             if (self.base.options.libc_installation) |libc_installation| {
   2558                 try argv.append("-L");
   2559                 try argv.append(libc_installation.crt_dir.?);
   2560             }
   2561 
   2562             if (have_dynamic_linker) {
   2563                 if (self.base.options.dynamic_linker) |dynamic_linker| {
   2564                     try argv.append("-dynamic-linker");
   2565                     try argv.append(dynamic_linker);
   2566                 }
   2567             }
   2568         }
   2569 
   2570         if (is_dyn_lib) {
   2571             if (self.base.options.soname) |soname| {
   2572                 try argv.append("-soname");
   2573                 try argv.append(soname);
   2574             }
   2575             if (self.base.options.version_script) |version_script| {
   2576                 try argv.append("-version-script");
   2577                 try argv.append(version_script);
   2578             }
   2579         }
   2580 
   2581         // Positional arguments to the linker such as object files.
   2582         var whole_archive = false;
   2583         for (self.base.options.objects) |obj| {
   2584             if (obj.must_link and !whole_archive) {
   2585                 try argv.append("-whole-archive");
   2586                 whole_archive = true;
   2587             } else if (!obj.must_link and whole_archive) {
   2588                 try argv.append("-no-whole-archive");
   2589                 whole_archive = false;
   2590             }
   2591 
   2592             if (obj.loption) {
   2593                 assert(obj.path[0] == ':');
   2594                 try argv.append("-l");
   2595             }
   2596             try argv.append(obj.path);
   2597         }
   2598         if (whole_archive) {
   2599             try argv.append("-no-whole-archive");
   2600             whole_archive = false;
   2601         }
   2602 
   2603         for (comp.c_object_table.keys()) |key| {
   2604             try argv.append(key.status.success.object_path);
   2605         }
   2606 
   2607         if (module_obj_path) |p| {
   2608             try argv.append(p);
   2609         }
   2610 
   2611         // TSAN
   2612         if (self.base.options.tsan) {
   2613             try argv.append(comp.tsan_static_lib.?.full_object_path);
   2614         }
   2615 
   2616         // libc
   2617         if (is_exe_or_dyn_lib and
   2618             !self.base.options.skip_linker_dependencies and
   2619             !self.base.options.link_libc)
   2620         {
   2621             if (comp.libc_static_lib) |lib| {
   2622                 try argv.append(lib.full_object_path);
   2623             }
   2624         }
   2625 
   2626         // stack-protector.
   2627         // Related: https://github.com/ziglang/zig/issues/7265
   2628         if (comp.libssp_static_lib) |ssp| {
   2629             try argv.append(ssp.full_object_path);
   2630         }
   2631 
   2632         // Shared libraries.
   2633         if (is_exe_or_dyn_lib) {
   2634             const system_libs = self.base.options.system_libs.keys();
   2635             const system_libs_values = self.base.options.system_libs.values();
   2636 
   2637             // Worst-case, we need an --as-needed argument for every lib, as well
   2638             // as one before and one after.
   2639             try argv.ensureUnusedCapacity(system_libs.len * 2 + 2);
   2640             argv.appendAssumeCapacity("--as-needed");
   2641             var as_needed = true;
   2642 
   2643             for (system_libs_values) |lib_info| {
   2644                 const lib_as_needed = !lib_info.needed;
   2645                 switch ((@as(u2, @intFromBool(lib_as_needed)) << 1) | @intFromBool(as_needed)) {
   2646                     0b00, 0b11 => {},
   2647                     0b01 => {
   2648                         argv.appendAssumeCapacity("--no-as-needed");
   2649                         as_needed = false;
   2650                     },
   2651                     0b10 => {
   2652                         argv.appendAssumeCapacity("--as-needed");
   2653                         as_needed = true;
   2654                     },
   2655                 }
   2656 
   2657                 // By this time, we depend on these libs being dynamically linked
   2658                 // libraries and not static libraries (the check for that needs to be earlier),
   2659                 // but they could be full paths to .so files, in which case we
   2660                 // want to avoid prepending "-l".
   2661                 argv.appendAssumeCapacity(lib_info.path.?);
   2662             }
   2663 
   2664             if (!as_needed) {
   2665                 argv.appendAssumeCapacity("--as-needed");
   2666                 as_needed = true;
   2667             }
   2668 
   2669             // libc++ dep
   2670             if (self.base.options.link_libcpp) {
   2671                 try argv.append(comp.libcxxabi_static_lib.?.full_object_path);
   2672                 try argv.append(comp.libcxx_static_lib.?.full_object_path);
   2673             }
   2674 
   2675             // libunwind dep
   2676             if (self.base.options.link_libunwind) {
   2677                 try argv.append(comp.libunwind_static_lib.?.full_object_path);
   2678             }
   2679 
   2680             // libc dep
   2681             self.error_flags.missing_libc = false;
   2682             if (self.base.options.link_libc) {
   2683                 if (self.base.options.libc_installation != null) {
   2684                     const needs_grouping = self.base.options.link_mode == .Static;
   2685                     if (needs_grouping) try argv.append("--start-group");
   2686                     try argv.appendSlice(target_util.libcFullLinkFlags(target));
   2687                     if (needs_grouping) try argv.append("--end-group");
   2688                 } else if (target.isGnuLibC()) {
   2689                     for (glibc.libs) |lib| {
   2690                         const lib_path = try std.fmt.allocPrint(arena, "{s}{c}lib{s}.so.{d}", .{
   2691                             comp.glibc_so_files.?.dir_path, fs.path.sep, lib.name, lib.sover,
   2692                         });
   2693                         try argv.append(lib_path);
   2694                     }
   2695                     try argv.append(try comp.get_libc_crt_file(arena, "libc_nonshared.a"));
   2696                 } else if (target.isMusl()) {
   2697                     try argv.append(try comp.get_libc_crt_file(arena, switch (self.base.options.link_mode) {
   2698                         .Static => "libc.a",
   2699                         .Dynamic => "libc.so",
   2700                     }));
   2701                 } else {
   2702                     self.error_flags.missing_libc = true;
   2703                     return error.FlushFailure;
   2704                 }
   2705             }
   2706         }
   2707 
   2708         // compiler-rt. Since compiler_rt exports symbols like `memset`, it needs
   2709         // to be after the shared libraries, so they are picked up from the shared
   2710         // libraries, not libcompiler_rt.
   2711         if (compiler_rt_path) |p| {
   2712             try argv.append(p);
   2713         }
   2714 
   2715         // crt postlude
   2716         if (csu.crtend) |v| try argv.append(v);
   2717         if (csu.crtn) |v| try argv.append(v);
   2718 
   2719         if (allow_shlib_undefined) {
   2720             try argv.append("--allow-shlib-undefined");
   2721         }
   2722 
   2723         switch (self.base.options.compress_debug_sections) {
   2724             .none => {},
   2725             .zlib => try argv.append("--compress-debug-sections=zlib"),
   2726             .zstd => try argv.append("--compress-debug-sections=zstd"),
   2727         }
   2728 
   2729         if (self.base.options.bind_global_refs_locally) {
   2730             try argv.append("-Bsymbolic");
   2731         }
   2732 
   2733         if (self.base.options.verbose_link) {
   2734             // Skip over our own name so that the LLD linker name is the first argv item.
   2735             Compilation.dump_argv(argv.items[1..]);
   2736         }
   2737 
   2738         if (std.process.can_spawn) {
   2739             // If possible, we run LLD as a child process because it does not always
   2740             // behave properly as a library, unfortunately.
   2741             // https://github.com/ziglang/zig/issues/3825
   2742             var child = std.ChildProcess.init(argv.items, arena);
   2743             if (comp.clang_passthrough_mode) {
   2744                 child.stdin_behavior = .Inherit;
   2745                 child.stdout_behavior = .Inherit;
   2746                 child.stderr_behavior = .Inherit;
   2747 
   2748                 const term = child.spawnAndWait() catch |err| {
   2749                     log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
   2750                     return error.UnableToSpawnSelf;
   2751                 };
   2752                 switch (term) {
   2753                     .Exited => |code| {
   2754                         if (code != 0) {
   2755                             std.process.exit(code);
   2756                         }
   2757                     },
   2758                     else => std.process.abort(),
   2759                 }
   2760             } else {
   2761                 child.stdin_behavior = .Ignore;
   2762                 child.stdout_behavior = .Ignore;
   2763                 child.stderr_behavior = .Pipe;
   2764 
   2765                 try child.spawn();
   2766 
   2767                 const stderr = try child.stderr.?.reader().readAllAlloc(arena, std.math.maxInt(usize));
   2768 
   2769                 const term = child.wait() catch |err| {
   2770                     log.err("unable to spawn {s}: {s}", .{ argv.items[0], @errorName(err) });
   2771                     return error.UnableToSpawnSelf;
   2772                 };
   2773 
   2774                 switch (term) {
   2775                     .Exited => |code| {
   2776                         if (code != 0) {
   2777                             comp.lockAndParseLldStderr(linker_command, stderr);
   2778                             return error.LLDReportedFailure;
   2779                         }
   2780                     },
   2781                     else => {
   2782                         log.err("{s} terminated with stderr:\n{s}", .{ argv.items[0], stderr });
   2783                         return error.LLDCrashed;
   2784                     },
   2785                 }
   2786 
   2787                 if (stderr.len != 0) {
   2788                     log.warn("unexpected LLD stderr:\n{s}", .{stderr});
   2789                 }
   2790             }
   2791         } else {
   2792             const exit_code = try lldMain(arena, argv.items, false);
   2793             if (exit_code != 0) {
   2794                 if (comp.clang_passthrough_mode) {
   2795                     std.process.exit(exit_code);
   2796                 } else {
   2797                     return error.LLDReportedFailure;
   2798                 }
   2799             }
   2800         }
   2801     }
   2802 
   2803     if (!self.base.options.disable_lld_caching) {
   2804         // Update the file with the digest. If it fails we can continue; it only
   2805         // means that the next invocation will have an unnecessary cache miss.
   2806         Cache.writeSmallFile(directory.handle, id_symlink_basename, &digest) catch |err| {
   2807             log.warn("failed to save linking hash digest file: {s}", .{@errorName(err)});
   2808         };
   2809         // Again failure here only means an unnecessary cache miss.
   2810         man.writeManifest() catch |err| {
   2811             log.warn("failed to write cache manifest when linking: {s}", .{@errorName(err)});
   2812         };
   2813         // We hang on to this lock so that the output file path can be used without
   2814         // other processes clobbering it.
   2815         self.base.lock = man.toOwnedLock();
   2816     }
   2817 }
   2818 
   2819 fn writeDwarfAddrAssumeCapacity(self: *Elf, buf: *std.ArrayList(u8), addr: u64) void {
   2820     const target_endian = self.base.options.target.cpu.arch.endian();
   2821     switch (self.ptr_width) {
   2822         .p32 => mem.writeInt(u32, buf.addManyAsArrayAssumeCapacity(4), @as(u32, @intCast(addr)), target_endian),
   2823         .p64 => mem.writeInt(u64, buf.addManyAsArrayAssumeCapacity(8), addr, target_endian),
   2824     }
   2825 }
   2826 
   2827 fn writeShdrTable(self: *Elf) !void {
   2828     const gpa = self.base.allocator;
   2829     const target_endian = self.base.options.target.cpu.arch.endian();
   2830     const foreign_endian = target_endian != builtin.cpu.arch.endian();
   2831     const shsize: u64 = switch (self.ptr_width) {
   2832         .p32 => @sizeOf(elf.Elf32_Shdr),
   2833         .p64 => @sizeOf(elf.Elf64_Shdr),
   2834     };
   2835     const shalign: u16 = switch (self.ptr_width) {
   2836         .p32 => @alignOf(elf.Elf32_Shdr),
   2837         .p64 => @alignOf(elf.Elf64_Shdr),
   2838     };
   2839 
   2840     const shoff = self.shdr_table_offset orelse 0;
   2841     const needed_size = self.shdrs.items.len * shsize;
   2842 
   2843     if (needed_size > self.allocatedSize(shoff)) {
   2844         self.shdr_table_offset = null;
   2845         self.shdr_table_offset = self.findFreeSpace(needed_size, shalign);
   2846     }
   2847 
   2848     log.debug("writing section headers from 0x{x} to 0x{x}", .{
   2849         self.shdr_table_offset.?,
   2850         self.shdr_table_offset.? + needed_size,
   2851     });
   2852 
   2853     switch (self.ptr_width) {
   2854         .p32 => {
   2855             const buf = try gpa.alloc(elf.Elf32_Shdr, self.shdrs.items.len);
   2856             defer gpa.free(buf);
   2857 
   2858             for (buf, 0..) |*shdr, i| {
   2859                 shdr.* = shdrTo32(self.shdrs.items[i]);
   2860                 if (foreign_endian) {
   2861                     mem.byteSwapAllFields(elf.Elf32_Shdr, shdr);
   2862                 }
   2863             }
   2864             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
   2865         },
   2866         .p64 => {
   2867             const buf = try gpa.alloc(elf.Elf64_Shdr, self.shdrs.items.len);
   2868             defer gpa.free(buf);
   2869 
   2870             for (buf, 0..) |*shdr, i| {
   2871                 shdr.* = self.shdrs.items[i];
   2872                 if (foreign_endian) {
   2873                     mem.byteSwapAllFields(elf.Elf64_Shdr, shdr);
   2874                 }
   2875             }
   2876             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), self.shdr_table_offset.?);
   2877         },
   2878     }
   2879 }
   2880 
   2881 fn writePhdrTable(self: *Elf) !void {
   2882     const gpa = self.base.allocator;
   2883     const target_endian = self.base.options.target.cpu.arch.endian();
   2884     const foreign_endian = target_endian != builtin.cpu.arch.endian();
   2885     const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
   2886 
   2887     log.debug("writing program headers from 0x{x} to 0x{x}", .{
   2888         phdr_table.p_offset,
   2889         phdr_table.p_offset + phdr_table.p_filesz,
   2890     });
   2891 
   2892     switch (self.ptr_width) {
   2893         .p32 => {
   2894             const buf = try gpa.alloc(elf.Elf32_Phdr, self.phdrs.items.len);
   2895             defer gpa.free(buf);
   2896 
   2897             for (buf, 0..) |*phdr, i| {
   2898                 phdr.* = phdrTo32(self.phdrs.items[i]);
   2899                 if (foreign_endian) {
   2900                     mem.byteSwapAllFields(elf.Elf32_Phdr, phdr);
   2901                 }
   2902             }
   2903             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
   2904         },
   2905         .p64 => {
   2906             const buf = try gpa.alloc(elf.Elf64_Phdr, self.phdrs.items.len);
   2907             defer gpa.free(buf);
   2908 
   2909             for (buf, 0..) |*phdr, i| {
   2910                 phdr.* = self.phdrs.items[i];
   2911                 if (foreign_endian) {
   2912                     mem.byteSwapAllFields(elf.Elf64_Phdr, phdr);
   2913                 }
   2914             }
   2915             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), phdr_table.p_offset);
   2916         },
   2917     }
   2918 }
   2919 
   2920 fn writeElfHeader(self: *Elf) !void {
   2921     var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
   2922 
   2923     var index: usize = 0;
   2924     hdr_buf[0..4].* = elf.MAGIC.*;
   2925     index += 4;
   2926 
   2927     hdr_buf[index] = switch (self.ptr_width) {
   2928         .p32 => elf.ELFCLASS32,
   2929         .p64 => elf.ELFCLASS64,
   2930     };
   2931     index += 1;
   2932 
   2933     const endian = self.base.options.target.cpu.arch.endian();
   2934     hdr_buf[index] = switch (endian) {
   2935         .little => elf.ELFDATA2LSB,
   2936         .big => elf.ELFDATA2MSB,
   2937     };
   2938     index += 1;
   2939 
   2940     hdr_buf[index] = 1; // ELF version
   2941     index += 1;
   2942 
   2943     // OS ABI, often set to 0 regardless of target platform
   2944     // ABI Version, possibly used by glibc but not by static executables
   2945     // padding
   2946     @memset(hdr_buf[index..][0..9], 0);
   2947     index += 9;
   2948 
   2949     assert(index == 16);
   2950 
   2951     const elf_type: elf.ET = switch (self.base.options.output_mode) {
   2952         .Exe => if (self.base.options.pie) .DYN else .EXEC,
   2953         .Obj => .REL,
   2954         .Lib => switch (self.base.options.link_mode) {
   2955             .Static => @as(elf.ET, .REL),
   2956             .Dynamic => .DYN,
   2957         },
   2958     };
   2959     mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(elf_type), endian);
   2960     index += 2;
   2961 
   2962     const machine = self.base.options.target.cpu.arch.toElfMachine();
   2963     mem.writeInt(u16, hdr_buf[index..][0..2], @intFromEnum(machine), endian);
   2964     index += 2;
   2965 
   2966     // ELF Version, again
   2967     mem.writeInt(u32, hdr_buf[index..][0..4], 1, endian);
   2968     index += 4;
   2969 
   2970     const e_entry = if (self.entry_index) |entry_index| self.symbol(entry_index).value else 0;
   2971     const phdr_table_offset = if (self.phdr_table_index) |phndx| self.phdrs.items[phndx].p_offset else 0;
   2972     switch (self.ptr_width) {
   2973         .p32 => {
   2974             mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(e_entry)), endian);
   2975             index += 4;
   2976 
   2977             // e_phoff
   2978             mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(phdr_table_offset)), endian);
   2979             index += 4;
   2980 
   2981             // e_shoff
   2982             mem.writeInt(u32, hdr_buf[index..][0..4], @as(u32, @intCast(self.shdr_table_offset.?)), endian);
   2983             index += 4;
   2984         },
   2985         .p64 => {
   2986             // e_entry
   2987             mem.writeInt(u64, hdr_buf[index..][0..8], e_entry, endian);
   2988             index += 8;
   2989 
   2990             // e_phoff
   2991             mem.writeInt(u64, hdr_buf[index..][0..8], phdr_table_offset, endian);
   2992             index += 8;
   2993 
   2994             // e_shoff
   2995             mem.writeInt(u64, hdr_buf[index..][0..8], self.shdr_table_offset.?, endian);
   2996             index += 8;
   2997         },
   2998     }
   2999 
   3000     const e_flags = 0;
   3001     mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian);
   3002     index += 4;
   3003 
   3004     const e_ehsize: u16 = switch (self.ptr_width) {
   3005         .p32 => @sizeOf(elf.Elf32_Ehdr),
   3006         .p64 => @sizeOf(elf.Elf64_Ehdr),
   3007     };
   3008     mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian);
   3009     index += 2;
   3010 
   3011     const e_phentsize: u16 = switch (self.ptr_width) {
   3012         .p32 => @sizeOf(elf.Elf32_Phdr),
   3013         .p64 => @sizeOf(elf.Elf64_Phdr),
   3014     };
   3015     mem.writeInt(u16, hdr_buf[index..][0..2], e_phentsize, endian);
   3016     index += 2;
   3017 
   3018     const e_phnum = @as(u16, @intCast(self.phdrs.items.len));
   3019     mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian);
   3020     index += 2;
   3021 
   3022     const e_shentsize: u16 = switch (self.ptr_width) {
   3023         .p32 => @sizeOf(elf.Elf32_Shdr),
   3024         .p64 => @sizeOf(elf.Elf64_Shdr),
   3025     };
   3026     mem.writeInt(u16, hdr_buf[index..][0..2], e_shentsize, endian);
   3027     index += 2;
   3028 
   3029     const e_shnum = @as(u16, @intCast(self.shdrs.items.len));
   3030     mem.writeInt(u16, hdr_buf[index..][0..2], e_shnum, endian);
   3031     index += 2;
   3032 
   3033     mem.writeInt(u16, hdr_buf[index..][0..2], self.shstrtab_section_index.?, endian);
   3034     index += 2;
   3035 
   3036     assert(index == e_ehsize);
   3037 
   3038     try self.base.file.?.pwriteAll(hdr_buf[0..index], 0);
   3039 }
   3040 
   3041 pub fn freeDecl(self: *Elf, decl_index: Module.Decl.Index) void {
   3042     if (self.llvm_object) |llvm_object| return llvm_object.freeDecl(decl_index);
   3043     return self.zigObjectPtr().?.freeDecl(self, decl_index);
   3044 }
   3045 
   3046 pub fn updateFunc(self: *Elf, mod: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {
   3047     if (build_options.skip_non_native and builtin.object_format != .elf) {
   3048         @panic("Attempted to compile for object format that was disabled by build configuration");
   3049     }
   3050     if (self.llvm_object) |llvm_object| return llvm_object.updateFunc(mod, func_index, air, liveness);
   3051     return self.zigObjectPtr().?.updateFunc(self, mod, func_index, air, liveness);
   3052 }
   3053 
   3054 pub fn updateDecl(
   3055     self: *Elf,
   3056     mod: *Module,
   3057     decl_index: Module.Decl.Index,
   3058 ) link.File.UpdateDeclError!void {
   3059     if (build_options.skip_non_native and builtin.object_format != .elf) {
   3060         @panic("Attempted to compile for object format that was disabled by build configuration");
   3061     }
   3062     if (self.llvm_object) |llvm_object| return llvm_object.updateDecl(mod, decl_index);
   3063     return self.zigObjectPtr().?.updateDecl(self, mod, decl_index);
   3064 }
   3065 
   3066 pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
   3067     return self.zigObjectPtr().?.lowerUnnamedConst(self, typed_value, decl_index);
   3068 }
   3069 
   3070 pub fn updateExports(
   3071     self: *Elf,
   3072     mod: *Module,
   3073     exported: Module.Exported,
   3074     exports: []const *Module.Export,
   3075 ) link.File.UpdateExportsError!void {
   3076     if (build_options.skip_non_native and builtin.object_format != .elf) {
   3077         @panic("Attempted to compile for object format that was disabled by build configuration");
   3078     }
   3079     if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
   3080     if (self.base.options.emit == null) return;
   3081     return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
   3082 }
   3083 
   3084 pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.Index) !void {
   3085     if (self.llvm_object) |_| return;
   3086     return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
   3087 }
   3088 
   3089 pub fn deleteDeclExport(
   3090     self: *Elf,
   3091     decl_index: Module.Decl.Index,
   3092     name: InternPool.NullTerminatedString,
   3093 ) void {
   3094     if (self.llvm_object) |_| return;
   3095     return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
   3096 }
   3097 
   3098 fn addLinkerDefinedSymbols(self: *Elf) !void {
   3099     const linker_defined_index = self.linker_defined_index orelse return;
   3100     const linker_defined = self.file(linker_defined_index).?.linker_defined;
   3101     self.dynamic_index = try linker_defined.addGlobal("_DYNAMIC", self);
   3102     self.ehdr_start_index = try linker_defined.addGlobal("__ehdr_start", self);
   3103     self.init_array_start_index = try linker_defined.addGlobal("__init_array_start", self);
   3104     self.init_array_end_index = try linker_defined.addGlobal("__init_array_end", self);
   3105     self.fini_array_start_index = try linker_defined.addGlobal("__fini_array_start", self);
   3106     self.fini_array_end_index = try linker_defined.addGlobal("__fini_array_end", self);
   3107     self.preinit_array_start_index = try linker_defined.addGlobal("__preinit_array_start", self);
   3108     self.preinit_array_end_index = try linker_defined.addGlobal("__preinit_array_end", self);
   3109     self.got_index = try linker_defined.addGlobal("_GLOBAL_OFFSET_TABLE_", self);
   3110     self.plt_index = try linker_defined.addGlobal("_PROCEDURE_LINKAGE_TABLE_", self);
   3111     self.end_index = try linker_defined.addGlobal("_end", self);
   3112 
   3113     if (self.base.options.eh_frame_hdr) {
   3114         self.gnu_eh_frame_hdr_index = try linker_defined.addGlobal("__GNU_EH_FRAME_HDR", self);
   3115     }
   3116 
   3117     if (self.globalByName("__dso_handle")) |index| {
   3118         if (self.symbol(index).file(self) == null)
   3119             self.dso_handle_index = try linker_defined.addGlobal("__dso_handle", self);
   3120     }
   3121 
   3122     self.rela_iplt_start_index = try linker_defined.addGlobal("__rela_iplt_start", self);
   3123     self.rela_iplt_end_index = try linker_defined.addGlobal("__rela_iplt_end", self);
   3124 
   3125     for (self.objects.items) |index| {
   3126         const object = self.file(index).?.object;
   3127         for (object.atoms.items) |atom_index| {
   3128             if (self.getStartStopBasename(atom_index)) |name| {
   3129                 const gpa = self.base.allocator;
   3130                 try self.start_stop_indexes.ensureUnusedCapacity(gpa, 2);
   3131 
   3132                 const start = try std.fmt.allocPrintZ(gpa, "__start_{s}", .{name});
   3133                 defer gpa.free(start);
   3134                 const stop = try std.fmt.allocPrintZ(gpa, "__stop_{s}", .{name});
   3135                 defer gpa.free(stop);
   3136 
   3137                 self.start_stop_indexes.appendAssumeCapacity(try linker_defined.addGlobal(start, self));
   3138                 self.start_stop_indexes.appendAssumeCapacity(try linker_defined.addGlobal(stop, self));
   3139             }
   3140         }
   3141     }
   3142 
   3143     linker_defined.resolveSymbols(self);
   3144 }
   3145 
   3146 fn allocateLinkerDefinedSymbols(self: *Elf) void {
   3147     // _DYNAMIC
   3148     if (self.dynamic_section_index) |shndx| {
   3149         const shdr = &self.shdrs.items[shndx];
   3150         const symbol_ptr = self.symbol(self.dynamic_index.?);
   3151         symbol_ptr.value = shdr.sh_addr;
   3152         symbol_ptr.output_section_index = shndx;
   3153     }
   3154 
   3155     // __ehdr_start
   3156     {
   3157         const symbol_ptr = self.symbol(self.ehdr_start_index.?);
   3158         symbol_ptr.value = self.calcImageBase();
   3159         symbol_ptr.output_section_index = 1;
   3160     }
   3161 
   3162     // __init_array_start, __init_array_end
   3163     if (self.sectionByName(".init_array")) |shndx| {
   3164         const start_sym = self.symbol(self.init_array_start_index.?);
   3165         const end_sym = self.symbol(self.init_array_end_index.?);
   3166         const shdr = &self.shdrs.items[shndx];
   3167         start_sym.output_section_index = shndx;
   3168         start_sym.value = shdr.sh_addr;
   3169         end_sym.output_section_index = shndx;
   3170         end_sym.value = shdr.sh_addr + shdr.sh_size;
   3171     }
   3172 
   3173     // __fini_array_start, __fini_array_end
   3174     if (self.sectionByName(".fini_array")) |shndx| {
   3175         const start_sym = self.symbol(self.fini_array_start_index.?);
   3176         const end_sym = self.symbol(self.fini_array_end_index.?);
   3177         const shdr = &self.shdrs.items[shndx];
   3178         start_sym.output_section_index = shndx;
   3179         start_sym.value = shdr.sh_addr;
   3180         end_sym.output_section_index = shndx;
   3181         end_sym.value = shdr.sh_addr + shdr.sh_size;
   3182     }
   3183 
   3184     // __preinit_array_start, __preinit_array_end
   3185     if (self.sectionByName(".preinit_array")) |shndx| {
   3186         const start_sym = self.symbol(self.preinit_array_start_index.?);
   3187         const end_sym = self.symbol(self.preinit_array_end_index.?);
   3188         const shdr = &self.shdrs.items[shndx];
   3189         start_sym.output_section_index = shndx;
   3190         start_sym.value = shdr.sh_addr;
   3191         end_sym.output_section_index = shndx;
   3192         end_sym.value = shdr.sh_addr + shdr.sh_size;
   3193     }
   3194 
   3195     // _GLOBAL_OFFSET_TABLE_
   3196     if (self.got_plt_section_index) |shndx| {
   3197         const shdr = &self.shdrs.items[shndx];
   3198         const symbol_ptr = self.symbol(self.got_index.?);
   3199         symbol_ptr.value = shdr.sh_addr;
   3200         symbol_ptr.output_section_index = shndx;
   3201     }
   3202 
   3203     // _PROCEDURE_LINKAGE_TABLE_
   3204     if (self.plt_section_index) |shndx| {
   3205         const shdr = &self.shdrs.items[shndx];
   3206         const symbol_ptr = self.symbol(self.plt_index.?);
   3207         symbol_ptr.value = shdr.sh_addr;
   3208         symbol_ptr.output_section_index = shndx;
   3209     }
   3210 
   3211     // __dso_handle
   3212     if (self.dso_handle_index) |index| {
   3213         const shdr = &self.shdrs.items[1];
   3214         const symbol_ptr = self.symbol(index);
   3215         symbol_ptr.value = shdr.sh_addr;
   3216         symbol_ptr.output_section_index = 0;
   3217     }
   3218 
   3219     // __GNU_EH_FRAME_HDR
   3220     if (self.eh_frame_hdr_section_index) |shndx| {
   3221         const shdr = &self.shdrs.items[shndx];
   3222         const symbol_ptr = self.symbol(self.gnu_eh_frame_hdr_index.?);
   3223         symbol_ptr.value = shdr.sh_addr;
   3224         symbol_ptr.output_section_index = shndx;
   3225     }
   3226 
   3227     // __rela_iplt_start, __rela_iplt_end
   3228     if (self.rela_dyn_section_index) |shndx| blk: {
   3229         if (self.base.options.link_mode != .Static or self.base.options.pie) break :blk;
   3230         const shdr = &self.shdrs.items[shndx];
   3231         const end_addr = shdr.sh_addr + shdr.sh_size;
   3232         const start_addr = end_addr - self.calcNumIRelativeRelocs() * @sizeOf(elf.Elf64_Rela);
   3233         const start_sym = self.symbol(self.rela_iplt_start_index.?);
   3234         const end_sym = self.symbol(self.rela_iplt_end_index.?);
   3235         start_sym.value = start_addr;
   3236         start_sym.output_section_index = shndx;
   3237         end_sym.value = end_addr;
   3238         end_sym.output_section_index = shndx;
   3239     }
   3240 
   3241     // _end
   3242     {
   3243         const end_symbol = self.symbol(self.end_index.?);
   3244         for (self.shdrs.items, 0..) |shdr, shndx| {
   3245             if (shdr.sh_flags & elf.SHF_ALLOC != 0) {
   3246                 end_symbol.value = shdr.sh_addr + shdr.sh_size;
   3247                 end_symbol.output_section_index = @intCast(shndx);
   3248             }
   3249         }
   3250     }
   3251 
   3252     // __start_*, __stop_*
   3253     {
   3254         var index: usize = 0;
   3255         while (index < self.start_stop_indexes.items.len) : (index += 2) {
   3256             const start = self.symbol(self.start_stop_indexes.items[index]);
   3257             const name = start.name(self);
   3258             const stop = self.symbol(self.start_stop_indexes.items[index + 1]);
   3259             const shndx = self.sectionByName(name["__start_".len..]).?;
   3260             const shdr = &self.shdrs.items[shndx];
   3261             start.value = shdr.sh_addr;
   3262             start.output_section_index = shndx;
   3263             stop.value = shdr.sh_addr + shdr.sh_size;
   3264             stop.output_section_index = shndx;
   3265         }
   3266     }
   3267 }
   3268 
   3269 fn initSections(self: *Elf) !void {
   3270     const ptr_size = self.ptrWidthBytes();
   3271 
   3272     for (self.objects.items) |index| {
   3273         try self.file(index).?.object.initOutputSections(self);
   3274     }
   3275 
   3276     const needs_eh_frame = for (self.objects.items) |index| {
   3277         if (self.file(index).?.object.cies.items.len > 0) break true;
   3278     } else false;
   3279     if (needs_eh_frame) {
   3280         self.eh_frame_section_index = try self.addSection(.{
   3281             .name = ".eh_frame",
   3282             .type = elf.SHT_PROGBITS,
   3283             .flags = elf.SHF_ALLOC,
   3284             .addralign = ptr_size,
   3285             .offset = std.math.maxInt(u64),
   3286         });
   3287 
   3288         if (self.base.options.eh_frame_hdr) {
   3289             self.eh_frame_hdr_section_index = try self.addSection(.{
   3290                 .name = ".eh_frame_hdr",
   3291                 .type = elf.SHT_PROGBITS,
   3292                 .flags = elf.SHF_ALLOC,
   3293                 .addralign = 4,
   3294                 .offset = std.math.maxInt(u64),
   3295             });
   3296         }
   3297     }
   3298 
   3299     if (self.got.entries.items.len > 0) {
   3300         self.got_section_index = try self.addSection(.{
   3301             .name = ".got",
   3302             .type = elf.SHT_PROGBITS,
   3303             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
   3304             .addralign = ptr_size,
   3305             .offset = std.math.maxInt(u64),
   3306         });
   3307     }
   3308 
   3309     const needs_rela_dyn = blk: {
   3310         if (self.got.flags.needs_rela or self.got.flags.needs_tlsld or
   3311             self.zig_got.flags.needs_rela or self.copy_rel.symbols.items.len > 0) break :blk true;
   3312         if (self.zigObjectPtr()) |zig_object| {
   3313             if (zig_object.num_dynrelocs > 0) break :blk true;
   3314         }
   3315         for (self.objects.items) |index| {
   3316             if (self.file(index).?.object.num_dynrelocs > 0) break :blk true;
   3317         }
   3318         break :blk false;
   3319     };
   3320     if (needs_rela_dyn) {
   3321         self.rela_dyn_section_index = try self.addSection(.{
   3322             .name = ".rela.dyn",
   3323             .type = elf.SHT_RELA,
   3324             .flags = elf.SHF_ALLOC,
   3325             .addralign = @alignOf(elf.Elf64_Rela),
   3326             .entsize = @sizeOf(elf.Elf64_Rela),
   3327             .offset = std.math.maxInt(u64),
   3328         });
   3329     }
   3330 
   3331     if (self.plt.symbols.items.len > 0) {
   3332         self.plt_section_index = try self.addSection(.{
   3333             .name = ".plt",
   3334             .type = elf.SHT_PROGBITS,
   3335             .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
   3336             .addralign = 16,
   3337             .offset = std.math.maxInt(u64),
   3338         });
   3339         self.got_plt_section_index = try self.addSection(.{
   3340             .name = ".got.plt",
   3341             .type = elf.SHT_PROGBITS,
   3342             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
   3343             .addralign = @alignOf(u64),
   3344             .offset = std.math.maxInt(u64),
   3345         });
   3346         self.rela_plt_section_index = try self.addSection(.{
   3347             .name = ".rela.plt",
   3348             .type = elf.SHT_RELA,
   3349             .flags = elf.SHF_ALLOC,
   3350             .addralign = @alignOf(elf.Elf64_Rela),
   3351             .entsize = @sizeOf(elf.Elf64_Rela),
   3352             .offset = std.math.maxInt(u64),
   3353         });
   3354     }
   3355 
   3356     if (self.plt_got.symbols.items.len > 0) {
   3357         self.plt_got_section_index = try self.addSection(.{
   3358             .name = ".plt.got",
   3359             .type = elf.SHT_PROGBITS,
   3360             .flags = elf.SHF_ALLOC | elf.SHF_EXECINSTR,
   3361             .addralign = 16,
   3362             .offset = std.math.maxInt(u64),
   3363         });
   3364     }
   3365 
   3366     if (self.copy_rel.symbols.items.len > 0) {
   3367         self.copy_rel_section_index = try self.addSection(.{
   3368             .name = ".copyrel",
   3369             .type = elf.SHT_NOBITS,
   3370             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
   3371             .offset = std.math.maxInt(u64),
   3372         });
   3373     }
   3374 
   3375     const needs_interp = blk: {
   3376         // On Ubuntu with musl-gcc, we get a weird combo of options looking like this:
   3377         // -dynamic-linker=<path> -static
   3378         // In this case, if we do generate .interp section and segment, we will get
   3379         // a segfault in the dynamic linker trying to load a binary that is static
   3380         // and doesn't contain .dynamic section.
   3381         if (self.isStatic() and !self.base.options.pie) break :blk false;
   3382         break :blk self.base.options.dynamic_linker != null;
   3383     };
   3384     if (needs_interp) {
   3385         self.interp_section_index = try self.addSection(.{
   3386             .name = ".interp",
   3387             .type = elf.SHT_PROGBITS,
   3388             .flags = elf.SHF_ALLOC,
   3389             .addralign = 1,
   3390             .offset = std.math.maxInt(u64),
   3391         });
   3392     }
   3393 
   3394     if (self.isDynLib() or self.shared_objects.items.len > 0 or self.base.options.pie) {
   3395         self.dynstrtab_section_index = try self.addSection(.{
   3396             .name = ".dynstr",
   3397             .flags = elf.SHF_ALLOC,
   3398             .type = elf.SHT_STRTAB,
   3399             .entsize = 1,
   3400             .addralign = 1,
   3401             .offset = std.math.maxInt(u64),
   3402         });
   3403         self.dynamic_section_index = try self.addSection(.{
   3404             .name = ".dynamic",
   3405             .flags = elf.SHF_ALLOC | elf.SHF_WRITE,
   3406             .type = elf.SHT_DYNAMIC,
   3407             .entsize = @sizeOf(elf.Elf64_Dyn),
   3408             .addralign = @alignOf(elf.Elf64_Dyn),
   3409             .offset = std.math.maxInt(u64),
   3410         });
   3411         self.dynsymtab_section_index = try self.addSection(.{
   3412             .name = ".dynsym",
   3413             .flags = elf.SHF_ALLOC,
   3414             .type = elf.SHT_DYNSYM,
   3415             .addralign = @alignOf(elf.Elf64_Sym),
   3416             .entsize = @sizeOf(elf.Elf64_Sym),
   3417             .info = 1,
   3418             .offset = std.math.maxInt(u64),
   3419         });
   3420         self.hash_section_index = try self.addSection(.{
   3421             .name = ".hash",
   3422             .flags = elf.SHF_ALLOC,
   3423             .type = elf.SHT_HASH,
   3424             .addralign = 4,
   3425             .entsize = 4,
   3426             .offset = std.math.maxInt(u64),
   3427         });
   3428         self.gnu_hash_section_index = try self.addSection(.{
   3429             .name = ".gnu.hash",
   3430             .flags = elf.SHF_ALLOC,
   3431             .type = elf.SHT_GNU_HASH,
   3432             .addralign = 8,
   3433             .offset = std.math.maxInt(u64),
   3434         });
   3435 
   3436         const needs_versions = for (self.dynsym.entries.items) |entry| {
   3437             const sym = self.symbol(entry.symbol_index);
   3438             if (sym.flags.import and sym.version_index & elf.VERSYM_VERSION > elf.VER_NDX_GLOBAL) break true;
   3439         } else false;
   3440         if (needs_versions) {
   3441             self.versym_section_index = try self.addSection(.{
   3442                 .name = ".gnu.version",
   3443                 .flags = elf.SHF_ALLOC,
   3444                 .type = elf.SHT_GNU_VERSYM,
   3445                 .addralign = @alignOf(elf.Elf64_Versym),
   3446                 .entsize = @sizeOf(elf.Elf64_Versym),
   3447                 .offset = std.math.maxInt(u64),
   3448             });
   3449             self.verneed_section_index = try self.addSection(.{
   3450                 .name = ".gnu.version_r",
   3451                 .flags = elf.SHF_ALLOC,
   3452                 .type = elf.SHT_GNU_VERNEED,
   3453                 .addralign = @alignOf(elf.Elf64_Verneed),
   3454                 .offset = std.math.maxInt(u64),
   3455             });
   3456         }
   3457     }
   3458 
   3459     try self.initSymtab();
   3460     try self.initShStrtab();
   3461 }
   3462 
   3463 fn initSymtab(self: *Elf) !void {
   3464     const small_ptr = switch (self.ptr_width) {
   3465         .p32 => true,
   3466         .p64 => false,
   3467     };
   3468     if (self.symtab_section_index == null) {
   3469         self.symtab_section_index = try self.addSection(.{
   3470             .name = ".symtab",
   3471             .type = elf.SHT_SYMTAB,
   3472             .addralign = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym),
   3473             .entsize = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym),
   3474             .offset = std.math.maxInt(u64),
   3475         });
   3476     }
   3477     if (self.strtab_section_index == null) {
   3478         self.strtab_section_index = try self.addSection(.{
   3479             .name = ".strtab",
   3480             .type = elf.SHT_STRTAB,
   3481             .entsize = 1,
   3482             .addralign = 1,
   3483             .offset = std.math.maxInt(u64),
   3484         });
   3485     }
   3486 }
   3487 
   3488 fn initShStrtab(self: *Elf) !void {
   3489     if (self.shstrtab_section_index == null) {
   3490         self.shstrtab_section_index = try self.addSection(.{
   3491             .name = ".shstrtab",
   3492             .type = elf.SHT_STRTAB,
   3493             .entsize = 1,
   3494             .addralign = 1,
   3495             .offset = std.math.maxInt(u64),
   3496         });
   3497     }
   3498 }
   3499 
   3500 fn initSpecialPhdrs(self: *Elf) !void {
   3501     comptime assert(max_number_of_special_phdrs == 5);
   3502 
   3503     if (self.interp_section_index != null) {
   3504         self.phdr_interp_index = try self.addPhdr(.{
   3505             .type = elf.PT_INTERP,
   3506             .flags = elf.PF_R,
   3507             .@"align" = 1,
   3508         });
   3509     }
   3510     if (self.dynamic_section_index != null) {
   3511         self.phdr_dynamic_index = try self.addPhdr(.{
   3512             .type = elf.PT_DYNAMIC,
   3513             .flags = elf.PF_R | elf.PF_W,
   3514         });
   3515     }
   3516     if (self.eh_frame_hdr_section_index != null) {
   3517         self.phdr_gnu_eh_frame_index = try self.addPhdr(.{
   3518             .type = elf.PT_GNU_EH_FRAME,
   3519             .flags = elf.PF_R,
   3520         });
   3521     }
   3522     self.phdr_gnu_stack_index = try self.addPhdr(.{
   3523         .type = elf.PT_GNU_STACK,
   3524         .flags = elf.PF_W | elf.PF_R,
   3525         .memsz = self.base.options.stack_size_override orelse 0,
   3526         .@"align" = 1,
   3527     });
   3528 
   3529     const has_tls = for (self.shdrs.items) |shdr| {
   3530         if (shdr.sh_flags & elf.SHF_TLS != 0) break true;
   3531     } else false;
   3532     if (has_tls) {
   3533         self.phdr_tls_index = try self.addPhdr(.{
   3534             .type = elf.PT_TLS,
   3535             .flags = elf.PF_R,
   3536             .@"align" = 1,
   3537         });
   3538     }
   3539 }
   3540 
   3541 /// We need to sort constructors/destuctors in the following sections:
   3542 /// * .init_array
   3543 /// * .fini_array
   3544 /// * .preinit_array
   3545 /// * .ctors
   3546 /// * .dtors
   3547 /// The prority of inclusion is defined as part of the input section's name. For example, .init_array.10000.
   3548 /// If no priority value has been specified,
   3549 /// * for .init_array, .fini_array and .preinit_array, we automatically assign that section max value of maxInt(i32)
   3550 ///   and push it to the back of the queue,
   3551 /// * for .ctors and .dtors, we automatically assign that section min value of -1
   3552 ///   and push it to the front of the queue,
   3553 /// crtbegin and ctrend are assigned minInt(i32) and maxInt(i32) respectively.
   3554 /// Ties are broken by the file prority which corresponds to the inclusion of input sections in this output section
   3555 /// we are about to sort.
   3556 fn sortInitFini(self: *Elf) !void {
   3557     const gpa = self.base.allocator;
   3558 
   3559     const Entry = struct {
   3560         priority: i32,
   3561         atom_index: Atom.Index,
   3562 
   3563         pub fn lessThan(ctx: *Elf, lhs: @This(), rhs: @This()) bool {
   3564             if (lhs.priority == rhs.priority) {
   3565                 return ctx.atom(lhs.atom_index).?.priority(ctx) < ctx.atom(rhs.atom_index).?.priority(ctx);
   3566             }
   3567             return lhs.priority < rhs.priority;
   3568         }
   3569     };
   3570 
   3571     for (self.shdrs.items, 0..) |*shdr, shndx| {
   3572         if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
   3573 
   3574         var is_init_fini = false;
   3575         var is_ctor_dtor = false;
   3576         switch (shdr.sh_type) {
   3577             elf.SHT_PREINIT_ARRAY,
   3578             elf.SHT_INIT_ARRAY,
   3579             elf.SHT_FINI_ARRAY,
   3580             => is_init_fini = true,
   3581             else => {
   3582                 const name = self.getShString(shdr.sh_name);
   3583                 is_ctor_dtor = mem.indexOf(u8, name, ".ctors") != null or mem.indexOf(u8, name, ".dtors") != null;
   3584             },
   3585         }
   3586 
   3587         if (!is_init_fini and !is_ctor_dtor) continue;
   3588 
   3589         const atom_list = self.output_sections.getPtr(@intCast(shndx)) orelse continue;
   3590 
   3591         var entries = std.ArrayList(Entry).init(gpa);
   3592         try entries.ensureTotalCapacityPrecise(atom_list.items.len);
   3593         defer entries.deinit();
   3594 
   3595         for (atom_list.items) |atom_index| {
   3596             const atom_ptr = self.atom(atom_index).?;
   3597             const object = atom_ptr.file(self).?.object;
   3598             const priority = blk: {
   3599                 if (is_ctor_dtor) {
   3600                     if (mem.indexOf(u8, object.path, "crtbegin") != null) break :blk std.math.minInt(i32);
   3601                     if (mem.indexOf(u8, object.path, "crtend") != null) break :blk std.math.maxInt(i32);
   3602                 }
   3603                 const default: i32 = if (is_ctor_dtor) -1 else std.math.maxInt(i32);
   3604                 const name = atom_ptr.name(self);
   3605                 var it = mem.splitBackwards(u8, name, ".");
   3606                 const priority = std.fmt.parseUnsigned(u16, it.first(), 10) catch default;
   3607                 break :blk priority;
   3608             };
   3609             entries.appendAssumeCapacity(.{ .priority = priority, .atom_index = atom_index });
   3610         }
   3611 
   3612         mem.sort(Entry, entries.items, self, Entry.lessThan);
   3613 
   3614         atom_list.clearRetainingCapacity();
   3615         for (entries.items) |entry| {
   3616             atom_list.appendAssumeCapacity(entry.atom_index);
   3617         }
   3618     }
   3619 }
   3620 
   3621 fn setDynamicSection(self: *Elf, rpaths: []const []const u8) !void {
   3622     if (self.dynamic_section_index == null) return;
   3623 
   3624     for (self.shared_objects.items) |index| {
   3625         const shared_object = self.file(index).?.shared_object;
   3626         if (!shared_object.alive) continue;
   3627         try self.dynamic.addNeeded(shared_object, self);
   3628     }
   3629 
   3630     if (self.base.options.soname) |soname| {
   3631         try self.dynamic.setSoname(soname, self);
   3632     }
   3633 
   3634     try self.dynamic.setRpath(rpaths, self);
   3635 }
   3636 
   3637 fn sortDynamicSymtab(self: *Elf) void {
   3638     if (self.gnu_hash_section_index == null) return;
   3639     self.dynsym.sort(self);
   3640 }
   3641 
   3642 fn setVersionSymtab(self: *Elf) !void {
   3643     if (self.versym_section_index == null) return;
   3644     try self.versym.resize(self.base.allocator, self.dynsym.count());
   3645     self.versym.items[0] = elf.VER_NDX_LOCAL;
   3646     for (self.dynsym.entries.items, 1..) |entry, i| {
   3647         const sym = self.symbol(entry.symbol_index);
   3648         self.versym.items[i] = sym.version_index;
   3649     }
   3650 
   3651     if (self.verneed_section_index) |shndx| {
   3652         try self.verneed.generate(self);
   3653         const shdr = &self.shdrs.items[shndx];
   3654         shdr.sh_info = @as(u32, @intCast(self.verneed.verneed.items.len));
   3655     }
   3656 }
   3657 
   3658 fn setHashSections(self: *Elf) !void {
   3659     if (self.hash_section_index != null) {
   3660         try self.hash.generate(self);
   3661     }
   3662     if (self.gnu_hash_section_index != null) {
   3663         try self.gnu_hash.calcSize(self);
   3664     }
   3665 }
   3666 
   3667 fn phdrRank(phdr: elf.Elf64_Phdr) u8 {
   3668     switch (phdr.p_type) {
   3669         elf.PT_NULL => return 0,
   3670         elf.PT_PHDR => return 1,
   3671         elf.PT_INTERP => return 2,
   3672         elf.PT_LOAD => return 3,
   3673         elf.PT_DYNAMIC, elf.PT_TLS => return 4,
   3674         elf.PT_GNU_EH_FRAME => return 5,
   3675         elf.PT_GNU_STACK => return 6,
   3676         else => return 7,
   3677     }
   3678 }
   3679 
   3680 fn sortPhdrs(self: *Elf) error{OutOfMemory}!void {
   3681     const Entry = struct {
   3682         phndx: u16,
   3683 
   3684         pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
   3685             const lhs_phdr = elf_file.phdrs.items[lhs.phndx];
   3686             const rhs_phdr = elf_file.phdrs.items[rhs.phndx];
   3687             const lhs_rank = phdrRank(lhs_phdr);
   3688             const rhs_rank = phdrRank(rhs_phdr);
   3689             if (lhs_rank == rhs_rank) return lhs_phdr.p_vaddr < rhs_phdr.p_vaddr;
   3690             return lhs_rank < rhs_rank;
   3691         }
   3692     };
   3693 
   3694     const gpa = self.base.allocator;
   3695     var entries = try std.ArrayList(Entry).initCapacity(gpa, self.phdrs.items.len);
   3696     defer entries.deinit();
   3697     for (0..self.phdrs.items.len) |phndx| {
   3698         entries.appendAssumeCapacity(.{ .phndx = @as(u16, @intCast(phndx)) });
   3699     }
   3700 
   3701     mem.sort(Entry, entries.items, self, Entry.lessThan);
   3702 
   3703     const backlinks = try gpa.alloc(u16, entries.items.len);
   3704     defer gpa.free(backlinks);
   3705     for (entries.items, 0..) |entry, i| {
   3706         backlinks[entry.phndx] = @as(u16, @intCast(i));
   3707     }
   3708 
   3709     var slice = try self.phdrs.toOwnedSlice(gpa);
   3710     defer gpa.free(slice);
   3711 
   3712     try self.phdrs.ensureTotalCapacityPrecise(gpa, slice.len);
   3713     for (entries.items) |sorted| {
   3714         self.phdrs.appendAssumeCapacity(slice[sorted.phndx]);
   3715     }
   3716 
   3717     for (&[_]*?u16{
   3718         &self.phdr_zig_load_re_index,
   3719         &self.phdr_zig_got_index,
   3720         &self.phdr_zig_load_ro_index,
   3721         &self.phdr_zig_load_zerofill_index,
   3722         &self.phdr_table_index,
   3723         &self.phdr_table_load_index,
   3724         &self.phdr_interp_index,
   3725         &self.phdr_dynamic_index,
   3726         &self.phdr_gnu_eh_frame_index,
   3727         &self.phdr_tls_index,
   3728     }) |maybe_index| {
   3729         if (maybe_index.*) |*index| {
   3730             index.* = backlinks[index.*];
   3731         }
   3732     }
   3733 
   3734     {
   3735         var it = self.phdr_to_shdr_table.iterator();
   3736         while (it.next()) |entry| {
   3737             entry.value_ptr.* = backlinks[entry.value_ptr.*];
   3738         }
   3739     }
   3740 }
   3741 
   3742 fn shdrRank(self: *Elf, shndx: u16) u8 {
   3743     const shdr = self.shdrs.items[shndx];
   3744     const name = self.getShString(shdr.sh_name);
   3745     const flags = shdr.sh_flags;
   3746 
   3747     switch (shdr.sh_type) {
   3748         elf.SHT_NULL => return 0,
   3749         elf.SHT_DYNSYM => return 2,
   3750         elf.SHT_HASH => return 3,
   3751         elf.SHT_GNU_HASH => return 3,
   3752         elf.SHT_GNU_VERSYM => return 4,
   3753         elf.SHT_GNU_VERDEF => return 4,
   3754         elf.SHT_GNU_VERNEED => return 4,
   3755 
   3756         elf.SHT_PREINIT_ARRAY,
   3757         elf.SHT_INIT_ARRAY,
   3758         elf.SHT_FINI_ARRAY,
   3759         => return 0xf2,
   3760 
   3761         elf.SHT_DYNAMIC => return 0xf3,
   3762 
   3763         elf.SHT_RELA => return 0xf,
   3764 
   3765         elf.SHT_PROGBITS => if (flags & elf.SHF_ALLOC != 0) {
   3766             if (flags & elf.SHF_EXECINSTR != 0) {
   3767                 return 0xf1;
   3768             } else if (flags & elf.SHF_WRITE != 0) {
   3769                 return if (flags & elf.SHF_TLS != 0) 0xf4 else 0xf6;
   3770             } else if (mem.eql(u8, name, ".interp")) {
   3771                 return 1;
   3772             } else {
   3773                 return 0xf0;
   3774             }
   3775         } else {
   3776             if (mem.startsWith(u8, name, ".debug")) {
   3777                 return 0xf8;
   3778             } else {
   3779                 return 0xf9;
   3780             }
   3781         },
   3782 
   3783         elf.SHT_NOBITS => return if (flags & elf.SHF_TLS != 0) 0xf5 else 0xf7,
   3784         elf.SHT_SYMTAB => return 0xfa,
   3785         elf.SHT_STRTAB => return if (mem.eql(u8, name, ".dynstr")) 0x4 else 0xfb,
   3786         else => return 0xff,
   3787     }
   3788 }
   3789 
   3790 fn sortShdrs(self: *Elf) !void {
   3791     const Entry = struct {
   3792         shndx: u16,
   3793 
   3794         pub fn lessThan(elf_file: *Elf, lhs: @This(), rhs: @This()) bool {
   3795             return elf_file.shdrRank(lhs.shndx) < elf_file.shdrRank(rhs.shndx);
   3796         }
   3797     };
   3798 
   3799     const gpa = self.base.allocator;
   3800     var entries = try std.ArrayList(Entry).initCapacity(gpa, self.shdrs.items.len);
   3801     defer entries.deinit();
   3802     for (0..self.shdrs.items.len) |shndx| {
   3803         entries.appendAssumeCapacity(.{ .shndx = @as(u16, @intCast(shndx)) });
   3804     }
   3805 
   3806     mem.sort(Entry, entries.items, self, Entry.lessThan);
   3807 
   3808     const backlinks = try gpa.alloc(u16, entries.items.len);
   3809     defer gpa.free(backlinks);
   3810     for (entries.items, 0..) |entry, i| {
   3811         backlinks[entry.shndx] = @as(u16, @intCast(i));
   3812     }
   3813 
   3814     var slice = try self.shdrs.toOwnedSlice(gpa);
   3815     defer gpa.free(slice);
   3816 
   3817     try self.shdrs.ensureTotalCapacityPrecise(gpa, slice.len);
   3818     for (entries.items) |sorted| {
   3819         self.shdrs.appendAssumeCapacity(slice[sorted.shndx]);
   3820     }
   3821 
   3822     for (&[_]*?u16{
   3823         &self.eh_frame_section_index,
   3824         &self.eh_frame_hdr_section_index,
   3825         &self.got_section_index,
   3826         &self.symtab_section_index,
   3827         &self.strtab_section_index,
   3828         &self.shstrtab_section_index,
   3829         &self.interp_section_index,
   3830         &self.dynamic_section_index,
   3831         &self.dynsymtab_section_index,
   3832         &self.dynstrtab_section_index,
   3833         &self.hash_section_index,
   3834         &self.gnu_hash_section_index,
   3835         &self.plt_section_index,
   3836         &self.got_plt_section_index,
   3837         &self.plt_got_section_index,
   3838         &self.rela_dyn_section_index,
   3839         &self.rela_plt_section_index,
   3840         &self.copy_rel_section_index,
   3841         &self.versym_section_index,
   3842         &self.verneed_section_index,
   3843         &self.zig_text_section_index,
   3844         &self.zig_text_rela_section_index,
   3845         &self.zig_got_section_index,
   3846         &self.zig_data_rel_ro_section_index,
   3847         &self.zig_data_rel_ro_rela_section_index,
   3848         &self.zig_data_section_index,
   3849         &self.zig_data_rela_section_index,
   3850         &self.zig_bss_section_index,
   3851         &self.debug_str_section_index,
   3852         &self.debug_info_section_index,
   3853         &self.debug_abbrev_section_index,
   3854         &self.debug_aranges_section_index,
   3855         &self.debug_line_section_index,
   3856     }) |maybe_index| {
   3857         if (maybe_index.*) |*index| {
   3858             index.* = backlinks[index.*];
   3859         }
   3860     }
   3861 
   3862     if (self.symtab_section_index) |index| {
   3863         const shdr = &self.shdrs.items[index];
   3864         shdr.sh_link = self.strtab_section_index.?;
   3865     }
   3866 
   3867     if (self.dynamic_section_index) |index| {
   3868         const shdr = &self.shdrs.items[index];
   3869         shdr.sh_link = self.dynstrtab_section_index.?;
   3870     }
   3871 
   3872     if (self.dynsymtab_section_index) |index| {
   3873         const shdr = &self.shdrs.items[index];
   3874         shdr.sh_link = self.dynstrtab_section_index.?;
   3875     }
   3876 
   3877     if (self.hash_section_index) |index| {
   3878         const shdr = &self.shdrs.items[index];
   3879         shdr.sh_link = self.dynsymtab_section_index.?;
   3880     }
   3881 
   3882     if (self.gnu_hash_section_index) |index| {
   3883         const shdr = &self.shdrs.items[index];
   3884         shdr.sh_link = self.dynsymtab_section_index.?;
   3885     }
   3886 
   3887     if (self.versym_section_index) |index| {
   3888         const shdr = &self.shdrs.items[index];
   3889         shdr.sh_link = self.dynsymtab_section_index.?;
   3890     }
   3891 
   3892     if (self.verneed_section_index) |index| {
   3893         const shdr = &self.shdrs.items[index];
   3894         shdr.sh_link = self.dynstrtab_section_index.?;
   3895     }
   3896 
   3897     if (self.rela_dyn_section_index) |index| {
   3898         const shdr = &self.shdrs.items[index];
   3899         shdr.sh_link = self.dynsymtab_section_index orelse 0;
   3900     }
   3901 
   3902     if (self.rela_plt_section_index) |index| {
   3903         const shdr = &self.shdrs.items[index];
   3904         shdr.sh_link = self.dynsymtab_section_index.?;
   3905         shdr.sh_info = self.plt_section_index.?;
   3906     }
   3907 
   3908     for (&[_]?u16{
   3909         self.zig_text_rela_section_index,
   3910         self.zig_data_rel_ro_rela_section_index,
   3911         self.zig_data_rela_section_index,
   3912     }) |maybe_index| {
   3913         const index = maybe_index orelse continue;
   3914         const shdr = &self.shdrs.items[index];
   3915         shdr.sh_link = self.symtab_section_index.?;
   3916         shdr.sh_info = backlinks[shdr.sh_info];
   3917     }
   3918 
   3919     {
   3920         var last_atom_and_free_list_table = try self.last_atom_and_free_list_table.clone(gpa);
   3921         defer last_atom_and_free_list_table.deinit(gpa);
   3922 
   3923         self.last_atom_and_free_list_table.clearRetainingCapacity();
   3924 
   3925         var it = last_atom_and_free_list_table.iterator();
   3926         while (it.next()) |entry| {
   3927             const shndx = entry.key_ptr.*;
   3928             const meta = entry.value_ptr.*;
   3929             self.last_atom_and_free_list_table.putAssumeCapacityNoClobber(backlinks[shndx], meta);
   3930         }
   3931     }
   3932 
   3933     {
   3934         var phdr_to_shdr_table = try self.phdr_to_shdr_table.clone(gpa);
   3935         defer phdr_to_shdr_table.deinit(gpa);
   3936 
   3937         self.phdr_to_shdr_table.clearRetainingCapacity();
   3938 
   3939         var it = phdr_to_shdr_table.iterator();
   3940         while (it.next()) |entry| {
   3941             const shndx = entry.key_ptr.*;
   3942             const phndx = entry.value_ptr.*;
   3943             self.phdr_to_shdr_table.putAssumeCapacityNoClobber(backlinks[shndx], phndx);
   3944         }
   3945     }
   3946 
   3947     if (self.zigObjectPtr()) |zig_object| {
   3948         for (zig_object.atoms.items) |atom_index| {
   3949             const atom_ptr = self.atom(atom_index) orelse continue;
   3950             atom_ptr.output_section_index = backlinks[atom_ptr.output_section_index];
   3951         }
   3952 
   3953         for (zig_object.locals()) |local_index| {
   3954             const local = self.symbol(local_index);
   3955             local.output_section_index = backlinks[local.output_section_index];
   3956         }
   3957 
   3958         for (zig_object.globals()) |global_index| {
   3959             const global = self.symbol(global_index);
   3960             const atom_ptr = global.atom(self) orelse continue;
   3961             if (!atom_ptr.flags.alive) continue;
   3962             // TODO claim unresolved for objects
   3963             if (global.file(self).?.index() != zig_object.index) continue;
   3964             const out_shndx = global.outputShndx() orelse continue;
   3965             global.output_section_index = backlinks[out_shndx];
   3966         }
   3967     }
   3968 }
   3969 
   3970 fn updateSectionSizes(self: *Elf) !void {
   3971     for (self.output_sections.keys(), self.output_sections.values()) |shndx, atom_list| {
   3972         if (atom_list.items.len == 0) continue;
   3973         const shdr = &self.shdrs.items[shndx];
   3974         for (atom_list.items) |atom_index| {
   3975             const atom_ptr = self.atom(atom_index) orelse continue;
   3976             if (!atom_ptr.flags.alive) continue;
   3977             const offset = atom_ptr.alignment.forward(shdr.sh_size);
   3978             const padding = offset - shdr.sh_size;
   3979             atom_ptr.value = offset;
   3980             shdr.sh_size += padding + atom_ptr.size;
   3981             shdr.sh_addralign = @max(shdr.sh_addralign, atom_ptr.alignment.toByteUnits(1));
   3982         }
   3983     }
   3984 
   3985     if (self.zigObjectPtr()) |zig_object| {
   3986         zig_object.updateRelaSectionSizes(self);
   3987     }
   3988 
   3989     if (self.eh_frame_section_index) |index| {
   3990         self.shdrs.items[index].sh_size = try eh_frame.calcEhFrameSize(self);
   3991     }
   3992 
   3993     if (self.eh_frame_hdr_section_index) |index| {
   3994         self.shdrs.items[index].sh_size = eh_frame.calcEhFrameHdrSize(self);
   3995     }
   3996 
   3997     if (self.got_section_index) |index| {
   3998         self.shdrs.items[index].sh_size = self.got.size(self);
   3999     }
   4000 
   4001     if (self.plt_section_index) |index| {
   4002         self.shdrs.items[index].sh_size = self.plt.size();
   4003     }
   4004 
   4005     if (self.got_plt_section_index) |index| {
   4006         self.shdrs.items[index].sh_size = self.got_plt.size(self);
   4007     }
   4008 
   4009     if (self.plt_got_section_index) |index| {
   4010         self.shdrs.items[index].sh_size = self.plt_got.size();
   4011     }
   4012 
   4013     if (self.rela_dyn_section_index) |shndx| {
   4014         var num = self.got.numRela(self) + self.copy_rel.numRela() + self.zig_got.numRela();
   4015         if (self.zigObjectPtr()) |zig_object| {
   4016             num += zig_object.num_dynrelocs;
   4017         }
   4018         for (self.objects.items) |index| {
   4019             num += self.file(index).?.object.num_dynrelocs;
   4020         }
   4021         self.shdrs.items[shndx].sh_size = num * @sizeOf(elf.Elf64_Rela);
   4022     }
   4023 
   4024     if (self.rela_plt_section_index) |index| {
   4025         self.shdrs.items[index].sh_size = self.plt.numRela() * @sizeOf(elf.Elf64_Rela);
   4026     }
   4027 
   4028     if (self.copy_rel_section_index) |index| {
   4029         try self.copy_rel.updateSectionSize(index, self);
   4030     }
   4031 
   4032     if (self.interp_section_index) |index| {
   4033         self.shdrs.items[index].sh_size = self.base.options.dynamic_linker.?.len + 1;
   4034     }
   4035 
   4036     if (self.hash_section_index) |index| {
   4037         self.shdrs.items[index].sh_size = self.hash.size();
   4038     }
   4039 
   4040     if (self.gnu_hash_section_index) |index| {
   4041         self.shdrs.items[index].sh_size = self.gnu_hash.size();
   4042     }
   4043 
   4044     if (self.dynamic_section_index) |index| {
   4045         self.shdrs.items[index].sh_size = self.dynamic.size(self);
   4046     }
   4047 
   4048     if (self.dynsymtab_section_index) |index| {
   4049         self.shdrs.items[index].sh_size = self.dynsym.size();
   4050     }
   4051 
   4052     if (self.dynstrtab_section_index) |index| {
   4053         self.shdrs.items[index].sh_size = self.dynstrtab.items.len;
   4054     }
   4055 
   4056     if (self.versym_section_index) |index| {
   4057         self.shdrs.items[index].sh_size = self.versym.items.len * @sizeOf(elf.Elf64_Versym);
   4058     }
   4059 
   4060     if (self.verneed_section_index) |index| {
   4061         self.shdrs.items[index].sh_size = self.verneed.size();
   4062     }
   4063 
   4064     try self.updateSymtabSize();
   4065     self.updateShStrtabSize();
   4066 }
   4067 
   4068 fn updateShStrtabSize(self: *Elf) void {
   4069     if (self.shstrtab_section_index) |index| {
   4070         self.shdrs.items[index].sh_size = self.shstrtab.items.len;
   4071     }
   4072 }
   4073 
   4074 fn shdrToPhdrFlags(sh_flags: u64) u32 {
   4075     const write = sh_flags & elf.SHF_WRITE != 0;
   4076     const exec = sh_flags & elf.SHF_EXECINSTR != 0;
   4077     var out_flags: u32 = elf.PF_R;
   4078     if (write) out_flags |= elf.PF_W;
   4079     if (exec) out_flags |= elf.PF_X;
   4080     return out_flags;
   4081 }
   4082 
   4083 /// Returns maximum number of program headers that may be emitted by the linker.
   4084 /// (This is an upper bound so that we can reserve enough space for the header and progam header
   4085 /// table without running out of space and being forced to move things around.)
   4086 fn getMaxNumberOfPhdrs() u64 {
   4087     // First, assume we compile Zig's source incrementally, this gives us:
   4088     var num: u64 = number_of_zig_segments;
   4089     // Next, the estimated maximum number of segments the linker can emit for input sections are:
   4090     num += max_number_of_object_segments;
   4091     // Next, any other non-loadable program headers, including TLS, DYNAMIC, GNU_STACK, GNU_EH_FRAME, INTERP:
   4092     num += max_number_of_special_phdrs;
   4093     // Finally, PHDR program header and corresponding read-only load segment:
   4094     num += 2;
   4095     return num;
   4096 }
   4097 
   4098 /// Calculates how many segments (PT_LOAD progam headers) are required
   4099 /// to cover the set of sections.
   4100 /// We permit a maximum of 3**2 number of segments.
   4101 fn calcNumberOfSegments(self: *Elf) usize {
   4102     var covers: [9]bool = [_]bool{false} ** 9;
   4103     for (self.shdrs.items, 0..) |shdr, shndx| {
   4104         if (shdr.sh_type == elf.SHT_NULL) continue;
   4105         if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
   4106         if (self.isZigSection(@intCast(shndx))) continue;
   4107         const flags = shdrToPhdrFlags(shdr.sh_flags);
   4108         covers[flags - 1] = true;
   4109     }
   4110     var count: usize = 0;
   4111     for (covers) |cover| {
   4112         if (cover) count += 1;
   4113     }
   4114     return count;
   4115 }
   4116 
   4117 /// Allocates PHDR table in virtual memory and in file.
   4118 fn allocatePhdrTable(self: *Elf) error{OutOfMemory}!void {
   4119     const new_load_segments = self.calcNumberOfSegments();
   4120     const phdr_table = &self.phdrs.items[self.phdr_table_index.?];
   4121     const phdr_table_load = &self.phdrs.items[self.phdr_table_load_index.?];
   4122 
   4123     const ehsize: u64 = switch (self.ptr_width) {
   4124         .p32 => @sizeOf(elf.Elf32_Ehdr),
   4125         .p64 => @sizeOf(elf.Elf64_Ehdr),
   4126     };
   4127     const phsize: u64 = switch (self.ptr_width) {
   4128         .p32 => @sizeOf(elf.Elf32_Phdr),
   4129         .p64 => @sizeOf(elf.Elf64_Phdr),
   4130     };
   4131     const needed_size = (self.phdrs.items.len + new_load_segments) * phsize;
   4132     const available_space = self.allocatedSize(phdr_table.p_offset);
   4133 
   4134     if (needed_size > available_space) {
   4135         // In this case, we have two options:
   4136         // 1. increase the available padding for EHDR + PHDR table so that we don't overflow it
   4137         //    (revisit getMaxNumberOfPhdrs())
   4138         // 2. shift everything in file to free more space for EHDR + PHDR table
   4139         // TODO verify `getMaxNumberOfPhdrs()` is accurate and convert this into no-op
   4140         var err = try self.addErrorWithNotes(1);
   4141         try err.addMsg(self, "fatal linker error: not enough space reserved for EHDR and PHDR table", .{});
   4142         try err.addNote(self, "required 0x{x}, available 0x{x}", .{ needed_size, available_space });
   4143     }
   4144 
   4145     phdr_table_load.p_filesz = needed_size + ehsize;
   4146     phdr_table_load.p_memsz = needed_size + ehsize;
   4147     phdr_table.p_filesz = needed_size;
   4148     phdr_table.p_memsz = needed_size;
   4149 }
   4150 
   4151 /// Allocates alloc sections and creates load segments for sections
   4152 /// extracted from input object files.
   4153 fn allocateAllocSections(self: *Elf) error{OutOfMemory}!void {
   4154     // We use this struct to track maximum alignment of all TLS sections.
   4155     // According to https://github.com/rui314/mold/commit/bd46edf3f0fe9e1a787ea453c4657d535622e61f in mold,
   4156     // in-file offsets have to be aligned against the start of TLS program header.
   4157     // If that's not ensured, then in a multi-threaded context, TLS variables across a shared object
   4158     // boundary may not get correctly loaded at an aligned address.
   4159     const Align = struct {
   4160         tls_start_align: u64 = 1,
   4161         first_tls_index: ?usize = null,
   4162 
   4163         fn isFirstTlsShdr(this: @This(), other: usize) bool {
   4164             if (this.first_tls_index) |index| return index == other;
   4165             return false;
   4166         }
   4167 
   4168         fn @"align"(this: @This(), index: usize, sh_addralign: u64, addr: u64) u64 {
   4169             const alignment = if (this.isFirstTlsShdr(index)) this.tls_start_align else sh_addralign;
   4170             return mem.alignForward(u64, addr, alignment);
   4171         }
   4172     };
   4173 
   4174     var alignment = Align{};
   4175     for (self.shdrs.items, 0..) |shdr, i| {
   4176         if (shdr.sh_type == elf.SHT_NULL) continue;
   4177         if (shdr.sh_flags & elf.SHF_TLS == 0) continue;
   4178         if (alignment.first_tls_index == null) alignment.first_tls_index = i;
   4179         alignment.tls_start_align = @max(alignment.tls_start_align, shdr.sh_addralign);
   4180     }
   4181 
   4182     // Next, calculate segment covers by scanning all alloc sections.
   4183     // If a section matches segment flags with the preceeding section,
   4184     // we put it in the same segment. Otherwise, we create a new cover.
   4185     // This algorithm is simple but suboptimal in terms of space re-use:
   4186     // normally we would also take into account any gaps in allocated
   4187     // virtual and file offsets. However, the simple one will do for one
   4188     // as we are more interested in quick turnaround and compatibility
   4189     // with `findFreeSpace` mechanics than anything else.
   4190     const Cover = std.ArrayList(u16);
   4191     const gpa = self.base.allocator;
   4192     var covers: [max_number_of_object_segments]Cover = undefined;
   4193     for (&covers) |*cover| {
   4194         cover.* = Cover.init(gpa);
   4195     }
   4196     defer for (&covers) |*cover| {
   4197         cover.deinit();
   4198     };
   4199 
   4200     for (self.shdrs.items, 0..) |shdr, shndx| {
   4201         if (shdr.sh_type == elf.SHT_NULL) continue;
   4202         if (shdr.sh_flags & elf.SHF_ALLOC == 0) continue;
   4203         if (self.isZigSection(@intCast(shndx))) continue;
   4204         const flags = shdrToPhdrFlags(shdr.sh_flags);
   4205         try covers[flags - 1].append(@intCast(shndx));
   4206     }
   4207 
   4208     // Now we can proceed with allocating the sections in virtual memory.
   4209     // As the base address we take the end address of the PHDR table.
   4210     // When allocating we first find the largest required alignment
   4211     // of any section that is contained in a cover and use it to align
   4212     // the start address of the segement (and first section).
   4213     const phdr_table = &self.phdrs.items[self.phdr_table_load_index.?];
   4214     var addr = phdr_table.p_vaddr + phdr_table.p_memsz;
   4215 
   4216     for (covers) |cover| {
   4217         if (cover.items.len == 0) continue;
   4218 
   4219         var @"align": u64 = self.page_size;
   4220         for (cover.items) |shndx| {
   4221             const shdr = self.shdrs.items[shndx];
   4222             if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) continue;
   4223             @"align" = @max(@"align", shdr.sh_addralign);
   4224         }
   4225 
   4226         addr = mem.alignForward(u64, addr, @"align");
   4227 
   4228         var memsz: u64 = 0;
   4229         var filesz: u64 = 0;
   4230         var i: usize = 0;
   4231         while (i < cover.items.len) : (i += 1) {
   4232             const shndx = cover.items[i];
   4233             const shdr = &self.shdrs.items[shndx];
   4234             if (shdr.sh_type == elf.SHT_NOBITS and shdr.sh_flags & elf.SHF_TLS != 0) {
   4235                 // .tbss is a little special as it's used only by the loader meaning it doesn't
   4236                 // need to be actually mmap'ed at runtime. We still need to correctly increment
   4237                 // the addresses of every TLS zerofill section tho. Thus, we hack it so that
   4238                 // we increment the start address like normal, however, after we are done,
   4239                 // the next ALLOC section will get its start address allocated within the same
   4240                 // range as the .tbss sections. We will get something like this:
   4241                 //
   4242                 // ...
   4243                 // .tbss 0x10
   4244                 // .tcommon 0x20
   4245                 // .data 0x10
   4246                 // ...
   4247                 var tbss_addr = addr;
   4248                 while (i < cover.items.len and
   4249                     self.shdrs.items[cover.items[i]].sh_type == elf.SHT_NOBITS and
   4250                     self.shdrs.items[cover.items[i]].sh_flags & elf.SHF_TLS != 0) : (i += 1)
   4251                 {
   4252                     const tbss_shndx = cover.items[i];
   4253                     const tbss_shdr = &self.shdrs.items[tbss_shndx];
   4254                     tbss_addr = alignment.@"align"(tbss_shndx, tbss_shdr.sh_addralign, tbss_addr);
   4255                     tbss_shdr.sh_addr = tbss_addr;
   4256                     tbss_addr += tbss_shdr.sh_size;
   4257                 }
   4258                 i -= 1;
   4259                 continue;
   4260             }
   4261             const next = alignment.@"align"(shndx, shdr.sh_addralign, addr);
   4262             const padding = next - addr;
   4263             addr = next;
   4264             shdr.sh_addr = addr;
   4265             if (shdr.sh_type != elf.SHT_NOBITS) {
   4266                 filesz += padding + shdr.sh_size;
   4267             }
   4268             memsz += padding + shdr.sh_size;
   4269             addr += shdr.sh_size;
   4270         }
   4271 
   4272         const first = self.shdrs.items[cover.items[0]];
   4273         var off = self.findFreeSpace(filesz, @"align");
   4274         const phndx = try self.addPhdr(.{
   4275             .type = elf.PT_LOAD,
   4276             .offset = off,
   4277             .addr = first.sh_addr,
   4278             .memsz = memsz,
   4279             .filesz = filesz,
   4280             .@"align" = @"align",
   4281             .flags = shdrToPhdrFlags(first.sh_flags),
   4282         });
   4283 
   4284         for (cover.items) |shndx| {
   4285             const shdr = &self.shdrs.items[shndx];
   4286             if (shdr.sh_type == elf.SHT_NOBITS) continue;
   4287             off = alignment.@"align"(shndx, shdr.sh_addralign, off);
   4288             shdr.sh_offset = off;
   4289             off += shdr.sh_size;
   4290             try self.phdr_to_shdr_table.putNoClobber(gpa, shndx, phndx);
   4291         }
   4292 
   4293         addr = mem.alignForward(u64, addr, self.page_size);
   4294     }
   4295 }
   4296 
   4297 /// Allocates non-alloc sections (debug info, symtabs, etc.).
   4298 fn allocateNonAllocSections(self: *Elf) !void {
   4299     for (self.shdrs.items, 0..) |*shdr, shndx| {
   4300         if (shdr.sh_type == elf.SHT_NULL) continue;
   4301         if (shdr.sh_flags & elf.SHF_ALLOC != 0) continue;
   4302         const needed_size = shdr.sh_size;
   4303         if (needed_size > self.allocatedSize(shdr.sh_offset)) {
   4304             shdr.sh_size = 0;
   4305             const new_offset = self.findFreeSpace(needed_size, shdr.sh_addralign);
   4306 
   4307             if (self.isDebugSection(@intCast(shndx))) {
   4308                 log.debug("moving {s} from 0x{x} to 0x{x}", .{
   4309                     self.getShString(shdr.sh_name),
   4310                     shdr.sh_offset,
   4311                     new_offset,
   4312                 });
   4313                 const zig_object = self.zigObjectPtr().?;
   4314                 const existing_size = blk: {
   4315                     if (shndx == self.debug_info_section_index.?)
   4316                         break :blk zig_object.debug_info_section_zig_size;
   4317                     if (shndx == self.debug_abbrev_section_index.?)
   4318                         break :blk zig_object.debug_abbrev_section_zig_size;
   4319                     if (shndx == self.debug_str_section_index.?)
   4320                         break :blk zig_object.debug_str_section_zig_size;
   4321                     if (shndx == self.debug_aranges_section_index.?)
   4322                         break :blk zig_object.debug_aranges_section_zig_size;
   4323                     if (shndx == self.debug_line_section_index.?)
   4324                         break :blk zig_object.debug_line_section_zig_size;
   4325                     unreachable;
   4326                 };
   4327                 const amt = try self.base.file.?.copyRangeAll(
   4328                     shdr.sh_offset,
   4329                     self.base.file.?,
   4330                     new_offset,
   4331                     existing_size,
   4332                 );
   4333                 if (amt != existing_size) return error.InputOutput;
   4334             }
   4335 
   4336             shdr.sh_offset = new_offset;
   4337             shdr.sh_size = needed_size;
   4338         }
   4339     }
   4340 }
   4341 
   4342 fn allocateSpecialPhdrs(self: *Elf) void {
   4343     for (&[_]struct { ?u16, ?u16 }{
   4344         .{ self.phdr_interp_index, self.interp_section_index },
   4345         .{ self.phdr_dynamic_index, self.dynamic_section_index },
   4346         .{ self.phdr_gnu_eh_frame_index, self.eh_frame_hdr_section_index },
   4347     }) |pair| {
   4348         if (pair[0]) |index| {
   4349             const shdr = self.shdrs.items[pair[1].?];
   4350             const phdr = &self.phdrs.items[index];
   4351             phdr.p_align = shdr.sh_addralign;
   4352             phdr.p_offset = shdr.sh_offset;
   4353             phdr.p_vaddr = shdr.sh_addr;
   4354             phdr.p_paddr = shdr.sh_addr;
   4355             phdr.p_filesz = shdr.sh_size;
   4356             phdr.p_memsz = shdr.sh_size;
   4357         }
   4358     }
   4359 
   4360     // Set the TLS segment boundaries.
   4361     // We assume TLS sections are laid out contiguously and that there is
   4362     // a single TLS segment.
   4363     if (self.phdr_tls_index) |index| {
   4364         const slice = self.shdrs.items;
   4365         const phdr = &self.phdrs.items[index];
   4366         var shndx: u16 = 0;
   4367         while (shndx < slice.len) {
   4368             const shdr = slice[shndx];
   4369             if (shdr.sh_flags & elf.SHF_TLS == 0) {
   4370                 shndx += 1;
   4371                 continue;
   4372             }
   4373             phdr.p_offset = shdr.sh_offset;
   4374             phdr.p_vaddr = shdr.sh_addr;
   4375             phdr.p_paddr = shdr.sh_addr;
   4376             phdr.p_align = shdr.sh_addralign;
   4377             shndx += 1;
   4378             phdr.p_align = @max(phdr.p_align, shdr.sh_addralign);
   4379             if (shdr.sh_type != elf.SHT_NOBITS) {
   4380                 phdr.p_filesz = shdr.sh_offset + shdr.sh_size - phdr.p_offset;
   4381             }
   4382             phdr.p_memsz = shdr.sh_addr + shdr.sh_size - phdr.p_vaddr;
   4383 
   4384             while (shndx < slice.len) : (shndx += 1) {
   4385                 const next = slice[shndx];
   4386                 if (next.sh_flags & elf.SHF_TLS == 0) break;
   4387                 phdr.p_align = @max(phdr.p_align, next.sh_addralign);
   4388                 if (next.sh_type != elf.SHT_NOBITS) {
   4389                     phdr.p_filesz = next.sh_offset + next.sh_size - phdr.p_offset;
   4390                 }
   4391                 phdr.p_memsz = next.sh_addr + next.sh_size - phdr.p_vaddr;
   4392             }
   4393         }
   4394     }
   4395 }
   4396 
   4397 fn allocateAtoms(self: *Elf) void {
   4398     for (self.objects.items) |index| {
   4399         self.file(index).?.object.allocateAtoms(self);
   4400     }
   4401 }
   4402 
   4403 fn writeAtoms(self: *Elf) !void {
   4404     const gpa = self.base.allocator;
   4405 
   4406     var undefs = std.AutoHashMap(Symbol.Index, std.ArrayList(Atom.Index)).init(gpa);
   4407     defer {
   4408         var it = undefs.iterator();
   4409         while (it.next()) |entry| {
   4410             entry.value_ptr.deinit();
   4411         }
   4412         undefs.deinit();
   4413     }
   4414 
   4415     // TODO iterate over `output_sections` directly
   4416     for (self.shdrs.items, 0..) |shdr, shndx| {
   4417         if (shdr.sh_type == elf.SHT_NULL) continue;
   4418         if (shdr.sh_type == elf.SHT_NOBITS) continue;
   4419 
   4420         const atom_list = self.output_sections.get(@intCast(shndx)) orelse continue;
   4421 
   4422         log.debug("writing atoms in '{s}' section", .{self.getShString(shdr.sh_name)});
   4423 
   4424         // TODO really, really handle debug section separately
   4425         const base_offset = if (self.isDebugSection(@intCast(shndx))) blk: {
   4426             const zig_object = self.zigObjectPtr().?;
   4427             if (shndx == self.debug_info_section_index.?)
   4428                 break :blk zig_object.debug_info_section_zig_size;
   4429             if (shndx == self.debug_abbrev_section_index.?)
   4430                 break :blk zig_object.debug_abbrev_section_zig_size;
   4431             if (shndx == self.debug_str_section_index.?)
   4432                 break :blk zig_object.debug_str_section_zig_size;
   4433             if (shndx == self.debug_aranges_section_index.?)
   4434                 break :blk zig_object.debug_aranges_section_zig_size;
   4435             if (shndx == self.debug_line_section_index.?)
   4436                 break :blk zig_object.debug_line_section_zig_size;
   4437             unreachable;
   4438         } else 0;
   4439         const sh_offset = shdr.sh_offset + base_offset;
   4440         const sh_size = math.cast(usize, shdr.sh_size - base_offset) orelse return error.Overflow;
   4441 
   4442         const buffer = try gpa.alloc(u8, sh_size);
   4443         defer gpa.free(buffer);
   4444         const padding_byte: u8 = if (shdr.sh_type == elf.SHT_PROGBITS and
   4445             shdr.sh_flags & elf.SHF_EXECINSTR != 0)
   4446             0xcc // int3
   4447         else
   4448             0;
   4449         @memset(buffer, padding_byte);
   4450 
   4451         for (atom_list.items) |atom_index| {
   4452             const atom_ptr = self.atom(atom_index).?;
   4453             assert(atom_ptr.flags.alive);
   4454 
   4455             const object = atom_ptr.file(self).?.object;
   4456             const offset = math.cast(usize, atom_ptr.value - shdr.sh_addr - base_offset) orelse
   4457                 return error.Overflow;
   4458             const size = math.cast(usize, atom_ptr.size) orelse return error.Overflow;
   4459 
   4460             log.debug("writing atom({d}) at 0x{x}", .{ atom_index, sh_offset + offset });
   4461 
   4462             // TODO decompress directly into provided buffer
   4463             const out_code = buffer[offset..][0..size];
   4464             const in_code = try object.codeDecompressAlloc(self, atom_index);
   4465             defer gpa.free(in_code);
   4466             @memcpy(out_code, in_code);
   4467 
   4468             if (shdr.sh_flags & elf.SHF_ALLOC == 0) {
   4469                 try atom_ptr.resolveRelocsNonAlloc(self, out_code, &undefs);
   4470             } else {
   4471                 atom_ptr.resolveRelocsAlloc(self, out_code) catch |err| switch (err) {
   4472                     // TODO
   4473                     error.RelaxFail, error.InvalidInstruction, error.CannotEncode => {
   4474                         log.err("relaxing intructions failed; TODO this should be a fatal linker error", .{});
   4475                     },
   4476                     else => |e| return e,
   4477                 };
   4478             }
   4479         }
   4480 
   4481         try self.base.file.?.pwriteAll(buffer, sh_offset);
   4482     }
   4483 
   4484     try self.reportUndefined(&undefs);
   4485 }
   4486 
   4487 fn updateSymtabSize(self: *Elf) !void {
   4488     var sizes = SymtabSize{};
   4489 
   4490     if (self.zigObjectPtr()) |zig_object| {
   4491         zig_object.asFile().updateSymtabSize(self);
   4492         sizes.add(zig_object.output_symtab_size);
   4493     }
   4494 
   4495     for (self.objects.items) |index| {
   4496         const file_ptr = self.file(index).?;
   4497         file_ptr.updateSymtabSize(self);
   4498         sizes.add(file_ptr.object.output_symtab_size);
   4499     }
   4500 
   4501     for (self.shared_objects.items) |index| {
   4502         const file_ptr = self.file(index).?;
   4503         file_ptr.updateSymtabSize(self);
   4504         sizes.add(file_ptr.shared_object.output_symtab_size);
   4505     }
   4506 
   4507     if (self.zig_got_section_index) |_| {
   4508         self.zig_got.updateSymtabSize(self);
   4509         sizes.add(self.zig_got.output_symtab_size);
   4510     }
   4511 
   4512     if (self.got_section_index) |_| {
   4513         self.got.updateSymtabSize(self);
   4514         sizes.add(self.got.output_symtab_size);
   4515     }
   4516 
   4517     if (self.plt_section_index) |_| {
   4518         self.plt.updateSymtabSize(self);
   4519         sizes.add(self.plt.output_symtab_size);
   4520     }
   4521 
   4522     if (self.plt_got_section_index) |_| {
   4523         self.plt_got.updateSymtabSize(self);
   4524         sizes.add(self.plt_got.output_symtab_size);
   4525     }
   4526 
   4527     if (self.linker_defined_index) |index| {
   4528         const file_ptr = self.file(index).?;
   4529         file_ptr.updateSymtabSize(self);
   4530         sizes.add(file_ptr.linker_defined.output_symtab_size);
   4531     }
   4532 
   4533     const symtab_shdr = &self.shdrs.items[self.symtab_section_index.?];
   4534     symtab_shdr.sh_info = sizes.nlocals + 1;
   4535     symtab_shdr.sh_link = self.strtab_section_index.?;
   4536 
   4537     const sym_size: u64 = switch (self.ptr_width) {
   4538         .p32 => @sizeOf(elf.Elf32_Sym),
   4539         .p64 => @sizeOf(elf.Elf64_Sym),
   4540     };
   4541     const needed_size = (sizes.nlocals + sizes.nglobals + 1) * sym_size;
   4542     symtab_shdr.sh_size = needed_size;
   4543 
   4544     const strtab = &self.shdrs.items[self.strtab_section_index.?];
   4545     strtab.sh_size = sizes.strsize + 1;
   4546 }
   4547 
   4548 fn writeSyntheticSections(self: *Elf) !void {
   4549     const gpa = self.base.allocator;
   4550 
   4551     if (self.zigObjectPtr()) |zig_object| {
   4552         try zig_object.writeRelaSections(self);
   4553     }
   4554 
   4555     if (self.interp_section_index) |shndx| {
   4556         const shdr = self.shdrs.items[shndx];
   4557         const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
   4558         var buffer = try gpa.alloc(u8, sh_size);
   4559         defer gpa.free(buffer);
   4560         const dylinker = self.base.options.dynamic_linker.?;
   4561         @memcpy(buffer[0..dylinker.len], dylinker);
   4562         buffer[dylinker.len] = 0;
   4563         try self.base.file.?.pwriteAll(buffer, shdr.sh_offset);
   4564     }
   4565 
   4566     if (self.hash_section_index) |shndx| {
   4567         const shdr = self.shdrs.items[shndx];
   4568         try self.base.file.?.pwriteAll(self.hash.buffer.items, shdr.sh_offset);
   4569     }
   4570 
   4571     if (self.gnu_hash_section_index) |shndx| {
   4572         const shdr = self.shdrs.items[shndx];
   4573         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.gnu_hash.size());
   4574         defer buffer.deinit();
   4575         try self.gnu_hash.write(self, buffer.writer());
   4576         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4577     }
   4578 
   4579     if (self.versym_section_index) |shndx| {
   4580         const shdr = self.shdrs.items[shndx];
   4581         try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.versym.items), shdr.sh_offset);
   4582     }
   4583 
   4584     if (self.verneed_section_index) |shndx| {
   4585         const shdr = self.shdrs.items[shndx];
   4586         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.verneed.size());
   4587         defer buffer.deinit();
   4588         try self.verneed.write(buffer.writer());
   4589         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4590     }
   4591 
   4592     if (self.dynamic_section_index) |shndx| {
   4593         const shdr = self.shdrs.items[shndx];
   4594         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynamic.size(self));
   4595         defer buffer.deinit();
   4596         try self.dynamic.write(self, buffer.writer());
   4597         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4598     }
   4599 
   4600     if (self.dynsymtab_section_index) |shndx| {
   4601         const shdr = self.shdrs.items[shndx];
   4602         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.dynsym.size());
   4603         defer buffer.deinit();
   4604         try self.dynsym.write(self, buffer.writer());
   4605         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4606     }
   4607 
   4608     if (self.dynstrtab_section_index) |shndx| {
   4609         const shdr = self.shdrs.items[shndx];
   4610         try self.base.file.?.pwriteAll(self.dynstrtab.items, shdr.sh_offset);
   4611     }
   4612 
   4613     if (self.eh_frame_section_index) |shndx| {
   4614         const shdr = self.shdrs.items[shndx];
   4615         const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
   4616         var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
   4617         defer buffer.deinit();
   4618         try eh_frame.writeEhFrame(self, buffer.writer());
   4619         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4620     }
   4621 
   4622     if (self.eh_frame_hdr_section_index) |shndx| {
   4623         const shdr = self.shdrs.items[shndx];
   4624         const sh_size = math.cast(usize, shdr.sh_size) orelse return error.Overflow;
   4625         var buffer = try std.ArrayList(u8).initCapacity(gpa, sh_size);
   4626         defer buffer.deinit();
   4627         try eh_frame.writeEhFrameHdr(self, buffer.writer());
   4628         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4629     }
   4630 
   4631     if (self.got_section_index) |index| {
   4632         const shdr = self.shdrs.items[index];
   4633         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got.size(self));
   4634         defer buffer.deinit();
   4635         try self.got.write(self, buffer.writer());
   4636         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4637     }
   4638 
   4639     if (self.rela_dyn_section_index) |shndx| {
   4640         const shdr = self.shdrs.items[shndx];
   4641         try self.got.addRela(self);
   4642         try self.copy_rel.addRela(self);
   4643         try self.zig_got.addRela(self);
   4644         self.sortRelaDyn();
   4645         try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_dyn.items), shdr.sh_offset);
   4646     }
   4647 
   4648     if (self.plt_section_index) |shndx| {
   4649         const shdr = self.shdrs.items[shndx];
   4650         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt.size());
   4651         defer buffer.deinit();
   4652         try self.plt.write(self, buffer.writer());
   4653         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4654     }
   4655 
   4656     if (self.got_plt_section_index) |shndx| {
   4657         const shdr = self.shdrs.items[shndx];
   4658         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.got_plt.size(self));
   4659         defer buffer.deinit();
   4660         try self.got_plt.write(self, buffer.writer());
   4661         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4662     }
   4663 
   4664     if (self.plt_got_section_index) |shndx| {
   4665         const shdr = self.shdrs.items[shndx];
   4666         var buffer = try std.ArrayList(u8).initCapacity(gpa, self.plt_got.size());
   4667         defer buffer.deinit();
   4668         try self.plt_got.write(self, buffer.writer());
   4669         try self.base.file.?.pwriteAll(buffer.items, shdr.sh_offset);
   4670     }
   4671 
   4672     if (self.rela_plt_section_index) |shndx| {
   4673         const shdr = self.shdrs.items[shndx];
   4674         try self.plt.addRela(self);
   4675         try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.rela_plt.items), shdr.sh_offset);
   4676     }
   4677 
   4678     try self.writeSymtab();
   4679     try self.writeShStrtab();
   4680 }
   4681 
   4682 fn writeShStrtab(self: *Elf) !void {
   4683     if (self.shstrtab_section_index) |index| {
   4684         const shdr = self.shdrs.items[index];
   4685         try self.base.file.?.pwriteAll(self.shstrtab.items, shdr.sh_offset);
   4686     }
   4687 }
   4688 
   4689 fn writeSymtab(self: *Elf) !void {
   4690     const gpa = self.base.allocator;
   4691     const symtab_shdr = self.shdrs.items[self.symtab_section_index.?];
   4692     const strtab_shdr = self.shdrs.items[self.strtab_section_index.?];
   4693     const sym_size: u64 = switch (self.ptr_width) {
   4694         .p32 => @sizeOf(elf.Elf32_Sym),
   4695         .p64 => @sizeOf(elf.Elf64_Sym),
   4696     };
   4697     const nsyms = math.cast(usize, @divExact(symtab_shdr.sh_size, sym_size)) orelse return error.Overflow;
   4698 
   4699     log.debug("writing {d} symbols at 0x{x}", .{ nsyms, symtab_shdr.sh_offset });
   4700 
   4701     try self.symtab.resize(gpa, nsyms);
   4702     const needed_strtab_size = math.cast(usize, strtab_shdr.sh_size - 1) orelse return error.Overflow;
   4703     try self.strtab.ensureUnusedCapacity(gpa, needed_strtab_size);
   4704 
   4705     const Ctx = struct {
   4706         ilocal: usize,
   4707         iglobal: usize,
   4708 
   4709         fn incr(this: *@This(), ss: SymtabSize) void {
   4710             this.ilocal += ss.nlocals;
   4711             this.iglobal += ss.nglobals;
   4712         }
   4713     };
   4714     var ctx: Ctx = .{
   4715         .ilocal = 1,
   4716         .iglobal = symtab_shdr.sh_info,
   4717     };
   4718 
   4719     if (self.zigObjectPtr()) |zig_object| {
   4720         zig_object.asFile().writeSymtab(self, ctx);
   4721         ctx.incr(zig_object.output_symtab_size);
   4722     }
   4723 
   4724     for (self.objects.items) |index| {
   4725         const file_ptr = self.file(index).?;
   4726         file_ptr.writeSymtab(self, ctx);
   4727         ctx.incr(file_ptr.object.output_symtab_size);
   4728     }
   4729 
   4730     for (self.shared_objects.items) |index| {
   4731         const file_ptr = self.file(index).?;
   4732         file_ptr.writeSymtab(self, ctx);
   4733         ctx.incr(file_ptr.shared_object.output_symtab_size);
   4734     }
   4735 
   4736     if (self.zig_got_section_index) |_| {
   4737         self.zig_got.writeSymtab(self, ctx);
   4738         ctx.incr(self.zig_got.output_symtab_size);
   4739     }
   4740 
   4741     if (self.got_section_index) |_| {
   4742         self.got.writeSymtab(self, ctx);
   4743         ctx.incr(self.got.output_symtab_size);
   4744     }
   4745 
   4746     if (self.plt_section_index) |_| {
   4747         self.plt.writeSymtab(self, ctx);
   4748         ctx.incr(self.plt.output_symtab_size);
   4749     }
   4750 
   4751     if (self.plt_got_section_index) |_| {
   4752         self.plt_got.writeSymtab(self, ctx);
   4753         ctx.incr(self.plt_got.output_symtab_size);
   4754     }
   4755 
   4756     if (self.linker_defined_index) |index| {
   4757         const file_ptr = self.file(index).?;
   4758         file_ptr.writeSymtab(self, ctx);
   4759         ctx.incr(file_ptr.linker_defined.output_symtab_size);
   4760     }
   4761 
   4762     const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian();
   4763     switch (self.ptr_width) {
   4764         .p32 => {
   4765             const buf = try gpa.alloc(elf.Elf32_Sym, self.symtab.items.len);
   4766             defer gpa.free(buf);
   4767 
   4768             for (buf, self.symtab.items) |*out, sym| {
   4769                 out.* = .{
   4770                     .st_name = sym.st_name,
   4771                     .st_info = sym.st_info,
   4772                     .st_other = sym.st_other,
   4773                     .st_shndx = sym.st_shndx,
   4774                     .st_value = @as(u32, @intCast(sym.st_value)),
   4775                     .st_size = @as(u32, @intCast(sym.st_size)),
   4776                 };
   4777                 if (foreign_endian) mem.byteSwapAllFields(elf.Elf32_Sym, out);
   4778             }
   4779             try self.base.file.?.pwriteAll(mem.sliceAsBytes(buf), symtab_shdr.sh_offset);
   4780         },
   4781         .p64 => {
   4782             if (foreign_endian) {
   4783                 for (self.symtab.items) |*sym| mem.byteSwapAllFields(elf.Elf64_Sym, sym);
   4784             }
   4785             try self.base.file.?.pwriteAll(mem.sliceAsBytes(self.symtab.items), symtab_shdr.sh_offset);
   4786         },
   4787     }
   4788 
   4789     try self.base.file.?.pwriteAll(self.strtab.items, strtab_shdr.sh_offset);
   4790 }
   4791 
   4792 /// Always 4 or 8 depending on whether this is 32-bit ELF or 64-bit ELF.
   4793 fn ptrWidthBytes(self: Elf) u8 {
   4794     return switch (self.ptr_width) {
   4795         .p32 => 4,
   4796         .p64 => 8,
   4797     };
   4798 }
   4799 
   4800 /// Does not necessarily match `ptrWidthBytes` for example can be 2 bytes
   4801 /// in a 32-bit ELF file.
   4802 pub fn archPtrWidthBytes(self: Elf) u8 {
   4803     return @as(u8, @intCast(@divExact(self.base.options.target.ptrBitWidth(), 8)));
   4804 }
   4805 
   4806 fn phdrTo32(phdr: elf.Elf64_Phdr) elf.Elf32_Phdr {
   4807     return .{
   4808         .p_type = phdr.p_type,
   4809         .p_flags = phdr.p_flags,
   4810         .p_offset = @as(u32, @intCast(phdr.p_offset)),
   4811         .p_vaddr = @as(u32, @intCast(phdr.p_vaddr)),
   4812         .p_paddr = @as(u32, @intCast(phdr.p_paddr)),
   4813         .p_filesz = @as(u32, @intCast(phdr.p_filesz)),
   4814         .p_memsz = @as(u32, @intCast(phdr.p_memsz)),
   4815         .p_align = @as(u32, @intCast(phdr.p_align)),
   4816     };
   4817 }
   4818 
   4819 fn shdrTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr {
   4820     return .{
   4821         .sh_name = shdr.sh_name,
   4822         .sh_type = shdr.sh_type,
   4823         .sh_flags = @as(u32, @intCast(shdr.sh_flags)),
   4824         .sh_addr = @as(u32, @intCast(shdr.sh_addr)),
   4825         .sh_offset = @as(u32, @intCast(shdr.sh_offset)),
   4826         .sh_size = @as(u32, @intCast(shdr.sh_size)),
   4827         .sh_link = shdr.sh_link,
   4828         .sh_info = shdr.sh_info,
   4829         .sh_addralign = @as(u32, @intCast(shdr.sh_addralign)),
   4830         .sh_entsize = @as(u32, @intCast(shdr.sh_entsize)),
   4831     };
   4832 }
   4833 
   4834 fn getLDMOption(target: std.Target) ?[]const u8 {
   4835     switch (target.cpu.arch) {
   4836         .x86 => return "elf_i386",
   4837         .aarch64 => return "aarch64linux",
   4838         .aarch64_be => return "aarch64_be_linux",
   4839         .arm, .thumb => return "armelf_linux_eabi",
   4840         .armeb, .thumbeb => return "armebelf_linux_eabi",
   4841         .powerpc => return "elf32ppclinux",
   4842         .powerpc64 => return "elf64ppc",
   4843         .powerpc64le => return "elf64lppc",
   4844         .sparc, .sparcel => return "elf32_sparc",
   4845         .sparc64 => return "elf64_sparc",
   4846         .mips => return "elf32btsmip",
   4847         .mipsel => return "elf32ltsmip",
   4848         .mips64 => {
   4849             if (target.abi == .gnuabin32) {
   4850                 return "elf32btsmipn32";
   4851             } else {
   4852                 return "elf64btsmip";
   4853             }
   4854         },
   4855         .mips64el => {
   4856             if (target.abi == .gnuabin32) {
   4857                 return "elf32ltsmipn32";
   4858             } else {
   4859                 return "elf64ltsmip";
   4860             }
   4861         },
   4862         .s390x => return "elf64_s390",
   4863         .x86_64 => {
   4864             if (target.abi == .gnux32) {
   4865                 return "elf32_x86_64";
   4866             } else {
   4867                 return "elf_x86_64";
   4868             }
   4869         },
   4870         .riscv32 => return "elf32lriscv",
   4871         .riscv64 => return "elf64lriscv",
   4872         else => return null,
   4873     }
   4874 }
   4875 
   4876 pub fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) {
   4877     return actual_size +| (actual_size / ideal_factor);
   4878 }
   4879 
   4880 // Provide a blueprint of csu (c-runtime startup) objects for supported
   4881 // link modes.
   4882 //
   4883 // This is for cross-mode targets only. For host-mode targets the system
   4884 // compiler can be probed to produce a robust blueprint.
   4885 //
   4886 // Targets requiring a libc for which zig does not bundle a libc are
   4887 // host-mode targets. Unfortunately, host-mode probes are not yet
   4888 // implemented. For now the data is hard-coded here. Such targets are
   4889 // { freebsd, netbsd, openbsd, dragonfly }.
   4890 const CsuObjects = struct {
   4891     crt0: ?[]const u8 = null,
   4892     crti: ?[]const u8 = null,
   4893     crtbegin: ?[]const u8 = null,
   4894     crtend: ?[]const u8 = null,
   4895     crtn: ?[]const u8 = null,
   4896 
   4897     fn init(arena: mem.Allocator, link_options: link.Options, comp: *const Compilation) !CsuObjects {
   4898         // crt objects are only required for libc.
   4899         if (!link_options.link_libc) return CsuObjects{};
   4900 
   4901         var result: CsuObjects = .{};
   4902 
   4903         // Flatten crt cases.
   4904         const mode: enum {
   4905             dynamic_lib,
   4906             dynamic_exe,
   4907             dynamic_pie,
   4908             static_exe,
   4909             static_pie,
   4910         } = switch (link_options.output_mode) {
   4911             .Obj => return CsuObjects{},
   4912             .Lib => switch (link_options.link_mode) {
   4913                 .Dynamic => .dynamic_lib,
   4914                 .Static => return CsuObjects{},
   4915             },
   4916             .Exe => switch (link_options.link_mode) {
   4917                 .Dynamic => if (link_options.pie) .dynamic_pie else .dynamic_exe,
   4918                 .Static => if (link_options.pie) .static_pie else .static_exe,
   4919             },
   4920         };
   4921 
   4922         if (link_options.target.isAndroid()) {
   4923             switch (mode) {
   4924                 // zig fmt: off
   4925                 .dynamic_lib => result.set( null, null, "crtbegin_so.o",      "crtend_so.o",      null ),
   4926                 .dynamic_exe,
   4927                 .dynamic_pie => result.set( null, null, "crtbegin_dynamic.o", "crtend_android.o", null ),
   4928                 .static_exe,
   4929                 .static_pie  => result.set( null, null, "crtbegin_static.o",  "crtend_android.o", null ),
   4930                 // zig fmt: on
   4931             }
   4932         } else {
   4933             switch (link_options.target.os.tag) {
   4934                 .linux => {
   4935                     switch (mode) {
   4936                         // zig fmt: off
   4937                         .dynamic_lib => result.set( null,      "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4938                         .dynamic_exe => result.set( "crt1.o",  "crti.o", "crtbegin.o",  "crtend.o",  "crtn.o" ),
   4939                         .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4940                         .static_exe  => result.set( "crt1.o",  "crti.o", "crtbeginT.o", "crtend.o",  "crtn.o" ),
   4941                         .static_pie  => result.set( "rcrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4942                         // zig fmt: on
   4943                     }
   4944                     if (link_options.libc_installation) |_| {
   4945                         // hosted-glibc provides crtbegin/end objects in platform/compiler-specific dirs
   4946                         // and they are not known at comptime. For now null-out crtbegin/end objects;
   4947                         // there is no feature loss, zig has never linked those objects in before.
   4948                         result.crtbegin = null;
   4949                         result.crtend = null;
   4950                     } else {
   4951                         // Bundled glibc only has Scrt1.o .
   4952                         if (result.crt0 != null and link_options.target.isGnuLibC()) result.crt0 = "Scrt1.o";
   4953                     }
   4954                 },
   4955                 .dragonfly => switch (mode) {
   4956                     // zig fmt: off
   4957                     .dynamic_lib => result.set( null,      "crti.o", "crtbeginS.o",  "crtendS.o", "crtn.o" ),
   4958                     .dynamic_exe => result.set( "crt1.o",  "crti.o", "crtbegin.o",   "crtend.o",  "crtn.o" ),
   4959                     .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o",  "crtendS.o", "crtn.o" ),
   4960                     .static_exe  => result.set( "crt1.o",  "crti.o", "crtbegin.o",   "crtend.o",  "crtn.o" ),
   4961                     .static_pie  => result.set( "Scrt1.o", "crti.o", "crtbeginS.o",  "crtendS.o", "crtn.o" ),
   4962                     // zig fmt: on
   4963                 },
   4964                 .freebsd => switch (mode) {
   4965                     // zig fmt: off
   4966                     .dynamic_lib => result.set( null,      "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4967                     .dynamic_exe => result.set( "crt1.o",  "crti.o", "crtbegin.o",  "crtend.o",  "crtn.o" ),
   4968                     .dynamic_pie => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4969                     .static_exe  => result.set( "crt1.o",  "crti.o", "crtbeginT.o", "crtend.o",  "crtn.o" ),
   4970                     .static_pie  => result.set( "Scrt1.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4971                     // zig fmt: on
   4972                 },
   4973                 .netbsd => switch (mode) {
   4974                     // zig fmt: off
   4975                     .dynamic_lib => result.set( null,     "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4976                     .dynamic_exe => result.set( "crt0.o", "crti.o", "crtbegin.o",  "crtend.o",  "crtn.o" ),
   4977                     .dynamic_pie => result.set( "crt0.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4978                     .static_exe  => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtend.o",  "crtn.o" ),
   4979                     .static_pie  => result.set( "crt0.o", "crti.o", "crtbeginT.o", "crtendS.o", "crtn.o" ),
   4980                     // zig fmt: on
   4981                 },
   4982                 .openbsd => switch (mode) {
   4983                     // zig fmt: off
   4984                     .dynamic_lib => result.set( null,      null, "crtbeginS.o", "crtendS.o", null ),
   4985                     .dynamic_exe,
   4986                     .dynamic_pie => result.set( "crt0.o",  null, "crtbegin.o",  "crtend.o",  null ),
   4987                     .static_exe,
   4988                     .static_pie  => result.set( "rcrt0.o", null, "crtbegin.o",  "crtend.o",  null ),
   4989                     // zig fmt: on
   4990                 },
   4991                 .haiku => switch (mode) {
   4992                     // zig fmt: off
   4993                     .dynamic_lib => result.set( null,          "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4994                     .dynamic_exe => result.set( "start_dyn.o", "crti.o", "crtbegin.o",  "crtend.o",  "crtn.o" ),
   4995                     .dynamic_pie => result.set( "start_dyn.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4996                     .static_exe  => result.set( "start_dyn.o", "crti.o", "crtbegin.o",  "crtend.o",  "crtn.o" ),
   4997                     .static_pie  => result.set( "start_dyn.o", "crti.o", "crtbeginS.o", "crtendS.o", "crtn.o" ),
   4998                     // zig fmt: on
   4999                 },
   5000                 .solaris, .illumos => switch (mode) {
   5001                     // zig fmt: off
   5002                     .dynamic_lib => result.set( null,     "crti.o", null, null, "crtn.o" ),
   5003                     .dynamic_exe,
   5004                     .dynamic_pie => result.set( "crt1.o", "crti.o", null, null, "crtn.o" ),
   5005                     .static_exe,
   5006                     .static_pie  => result.set( null,     null,     null, null, null     ),
   5007                     // zig fmt: on
   5008                 },
   5009                 else => {},
   5010             }
   5011         }
   5012 
   5013         // Convert each object to a full pathname.
   5014         if (link_options.libc_installation) |lci| {
   5015             const crt_dir_path = lci.crt_dir orelse return error.LibCInstallationMissingCRTDir;
   5016             switch (link_options.target.os.tag) {
   5017                 .dragonfly => {
   5018                     if (result.crt0) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
   5019                     if (result.crti) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
   5020                     if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
   5021 
   5022                     var gccv: []const u8 = undefined;
   5023                     if (link_options.target.os.version_range.semver.isAtLeast(.{ .major = 5, .minor = 4, .patch = 0 }) orelse true) {
   5024                         gccv = "gcc80";
   5025                     } else {
   5026                         gccv = "gcc54";
   5027                     }
   5028 
   5029                     if (result.crtbegin) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
   5030                     if (result.crtend) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, gccv, obj.* });
   5031                 },
   5032                 .haiku => {
   5033                     const gcc_dir_path = lci.gcc_dir orelse return error.LibCInstallationMissingCRTDir;
   5034                     if (result.crt0) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
   5035                     if (result.crti) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
   5036                     if (result.crtn) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
   5037 
   5038                     if (result.crtbegin) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ gcc_dir_path, obj.* });
   5039                     if (result.crtend) |*obj| obj.* = try fs.path.join(arena, &[_][]const u8{ gcc_dir_path, obj.* });
   5040                 },
   5041                 else => {
   5042                     inline for (std.meta.fields(@TypeOf(result))) |f| {
   5043                         if (@field(result, f.name)) |*obj| {
   5044                             obj.* = try fs.path.join(arena, &[_][]const u8{ crt_dir_path, obj.* });
   5045                         }
   5046                     }
   5047                 },
   5048             }
   5049         } else {
   5050             inline for (std.meta.fields(@TypeOf(result))) |f| {
   5051                 if (@field(result, f.name)) |*obj| {
   5052                     if (comp.crt_files.get(obj.*)) |crtf| {
   5053                         obj.* = crtf.full_object_path;
   5054                     } else {
   5055                         @field(result, f.name) = null;
   5056                     }
   5057                 }
   5058             }
   5059         }
   5060 
   5061         return result;
   5062     }
   5063 
   5064     fn set(
   5065         self: *CsuObjects,
   5066         crt0: ?[]const u8,
   5067         crti: ?[]const u8,
   5068         crtbegin: ?[]const u8,
   5069         crtend: ?[]const u8,
   5070         crtn: ?[]const u8,
   5071     ) void {
   5072         self.crt0 = crt0;
   5073         self.crti = crti;
   5074         self.crtbegin = crtbegin;
   5075         self.crtend = crtend;
   5076         self.crtn = crtn;
   5077     }
   5078 };
   5079 
   5080 pub fn calcImageBase(self: Elf) u64 {
   5081     if (self.isDynLib()) return 0;
   5082     if (self.isExe() and self.base.options.pie) return 0;
   5083     return self.base.options.image_base_override orelse switch (self.ptr_width) {
   5084         .p32 => 0x1000,
   5085         .p64 => 0x1000000,
   5086     };
   5087 }
   5088 
   5089 pub fn isStatic(self: Elf) bool {
   5090     return self.base.options.link_mode == .Static;
   5091 }
   5092 
   5093 pub fn isObject(self: Elf) bool {
   5094     return self.base.options.output_mode == .Obj;
   5095 }
   5096 
   5097 pub fn isExe(self: Elf) bool {
   5098     return self.base.options.output_mode == .Exe;
   5099 }
   5100 
   5101 pub fn isStaticLib(self: Elf) bool {
   5102     return self.base.options.output_mode == .Lib and self.isStatic();
   5103 }
   5104 
   5105 pub fn isRelocatable(self: Elf) bool {
   5106     return self.isObject() or self.isStaticLib();
   5107 }
   5108 
   5109 pub fn isDynLib(self: Elf) bool {
   5110     return self.base.options.output_mode == .Lib and !self.isStatic();
   5111 }
   5112 
   5113 pub fn isZigSection(self: Elf, shndx: u16) bool {
   5114     inline for (&[_]?u16{
   5115         self.zig_text_section_index,
   5116         self.zig_data_rel_ro_section_index,
   5117         self.zig_data_section_index,
   5118         self.zig_bss_section_index,
   5119         self.zig_got_section_index,
   5120     }) |maybe_index| {
   5121         if (maybe_index) |index| {
   5122             if (index == shndx) return true;
   5123         }
   5124     }
   5125     return false;
   5126 }
   5127 
   5128 pub fn isDebugSection(self: Elf, shndx: u16) bool {
   5129     inline for (&[_]?u16{
   5130         self.debug_info_section_index,
   5131         self.debug_abbrev_section_index,
   5132         self.debug_str_section_index,
   5133         self.debug_aranges_section_index,
   5134         self.debug_line_section_index,
   5135     }) |maybe_index| {
   5136         if (maybe_index) |index| {
   5137             if (index == shndx) return true;
   5138         }
   5139     }
   5140     return false;
   5141 }
   5142 
   5143 fn addPhdr(self: *Elf, opts: struct {
   5144     type: u32 = 0,
   5145     flags: u32 = 0,
   5146     @"align": u64 = 0,
   5147     offset: u64 = 0,
   5148     addr: u64 = 0,
   5149     filesz: u64 = 0,
   5150     memsz: u64 = 0,
   5151 }) error{OutOfMemory}!u16 {
   5152     const index = @as(u16, @intCast(self.phdrs.items.len));
   5153     try self.phdrs.append(self.base.allocator, .{
   5154         .p_type = opts.type,
   5155         .p_flags = opts.flags,
   5156         .p_offset = opts.offset,
   5157         .p_vaddr = opts.addr,
   5158         .p_paddr = opts.addr,
   5159         .p_filesz = opts.filesz,
   5160         .p_memsz = opts.memsz,
   5161         .p_align = opts.@"align",
   5162     });
   5163     return index;
   5164 }
   5165 
   5166 fn addRelaShdr(self: *Elf, name: [:0]const u8, shndx: u16) !u16 {
   5167     const entsize: u64 = switch (self.ptr_width) {
   5168         .p32 => @sizeOf(elf.Elf32_Rela),
   5169         .p64 => @sizeOf(elf.Elf64_Rela),
   5170     };
   5171     const addralign: u64 = switch (self.ptr_width) {
   5172         .p32 => @alignOf(elf.Elf32_Rela),
   5173         .p64 => @alignOf(elf.Elf64_Rela),
   5174     };
   5175     return self.addSection(.{
   5176         .name = name,
   5177         .type = elf.SHT_RELA,
   5178         .flags = elf.SHF_INFO_LINK,
   5179         .entsize = entsize,
   5180         .info = shndx,
   5181         .addralign = addralign,
   5182         .offset = std.math.maxInt(u64),
   5183     });
   5184 }
   5185 
   5186 pub const AddSectionOpts = struct {
   5187     name: [:0]const u8,
   5188     type: u32 = elf.SHT_NULL,
   5189     flags: u64 = 0,
   5190     link: u32 = 0,
   5191     info: u32 = 0,
   5192     addralign: u64 = 0,
   5193     entsize: u64 = 0,
   5194     offset: u64 = 0,
   5195 };
   5196 
   5197 pub fn addSection(self: *Elf, opts: AddSectionOpts) !u16 {
   5198     const gpa = self.base.allocator;
   5199     const index = @as(u16, @intCast(self.shdrs.items.len));
   5200     const shdr = try self.shdrs.addOne(gpa);
   5201     shdr.* = .{
   5202         .sh_name = try self.insertShString(opts.name),
   5203         .sh_type = opts.type,
   5204         .sh_flags = opts.flags,
   5205         .sh_addr = 0,
   5206         .sh_offset = opts.offset,
   5207         .sh_size = 0,
   5208         .sh_link = opts.link,
   5209         .sh_info = opts.info,
   5210         .sh_addralign = opts.addralign,
   5211         .sh_entsize = opts.entsize,
   5212     };
   5213     return index;
   5214 }
   5215 
   5216 pub fn sectionByName(self: *Elf, name: [:0]const u8) ?u16 {
   5217     for (self.shdrs.items, 0..) |*shdr, i| {
   5218         const this_name = self.getShString(shdr.sh_name);
   5219         if (mem.eql(u8, this_name, name)) return @as(u16, @intCast(i));
   5220     } else return null;
   5221 }
   5222 
   5223 const RelaDyn = struct {
   5224     offset: u64,
   5225     sym: u64 = 0,
   5226     type: u32,
   5227     addend: i64 = 0,
   5228 };
   5229 
   5230 pub fn addRelaDyn(self: *Elf, opts: RelaDyn) !void {
   5231     try self.rela_dyn.ensureUnusedCapacity(self.base.alloctor, 1);
   5232     self.addRelaDynAssumeCapacity(opts);
   5233 }
   5234 
   5235 pub fn addRelaDynAssumeCapacity(self: *Elf, opts: RelaDyn) void {
   5236     self.rela_dyn.appendAssumeCapacity(.{
   5237         .r_offset = opts.offset,
   5238         .r_info = (opts.sym << 32) | opts.type,
   5239         .r_addend = opts.addend,
   5240     });
   5241 }
   5242 
   5243 fn sortRelaDyn(self: *Elf) void {
   5244     const Sort = struct {
   5245         fn rank(rel: elf.Elf64_Rela) u2 {
   5246             return switch (rel.r_type()) {
   5247                 elf.R_X86_64_RELATIVE => 0,
   5248                 elf.R_X86_64_IRELATIVE => 2,
   5249                 else => 1,
   5250             };
   5251         }
   5252 
   5253         pub fn lessThan(ctx: void, lhs: elf.Elf64_Rela, rhs: elf.Elf64_Rela) bool {
   5254             _ = ctx;
   5255             if (rank(lhs) == rank(rhs)) {
   5256                 if (lhs.r_sym() == rhs.r_sym()) return lhs.r_offset < rhs.r_offset;
   5257                 return lhs.r_sym() < rhs.r_sym();
   5258             }
   5259             return rank(lhs) < rank(rhs);
   5260         }
   5261     };
   5262     mem.sort(elf.Elf64_Rela, self.rela_dyn.items, {}, Sort.lessThan);
   5263 }
   5264 
   5265 fn calcNumIRelativeRelocs(self: *Elf) usize {
   5266     var count: usize = self.num_ifunc_dynrelocs;
   5267 
   5268     for (self.got.entries.items) |entry| {
   5269         if (entry.tag != .got) continue;
   5270         const sym = self.symbol(entry.symbol_index);
   5271         if (sym.isIFunc(self)) count += 1;
   5272     }
   5273 
   5274     return count;
   5275 }
   5276 
   5277 pub fn isCIdentifier(name: []const u8) bool {
   5278     if (name.len == 0) return false;
   5279     const first_c = name[0];
   5280     if (!std.ascii.isAlphabetic(first_c) and first_c != '_') return false;
   5281     for (name[1..]) |c| {
   5282         if (!std.ascii.isAlphanumeric(c) and c != '_') return false;
   5283     }
   5284     return true;
   5285 }
   5286 
   5287 fn getStartStopBasename(self: *Elf, atom_index: Atom.Index) ?[]const u8 {
   5288     const atom_ptr = self.atom(atom_index) orelse return null;
   5289     const name = atom_ptr.name(self);
   5290     if (atom_ptr.inputShdr(self).sh_flags & elf.SHF_ALLOC != 0 and name.len > 0) {
   5291         if (isCIdentifier(name)) return name;
   5292     }
   5293     return null;
   5294 }
   5295 
   5296 pub fn atom(self: *Elf, atom_index: Atom.Index) ?*Atom {
   5297     if (atom_index == 0) return null;
   5298     assert(atom_index < self.atoms.items.len);
   5299     return &self.atoms.items[atom_index];
   5300 }
   5301 
   5302 pub fn addAtom(self: *Elf) !Atom.Index {
   5303     const index = @as(Atom.Index, @intCast(self.atoms.items.len));
   5304     const atom_ptr = try self.atoms.addOne(self.base.allocator);
   5305     atom_ptr.* = .{ .atom_index = index };
   5306     return index;
   5307 }
   5308 
   5309 pub fn file(self: *Elf, index: File.Index) ?File {
   5310     const tag = self.files.items(.tags)[index];
   5311     return switch (tag) {
   5312         .null => null,
   5313         .linker_defined => .{ .linker_defined = &self.files.items(.data)[index].linker_defined },
   5314         .zig_object => .{ .zig_object = &self.files.items(.data)[index].zig_object },
   5315         .object => .{ .object = &self.files.items(.data)[index].object },
   5316         .shared_object => .{ .shared_object = &self.files.items(.data)[index].shared_object },
   5317     };
   5318 }
   5319 
   5320 /// Returns pointer-to-symbol described at sym_index.
   5321 pub fn symbol(self: *Elf, sym_index: Symbol.Index) *Symbol {
   5322     return &self.symbols.items[sym_index];
   5323 }
   5324 
   5325 pub fn addSymbol(self: *Elf) !Symbol.Index {
   5326     try self.symbols.ensureUnusedCapacity(self.base.allocator, 1);
   5327     const index = blk: {
   5328         if (self.symbols_free_list.popOrNull()) |index| {
   5329             log.debug("  (reusing symbol index {d})", .{index});
   5330             break :blk index;
   5331         } else {
   5332             log.debug("  (allocating symbol index {d})", .{self.symbols.items.len});
   5333             const index = @as(Symbol.Index, @intCast(self.symbols.items.len));
   5334             _ = self.symbols.addOneAssumeCapacity();
   5335             break :blk index;
   5336         }
   5337     };
   5338     self.symbols.items[index] = .{};
   5339     return index;
   5340 }
   5341 
   5342 pub fn addSymbolExtra(self: *Elf, extra: Symbol.Extra) !u32 {
   5343     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   5344     try self.symbols_extra.ensureUnusedCapacity(self.base.allocator, fields.len);
   5345     return self.addSymbolExtraAssumeCapacity(extra);
   5346 }
   5347 
   5348 pub fn addSymbolExtraAssumeCapacity(self: *Elf, extra: Symbol.Extra) u32 {
   5349     const index = @as(u32, @intCast(self.symbols_extra.items.len));
   5350     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   5351     inline for (fields) |field| {
   5352         self.symbols_extra.appendAssumeCapacity(switch (field.type) {
   5353             u32 => @field(extra, field.name),
   5354             else => @compileError("bad field type"),
   5355         });
   5356     }
   5357     return index;
   5358 }
   5359 
   5360 pub fn symbolExtra(self: *Elf, index: u32) ?Symbol.Extra {
   5361     if (index == 0) return null;
   5362     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   5363     var i: usize = index;
   5364     var result: Symbol.Extra = undefined;
   5365     inline for (fields) |field| {
   5366         @field(result, field.name) = switch (field.type) {
   5367             u32 => self.symbols_extra.items[i],
   5368             else => @compileError("bad field type"),
   5369         };
   5370         i += 1;
   5371     }
   5372     return result;
   5373 }
   5374 
   5375 pub fn setSymbolExtra(self: *Elf, index: u32, extra: Symbol.Extra) void {
   5376     assert(index > 0);
   5377     const fields = @typeInfo(Symbol.Extra).Struct.fields;
   5378     inline for (fields, 0..) |field, i| {
   5379         self.symbols_extra.items[index + i] = switch (field.type) {
   5380             u32 => @field(extra, field.name),
   5381             else => @compileError("bad field type"),
   5382         };
   5383     }
   5384 }
   5385 
   5386 const GetOrPutGlobalResult = struct {
   5387     found_existing: bool,
   5388     index: Symbol.Index,
   5389 };
   5390 
   5391 pub fn getOrPutGlobal(self: *Elf, name: []const u8) !GetOrPutGlobalResult {
   5392     const gpa = self.base.allocator;
   5393     const name_off = try self.strings.insert(gpa, name);
   5394     const gop = try self.resolver.getOrPut(gpa, name_off);
   5395     if (!gop.found_existing) {
   5396         const index = try self.addSymbol();
   5397         const global = self.symbol(index);
   5398         global.name_offset = name_off;
   5399         global.flags.global = true;
   5400         gop.value_ptr.* = index;
   5401     }
   5402     return .{
   5403         .found_existing = gop.found_existing,
   5404         .index = gop.value_ptr.*,
   5405     };
   5406 }
   5407 
   5408 pub fn globalByName(self: *Elf, name: []const u8) ?Symbol.Index {
   5409     const name_off = self.strings.getOffset(name) orelse return null;
   5410     return self.resolver.get(name_off);
   5411 }
   5412 
   5413 pub fn getGlobalSymbol(self: *Elf, name: []const u8, lib_name: ?[]const u8) !u32 {
   5414     return self.zigObjectPtr().?.getGlobalSymbol(self, name, lib_name);
   5415 }
   5416 
   5417 pub fn zigObjectPtr(self: *Elf) ?*ZigObject {
   5418     const index = self.zig_object_index orelse return null;
   5419     return self.file(index).?.zig_object;
   5420 }
   5421 
   5422 const GetOrCreateComdatGroupOwnerResult = struct {
   5423     found_existing: bool,
   5424     index: ComdatGroupOwner.Index,
   5425 };
   5426 
   5427 pub fn getOrCreateComdatGroupOwner(self: *Elf, name: [:0]const u8) !GetOrCreateComdatGroupOwnerResult {
   5428     const gpa = self.base.allocator;
   5429     const off = try self.strings.insert(gpa, name);
   5430     const gop = try self.comdat_groups_table.getOrPut(gpa, off);
   5431     if (!gop.found_existing) {
   5432         const index = @as(ComdatGroupOwner.Index, @intCast(self.comdat_groups_owners.items.len));
   5433         const owner = try self.comdat_groups_owners.addOne(gpa);
   5434         owner.* = .{};
   5435         gop.value_ptr.* = index;
   5436     }
   5437     return .{
   5438         .found_existing = gop.found_existing,
   5439         .index = gop.value_ptr.*,
   5440     };
   5441 }
   5442 
   5443 pub fn addComdatGroup(self: *Elf) !ComdatGroup.Index {
   5444     const index = @as(ComdatGroup.Index, @intCast(self.comdat_groups.items.len));
   5445     _ = try self.comdat_groups.addOne(self.base.allocator);
   5446     return index;
   5447 }
   5448 
   5449 pub fn comdatGroup(self: *Elf, index: ComdatGroup.Index) *ComdatGroup {
   5450     assert(index < self.comdat_groups.items.len);
   5451     return &self.comdat_groups.items[index];
   5452 }
   5453 
   5454 pub fn comdatGroupOwner(self: *Elf, index: ComdatGroupOwner.Index) *ComdatGroupOwner {
   5455     assert(index < self.comdat_groups_owners.items.len);
   5456     return &self.comdat_groups_owners.items[index];
   5457 }
   5458 
   5459 pub fn tpAddress(self: *Elf) u64 {
   5460     const index = self.phdr_tls_index orelse return 0;
   5461     const phdr = self.phdrs.items[index];
   5462     return mem.alignForward(u64, phdr.p_vaddr + phdr.p_memsz, phdr.p_align);
   5463 }
   5464 
   5465 pub fn dtpAddress(self: *Elf) u64 {
   5466     return self.tlsAddress();
   5467 }
   5468 
   5469 pub fn tlsAddress(self: *Elf) u64 {
   5470     const index = self.phdr_tls_index orelse return 0;
   5471     const phdr = self.phdrs.items[index];
   5472     return phdr.p_vaddr;
   5473 }
   5474 
   5475 const ErrorWithNotes = struct {
   5476     /// Allocated index in misc_errors array.
   5477     index: usize,
   5478 
   5479     /// Next available note slot.
   5480     note_slot: usize = 0,
   5481 
   5482     pub fn addMsg(
   5483         err: ErrorWithNotes,
   5484         elf_file: *Elf,
   5485         comptime format: []const u8,
   5486         args: anytype,
   5487     ) error{OutOfMemory}!void {
   5488         const gpa = elf_file.base.allocator;
   5489         const err_msg = &elf_file.misc_errors.items[err.index];
   5490         err_msg.msg = try std.fmt.allocPrint(gpa, format, args);
   5491     }
   5492 
   5493     pub fn addNote(
   5494         err: *ErrorWithNotes,
   5495         elf_file: *Elf,
   5496         comptime format: []const u8,
   5497         args: anytype,
   5498     ) error{OutOfMemory}!void {
   5499         const gpa = elf_file.base.allocator;
   5500         const err_msg = &elf_file.misc_errors.items[err.index];
   5501         assert(err.note_slot < err_msg.notes.len);
   5502         err_msg.notes[err.note_slot] = .{ .msg = try std.fmt.allocPrint(gpa, format, args) };
   5503         err.note_slot += 1;
   5504     }
   5505 };
   5506 
   5507 pub fn addErrorWithNotes(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
   5508     try self.misc_errors.ensureUnusedCapacity(self.base.allocator, 1);
   5509     return self.addErrorWithNotesAssumeCapacity(note_count);
   5510 }
   5511 
   5512 fn addErrorWithNotesAssumeCapacity(self: *Elf, note_count: usize) error{OutOfMemory}!ErrorWithNotes {
   5513     const index = self.misc_errors.items.len;
   5514     const err = self.misc_errors.addOneAssumeCapacity();
   5515     err.* = .{ .msg = undefined, .notes = try self.base.allocator.alloc(link.File.ErrorMsg, note_count) };
   5516     return .{ .index = index };
   5517 }
   5518 
   5519 pub fn getShString(self: Elf, off: u32) [:0]const u8 {
   5520     assert(off < self.shstrtab.items.len);
   5521     return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.shstrtab.items.ptr + off)), 0);
   5522 }
   5523 
   5524 pub fn insertShString(self: *Elf, name: [:0]const u8) error{OutOfMemory}!u32 {
   5525     const off = @as(u32, @intCast(self.shstrtab.items.len));
   5526     try self.shstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
   5527     self.shstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
   5528     return off;
   5529 }
   5530 
   5531 pub fn getDynString(self: Elf, off: u32) [:0]const u8 {
   5532     assert(off < self.dynstrtab.items.len);
   5533     return mem.sliceTo(@as([*:0]const u8, @ptrCast(self.dynstrtab.items.ptr + off)), 0);
   5534 }
   5535 
   5536 pub fn insertDynString(self: *Elf, name: []const u8) error{OutOfMemory}!u32 {
   5537     const off = @as(u32, @intCast(self.dynstrtab.items.len));
   5538     try self.dynstrtab.ensureUnusedCapacity(self.base.allocator, name.len + 1);
   5539     self.dynstrtab.writer(self.base.allocator).print("{s}\x00", .{name}) catch unreachable;
   5540     return off;
   5541 }
   5542 
   5543 fn reportUndefined(self: *Elf, undefs: anytype) !void {
   5544     const gpa = self.base.allocator;
   5545     const max_notes = 4;
   5546 
   5547     try self.misc_errors.ensureUnusedCapacity(gpa, undefs.count());
   5548 
   5549     var it = undefs.iterator();
   5550     while (it.next()) |entry| {
   5551         const undef_index = entry.key_ptr.*;
   5552         const atoms = entry.value_ptr.*.items;
   5553         const natoms = @min(atoms.len, max_notes);
   5554         const nnotes = natoms + @intFromBool(atoms.len > max_notes);
   5555 
   5556         var err = try self.addErrorWithNotesAssumeCapacity(nnotes);
   5557         try err.addMsg(self, "undefined symbol: {s}", .{self.symbol(undef_index).name(self)});
   5558 
   5559         for (atoms[0..natoms]) |atom_index| {
   5560             const atom_ptr = self.atom(atom_index).?;
   5561             const file_ptr = self.file(atom_ptr.file_index).?;
   5562             try err.addNote(self, "referenced by {s}:{s}", .{ file_ptr.fmtPath(), atom_ptr.name(self) });
   5563         }
   5564 
   5565         if (atoms.len > max_notes) {
   5566             const remaining = atoms.len - max_notes;
   5567             try err.addNote(self, "referenced {d} more times", .{remaining});
   5568         }
   5569     }
   5570 }
   5571 
   5572 fn reportMissingLibraryError(
   5573     self: *Elf,
   5574     checked_paths: []const []const u8,
   5575     comptime format: []const u8,
   5576     args: anytype,
   5577 ) error{OutOfMemory}!void {
   5578     var err = try self.addErrorWithNotes(checked_paths.len);
   5579     try err.addMsg(self, format, args);
   5580     for (checked_paths) |path| {
   5581         try err.addNote(self, "tried {s}", .{path});
   5582     }
   5583 }
   5584 
   5585 const ParseErrorCtx = struct {
   5586     detected_cpu_arch: std.Target.Cpu.Arch,
   5587 };
   5588 
   5589 fn handleAndReportParseError(
   5590     self: *Elf,
   5591     path: []const u8,
   5592     err: ParseError,
   5593     ctx: *const ParseErrorCtx,
   5594 ) error{OutOfMemory}!void {
   5595     const cpu_arch = self.base.options.target.cpu.arch;
   5596     switch (err) {
   5597         error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
   5598         error.InvalidCpuArch => try self.reportParseError(
   5599             path,
   5600             "invalid cpu architecture: expected '{s}', but found '{s}'",
   5601             .{ @tagName(cpu_arch), @tagName(ctx.detected_cpu_arch) },
   5602         ),
   5603         else => |e| try self.reportParseError(
   5604             path,
   5605             "unexpected error: parsing object failed with error {s}",
   5606             .{@errorName(e)},
   5607         ),
   5608     }
   5609 }
   5610 
   5611 fn reportParseError(
   5612     self: *Elf,
   5613     path: []const u8,
   5614     comptime format: []const u8,
   5615     args: anytype,
   5616 ) error{OutOfMemory}!void {
   5617     var err = try self.addErrorWithNotes(1);
   5618     try err.addMsg(self, format, args);
   5619     try err.addNote(self, "while parsing {s}", .{path});
   5620 }
   5621 
   5622 const FormatShdrCtx = struct {
   5623     elf_file: *Elf,
   5624     shdr: elf.Elf64_Shdr,
   5625 };
   5626 
   5627 fn fmtShdr(self: *Elf, shdr: elf.Elf64_Shdr) std.fmt.Formatter(formatShdr) {
   5628     return .{ .data = .{
   5629         .shdr = shdr,
   5630         .elf_file = self,
   5631     } };
   5632 }
   5633 
   5634 fn formatShdr(
   5635     ctx: FormatShdrCtx,
   5636     comptime unused_fmt_string: []const u8,
   5637     options: std.fmt.FormatOptions,
   5638     writer: anytype,
   5639 ) !void {
   5640     _ = options;
   5641     _ = unused_fmt_string;
   5642     const shdr = ctx.shdr;
   5643     try writer.print("{s} : @{x} ({x}) : align({x}) : size({x})", .{
   5644         ctx.elf_file.getShString(shdr.sh_name), shdr.sh_offset,
   5645         shdr.sh_addr,                           shdr.sh_addralign,
   5646         shdr.sh_size,
   5647     });
   5648 }
   5649 
   5650 const FormatPhdrCtx = struct {
   5651     elf_file: *Elf,
   5652     phdr: elf.Elf64_Phdr,
   5653 };
   5654 
   5655 fn fmtPhdr(self: *Elf, phdr: elf.Elf64_Phdr) std.fmt.Formatter(formatPhdr) {
   5656     return .{ .data = .{
   5657         .phdr = phdr,
   5658         .elf_file = self,
   5659     } };
   5660 }
   5661 
   5662 fn formatPhdr(
   5663     ctx: FormatPhdrCtx,
   5664     comptime unused_fmt_string: []const u8,
   5665     options: std.fmt.FormatOptions,
   5666     writer: anytype,
   5667 ) !void {
   5668     _ = options;
   5669     _ = unused_fmt_string;
   5670     const phdr = ctx.phdr;
   5671     const write = phdr.p_flags & elf.PF_W != 0;
   5672     const read = phdr.p_flags & elf.PF_R != 0;
   5673     const exec = phdr.p_flags & elf.PF_X != 0;
   5674     var flags: [3]u8 = [_]u8{'_'} ** 3;
   5675     if (exec) flags[0] = 'X';
   5676     if (write) flags[1] = 'W';
   5677     if (read) flags[2] = 'R';
   5678     const p_type = switch (phdr.p_type) {
   5679         elf.PT_LOAD => "LOAD",
   5680         elf.PT_TLS => "TLS",
   5681         elf.PT_GNU_EH_FRAME => "GNU_EH_FRAME",
   5682         elf.PT_GNU_STACK => "GNU_STACK",
   5683         elf.PT_DYNAMIC => "DYNAMIC",
   5684         elf.PT_INTERP => "INTERP",
   5685         elf.PT_NULL => "NULL",
   5686         elf.PT_PHDR => "PHDR",
   5687         elf.PT_NOTE => "NOTE",
   5688         else => "UNKNOWN",
   5689     };
   5690     try writer.print("{s} : {s} : @{x} ({x}) : align({x}) : filesz({x}) : memsz({x})", .{
   5691         p_type,       flags,         phdr.p_offset, phdr.p_vaddr,
   5692         phdr.p_align, phdr.p_filesz, phdr.p_memsz,
   5693     });
   5694 }
   5695 
   5696 fn dumpState(self: *Elf) std.fmt.Formatter(fmtDumpState) {
   5697     return .{ .data = self };
   5698 }
   5699 
   5700 fn fmtDumpState(
   5701     self: *Elf,
   5702     comptime unused_fmt_string: []const u8,
   5703     options: std.fmt.FormatOptions,
   5704     writer: anytype,
   5705 ) !void {
   5706     _ = unused_fmt_string;
   5707     _ = options;
   5708 
   5709     if (self.zigObjectPtr()) |zig_object| {
   5710         try writer.print("zig_object({d}) : {s}\n", .{ zig_object.index, zig_object.path });
   5711         try writer.print("{}{}\n", .{
   5712             zig_object.fmtAtoms(self),
   5713             zig_object.fmtSymtab(self),
   5714         });
   5715     }
   5716 
   5717     for (self.objects.items) |index| {
   5718         const object = self.file(index).?.object;
   5719         try writer.print("object({d}) : {}", .{ index, object.fmtPath() });
   5720         if (!object.alive) try writer.writeAll(" : [*]");
   5721         try writer.writeByte('\n');
   5722         try writer.print("{}{}{}{}{}\n", .{
   5723             object.fmtAtoms(self),
   5724             object.fmtCies(self),
   5725             object.fmtFdes(self),
   5726             object.fmtSymtab(self),
   5727             object.fmtComdatGroups(self),
   5728         });
   5729     }
   5730 
   5731     for (self.shared_objects.items) |index| {
   5732         const shared_object = self.file(index).?.shared_object;
   5733         try writer.print("shared_object({d}) : ", .{index});
   5734         try writer.print("{s}", .{shared_object.path});
   5735         try writer.print(" : needed({})", .{shared_object.needed});
   5736         if (!shared_object.alive) try writer.writeAll(" : [*]");
   5737         try writer.writeByte('\n');
   5738         try writer.print("{}\n", .{shared_object.fmtSymtab(self)});
   5739     }
   5740 
   5741     if (self.linker_defined_index) |index| {
   5742         const linker_defined = self.file(index).?.linker_defined;
   5743         try writer.print("linker_defined({d}) : (linker defined)\n", .{index});
   5744         try writer.print("{}\n", .{linker_defined.fmtSymtab(self)});
   5745     }
   5746     try writer.print("{}\n", .{self.got.fmt(self)});
   5747     try writer.print("{}\n", .{self.zig_got.fmt(self)});
   5748 
   5749     try writer.writeAll("Output shdrs\n");
   5750     for (self.shdrs.items, 0..) |shdr, shndx| {
   5751         try writer.print("shdr({d}) : phdr({?d}) : {}\n", .{
   5752             shndx,
   5753             self.phdr_to_shdr_table.get(@intCast(shndx)),
   5754             self.fmtShdr(shdr),
   5755         });
   5756     }
   5757     try writer.writeAll("\nOutput phdrs\n");
   5758     for (self.phdrs.items, 0..) |phdr, phndx| {
   5759         try writer.print("phdr{d} : {}\n", .{ phndx, self.fmtPhdr(phdr) });
   5760     }
   5761 }
   5762 
   5763 /// Binary search
   5764 pub fn bsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {
   5765     if (!@hasDecl(@TypeOf(predicate), "predicate"))
   5766         @compileError("Predicate is required to define fn predicate(@This(), T) bool");
   5767 
   5768     var min: usize = 0;
   5769     var max: usize = haystack.len;
   5770     while (min < max) {
   5771         const index = (min + max) / 2;
   5772         const curr = haystack[index];
   5773         if (predicate.predicate(curr)) {
   5774             min = index + 1;
   5775         } else {
   5776             max = index;
   5777         }
   5778     }
   5779     return min;
   5780 }
   5781 
   5782 /// Linear search
   5783 pub fn lsearch(comptime T: type, haystack: []align(1) const T, predicate: anytype) usize {
   5784     if (!@hasDecl(@TypeOf(predicate), "predicate"))
   5785         @compileError("Predicate is required to define fn predicate(@This(), T) bool");
   5786 
   5787     var i: usize = 0;
   5788     while (i < haystack.len) : (i += 1) {
   5789         if (predicate.predicate(haystack[i])) break;
   5790     }
   5791     return i;
   5792 }
   5793 
   5794 /// The following three values are only observed at compile-time and used to emit a compile error
   5795 /// to remind the programmer to update expected maximum numbers of different program header types
   5796 /// so that we reserve enough space for the program header table up-front.
   5797 /// Bump these numbers when adding or deleting a Zig specific pre-allocated segment, or adding
   5798 /// more special-purpose program headers.
   5799 const number_of_zig_segments = 5;
   5800 const max_number_of_object_segments = 9;
   5801 const max_number_of_special_phdrs = 5;
   5802 
   5803 const default_entry_addr = 0x8000000;
   5804 
   5805 pub const base_tag: link.File.Tag = .elf;
   5806 
   5807 const ComdatGroupOwner = struct {
   5808     file: File.Index = 0,
   5809     const Index = u32;
   5810 };
   5811 
   5812 pub const ComdatGroup = struct {
   5813     owner: ComdatGroupOwner.Index,
   5814     shndx: u16,
   5815     pub const Index = u32;
   5816 };
   5817 
   5818 pub const SymtabSize = struct {
   5819     nlocals: u32 = 0,
   5820     nglobals: u32 = 0,
   5821     strsize: u32 = 0,
   5822 
   5823     fn add(ss: *SymtabSize, other: SymtabSize) void {
   5824         ss.nlocals += other.nlocals;
   5825         ss.nglobals += other.nglobals;
   5826         ss.strsize += other.strsize;
   5827     }
   5828 };
   5829 
   5830 pub const null_sym = elf.Elf64_Sym{
   5831     .st_name = 0,
   5832     .st_info = 0,
   5833     .st_other = 0,
   5834     .st_shndx = 0,
   5835     .st_value = 0,
   5836     .st_size = 0,
   5837 };
   5838 
   5839 pub const null_shdr = elf.Elf64_Shdr{
   5840     .sh_name = 0,
   5841     .sh_type = 0,
   5842     .sh_flags = 0,
   5843     .sh_addr = 0,
   5844     .sh_offset = 0,
   5845     .sh_size = 0,
   5846     .sh_link = 0,
   5847     .sh_info = 0,
   5848     .sh_addralign = 0,
   5849     .sh_entsize = 0,
   5850 };
   5851 
   5852 pub const SystemLib = struct {
   5853     needed: bool = false,
   5854     path: []const u8,
   5855 };
   5856 
   5857 const LastAtomAndFreeList = struct {
   5858     /// Index of the last allocated atom in this section.
   5859     last_atom_index: Atom.Index = 0,
   5860 
   5861     /// A list of atoms that have surplus capacity. This list can have false
   5862     /// positives, as functions grow and shrink over time, only sometimes being added
   5863     /// or removed from the freelist.
   5864     ///
   5865     /// An atom has surplus capacity when its overcapacity value is greater than
   5866     /// padToIdeal(minimum_atom_size). That is, when it has so
   5867     /// much extra capacity, that we could fit a small new symbol in it, itself with
   5868     /// ideal_capacity or more.
   5869     ///
   5870     /// Ideal capacity is defined by size + (size / ideal_factor)
   5871     ///
   5872     /// Overcapacity is measured by actual_capacity - ideal_capacity. Note that
   5873     /// overcapacity can be negative. A simple way to have negative overcapacity is to
   5874     /// allocate a fresh text block, which will have ideal capacity, and then grow it
   5875     /// by 1 byte. It will then have -1 overcapacity.
   5876     free_list: std.ArrayListUnmanaged(Atom.Index) = .{},
   5877 };
   5878 
   5879 const LastAtomAndFreeListTable = std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFreeList);
   5880 
   5881 pub const R_X86_64_ZIG_GOT32 = elf.R_X86_64_NUM + 1;
   5882 pub const R_X86_64_ZIG_GOTPCREL = elf.R_X86_64_NUM + 2;
   5883 
   5884 const std = @import("std");
   5885 const build_options = @import("build_options");
   5886 const builtin = @import("builtin");
   5887 const assert = std.debug.assert;
   5888 const elf = std.elf;
   5889 const fs = std.fs;
   5890 const log = std.log.scoped(.link);
   5891 const state_log = std.log.scoped(.link_state);
   5892 const math = std.math;
   5893 const mem = std.mem;
   5894 
   5895 const codegen = @import("../codegen.zig");
   5896 const eh_frame = @import("Elf/eh_frame.zig");
   5897 const gc = @import("Elf/gc.zig");
   5898 const glibc = @import("../glibc.zig");
   5899 const link = @import("../link.zig");
   5900 const lldMain = @import("../main.zig").lldMain;
   5901 const musl = @import("../musl.zig");
   5902 const target_util = @import("../target.zig");
   5903 const trace = @import("../tracy.zig").trace;
   5904 const synthetic_sections = @import("Elf/synthetic_sections.zig");
   5905 
   5906 const Air = @import("../Air.zig");
   5907 const Allocator = std.mem.Allocator;
   5908 const Archive = @import("Elf/Archive.zig");
   5909 pub const Atom = @import("Elf/Atom.zig");
   5910 const Cache = std.Build.Cache;
   5911 const Compilation = @import("../Compilation.zig");
   5912 const CopyRelSection = synthetic_sections.CopyRelSection;
   5913 const DynamicSection = synthetic_sections.DynamicSection;
   5914 const DynsymSection = synthetic_sections.DynsymSection;
   5915 const Dwarf = @import("Dwarf.zig");
   5916 const Elf = @This();
   5917 const File = @import("Elf/file.zig").File;
   5918 const GnuHashSection = synthetic_sections.GnuHashSection;
   5919 const GotSection = synthetic_sections.GotSection;
   5920 const GotPltSection = synthetic_sections.GotPltSection;
   5921 const HashSection = synthetic_sections.HashSection;
   5922 const LdScript = @import("Elf/LdScript.zig");
   5923 const LinkerDefined = @import("Elf/LinkerDefined.zig");
   5924 const Liveness = @import("../Liveness.zig");
   5925 const LlvmObject = @import("../codegen/llvm.zig").Object;
   5926 const Module = @import("../Module.zig");
   5927 const Object = @import("Elf/Object.zig");
   5928 const InternPool = @import("../InternPool.zig");
   5929 const PltSection = synthetic_sections.PltSection;
   5930 const PltGotSection = synthetic_sections.PltGotSection;
   5931 const SharedObject = @import("Elf/SharedObject.zig");
   5932 const Symbol = @import("Elf/Symbol.zig");
   5933 const StringTable = @import("StringTable.zig");
   5934 const TypedValue = @import("../TypedValue.zig");
   5935 const VerneedSection = synthetic_sections.VerneedSection;
   5936 const ZigGotSection = synthetic_sections.ZigGotSection;
   5937 const ZigObject = @import("Elf/ZigObject.zig");