| ... | ... | @@ -126,8 +126,14 @@ needed: std.array_hash_map.Auto(String(.dynstr), void), |
| 126 | 126 | inputs: std.ArrayList(struct { |
| 127 | 127 | path: std.Build.Cache.Path, |
| 128 | 128 | member: ?[]const u8, |
| 129 | | file_symbol: Symbol.LocalIndex, |
| 129 | extra: union { |
| 130 | /// Active for static libraries. |
| 131 | node: MappedFile.Node.Index, |
| 132 | /// Active otherwise. |
| 133 | file_symbol: Symbol.LocalIndex, |
| 134 | }, |
| 130 | 135 | }), |
| 136 | input_pending_index: u32, |
| 131 | 137 | input_sections: std.ArrayList(InputSection), |
| 132 | 138 | input_section_pending_index: u32, |
| 133 | 139 | navs: std.array_hash_map.Auto(InternPool.Nav.Index, struct { |
| ... | ... | @@ -181,7 +187,10 @@ input_prog_node: std.Progress.Node, |
| 181 | 187 | const Error = link.Error || error{MappedFileIo}; |
| 182 | 188 | |
| 183 | 189 | const Node = union(enum) { |
| 184 | | file, |
| 190 | archive, |
| 191 | /// This includes the archive magic and long file member. |
| 192 | archive_header, |
| 193 | elf, |
| 185 | 194 | ehdr, |
| 186 | 195 | shdr, |
| 187 | 196 | segment: u32, |
| ... | ... | @@ -189,6 +198,8 @@ const Node = union(enum) { |
| 189 | 198 | /// |
| 190 | 199 | /// The section '.dynamic' may contain relocations via `elf.dynamic_first_symbol_reloc`. |
| 191 | 200 | section: Section.Index, |
| 201 | /// Only valid for static libraries, represents one non-zcu archive member. |
| 202 | input_member: InputIndex, |
| 192 | 203 | /// May contain relocations. |
| 193 | 204 | input_section: InputSection.Index, |
| 194 | 205 | /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for |
| ... | ... | @@ -219,19 +230,23 @@ const Node = union(enum) { |
| 219 | 230 | return elf.inputs.items[@backingInt(ii)].member; |
| 220 | 231 | } |
| 221 | 232 | |
| 233 | pub fn node(ii: InputIndex, elf: *const Elf) MappedFile.Node.Index { |
| 234 | return elf.inputs.items[@backingInt(ii)].extra.node; |
| 235 | } |
| 236 | |
| 222 | 237 | pub fn fileSymbol(ii: InputIndex, elf: *const Elf) Symbol.LocalIndex { |
| 223 | | return elf.inputs.items[@backingInt(ii)].file_symbol; |
| 238 | return elf.inputs.items[@backingInt(ii)].extra.file_symbol; |
| 224 | 239 | } |
| 225 | 240 | |
| 226 | 241 | pub fn localSymbolRange(ii: InputIndex, elf: *Elf) [2]Symbol.LocalIndex { |
| 227 | 242 | if (@backingInt(ii) + 1 < elf.inputs.items.len) { |
| 228 | | const next_ii: InputIndex = @fromBackingInt(@intCast(@backingInt(ii) + 1)); |
| 243 | const next_ii: InputIndex = @fromBackingInt(@backingInt(ii) + 1); |
| 229 | 244 | return .{ ii.fileSymbol(elf), next_ii.fileSymbol(elf) }; |
| 230 | 245 | } else { |
| 231 | 246 | const local_symbols_len = switch (elf.shdrPtr(.symtab)) { |
| 232 | 247 | inline else => |shdr| elf.targetLoad(&shdr.info), |
| 233 | 248 | }; |
| 234 | | return .{ ii.fileSymbol(elf), @fromBackingInt(@intCast(local_symbols_len)) }; |
| 249 | return .{ ii.fileSymbol(elf), @fromBackingInt(local_symbols_len) }; |
| 235 | 250 | } |
| 236 | 251 | } |
| 237 | 252 | }; |
| ... | ... | @@ -315,15 +330,16 @@ const Node = union(enum) { |
| 315 | 330 | }; |
| 316 | 331 | |
| 317 | 332 | pub const Known = struct { |
| 318 | | comptime file: MappedFile.Node.Index = .root, |
| 319 | | comptime ehdr: MappedFile.Node.Index = @fromBackingInt(@intCast(1)), |
| 320 | | comptime shdr: MappedFile.Node.Index = @fromBackingInt(@intCast(2)), |
| 321 | | comptime rodata: MappedFile.Node.Index = @fromBackingInt(@intCast(3)), |
| 322 | | comptime phdr: MappedFile.Node.Index = @fromBackingInt(@intCast(4)), |
| 323 | | comptime text: MappedFile.Node.Index = @fromBackingInt(@intCast(5)), |
| 324 | | comptime data: MappedFile.Node.Index = @fromBackingInt(@intCast(6)), |
| 325 | | comptime data_rel_ro: MappedFile.Node.Index = @fromBackingInt(@intCast(7)), |
| 326 | | |
| 333 | archive: MappedFile.Node.Index, |
| 334 | archive_header: MappedFile.Node.Index, |
| 335 | elf: MappedFile.Node.Index, |
| 336 | ehdr: MappedFile.Node.Index, |
| 337 | shdr: MappedFile.Node.Index, |
| 338 | rodata: MappedFile.Node.Index, |
| 339 | phdr: MappedFile.Node.Index, |
| 340 | text: MappedFile.Node.Index, |
| 341 | data: MappedFile.Node.Index, |
| 342 | data_rel_ro: MappedFile.Node.Index, |
| 327 | 343 | tls: MappedFile.Node.Index, |
| 328 | 344 | }; |
| 329 | 345 | |
| ... | ... | @@ -333,11 +349,11 @@ const Node = union(enum) { |
| 333 | 349 | |
| 334 | 350 | /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`. |
| 335 | 351 | fn toAtom(ni: MappedFile.Node.Index) link.File.AtomId { |
| 336 | | return @fromBackingInt(@intCast(@backingInt(ni))); |
| 352 | return @fromBackingInt(@backingInt(ni)); |
| 337 | 353 | } |
| 338 | 354 | /// In this linker implementation, `link.File.AtomId` is a type-erased `MappedFile.Node.Index`. |
| 339 | 355 | fn fromAtom(atom: link.File.AtomId) MappedFile.Node.Index { |
| 340 | | return @fromBackingInt(@intCast(@backingInt(atom))); |
| 356 | return @fromBackingInt(@backingInt(atom)); |
| 341 | 357 | } |
| 342 | 358 | }; |
| 343 | 359 | |
| ... | ... | @@ -424,13 +440,13 @@ const Section = struct { |
| 424 | 440 | fn unwrap(opt: RelaIndex.Optional) ?RelaIndex { |
| 425 | 441 | return switch (opt) { |
| 426 | 442 | .none => null, |
| 427 | | _ => @fromBackingInt(@intCast(@backingInt(opt))), |
| 443 | _ => @fromBackingInt(@backingInt(opt)), |
| 428 | 444 | }; |
| 429 | 445 | } |
| 430 | 446 | }; |
| 431 | 447 | |
| 432 | 448 | fn toOptional(i: RelaIndex) RelaIndex.Optional { |
| 433 | | return @fromBackingInt(@intCast(@backingInt(i))); |
| 449 | return @fromBackingInt(@backingInt(i)); |
| 434 | 450 | } |
| 435 | 451 | }; |
| 436 | 452 | |
| ... | ... | @@ -465,8 +481,8 @@ const Section = struct { |
| 465 | 481 | |
| 466 | 482 | pub fn fromSection(sec: std.elf.Section) Index { |
| 467 | 483 | return switch (sec) { |
| 468 | | std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @fromBackingInt(@intCast(sec)), |
| 469 | | std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @fromBackingInt(@intCast(reserve(sec))), |
| 484 | std.elf.SHN_UNDEF...std.elf.SHN_LORESERVE - 1 => @fromBackingInt(sec), |
| 485 | std.elf.SHN_LORESERVE...std.elf.SHN_HIRESERVE => @fromBackingInt(reserve(sec)), |
| 470 | 486 | }; |
| 471 | 487 | } |
| 472 | 488 | pub fn toSection(s: Index) ?std.elf.Section { |
| ... | ... | @@ -485,7 +501,7 @@ const Section = struct { |
| 485 | 501 | |
| 486 | 502 | fn name(s: Index, elf: *Elf) String(.shstrtab) { |
| 487 | 503 | return switch (elf.shdrPtr(s)) { |
| 488 | | inline else => |shdr| @fromBackingInt(@intCast(elf.targetLoad(&shdr.name))), |
| 504 | inline else => |shdr| @fromBackingInt(elf.targetLoad(&shdr.name)), |
| 489 | 505 | }; |
| 490 | 506 | } |
| 491 | 507 | |
| ... | ... | @@ -928,21 +944,7 @@ const GotReloc = struct { |
| 928 | 944 | } |
| 929 | 945 | } |
| 930 | 946 | fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { |
| 931 | | const node_vaddr: u64 = switch (elf.getNode(reloc.node)) { |
| 932 | | .file => unreachable, |
| 933 | | .ehdr => unreachable, |
| 934 | | .shdr => unreachable, |
| 935 | | .segment => unreachable, |
| 936 | | .copied_global => unreachable, |
| 937 | | .section => |shndx| shndx.vaddr(elf), |
| 938 | | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 939 | | inline .nav, |
| 940 | | .uav, |
| 941 | | .lazy_code, |
| 942 | | .lazy_const_data, |
| 943 | | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 944 | | }; |
| 945 | | const dest_vaddr = node_vaddr + reloc.offset; |
| 947 | const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset; |
| 946 | 948 | const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; |
| 947 | 949 | |
| 948 | 950 | const got_vaddr = elf.shndx.got.vaddr(elf); |
| ... | ... | @@ -1131,12 +1133,12 @@ pub const MachineRelocType = union { |
| 1131 | 1133 | |
| 1132 | 1134 | pub fn wrap(int: u32, elf: *const Elf) MachineRelocType { |
| 1133 | 1135 | return switch (elf.ehdrMachine()) { |
| 1134 | | .AARCH64 => .{ .AARCH64 = @fromBackingInt(@intCast(int)) }, |
| 1135 | | .LOONGARCH => .{ .LARCH = @fromBackingInt(@intCast(int)) }, |
| 1136 | | .PPC64 => .{ .PPC64 = @fromBackingInt(@intCast(int)) }, |
| 1137 | | .RISCV => .{ .RISCV = @fromBackingInt(@intCast(int)) }, |
| 1138 | | .SPARCV9 => .{ .SPARC = @fromBackingInt(@intCast(int)) }, |
| 1139 | | .X86_64 => .{ .X86_64 = @fromBackingInt(@intCast(int)) }, |
| 1136 | .AARCH64 => .{ .AARCH64 = @fromBackingInt(int) }, |
| 1137 | .LOONGARCH => .{ .LARCH = @fromBackingInt(int) }, |
| 1138 | .PPC64 => .{ .PPC64 = @fromBackingInt(int) }, |
| 1139 | .RISCV => .{ .RISCV = @fromBackingInt(int) }, |
| 1140 | .SPARCV9 => .{ .SPARC = @fromBackingInt(int) }, |
| 1141 | .X86_64 => .{ .X86_64 = @fromBackingInt(int) }, |
| 1140 | 1142 | }; |
| 1141 | 1143 | } |
| 1142 | 1144 | pub fn unwrap(rt: MachineRelocType, elf: *const Elf) u32 { |
| ... | ... | @@ -1646,21 +1648,7 @@ const SymbolReloc = struct { |
| 1646 | 1648 | } |
| 1647 | 1649 | } |
| 1648 | 1650 | fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { |
| 1649 | | const node_vaddr: u64 = switch (elf.getNode(reloc.node)) { |
| 1650 | | .file => unreachable, |
| 1651 | | .ehdr => unreachable, |
| 1652 | | .shdr => unreachable, |
| 1653 | | .segment => unreachable, |
| 1654 | | .copied_global => unreachable, |
| 1655 | | .section => |shndx| shndx.vaddr(elf), |
| 1656 | | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 1657 | | inline .nav, |
| 1658 | | .uav, |
| 1659 | | .lazy_code, |
| 1660 | | .lazy_const_data, |
| 1661 | | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 1662 | | }; |
| 1663 | | const dest_vaddr = node_vaddr + reloc.offset; |
| 1651 | const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset; |
| 1664 | 1652 | const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; |
| 1665 | 1653 | |
| 1666 | 1654 | const addend: u64 = @bitCast(reloc.addend); |
| ... | ... | @@ -1875,7 +1863,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L |
| 1875 | 1863 | |
| 1876 | 1864 | // `shdr.info` stores the index of the first global symbol. We will replace it with our |
| 1877 | 1865 | // new local symbol, and move the global symbol to a new index at the end of the symtab. |
| 1878 | | const target_index: Symbol.Index = @fromBackingInt(@intCast(elf.targetLoad(&shdr.info))); |
| 1866 | const target_index: Symbol.Index = @fromBackingInt(elf.targetLoad(&shdr.info)); |
| 1879 | 1867 | |
| 1880 | 1868 | const old_size = elf.targetLoad(&shdr.size); |
| 1881 | 1869 | const new_size = old_size + ent_size; |
| ... | ... | @@ -1897,7 +1885,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L |
| 1897 | 1885 | // ...then the `elf.symtab` metadata... |
| 1898 | 1886 | new_index.ptr(elf).* = target_index.ptr(elf).*; |
| 1899 | 1887 | // ...then update the `elf.globals` tracking. |
| 1900 | | const global_name: String(.strtab) = @fromBackingInt(@intCast(elf.targetLoad(&new_sym.name))); |
| 1888 | const global_name: String(.strtab) = @fromBackingInt(elf.targetLoad(&new_sym.name)); |
| 1901 | 1889 | elf.globalByName(global_name).?.symtab_index = new_index; |
| 1902 | 1890 | |
| 1903 | 1891 | if (elf.ehdrType() == .REL and target_index.ptr(elf).first_target_reloc != .none) { |
| ... | ... | @@ -1923,7 +1911,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L |
| 1923 | 1911 | std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym); |
| 1924 | 1912 | } |
| 1925 | 1913 | |
| 1926 | | return @fromBackingInt(@intCast(@backingInt(target_index))); |
| 1914 | return @fromBackingInt(@backingInt(target_index)); |
| 1927 | 1915 | }, |
| 1928 | 1916 | } |
| 1929 | 1917 | } |
| ... | ... | @@ -2371,7 +2359,7 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { |
| 2371 | 2359 | inline else => |shdr, class| { |
| 2372 | 2360 | // `shdr.info` stores the index of the first global symbol. We are going to swap the |
| 2373 | 2361 | // demoted symbol with that first global symbol, then increment that start index. |
| 2374 | | const dest_index: Symbol.Index = @fromBackingInt(@intCast(elf.targetLoad(&shdr.info))); |
| 2362 | const dest_index: Symbol.Index = @fromBackingInt(elf.targetLoad(&shdr.info)); |
| 2375 | 2363 | const src_index = global_ptr.symtab_index; |
| 2376 | 2364 | |
| 2377 | 2365 | // This global should currently be in the "global symbols" part of the symtab, since our |
| ... | ... | @@ -2387,10 +2375,10 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { |
| 2387 | 2375 | const src_sym_ptr = @field(elf.symPtr(src_index), @tagName(class)); |
| 2388 | 2376 | const dest_sym_ptr = @field(elf.symPtr(dest_index), @tagName(class)); |
| 2389 | 2377 | |
| 2390 | | const this_name: String(.strtab) = @fromBackingInt(@intCast(elf.targetLoad(&src_sym_ptr.name))); |
| 2378 | const this_name: String(.strtab) = @fromBackingInt(elf.targetLoad(&src_sym_ptr.name)); |
| 2391 | 2379 | assert(elf.globalByName(this_name).? == global_ptr); |
| 2392 | 2380 | |
| 2393 | | const other_name: String(.strtab) = @fromBackingInt(@intCast(elf.targetLoad(&dest_sym_ptr.name))); |
| 2381 | const other_name: String(.strtab) = @fromBackingInt(elf.targetLoad(&dest_sym_ptr.name)); |
| 2394 | 2382 | const other_global_ptr = elf.globalByName(other_name).?; |
| 2395 | 2383 | assert(other_global_ptr.symtab_index == dest_index); |
| 2396 | 2384 | |
| ... | ... | @@ -2426,7 +2414,7 @@ fn moveDemotedGlobal(elf: *Elf, global_ptr: *Symbol.Global) void { |
| 2426 | 2414 | const src_dynsym_ptr = @field(elf.dynsymPtr(remove_dynsym_index), @tagName(class)); |
| 2427 | 2415 | const dest_dynsym_ptr = @field(elf.dynsymPtr(free_dynsym_index), @tagName(class)); |
| 2428 | 2416 | |
| 2429 | | const moved_name_dynstr: String(.dynstr) = @fromBackingInt(@intCast(elf.targetLoad(&src_dynsym_ptr.name))); |
| 2417 | const moved_name_dynstr: String(.dynstr) = @fromBackingInt(elf.targetLoad(&src_dynsym_ptr.name)); |
| 2430 | 2418 | const moved_name = elf.stringExisting(.strtab, moved_name_dynstr.slice(elf)); |
| 2431 | 2419 | const moved_global_ptr = elf.globalByName(moved_name).?; |
| 2432 | 2420 | |
| ... | ... | @@ -2505,7 +2493,7 @@ const Symbol = struct { |
| 2505 | 2493 | _, |
| 2506 | 2494 | |
| 2507 | 2495 | fn index(li: LocalIndex) Index { |
| 2508 | | return @fromBackingInt(@intCast(@backingInt(li))); |
| 2496 | return @fromBackingInt(@backingInt(li)); |
| 2509 | 2497 | } |
| 2510 | 2498 | }; |
| 2511 | 2499 | |
| ... | ... | @@ -2527,16 +2515,16 @@ const Symbol = struct { |
| 2527 | 2515 | global: String(.strtab), |
| 2528 | 2516 | } { |
| 2529 | 2517 | return switch (s.kind) { |
| 2530 | | .local => .{ .local = @fromBackingInt(@intCast(s.raw)) }, |
| 2531 | | .global => .{ .global = @fromBackingInt(@intCast(s.raw)) }, |
| 2518 | .local => .{ .local = @fromBackingInt(s.raw) }, |
| 2519 | .global => .{ .global = @fromBackingInt(s.raw) }, |
| 2532 | 2520 | }; |
| 2533 | 2521 | } |
| 2534 | 2522 | |
| 2535 | 2523 | fn toTypeErased(s: Symbol.Id) link.File.SymbolId { |
| 2536 | | return @fromBackingInt(@intCast(@as(u32, @bitCast(s)))); |
| 2524 | return @bitCast(s); |
| 2537 | 2525 | } |
| 2538 | 2526 | fn fromTypeErased(s: link.File.SymbolId) Symbol.Id { |
| 2539 | | return @bitCast(@backingInt(s)); |
| 2527 | return @bitCast(s); |
| 2540 | 2528 | } |
| 2541 | 2529 | |
| 2542 | 2530 | fn index(s: Symbol.Id, elf: *const Elf) Symbol.Index { |
| ... | ... | @@ -2648,24 +2636,10 @@ const Symbol = struct { |
| 2648 | 2636 | .yes_textrel => elf.textrel_count += 1, |
| 2649 | 2637 | .yes => {}, |
| 2650 | 2638 | } |
| 2651 | | const node_vaddr: u64 = switch (elf.getNode(reloc.node)) { |
| 2652 | | .file => unreachable, |
| 2653 | | .ehdr => unreachable, |
| 2654 | | .shdr => unreachable, |
| 2655 | | .segment => unreachable, |
| 2656 | | .copied_global => unreachable, |
| 2657 | | .section => |shndx| shndx.vaddr(elf), |
| 2658 | | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 2659 | | inline .nav, |
| 2660 | | .uav, |
| 2661 | | .lazy_code, |
| 2662 | | .lazy_const_data, |
| 2663 | | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 2664 | | }; |
| 2665 | 2639 | // There is capacity for a relocation because we just deleted one earlier. |
| 2666 | 2640 | reloc.rela_index = elf.shndx.rela_dyn.relaAddOneAssumeCapacity(elf, .{ |
| 2667 | 2641 | .type = .relative(elf), |
| 2668 | | .offset = node_vaddr + reloc.offset, |
| 2642 | .offset = elf.getNodeVAddr(reloc.node) + reloc.offset, |
| 2669 | 2643 | .raw_sym_index = 0, |
| 2670 | 2644 | .addend = 0, |
| 2671 | 2645 | }).toOptional(); |
| ... | ... | @@ -2771,11 +2745,14 @@ fn classifySymbolValue(elf: *Elf, sym: Symbol.Id) enum { |
| 2771 | 2745 | |
| 2772 | 2746 | pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { |
| 2773 | 2747 | const lsi: Symbol.LocalIndex = switch (elf.getNode(Node.fromAtom(atom))) { |
| 2774 | | .file, |
| 2748 | .archive, |
| 2749 | .archive_header, |
| 2750 | .elf, |
| 2775 | 2751 | .ehdr, |
| 2776 | 2752 | .shdr, |
| 2777 | 2753 | .segment, |
| 2778 | 2754 | .section, |
| 2755 | .input_member, |
| 2779 | 2756 | .input_section, |
| 2780 | 2757 | .copied_global, |
| 2781 | 2758 | => unreachable, |
| ... | ... | @@ -3001,12 +2978,12 @@ fn String(section: StringSection) type { |
| 3001 | 2978 | } |
| 3002 | 2979 | fn string(elf: *Elf, comptime section: StringSection, key: []const u8) Error!String(section) { |
| 3003 | 2980 | const st: *StringTable = &@field(elf, @tagName(section)); |
| 3004 | | return @fromBackingInt(@intCast(try st.get(elf, section.shndx(elf), key))); |
| 2981 | return @fromBackingInt(try st.get(elf, section.shndx(elf), key)); |
| 3005 | 2982 | } |
| 3006 | 2983 | /// Like `string`, but asserts that the string is already in `section`. |
| 3007 | 2984 | fn stringExisting(elf: *Elf, comptime section: StringSection, key: []const u8) String(section) { |
| 3008 | 2985 | const st: *StringTable = &@field(elf, @tagName(section)); |
| 3009 | | return @fromBackingInt(@intCast(st.getExisting(elf, section.shndx(elf), key))); |
| 2986 | return @fromBackingInt(st.getExisting(elf, section.shndx(elf), key)); |
| 3010 | 2987 | } |
| 3011 | 2988 | |
| 3012 | 2989 | const StringTable = struct { |
| ... | ... | @@ -3172,6 +3149,16 @@ fn create( |
| 3172 | 3149 | .options = options, |
| 3173 | 3150 | .mf = try .init(file, comp.gpa, io), |
| 3174 | 3151 | .ni = .{ |
| 3152 | .archive = .root, |
| 3153 | .archive_header = .none, |
| 3154 | .elf = .root, |
| 3155 | .ehdr = .none, |
| 3156 | .shdr = .none, |
| 3157 | .rodata = .none, |
| 3158 | .phdr = .none, |
| 3159 | .text = .none, |
| 3160 | .data = .none, |
| 3161 | .data_rel_ro = .none, |
| 3175 | 3162 | .tls = .none, |
| 3176 | 3163 | }, |
| 3177 | 3164 | .nodes = .empty, |
| ... | ... | @@ -3218,6 +3205,7 @@ fn create( |
| 3218 | 3205 | .dynamic_first_symbol_reloc = .none, |
| 3219 | 3206 | .needed = .empty, |
| 3220 | 3207 | .inputs = .empty, |
| 3208 | .input_pending_index = 0, |
| 3221 | 3209 | .input_sections = .empty, |
| 3222 | 3210 | .input_section_pending_index = 0, |
| 3223 | 3211 | .navs = .empty, |
| ... | ... | @@ -3293,6 +3281,7 @@ fn initHeaders( |
| 3293 | 3281 | const comp = elf.base.comp; |
| 3294 | 3282 | const gpa = comp.gpa; |
| 3295 | 3283 | |
| 3284 | const is_archive = comp.config.output_mode == .Lib and comp.config.link_mode == .static; |
| 3296 | 3285 | const have_dynamic_section = switch (@"type") { |
| 3297 | 3286 | .REL => false, |
| 3298 | 3287 | .EXEC => comp.config.link_mode == .dynamic, |
| ... | ... | @@ -3389,7 +3378,8 @@ fn initHeaders( |
| 3389 | 3378 | }, phnum }; |
| 3390 | 3379 | }; |
| 3391 | 3380 | |
| 3392 | | const expected_nodes_len = 3 + // `.file`, `.ehdr`, and `.shdr` nodes |
| 3381 | const expected_nodes_len = @as(usize, if (is_archive) 2 else 0) + // .archive, .archive_header |
| 3382 | 3 + // `.file`, `.ehdr`, and `.shdr` nodes |
| 3393 | 3383 | (shnum - 1) + // -1 because the null shdr does not have a `.section` node |
| 3394 | 3384 | (phnum -| 1); // -1 because the GNU_STACK phdr does not have a `.segment` node |
| 3395 | 3385 | |
| ... | ... | @@ -3398,17 +3388,49 @@ fn initHeaders( |
| 3398 | 3388 | try elf.section_by_name.ensureUnusedCapacity(gpa, shnum); |
| 3399 | 3389 | try elf.phdrs.resize(gpa, phnum); |
| 3400 | 3390 | try elf.symtab.ensureTotalCapacity(gpa, 1); |
| 3401 | | elf.nodes.appendAssumeCapacity(.file); |
| 3391 | |
| 3392 | if (is_archive) { |
| 3393 | elf.nodes.appendAssumeCapacity(.archive); |
| 3394 | elf.ni.archive_header = try elf.mf.addOnlyChildNode(gpa, elf.ni.archive, .{ |
| 3395 | .size = std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr) * 2, |
| 3396 | .alignment = .@"2", |
| 3397 | .fixed = true, |
| 3398 | .next_moved = true, |
| 3399 | .bubbles_moved = false, |
| 3400 | .enable_next_moved = true, |
| 3401 | }); |
| 3402 | const archive_header_slice = elf.ni.archive_header.slice(&elf.mf); |
| 3403 | @memcpy(archive_header_slice[0..std.elf.ARMAG.len], std.elf.ARMAG); |
| 3404 | const strtab_ar_hdr: *std.elf.ar_hdr = @ptrCast(archive_header_slice[std.elf.ARMAG.len..]); |
| 3405 | strtab_ar_hdr.* = .{ |
| 3406 | .ar_name = std.elf.STRNAME.*, |
| 3407 | .ar_date = @splat(' '), |
| 3408 | .ar_uid = @splat(' '), |
| 3409 | .ar_gid = @splat(' '), |
| 3410 | .ar_mode = @splat(' '), |
| 3411 | .ar_size = @splat(' '), |
| 3412 | .ar_fmag = std.elf.ARFMAG.*, |
| 3413 | }; |
| 3414 | |
| 3415 | elf.nodes.appendAssumeCapacity(.archive_header); |
| 3416 | elf.ni.elf = try elf.mf.addLastChildNode(gpa, elf.ni.archive, .{ |
| 3417 | .alignment = elf.mf.flags.block_size.max(.@"2"), |
| 3418 | .next_moved = true, |
| 3419 | .bubbles_moved = false, |
| 3420 | .enable_next_moved = true, |
| 3421 | }); |
| 3422 | } |
| 3423 | elf.nodes.appendAssumeCapacity(.elf); |
| 3402 | 3424 | |
| 3403 | 3425 | const entsize: struct { ph: u32, sh: u32 } = switch (class) { |
| 3404 | 3426 | .NONE, _ => unreachable, |
| 3405 | 3427 | inline else => |ct_class| entsize: { |
| 3406 | 3428 | const ElfN = ct_class.ElfN(); |
| 3407 | | assert(elf.ni.ehdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.file, .{ |
| 3429 | elf.ni.ehdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| 3408 | 3430 | .size = @sizeOf(ElfN.Ehdr), |
| 3409 | 3431 | .alignment = addr_align, |
| 3410 | 3432 | .fixed = true, |
| 3411 | | })); |
| 3433 | }); |
| 3412 | 3434 | elf.nodes.appendAssumeCapacity(.ehdr); |
| 3413 | 3435 | |
| 3414 | 3436 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf))); |
| ... | ... | @@ -3461,12 +3483,12 @@ fn initHeaders( |
| 3461 | 3483 | }, |
| 3462 | 3484 | }; |
| 3463 | 3485 | |
| 3464 | | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 3486 | elf.ni.shdr = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| 3465 | 3487 | .size = 1 * entsize.sh, // as above, only the null shdr initially |
| 3466 | 3488 | .alignment = elf.mf.flags.block_size, |
| 3467 | 3489 | .moved = true, |
| 3468 | 3490 | .resized = true, |
| 3469 | | })); |
| 3491 | }); |
| 3470 | 3492 | elf.nodes.appendAssumeCapacity(.shdr); |
| 3471 | 3493 | |
| 3472 | 3494 | const page_align: std.mem.Alignment = .fromByteUnits(switch (machine) { |
| ... | ... | @@ -3491,45 +3513,45 @@ fn initHeaders( |
| 3491 | 3513 | }); |
| 3492 | 3514 | |
| 3493 | 3515 | var ph_vaddr: u32 = if (@"type" != .REL) ph_vaddr: { |
| 3494 | | assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 3516 | elf.ni.rodata = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| 3495 | 3517 | .alignment = elf.mf.flags.block_size, |
| 3496 | 3518 | .moved = true, |
| 3497 | 3519 | .bubbles_moved = false, |
| 3498 | | })); |
| 3520 | }); |
| 3499 | 3521 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.rodata }); |
| 3500 | 3522 | elf.phdrs.items[phndx.rodata] = elf.ni.rodata; |
| 3501 | 3523 | |
| 3502 | | assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ |
| 3524 | elf.ni.phdr = try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ |
| 3503 | 3525 | .size = @as(u64, phnum) * entsize.ph, |
| 3504 | 3526 | .alignment = addr_align, |
| 3505 | 3527 | .moved = true, |
| 3506 | 3528 | .resized = true, |
| 3507 | 3529 | .bubbles_moved = false, |
| 3508 | | })); |
| 3530 | }); |
| 3509 | 3531 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.phdr }); |
| 3510 | 3532 | elf.phdrs.items[phndx.phdr] = elf.ni.phdr; |
| 3511 | 3533 | |
| 3512 | | assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 3534 | elf.ni.text = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| 3513 | 3535 | .alignment = elf.mf.flags.block_size, |
| 3514 | 3536 | .moved = true, |
| 3515 | 3537 | .bubbles_moved = false, |
| 3516 | | })); |
| 3538 | }); |
| 3517 | 3539 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.text }); |
| 3518 | 3540 | elf.phdrs.items[phndx.text] = elf.ni.text; |
| 3519 | 3541 | |
| 3520 | | assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 3542 | elf.ni.data = try elf.mf.addLastChildNode(gpa, elf.ni.elf, .{ |
| 3521 | 3543 | .alignment = elf.mf.flags.block_size, |
| 3522 | 3544 | .moved = true, |
| 3523 | 3545 | .bubbles_moved = false, |
| 3524 | | })); |
| 3546 | }); |
| 3525 | 3547 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.data }); |
| 3526 | 3548 | elf.phdrs.items[phndx.data] = elf.ni.data; |
| 3527 | 3549 | |
| 3528 | | assert(elf.ni.data_rel_ro == try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{ |
| 3550 | elf.ni.data_rel_ro = try elf.mf.addOnlyChildNode(gpa, elf.ni.data, .{ |
| 3529 | 3551 | .alignment = elf.mf.flags.block_size, |
| 3530 | 3552 | .moved = true, |
| 3531 | 3553 | .bubbles_moved = false, |
| 3532 | | })); |
| 3554 | }); |
| 3533 | 3555 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.relro }); |
| 3534 | 3556 | elf.phdrs.items[phndx.relro] = elf.ni.data_rel_ro; |
| 3535 | 3557 | |
| ... | ... | @@ -3706,7 +3728,7 @@ fn initHeaders( |
| 3706 | 3728 | .node = .none, |
| 3707 | 3729 | .first_target_reloc = .none, |
| 3708 | 3730 | }; |
| 3709 | | assert(.symtab == try elf.addSection(elf.ni.file, .{ |
| 3731 | assert(.symtab == try elf.addSection(elf.ni.elf, .{ |
| 3710 | 3732 | .type = .SYMTAB, |
| 3711 | 3733 | .size = @sizeOf(ElfN.Sym) * 1, |
| 3712 | 3734 | .addralign = addr_align, |
| ... | ... | @@ -3729,7 +3751,7 @@ fn initHeaders( |
| 3729 | 3751 | ehdr.shstrndx = ehdr.shnum; |
| 3730 | 3752 | }, |
| 3731 | 3753 | } |
| 3732 | | assert(.shstrtab == try elf.addSection(elf.ni.file, .{ |
| 3754 | assert(.shstrtab == try elf.addSection(elf.ni.elf, .{ |
| 3733 | 3755 | .type = .STRTAB, |
| 3734 | 3756 | .size = 1, |
| 3735 | 3757 | .entsize = 1, |
| ... | ... | @@ -3740,7 +3762,7 @@ fn initHeaders( |
| 3740 | 3762 | try Section.Index.symtab.rename(elf, ".symtab"); |
| 3741 | 3763 | try Section.Index.shstrtab.rename(elf, ".shstrtab"); |
| 3742 | 3764 | |
| 3743 | | assert(.strtab == try elf.addSection(elf.ni.file, .{ |
| 3765 | assert(.strtab == try elf.addSection(elf.ni.elf, .{ |
| 3744 | 3766 | .name = ".strtab", |
| 3745 | 3767 | .type = .STRTAB, |
| 3746 | 3768 | .size = 1, |
| ... | ... | @@ -4210,6 +4232,8 @@ fn initHeaders( |
| 4210 | 4232 | break :str try elf.string(.dynstr, slice); |
| 4211 | 4233 | }, |
| 4212 | 4234 | }; |
| 4235 | |
| 4236 | try elf.ensureElfNodeSize(); |
| 4213 | 4237 | } |
| 4214 | 4238 | |
| 4215 | 4239 | pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { |
| ... | ... | @@ -4221,10 +4245,8 @@ pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { |
| 4221 | 4245 | break :count count; |
| 4222 | 4246 | }); |
| 4223 | 4247 | elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len); |
| 4224 | | elf.input_prog_node = prog_node.start( |
| 4225 | | "Inputs", |
| 4226 | | elf.input_sections.items.len - elf.input_section_pending_index, |
| 4227 | | ); |
| 4248 | elf.input_prog_node = prog_node.start("Inputs", (elf.inputs.items.len - elf.input_pending_index) + |
| 4249 | (elf.input_sections.items.len - elf.input_section_pending_index)); |
| 4228 | 4250 | } |
| 4229 | 4251 | |
| 4230 | 4252 | pub fn endProgress(elf: *Elf) void { |
| ... | ... | @@ -4244,13 +4266,15 @@ fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 4244 | 4266 | /// Asserts that `ni` is a section, input section, copied global, NAV, UAV, or lazy code/data. |
| 4245 | 4267 | fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { |
| 4246 | 4268 | return switch (elf.getNode(ni)) { |
| 4247 | | .file => unreachable, |
| 4248 | | .ehdr => unreachable, |
| 4249 | | .shdr => unreachable, |
| 4250 | | .segment => unreachable, |
| 4251 | | |
| 4269 | .archive, |
| 4270 | .archive_header, |
| 4271 | .elf, |
| 4272 | .ehdr, |
| 4273 | .shdr, |
| 4274 | .segment, |
| 4275 | .input_member, |
| 4276 | => unreachable, |
| 4252 | 4277 | .section => |shndx| shndx, |
| 4253 | | |
| 4254 | 4278 | .input_section, |
| 4255 | 4279 | .copied_global, |
| 4256 | 4280 | .nav, |
| ... | ... | @@ -4260,21 +4284,44 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { |
| 4260 | 4284 | => elf.getNode(ni.parent(&elf.mf)).section, |
| 4261 | 4285 | }; |
| 4262 | 4286 | } |
| 4287 | fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4288 | return switch (elf.getNode(ni)) { |
| 4289 | .archive, |
| 4290 | .archive_header, |
| 4291 | .elf, |
| 4292 | .ehdr, |
| 4293 | .shdr, |
| 4294 | .segment, |
| 4295 | .input_member, |
| 4296 | .copied_global, |
| 4297 | => unreachable, |
| 4298 | .section => |shndx| shndx.vaddr(elf), |
| 4299 | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 4300 | inline .nav, |
| 4301 | .uav, |
| 4302 | .lazy_code, |
| 4303 | .lazy_const_data, |
| 4304 | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 4305 | }; |
| 4306 | } |
| 4263 | 4307 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4264 | 4308 | const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf))) { |
| 4265 | | .file => return 0, |
| 4309 | .archive, .archive_header => unreachable, |
| 4310 | .elf => return 0, |
| 4266 | 4311 | .ehdr, .shdr => unreachable, |
| 4267 | 4312 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 4268 | 4313 | inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr), |
| 4269 | 4314 | }, |
| 4270 | 4315 | .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), |
| 4271 | | .input_section => unreachable, |
| 4272 | | .copied_global => unreachable, |
| 4316 | .input_member, .input_section, .copied_global => unreachable, |
| 4273 | 4317 | inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 4274 | 4318 | }; |
| 4275 | 4319 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); |
| 4276 | 4320 | return parent_vaddr + offset; |
| 4277 | 4321 | } |
| 4322 | fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4323 | return ni.fileLocation(&elf.mf, false).offset - elf.ni.elf.fileLocation(&elf.mf, false).offset; |
| 4324 | } |
| 4278 | 4325 | |
| 4279 | 4326 | /// Deletes any existing relocations in the given node, and marks the start of the node's contiguous |
| 4280 | 4327 | /// sequence of relocations, so that the caller may append the node's updated relocations. |
| ... | ... | @@ -4283,12 +4330,16 @@ fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4283 | 4330 | /// the special-case sections '.plt' and '.dynamic'. |
| 4284 | 4331 | fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 4285 | 4332 | const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { |
| 4286 | | .file => unreachable, // cannot contain relocs |
| 4287 | | .ehdr => unreachable, // cannot contain relocs |
| 4288 | | .shdr => unreachable, // cannot contain relocs |
| 4289 | | .segment => unreachable, // cannot contain relocs |
| 4333 | .archive, |
| 4334 | .archive_header, |
| 4335 | .elf, |
| 4336 | .ehdr, |
| 4337 | .shdr, |
| 4338 | .segment, |
| 4339 | .input_member, |
| 4340 | .copied_global, |
| 4341 | => unreachable, // cannot contain relocs |
| 4290 | 4342 | .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported) |
| 4291 | | .copied_global => unreachable, // cannot contain relocs |
| 4292 | 4343 | .input_section => |isi| .{ |
| 4293 | 4344 | &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc, |
| 4294 | 4345 | &elf.input_sections.items[@backingInt(isi)].first_got_reloc, |
| ... | ... | @@ -4359,7 +4410,7 @@ fn flushMovedNodeRelocs( |
| 4359 | 4410 | } |
| 4360 | 4411 | |
| 4361 | 4412 | fn identClass(elf: *const Elf) std.elf.CLASS { |
| 4362 | | return @fromBackingInt(@intCast(elf.mf.memory_map.memory[std.elf.EI.CLASS])); |
| 4413 | return @fromBackingInt(elf.ni.elf.sliceConst(&elf.mf)[std.elf.EI.CLASS]); |
| 4363 | 4414 | } |
| 4364 | 4415 | |
| 4365 | 4416 | /// Like `std.elf.ET`, but only includes the ELF machine architectures we support, so that we can |
| ... | ... | @@ -4415,7 +4466,7 @@ fn targetPtrSize(elf: *const Elf) u8 { |
| 4415 | 4466 | return elf.identClass().size(); |
| 4416 | 4467 | } |
| 4417 | 4468 | fn targetEndian(elf: *const Elf) std.lang.Endian { |
| 4418 | | const ident_data: std.elf.DATA = @fromBackingInt(@intCast(elf.mf.memory_map.memory[std.elf.EI.DATA])); |
| 4469 | const ident_data: std.elf.DATA = @fromBackingInt(elf.ni.elf.sliceConst(&elf.mf)[std.elf.EI.DATA]); |
| 4419 | 4470 | return ident_data.endian(); |
| 4420 | 4471 | } |
| 4421 | 4472 | fn targetTlsVariant(elf: *const Elf) union(enum) { |
| ... | ... | @@ -4487,7 +4538,7 @@ fn targetLoad(elf: *const Elf, ptr: anytype) @typeInfo(@TypeOf(ptr)).pointer.chi |
| 4487 | 4538 | return switch (@typeInfo(Child)) { |
| 4488 | 4539 | else => @compileError(@typeName(Child)), |
| 4489 | 4540 | .int => std.mem.toNative(Child, ptr.*, elf.targetEndian()), |
| 4490 | | .@"enum" => |@"enum"| @fromBackingInt(@intCast(elf.targetLoad(@as(*align(alignment) const @"enum".tag_type, @ptrCast(ptr))))), |
| 4541 | .@"enum" => |@"enum"| @fromBackingInt(elf.targetLoad(@as(*align(alignment) const @"enum".tag_type, @ptrCast(ptr)))), |
| 4491 | 4542 | .@"struct" => |@"struct"| @bitCast( |
| 4492 | 4543 | elf.targetLoad(@as(*align(alignment) @"struct".backing_integer.?, @ptrCast(ptr))), |
| 4493 | 4544 | ), |
| ... | ... | @@ -4563,6 +4614,16 @@ fn shdrPtr(elf: *Elf, shndx: Section.Index) ShdrPtr { |
| 4563 | 4614 | } |
| 4564 | 4615 | } |
| 4565 | 4616 | |
| 4617 | fn arHdrPtr(elf: *Elf, ni: MappedFile.Node.Index) *align(2) std.elf.ar_hdr { |
| 4618 | assert(elf.ni.elf != MappedFile.Node.Index.root); |
| 4619 | const file_offset = ni.fileLocation(&elf.mf, false).offset; |
| 4620 | return @ptrCast(@alignCast(elf.mf.memory_map.memory[@intCast(switch (elf.getNode(ni)) { |
| 4621 | else => unreachable, |
| 4622 | .archive_header => file_offset + std.elf.ARMAG.len, |
| 4623 | .elf, .input_member => file_offset - @sizeOf(std.elf.ar_hdr), |
| 4624 | })..][0..@sizeOf(std.elf.ar_hdr)])); |
| 4625 | } |
| 4626 | |
| 4566 | 4627 | const SymPtr = union(std.elf.CLASS) { |
| 4567 | 4628 | NONE: noreturn, |
| 4568 | 4629 | @"32": *std.elf.Elf32.Sym, |
| ... | ... | @@ -4657,7 +4718,7 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 4657 | 4718 | } |
| 4658 | 4719 | errdefer assert(elf.section_by_name.pop().?.key == name_shstrtab); |
| 4659 | 4720 | const parent_node: MappedFile.Node.Index = parent: { |
| 4660 | | if (!opts.flags.ALLOC) break :parent elf.ni.file; |
| 4721 | if (!opts.flags.ALLOC) break :parent elf.ni.elf; |
| 4661 | 4722 | if (opts.flags.EXECINSTR) break :parent elf.ni.text; |
| 4662 | 4723 | if (opts.flags.TLS) break :parent elf.ni.tls; |
| 4663 | 4724 | if (opts.flags.WRITE) break :parent elf.ni.data; |
| ... | ... | @@ -4878,7 +4939,7 @@ const LoadParseInputError = Error || Io.File.SeekError || Io.Reader.Error; |
| 4878 | 4939 | /// indicates to the frontend that the input could be a GNU ld script instead. |
| 4879 | 4940 | pub fn loadInput(elf: *Elf, input: link.Input) (link.Error || error{BadMagic})!void { |
| 4880 | 4941 | const diags = &elf.base.comp.link_diags; |
| 4881 | | return elf.loadInputInner(input) catch |err| switch (err) { |
| 4942 | elf.loadInputInner(input) catch |err| switch (err) { |
| 4882 | 4943 | else => |e| return e, |
| 4883 | 4944 | error.MappedFileIo => return diags.fail( |
| 4884 | 4945 | "failed to write output file: {t}", |
| ... | ... | @@ -4986,6 +5047,9 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load |
| 4986 | 5047 | const r = &fr.interface; |
| 4987 | 5048 | |
| 4988 | 5049 | log.debug("loadArchive({f})", .{path.fmtEscapeString()}); |
| 5050 | |
| 5051 | if (elf.ehdrType() == .REL) return; // this input does not affect the output artifact |
| 5052 | |
| 4989 | 5053 | { |
| 4990 | 5054 | const magic = r.take(std.elf.ARMAG.len) catch |err| switch (err) { |
| 4991 | 5055 | error.ReadFailed => |e| return e, |
| ... | ... | @@ -5071,21 +5135,40 @@ fn loadObject( |
| 5071 | 5135 | .{}, |
| 5072 | 5136 | ), |
| 5073 | 5137 | }; |
| 5138 | |
| 5139 | const input = try elf.inputs.addOne(gpa); |
| 5140 | input.* = .{ |
| 5141 | .path = path, |
| 5142 | .member = if (member) |m| try gpa.dupe(u8, m) else null, |
| 5143 | .extra = undefined, |
| 5144 | }; |
| 5145 | if (elf.ni.elf != MappedFile.Node.Index.root) { |
| 5146 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 5147 | input.extra = .{ .node = try elf.mf.addLastChildNode(gpa, .root, .{ |
| 5148 | .size = fl.size + @sizeOf(std.elf.ar_hdr), |
| 5149 | .alignment = .@"2", |
| 5150 | .next_moved = true, |
| 5151 | .bubbles_moved = false, |
| 5152 | .enable_next_moved = true, |
| 5153 | }) }; |
| 5154 | elf.nodes.appendAssumeCapacity(.{ .input_member = input_index }); |
| 5155 | elf.input_prog_node.increaseEstimatedTotalItems(1); |
| 5156 | |
| 5157 | // Since we are not emitting the archive symbol table (yet?) we do not need to parse |
| 5158 | // the symbols in this input. |
| 5159 | return; |
| 5160 | } |
| 5161 | |
| 5162 | elf.input_pending_index += 1; |
| 5074 | 5163 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 5075 | | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 5076 | | const file_symbol = elf.addLocalSymbolAssumeCapacity(.{ |
| 5164 | input.extra = .{ .file_symbol = elf.addLocalSymbolAssumeCapacity(.{ |
| 5077 | 5165 | .node = .none, |
| 5078 | 5166 | .name = try elf.string(.strtab, std.fs.path.stem(member orelse path.sub_path)), |
| 5079 | 5167 | .value = 0, |
| 5080 | 5168 | .size = 0, |
| 5081 | 5169 | .type = .FILE, |
| 5082 | 5170 | .shndx = .ABS, |
| 5083 | | }); |
| 5084 | | elf.inputs.addOneAssumeCapacity().* = .{ |
| 5085 | | .path = path, |
| 5086 | | .member = if (member) |m| try gpa.dupe(u8, m) else null, |
| 5087 | | .file_symbol = file_symbol, |
| 5088 | | }; |
| 5171 | }) }; |
| 5089 | 5172 | const target_endian = elf.targetEndian(); |
| 5090 | 5173 | switch (elf.identClass()) { |
| 5091 | 5174 | .NONE, _ => unreachable, |
| ... | ... | @@ -5479,6 +5562,9 @@ fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (LoadPars |
| 5479 | 5562 | |
| 5480 | 5563 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); |
| 5481 | 5564 | try elf.checkInputIdent(path, r); |
| 5565 | |
| 5566 | if (elf.ehdrType() == .REL) return; // this input does not affect the output artifact |
| 5567 | |
| 5482 | 5568 | const target_endian = elf.targetEndian(); |
| 5483 | 5569 | switch (elf.identClass()) { |
| 5484 | 5570 | .NONE, _ => unreachable, |
| ... | ... | @@ -5709,7 +5795,8 @@ fn checkInputIdent( |
| 5709 | 5795 | } |
| 5710 | 5796 | |
| 5711 | 5797 | const ident = try r.peekStructPointer(std.elf.Ident); |
| 5712 | | const target: *const std.elf.Ident = @ptrCast(elf.mf.memory_map.memory[0..@sizeOf(std.elf.Ident)]); |
| 5798 | const target: *const std.elf.Ident = |
| 5799 | @ptrCast(elf.ni.elf.sliceConst(&elf.mf)[0..@sizeOf(std.elf.Ident)]); |
| 5713 | 5800 | |
| 5714 | 5801 | if (ident.class != target.class) return diags.failParse( |
| 5715 | 5802 | path, |
| ... | ... | @@ -5825,13 +5912,11 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 5825 | 5912 | const comp = elf.base.comp; |
| 5826 | 5913 | const gpa = comp.gpa; |
| 5827 | 5914 | |
| 5828 | | if (comp.zcu != null and !comp.config.use_llvm) { |
| 5829 | | // We're use self-hosted codegen---add an input representing the Zig "object". |
| 5915 | if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == MappedFile.Node.Index.root) { |
| 5916 | // We're using self-hosted codegen---add an input representing the Zig "object". |
| 5830 | 5917 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 5831 | 5918 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 5832 | | const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{ |
| 5833 | | std.fs.path.stem(elf.base.emit.sub_path), |
| 5834 | | }); |
| 5919 | const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{comp.root_name}); |
| 5835 | 5920 | defer gpa.free(zcu_name); |
| 5836 | 5921 | const zcu_file_symbol = elf.addLocalSymbolAssumeCapacity(.{ |
| 5837 | 5922 | .node = .none, |
| ... | ... | @@ -5844,9 +5929,12 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 5844 | 5929 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 5845 | 5930 | .path = elf.base.emit, |
| 5846 | 5931 | .member = null, |
| 5847 | | .file_symbol = zcu_file_symbol, |
| 5932 | .extra = .{ .file_symbol = zcu_file_symbol }, |
| 5848 | 5933 | }; |
| 5934 | elf.input_pending_index += 1; |
| 5849 | 5935 | } |
| 5936 | |
| 5937 | try elf.ensureElfNodeSize(); |
| 5850 | 5938 | } |
| 5851 | 5939 | |
| 5852 | 5940 | fn prepareDynamic(elf: *Elf) Error!void { |
| ... | ... | @@ -6036,12 +6124,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6036 | 6124 | }, |
| 6037 | 6125 | }; |
| 6038 | 6126 | assert(shndx < @backingInt(Section.Index.LORESERVE)); |
| 6039 | | break :shndx .{ @fromBackingInt(@intCast(shndx)), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) }; |
| 6127 | break :shndx .{ @fromBackingInt(shndx), @as(u64, elf.targetLoad(&ehdr.shentsize)) * @as(u64, shnum) }; |
| 6040 | 6128 | }, |
| 6041 | 6129 | }; |
| 6042 | 6130 | try elf.ensureNodeSize(elf.ni.shdr, new_shdr_size); |
| 6043 | 6131 | const ni = try elf.mf.addLastChildNode(gpa, switch (elf.ehdrType()) { |
| 6044 | | .REL => elf.ni.file, |
| 6132 | .REL => elf.ni.elf, |
| 6045 | 6133 | .EXEC, .DYN => segment_ni, |
| 6046 | 6134 | }, .{ |
| 6047 | 6135 | .size = opts.size, |
| ... | ... | @@ -6064,7 +6152,6 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6064 | 6152 | else => .{ .shndx = .UNDEF }, |
| 6065 | 6153 | } }); |
| 6066 | 6154 | elf.nodes.appendAssumeCapacity(.{ .section = shndx }); |
| 6067 | | const offset = ni.fileLocation(&elf.mf, false).offset; |
| 6068 | 6155 | switch (elf.shdrPtr(shndx)) { |
| 6069 | 6156 | inline else => |shdr, class| { |
| 6070 | 6157 | shdr.* = .{ |
| ... | ... | @@ -6072,7 +6159,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6072 | 6159 | .type = opts.type, |
| 6073 | 6160 | .flags = .{ .shf = opts.flags }, |
| 6074 | 6161 | .addr = @intCast(addr), |
| 6075 | | .offset = @intCast(offset), |
| 6162 | .offset = @intCast(elf.getNodeElfOffset(ni)), |
| 6076 | 6163 | .size = @intCast(opts.size), |
| 6077 | 6164 | .link = opts.link, |
| 6078 | 6165 | .info = opts.info, |
| ... | ... | @@ -6506,20 +6593,7 @@ fn addSymbolRelocAssumeCapacity( |
| 6506 | 6593 | |
| 6507 | 6594 | // If we emit a runtime relocation entry, its `offset` is a virtual address, so we need to |
| 6508 | 6595 | // determine the vaddr of `node`. |
| 6509 | | const node_vaddr: u64 = switch (elf.getNode(node)) { |
| 6510 | | .file => unreachable, |
| 6511 | | .ehdr => unreachable, |
| 6512 | | .shdr => unreachable, |
| 6513 | | .segment => unreachable, |
| 6514 | | .copied_global => unreachable, |
| 6515 | | .section => |shndx| shndx.vaddr(elf), |
| 6516 | | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 6517 | | inline .nav, |
| 6518 | | .uav, |
| 6519 | | .lazy_code, |
| 6520 | | .lazy_const_data, |
| 6521 | | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 6522 | | }; |
| 6596 | const node_vaddr = elf.getNodeVAddr(node); |
| 6523 | 6597 | |
| 6524 | 6598 | // If this is `true`, we will try to create a copy relocation for the target symbol if it is |
| 6525 | 6599 | // not locally defined. If the relocation value is always computed from the target symbol's |
| ... | ... | @@ -6658,20 +6732,23 @@ fn addGotRelocAssumeCapacity( |
| 6658 | 6732 | ) void { |
| 6659 | 6733 | assert(elf.ehdrType() != .REL); |
| 6660 | 6734 | switch (elf.getNode(node)) { |
| 6735 | .archive, |
| 6736 | .archive_header, |
| 6737 | .elf, |
| 6738 | .ehdr, |
| 6739 | .shdr, |
| 6740 | .segment, |
| 6741 | .input_member, |
| 6742 | .copied_global, |
| 6743 | => unreachable, // cannot contain relocs, |
| 6744 | .section, |
| 6745 | .uav, |
| 6746 | => unreachable, // cannot contain GOT relocs |
| 6661 | 6747 | .input_section, |
| 6662 | 6748 | .nav, |
| 6663 | 6749 | .lazy_code, |
| 6664 | 6750 | .lazy_const_data, |
| 6665 | 6751 | => {}, |
| 6666 | | |
| 6667 | | .section => unreachable, // cannot contain GOT relocs |
| 6668 | | .uav => unreachable, // cannot contain GOT relocs |
| 6669 | | |
| 6670 | | .file => unreachable, // cannot contain relocs |
| 6671 | | .ehdr => unreachable, // cannot contain relocs |
| 6672 | | .shdr => unreachable, // cannot contain relocs |
| 6673 | | .segment => unreachable, // cannot contain relocs |
| 6674 | | .copied_global => unreachable, // cannot contain relocs |
| 6675 | 6752 | } |
| 6676 | 6753 | |
| 6677 | 6754 | const gop = elf.got.getOrPutAssumeCapacity(target); |
| ... | ... | @@ -7055,6 +7132,17 @@ pub fn flush( |
| 7055 | 7132 | tid: Zcu.PerThread.Id, |
| 7056 | 7133 | prog_node: std.Progress.Node, |
| 7057 | 7134 | ) link.Error!void { |
| 7135 | elf.flushInner(arena, tid, prog_node) catch |err| switch (err) { |
| 7136 | error.MappedFileIo => return elf.base.comp.link_diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), |
| 7137 | else => |e| return e, |
| 7138 | }; |
| 7139 | } |
| 7140 | fn flushInner( |
| 7141 | elf: *Elf, |
| 7142 | arena: std.mem.Allocator, |
| 7143 | tid: Zcu.PerThread.Id, |
| 7144 | prog_node: std.Progress.Node, |
| 7145 | ) Error!void { |
| 7058 | 7146 | const comp = elf.base.comp; |
| 7059 | 7147 | const diags = &comp.link_diags; |
| 7060 | 7148 | _ = arena; |
| ... | ... | @@ -7072,11 +7160,9 @@ pub fn flush( |
| 7072 | 7160 | if (any_undef) return error.AlreadyReported; |
| 7073 | 7161 | } |
| 7074 | 7162 | |
| 7075 | | elf.prepareDynamic() catch |err| switch (err) { |
| 7076 | | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), |
| 7077 | | else => |e| return e, |
| 7078 | | }; |
| 7163 | try elf.prepareDynamic(); |
| 7079 | 7164 | |
| 7165 | try elf.ensureElfNodeSize(); |
| 7080 | 7166 | while (try elf.idle(tid)) {} |
| 7081 | 7167 | |
| 7082 | 7168 | // We've done the final `idle` loop, so everything is at its final place in the file. We have a |
| ... | ... | @@ -7101,10 +7187,7 @@ pub fn flush( |
| 7101 | 7187 | .enabled => "_start", |
| 7102 | 7188 | .named => |named| named, |
| 7103 | 7189 | }; |
| 7104 | | const sym_name_strtab = elf.string(.strtab, sym_name_slice) catch |err| switch (err) { |
| 7105 | | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), |
| 7106 | | else => |e| return e, |
| 7107 | | }; |
| 7190 | const sym_name_strtab = try elf.string(.strtab, sym_name_slice); |
| 7108 | 7191 | if (elf.globalByName(sym_name_strtab) == null) break :entry 0; |
| 7109 | 7192 | break :entry Symbol.Id.global(sym_name_strtab).value(elf); |
| 7110 | 7193 | }; |
| ... | ... | @@ -7112,10 +7195,11 @@ pub fn flush( |
| 7112 | 7195 | inline else => |ehdr| elf.targetStore(&ehdr.entry, @intCast(entry_addr)), |
| 7113 | 7196 | } |
| 7114 | 7197 | |
| 7115 | | elf.mf.flush() catch |err| switch (err) { |
| 7116 | | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), |
| 7117 | | else => |e| return e, |
| 7118 | | }; |
| 7198 | try elf.mf.flush(); |
| 7199 | |
| 7200 | if (elf.options.enable_link_snapshots) |
| 7201 | elf.dumpStderr(tid) catch |err| |
| 7202 | return comp.link_diags.fail("dumping link snapshot failed: {t}", .{err}); |
| 7119 | 7203 | } |
| 7120 | 7204 | |
| 7121 | 7205 | pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| ... | ... | @@ -7128,8 +7212,19 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7128 | 7212 | } |
| 7129 | 7213 | |
| 7130 | 7214 | task: { |
| 7215 | if (elf.input_pending_index < elf.inputs.items.len) { |
| 7216 | const ii: Node.InputIndex = @fromBackingInt(elf.input_pending_index); |
| 7217 | elf.input_pending_index += 1; |
| 7218 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(ii.node(elf))); |
| 7219 | defer sub_prog_node.end(); |
| 7220 | elf.flushInput(ii) catch |err| switch (err) { |
| 7221 | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), |
| 7222 | else => |e| return e, |
| 7223 | }; |
| 7224 | break :task; |
| 7225 | } |
| 7131 | 7226 | if (elf.input_section_pending_index < elf.input_sections.items.len) { |
| 7132 | | const isi: InputSection.Index = @fromBackingInt(@intCast(elf.input_section_pending_index)); |
| 7227 | const isi: InputSection.Index = @fromBackingInt(elf.input_section_pending_index); |
| 7133 | 7228 | elf.input_section_pending_index += 1; |
| 7134 | 7229 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.node(elf))); |
| 7135 | 7230 | defer sub_prog_node.end(); |
| ... | ... | @@ -7217,11 +7312,13 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) link.Error!bool { |
| 7217 | 7312 | while (elf.mf.updates.pop()) |ni| { |
| 7218 | 7313 | const clean_moved = ni.cleanMoved(&elf.mf); |
| 7219 | 7314 | const clean_resized = ni.cleanResized(&elf.mf); |
| 7220 | | if (clean_moved or clean_resized) { |
| 7315 | const clean_next_moved = ni.cleanNextMoved(&elf.mf); |
| 7316 | if (clean_moved or clean_resized or clean_next_moved) { |
| 7221 | 7317 | const sub_prog_node = elf.idleProgNode(tid, elf.mf.update_prog_node, elf.getNode(ni)); |
| 7222 | 7318 | defer sub_prog_node.end(); |
| 7223 | 7319 | if (clean_moved) try elf.flushMoved(ni); |
| 7224 | 7320 | if (clean_resized) try elf.flushResized(ni); |
| 7321 | if (clean_next_moved) try elf.flushNextMoved(ni); |
| 7225 | 7322 | break :task; |
| 7226 | 7323 | } else elf.mf.update_prog_node.completeOne(); |
| 7227 | 7324 | } |
| ... | ... | @@ -7242,6 +7339,10 @@ fn idleProgNode( |
| 7242 | 7339 | return prog_node.start(name: switch (node) { |
| 7243 | 7340 | else => |tag| @tagName(tag), |
| 7244 | 7341 | .section => |shndx| shndx.name(elf).slice(elf), |
| 7342 | .input_member => |ii| std.fmt.bufPrint(&name, "{f}{f}", .{ |
| 7343 | ii.path(elf).fmtEscapeString(), |
| 7344 | fmtMemberString(ii.member(elf)), |
| 7345 | }) catch &name, |
| 7245 | 7346 | .input_section => |isi| { |
| 7246 | 7347 | const ii = isi.input(elf); |
| 7247 | 7348 | break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ |
| ... | ... | @@ -7294,6 +7395,8 @@ fn genPending(elf: *Elf, pt: Zcu.PerThread) Error!void { |
| 7294 | 7395 | }; |
| 7295 | 7396 | break; |
| 7296 | 7397 | } |
| 7398 | |
| 7399 | try elf.ensureElfNodeSize(); |
| 7297 | 7400 | } |
| 7298 | 7401 | |
| 7299 | 7402 | fn genUav( |
| ... | ... | @@ -7362,6 +7465,36 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { |
| 7362 | 7465 | } |
| 7363 | 7466 | } |
| 7364 | 7467 | |
| 7468 | fn flushInput(elf: *Elf, ii: Node.InputIndex) Error!void { |
| 7469 | const comp = elf.base.comp; |
| 7470 | const io = comp.io; |
| 7471 | const gpa = comp.gpa; |
| 7472 | const diags = &comp.link_diags; |
| 7473 | const path = ii.path(elf); |
| 7474 | const file = path.root_dir.handle.openFile(io, path.sub_path, .{}) catch |err| switch (err) { |
| 7475 | error.Canceled => |e| return e, |
| 7476 | else => |e| return diags.fail("failed to open input file \"{f}\": {t}", .{ path.fmtEscapeString(), e }), |
| 7477 | }; |
| 7478 | defer file.close(io); |
| 7479 | var fr = file.reader(io, &.{}); |
| 7480 | var nw: MappedFile.Node.Writer = undefined; |
| 7481 | ii.node(elf).writer(&elf.mf, gpa, &nw); |
| 7482 | defer nw.deinit(); |
| 7483 | const size = nw.interface.buffer.len - @sizeOf(std.elf.ar_hdr); |
| 7484 | const n_bytes = nw.interface.sendFileAll(&fr, .limited(size)) catch |err| switch (err) { |
| 7485 | error.ReadFailed => return diags.fail("failed to read input \"{f}{f}\": {t}", .{ |
| 7486 | path.fmtEscapeString(), |
| 7487 | fmtMemberString(ii.member(elf)), |
| 7488 | fr.err orelse (fr.seek_err orelse fr.size_err.?), |
| 7489 | }), |
| 7490 | error.WriteFailed => return nw.err.?, |
| 7491 | }; |
| 7492 | if (n_bytes + 1 < size) return diags.fail("failed to read input \"{f}{f}\": unexpected eof", .{ |
| 7493 | path.fmtEscapeString(), |
| 7494 | fmtMemberString(ii.member(elf)), |
| 7495 | }); |
| 7496 | } |
| 7497 | |
| 7365 | 7498 | fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { |
| 7366 | 7499 | const file_loc = isi.fileLocation(elf); |
| 7367 | 7500 | if (file_loc.size == 0) return; |
| ... | ... | @@ -7408,33 +7541,29 @@ fn flushInputSection(elf: *Elf, isi: InputSection.Index) Error!void { |
| 7408 | 7541 | assert(isi.node(elf).hasMoved(&elf.mf)); |
| 7409 | 7542 | } |
| 7410 | 7543 | |
| 7411 | | fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 7544 | fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 7545 | const elf_offset = elf.getNodeElfOffset(ni); |
| 7412 | 7546 | switch (elf.getNode(ni)) { |
| 7413 | 7547 | else => unreachable, |
| 7414 | | .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0), |
| 7548 | .ehdr => assert(elf_offset == 0), |
| 7415 | 7549 | .shdr => switch (elf.ehdrPtr()) { |
| 7416 | | inline else => |ehdr| elf.targetStore( |
| 7417 | | &ehdr.shoff, |
| 7418 | | @intCast(ni.fileLocation(&elf.mf, false).offset), |
| 7419 | | ), |
| 7550 | inline else => |ehdr| elf.targetStore(&ehdr.shoff, @intCast(elf_offset)), |
| 7420 | 7551 | }, |
| 7421 | 7552 | .segment => |phndx| { |
| 7422 | 7553 | switch (elf.phdrSlice()) { |
| 7423 | 7554 | inline else => |phdr, class| { |
| 7424 | 7555 | const ph = &phdr[phndx]; |
| 7425 | | elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); |
| 7556 | elf.targetStore(&ph.offset, @intCast(elf_offset)); |
| 7426 | 7557 | if (elf.targetLoad(&ph.type) == .PHDR) { |
| 7427 | 7558 | @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset; |
| 7428 | 7559 | } |
| 7429 | 7560 | }, |
| 7430 | 7561 | } |
| 7431 | 7562 | var child_it = ni.children(&elf.mf); |
| 7432 | | while (child_it.next()) |child_ni| elf.flushFileOffset(child_ni); |
| 7563 | while (child_it.next()) |child_ni| elf.flushElfOffset(child_ni); |
| 7433 | 7564 | }, |
| 7434 | 7565 | .section => |shndx| switch (elf.shdrPtr(shndx)) { |
| 7435 | | inline else => |shdr| elf.targetStore(&shdr.offset, @intCast( |
| 7436 | | ni.fileLocation(&elf.mf, false).offset, |
| 7437 | | )), |
| 7566 | inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)), |
| 7438 | 7567 | }, |
| 7439 | 7568 | } |
| 7440 | 7569 | } |
| ... | ... | @@ -7447,10 +7576,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7447 | 7576 | defer elf.mf.nodes_lock.unlock(); |
| 7448 | 7577 | |
| 7449 | 7578 | switch (elf.getNode(ni)) { |
| 7450 | | .file => unreachable, |
| 7451 | | .ehdr, .shdr => elf.flushFileOffset(ni), |
| 7579 | .archive, .archive_header => unreachable, |
| 7580 | .elf => {}, |
| 7581 | .ehdr, .shdr => elf.flushElfOffset(ni), |
| 7452 | 7582 | .segment => |phndx| { |
| 7453 | | elf.flushFileOffset(ni); |
| 7583 | elf.flushElfOffset(ni); |
| 7454 | 7584 | switch (elf.phdrSlice()) { |
| 7455 | 7585 | inline else => |phdr| { |
| 7456 | 7586 | const ph = &phdr[phndx]; |
| ... | ... | @@ -7471,7 +7601,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7471 | 7601 | } |
| 7472 | 7602 | }, |
| 7473 | 7603 | .section => |shndx| { |
| 7474 | | elf.flushFileOffset(ni); |
| 7604 | elf.flushElfOffset(ni); |
| 7475 | 7605 | const addr = elf.computeNodeVAddr(ni); |
| 7476 | 7606 | const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) { |
| 7477 | 7607 | inline else => |shdr| .{ |
| ... | ... | @@ -7522,6 +7652,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7522 | 7652 | elf.flushMovedNodeRelocs(ni, addr, elf.dynamic_first_symbol_reloc, .none); |
| 7523 | 7653 | } |
| 7524 | 7654 | }, |
| 7655 | .input_member => {}, |
| 7525 | 7656 | .input_section => |isi| { |
| 7526 | 7657 | const old_section_addr = isi.ptr(elf).vaddr; |
| 7527 | 7658 | const new_section_addr = elf.computeNodeVAddr(ni); |
| ... | ... | @@ -7530,7 +7661,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 7530 | 7661 | // Update local symbols |
| 7531 | 7662 | const ii = isi.input(elf); |
| 7532 | 7663 | var lsi, const end_lsi = ii.localSymbolRange(elf); |
| 7533 | | while (lsi != end_lsi) : (lsi = @fromBackingInt(@intCast(@backingInt(lsi) + 1))) { |
| 7664 | while (lsi != end_lsi) : (lsi = @fromBackingInt(@backingInt(lsi) + 1)) { |
| 7534 | 7665 | if (lsi.index().ptr(elf).node != ni) continue; |
| 7535 | 7666 | const visibility: std.elf.STV = switch (elf.symPtr(lsi.index())) { |
| 7536 | 7667 | inline else => |sym| elf.targetLoad(&sym.other).visibility, |
| ... | ... | @@ -7617,7 +7748,17 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 7617 | 7748 | |
| 7618 | 7749 | _, const size = ni.location(&elf.mf).resolve(&elf.mf); |
| 7619 | 7750 | switch (elf.getNode(ni)) { |
| 7620 | | .file => {}, |
| 7751 | .archive => { |
| 7752 | var child_it = ni.reverseChildren(&elf.mf); |
| 7753 | if (child_it.next()) |last_ni| { |
| 7754 | if (child_it.next()) |prev_ni| if (prev_ni.hasNextMoved(&elf.mf)) return; |
| 7755 | const offset, _ = last_ni.location(&elf.mf).resolve(&elf.mf); |
| 7756 | _ = std.mem.print(&elf.arHdrPtr(last_ni).ar_size, "{d:<10}", .{ |
| 7757 | size - offset, |
| 7758 | }) catch @panic("archive member too large"); |
| 7759 | } |
| 7760 | }, |
| 7761 | .archive_header, .elf => {}, |
| 7621 | 7762 | .ehdr => unreachable, |
| 7622 | 7763 | .shdr => {}, |
| 7623 | 7764 | .segment => |phndx| switch (elf.phdrSlice()) { |
| ... | ... | @@ -7717,9 +7858,88 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 7717 | 7858 | } |
| 7718 | 7859 | }, |
| 7719 | 7860 | }, |
| 7720 | | .copied_global, .input_section, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 7861 | .input_member, .input_section, .copied_global, .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 7862 | } |
| 7863 | } |
| 7864 | |
| 7865 | fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void { |
| 7866 | const trace = tracy.trace(@src()); |
| 7867 | defer trace.end(); |
| 7868 | |
| 7869 | elf.mf.nodes_lock.lock(); |
| 7870 | defer elf.mf.nodes_lock.unlock(); |
| 7871 | |
| 7872 | switch (elf.getNode(ni)) { |
| 7873 | .archive, |
| 7874 | .ehdr, |
| 7875 | .shdr, |
| 7876 | .segment, |
| 7877 | .section, |
| 7878 | .input_section, |
| 7879 | .copied_global, |
| 7880 | .nav, |
| 7881 | .uav, |
| 7882 | .lazy_code, |
| 7883 | .lazy_const_data, |
| 7884 | => unreachable, |
| 7885 | .archive_header, .elf, .input_member => |_, tag| { |
| 7886 | const member_offset, const update_size = member_offset: { |
| 7887 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); |
| 7888 | break :member_offset switch (tag) { |
| 7889 | else => unreachable, |
| 7890 | .archive_header => .{ offset + std.elf.ARMAG.len + @sizeOf(std.elf.ar_hdr), true }, |
| 7891 | .elf, .input_member => .{ offset, switch (ni.prev(&elf.mf)) { |
| 7892 | .none => unreachable, |
| 7893 | else => |prev_ni| !prev_ni.hasNextMoved(&elf.mf), |
| 7894 | } }, |
| 7895 | }; |
| 7896 | }; |
| 7897 | const member_size = member_end: switch (ni.next(&elf.mf)) { |
| 7898 | else => |next_ni| { |
| 7899 | const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); |
| 7900 | const next_member_size = next_member_end: switch (next_ni.next(&elf.mf)) { |
| 7901 | else => |next_next_ni| { |
| 7902 | const next_next_offset, _ = next_next_ni.location(&elf.mf).resolve(&elf.mf); |
| 7903 | break :next_member_end next_next_offset - @sizeOf(std.elf.ar_hdr); |
| 7904 | }, |
| 7905 | .none => { |
| 7906 | _, const parent_size = |
| 7907 | ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf); |
| 7908 | break :next_member_end parent_size; |
| 7909 | }, |
| 7910 | } - next_offset; |
| 7911 | const ar_hdr = elf.arHdrPtr(next_ni); |
| 7912 | var name_buf: [16]u8 = undefined; |
| 7913 | _ = std.mem.print(&ar_hdr.ar_name, "{s:<16}", .{ |
| 7914 | switch (elf.getNode(next_ni)) { |
| 7915 | else => unreachable, |
| 7916 | .elf => std.mem.print(&name_buf, "{s}_zcu.o/", .{elf.base.comp.root_name}), |
| 7917 | .input_member => |ii| std.mem.print(&name_buf, "{s}/", .{ |
| 7918 | std.fs.path.basename(ii.path(elf).sub_path), |
| 7919 | }), |
| 7920 | } catch @panic("TODO: long archive member names"), |
| 7921 | }) catch @panic("TODO: long archive member names"); |
| 7922 | ar_hdr.ar_date = "0 ".*; |
| 7923 | ar_hdr.ar_uid = "0 ".*; |
| 7924 | ar_hdr.ar_gid = "0 ".*; |
| 7925 | ar_hdr.ar_mode = "644 ".*; |
| 7926 | _ = std.mem.print(&ar_hdr.ar_size, "{d:<10}", .{next_member_size}) catch |
| 7927 | @panic("archive member too large"); |
| 7928 | ar_hdr.ar_fmag = std.elf.ARFMAG.*; |
| 7929 | break :member_end next_offset - @sizeOf(std.elf.ar_hdr); |
| 7930 | }, |
| 7931 | .none => { |
| 7932 | _, const parent_size = ni.parent(&elf.mf).location(&elf.mf).resolve(&elf.mf); |
| 7933 | break :member_end parent_size; |
| 7934 | }, |
| 7935 | } - member_offset; |
| 7936 | if (update_size) _ = std.mem.print(&elf.arHdrPtr(ni).ar_size, "{d:<10}", .{ |
| 7937 | member_size, |
| 7938 | }) catch @panic("archive member too large"); |
| 7939 | }, |
| 7721 | 7940 | } |
| 7722 | 7941 | } |
| 7942 | |
| 7723 | 7943 | fn updateDynamicEntry(elf: *Elf, key: u32, new_val: u64) void { |
| 7724 | 7944 | switch (elf.shdrPtr(elf.shndx.dynamic)) { |
| 7725 | 7945 | inline else => |shdr, class| { |
| ... | ... | @@ -7760,7 +7980,7 @@ fn addPltEntry(elf: *Elf, global_name: String(.strtab), dynsym_index: u32) void |
| 7760 | 7980 | }; |
| 7761 | 7981 | |
| 7762 | 7982 | // Now that we know the index, we can set the relocation's offset. |
| 7763 | | elf.shndx.rela_plt.relaSetOffset(elf, @fromBackingInt(@intCast(plt_index)), got_plt_section.vaddr(elf) + got_plt_offset); |
| 7983 | elf.shndx.rela_plt.relaSetOffset(elf, @fromBackingInt(plt_index), got_plt_section.vaddr(elf) + got_plt_offset); |
| 7764 | 7984 | |
| 7765 | 7985 | if (plt_index < elf.plt.count()) { |
| 7766 | 7986 | // We reused a free entry, so we're already done! |
| ... | ... | @@ -8100,7 +8320,10 @@ fn updateExportsInner( |
| 8100 | 8320 | }, |
| 8101 | 8321 | .uav => |uav| .{ (try elf.uavMapIndex(uav, .none)).symbol(elf), .OBJECT }, |
| 8102 | 8322 | }; |
| 8323 | |
| 8324 | try elf.ensureElfNodeSize(); |
| 8103 | 8325 | while (try elf.idle(pt.tid)) {} |
| 8326 | |
| 8104 | 8327 | const value: u64 = Symbol.Id.local(exported_lsi).value(elf); |
| 8105 | 8328 | const size: u64, const shndx: Section.Index = switch (elf.symPtr(exported_lsi.index())) { |
| 8106 | 8329 | inline else => |exported_sym| .{ |
| ... | ... | @@ -8154,6 +8377,16 @@ pub fn deleteExport(elf: *Elf, exported: Zcu.Exported, name: InternPool.NullTerm |
| 8154 | 8377 | _ = name; |
| 8155 | 8378 | } |
| 8156 | 8379 | |
| 8380 | fn dumpStderr(elf: *Elf, tid: Zcu.PerThread.Id) !void { |
| 8381 | const comp = elf.base.comp; |
| 8382 | const io = comp.io; |
| 8383 | var buffer: [512]u8 = undefined; |
| 8384 | const stderr = try io.lockStderr(&buffer, null); |
| 8385 | defer io.unlockStderr(); |
| 8386 | const w = &stderr.file_writer.interface; |
| 8387 | _ = try elf.dump(w, tid); |
| 8388 | } |
| 8389 | |
| 8157 | 8390 | pub fn dump(elf: *Elf, w: *Io.Writer, tid: Zcu.PerThread.Id) !link.File.DumpResult { |
| 8158 | 8391 | if (elf.options.enable_link_snapshots) { |
| 8159 | 8392 | try elf.printNode(tid, w, .root, 0); |
| ... | ... | @@ -8231,13 +8464,14 @@ pub fn printNode( |
| 8231 | 8464 | { |
| 8232 | 8465 | const mf_node = &elf.mf.nodes.items[@backingInt(ni)]; |
| 8233 | 8466 | const off, const size = mf_node.location().resolve(&elf.mf); |
| 8234 | | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}\n", .{ |
| 8467 | try w.print(" index={d} offset=0x{x} size=0x{x} align=0x{x}{s}{s}{s}{s}{s}\n", .{ |
| 8235 | 8468 | @backingInt(ni), |
| 8236 | 8469 | off, |
| 8237 | 8470 | size, |
| 8238 | 8471 | mf_node.flags.alignment.toByteUnits(), |
| 8239 | 8472 | if (mf_node.flags.fixed) " fixed" else "", |
| 8240 | 8473 | if (mf_node.flags.moved) " moved" else "", |
| 8474 | if (mf_node.flags.next_moved) " next_moved" else "", |
| 8241 | 8475 | if (mf_node.flags.resized) " resized" else "", |
| 8242 | 8476 | if (mf_node.flags.has_content) " has_content" else "", |
| 8243 | 8477 | }); |
| ... | ... | @@ -8273,11 +8507,19 @@ pub fn printNode( |
| 8273 | 8507 | } |
| 8274 | 8508 | } |
| 8275 | 8509 | |
| 8276 | | fn ensureNodeSize( |
| 8277 | | elf: *Elf, |
| 8278 | | node: MappedFile.Node.Index, |
| 8279 | | need_size: u64, |
| 8280 | | ) Error!void { |
| 8510 | /// Must be called deterministically after any call to `MappedFile.Node.Index.resize` |
| 8511 | /// (of `elf.ni.elf` or one of its children) before any possible calls to `idle`. |
| 8512 | fn ensureElfNodeSize(elf: *Elf) MappedFile.Error!void { |
| 8513 | if (elf.ni.elf == MappedFile.Node.Index.root) return; |
| 8514 | var child_it = elf.ni.elf.reverseChildren(&elf.mf); |
| 8515 | const last_end = if (child_it.next()) |last_ni| last_end: { |
| 8516 | const last_offset, const last_size = last_ni.location(&elf.mf).resolve(&elf.mf); |
| 8517 | break :last_end last_offset + last_size; |
| 8518 | } else 0; |
| 8519 | try elf.ensureNodeSize(elf.ni.elf, last_end + @sizeOf(std.elf.ar_hdr)); |
| 8520 | } |
| 8521 | |
| 8522 | fn ensureNodeSize(elf: *Elf, node: MappedFile.Node.Index, need_size: u64) MappedFile.Error!void { |
| 8281 | 8523 | _, const node_size = node.location(&elf.mf).resolve(&elf.mf); |
| 8282 | 8524 | if (need_size <= node_size) return; |
| 8283 | 8525 | const gpa = elf.base.comp.gpa; |