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