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");