| ... | ... | @@ -1,11 +1,27 @@ |
| 1 | 1 | base: link.File, |
| 2 | options: link.File.OpenOptions, |
| 2 | 3 | mf: MappedFile, |
| 3 | | known: Node.Known, |
| 4 | ni: Node.Known, |
| 4 | 5 | nodes: std.MultiArrayList(Node), |
| 5 | 6 | phdrs: std.ArrayList(MappedFile.Node.Index), |
| 7 | si: Symbol.Known, |
| 6 | 8 | symtab: std.ArrayList(Symbol), |
| 7 | 9 | shstrtab: StringTable, |
| 8 | 10 | strtab: StringTable, |
| 11 | dynsym: std.ArrayList(Symbol.Index), |
| 12 | dynstr: StringTable, |
| 13 | needed: std.AutoArrayHashMapUnmanaged(u32, void), |
| 14 | inputs: std.ArrayList(struct { |
| 15 | path: std.Build.Cache.Path, |
| 16 | member: ?[]const u8, |
| 17 | si: Symbol.Index, |
| 18 | }), |
| 19 | input_sections: std.ArrayList(struct { |
| 20 | ii: Node.InputIndex, |
| 21 | file_location: MappedFile.Node.FileLocation, |
| 22 | si: Symbol.Index, |
| 23 | }), |
| 24 | input_section_pending_index: u32, |
| 9 | 25 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), |
| 10 | 26 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), |
| 11 | 27 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), |
| ... | ... | @@ -20,6 +36,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { |
| 20 | 36 | relocs: std.ArrayList(Reloc), |
| 21 | 37 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. |
| 22 | 38 | entry_hack: Symbol.Index, |
| 39 | const_prog_node: std.Progress.Node, |
| 40 | synth_prog_node: std.Progress.Node, |
| 41 | input_prog_node: std.Progress.Node, |
| 23 | 42 | |
| 24 | 43 | pub const Node = union(enum) { |
| 25 | 44 | file, |
| ... | ... | @@ -27,11 +46,52 @@ pub const Node = union(enum) { |
| 27 | 46 | shdr, |
| 28 | 47 | segment: u32, |
| 29 | 48 | section: Symbol.Index, |
| 49 | input_section: InputSectionIndex, |
| 30 | 50 | nav: NavMapIndex, |
| 31 | 51 | uav: UavMapIndex, |
| 32 | 52 | lazy_code: LazyMapRef.Index(.code), |
| 33 | 53 | lazy_const_data: LazyMapRef.Index(.const_data), |
| 34 | 54 | |
| 55 | pub const InputIndex = enum(u32) { |
| 56 | _, |
| 57 | |
| 58 | pub fn path(ii: InputIndex, elf: *const Elf) std.Build.Cache.Path { |
| 59 | return elf.inputs.items[@intFromEnum(ii)].path; |
| 60 | } |
| 61 | |
| 62 | pub fn member(ii: InputIndex, elf: *const Elf) ?[]const u8 { |
| 63 | return elf.inputs.items[@intFromEnum(ii)].member; |
| 64 | } |
| 65 | |
| 66 | pub fn symbol(ii: InputIndex, elf: *const Elf) Symbol.Index { |
| 67 | return elf.inputs.items[@intFromEnum(ii)].si; |
| 68 | } |
| 69 | |
| 70 | pub fn endSymbol(ii: InputIndex, elf: *const Elf) Symbol.Index { |
| 71 | const next_ii = @intFromEnum(ii) + 1; |
| 72 | return if (next_ii < elf.inputs.items.len) |
| 73 | @as(InputIndex, @enumFromInt(next_ii)).symbol(elf) |
| 74 | else |
| 75 | @enumFromInt(elf.symtab.items.len); |
| 76 | } |
| 77 | }; |
| 78 | |
| 79 | pub const InputSectionIndex = enum(u32) { |
| 80 | _, |
| 81 | |
| 82 | pub fn input(isi: InputSectionIndex, elf: *const Elf) InputIndex { |
| 83 | return elf.input_sections.items[@intFromEnum(isi)].ii; |
| 84 | } |
| 85 | |
| 86 | pub fn fileLocation(isi: InputSectionIndex, elf: *const Elf) MappedFile.Node.FileLocation { |
| 87 | return elf.input_sections.items[@intFromEnum(isi)].file_location; |
| 88 | } |
| 89 | |
| 90 | pub fn symbol(isi: InputSectionIndex, elf: *const Elf) Symbol.Index { |
| 91 | return elf.input_sections.items[@intFromEnum(isi)].si; |
| 92 | } |
| 93 | }; |
| 94 | |
| 35 | 95 | pub const NavMapIndex = enum(u32) { |
| 36 | 96 | _, |
| 37 | 97 | |
| ... | ... | @@ -88,13 +148,13 @@ pub const Node = union(enum) { |
| 88 | 148 | }; |
| 89 | 149 | |
| 90 | 150 | pub const Known = struct { |
| 91 | | pub const rodata: MappedFile.Node.Index = @enumFromInt(1); |
| 92 | | pub const ehdr: MappedFile.Node.Index = @enumFromInt(2); |
| 93 | | pub const phdr: MappedFile.Node.Index = @enumFromInt(3); |
| 94 | | pub const shdr: MappedFile.Node.Index = @enumFromInt(4); |
| 95 | | pub const text: MappedFile.Node.Index = @enumFromInt(5); |
| 96 | | pub const data: MappedFile.Node.Index = @enumFromInt(6); |
| 97 | | |
| 151 | comptime file: MappedFile.Node.Index = .root, |
| 152 | comptime ehdr: MappedFile.Node.Index = @enumFromInt(1), |
| 153 | comptime shdr: MappedFile.Node.Index = @enumFromInt(2), |
| 154 | comptime rodata: MappedFile.Node.Index = @enumFromInt(3), |
| 155 | comptime phdr: MappedFile.Node.Index = @enumFromInt(4), |
| 156 | comptime text: MappedFile.Node.Index = @enumFromInt(5), |
| 157 | comptime data: MappedFile.Node.Index = @enumFromInt(6), |
| 98 | 158 | tls: MappedFile.Node.Index, |
| 99 | 159 | }; |
| 100 | 160 | |
| ... | ... | @@ -176,7 +236,6 @@ pub const Symbol = struct { |
| 176 | 236 | rodata, |
| 177 | 237 | text, |
| 178 | 238 | data, |
| 179 | | tdata, |
| 180 | 239 | _, |
| 181 | 240 | |
| 182 | 241 | pub fn get(si: Symbol.Index, elf: *Elf) *Symbol { |
| ... | ... | @@ -189,44 +248,65 @@ pub const Symbol = struct { |
| 189 | 248 | return ni; |
| 190 | 249 | } |
| 191 | 250 | |
| 251 | pub fn next(si: Symbol.Index) Symbol.Index { |
| 252 | return @enumFromInt(@intFromEnum(si) + 1); |
| 253 | } |
| 254 | |
| 192 | 255 | pub const InitOptions = struct { |
| 193 | 256 | name: []const u8 = "", |
| 194 | | size: std.elf.Word = 0, |
| 257 | lib_name: ?[]const u8 = null, |
| 258 | value: u64 = 0, |
| 259 | size: u64 = 0, |
| 195 | 260 | type: std.elf.STT, |
| 196 | 261 | bind: std.elf.STB = .LOCAL, |
| 197 | 262 | visibility: std.elf.STV = .DEFAULT, |
| 198 | 263 | shndx: std.elf.Section = std.elf.SHN_UNDEF, |
| 199 | 264 | }; |
| 200 | 265 | pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void { |
| 201 | | const name_entry = try elf.string(.strtab, opts.name); |
| 202 | | try Symbol.Index.symtab.node(elf).resize( |
| 203 | | &elf.mf, |
| 204 | | elf.base.comp.gpa, |
| 205 | | @as(usize, switch (elf.identClass()) { |
| 206 | | .NONE, _ => unreachable, |
| 207 | | .@"32" => @sizeOf(std.elf.Elf32.Sym), |
| 208 | | .@"64" => @sizeOf(std.elf.Elf64.Sym), |
| 209 | | }) * elf.symtab.items.len, |
| 210 | | ); |
| 266 | const gpa = elf.base.comp.gpa; |
| 267 | const target_endian = elf.targetEndian(); |
| 268 | const sym_size: usize = switch (elf.identClass()) { |
| 269 | .NONE, _ => unreachable, |
| 270 | inline else => |class| @sizeOf(class.ElfN().Sym), |
| 271 | }; |
| 272 | const name_strtab_entry = try elf.string(.strtab, opts.name); |
| 273 | try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len); |
| 211 | 274 | switch (elf.symPtr(si)) { |
| 212 | | inline else => |sym| sym.* = .{ |
| 213 | | .name = name_entry, |
| 214 | | .value = 0, |
| 215 | | .size = opts.size, |
| 216 | | .info = .{ |
| 217 | | .type = opts.type, |
| 218 | | .bind = opts.bind, |
| 219 | | }, |
| 220 | | .other = .{ |
| 221 | | .visibility = opts.visibility, |
| 222 | | }, |
| 223 | | .shndx = opts.shndx, |
| 275 | inline else => |sym, class| { |
| 276 | sym.* = .{ |
| 277 | .name = name_strtab_entry, |
| 278 | .value = @intCast(opts.value), |
| 279 | .size = @intCast(opts.size), |
| 280 | .info = .{ .type = opts.type, .bind = opts.bind }, |
| 281 | .other = .{ .visibility = opts.visibility }, |
| 282 | .shndx = opts.shndx, |
| 283 | }; |
| 284 | if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym); |
| 285 | }, |
| 286 | } |
| 287 | if (opts.bind == .LOCAL or elf.si.dynsym == .null) return; |
| 288 | const dsi = elf.dynsym.items.len; |
| 289 | try elf.dynsym.append(gpa, si); |
| 290 | const dynsym_ni = elf.si.dynsym.node(elf); |
| 291 | const name_dynstr_entry = try elf.string(.dynstr, opts.name); |
| 292 | try dynsym_ni.resize(&elf.mf, gpa, sym_size * elf.dynsym.items.len); |
| 293 | switch (elf.dynsymSlice()) { |
| 294 | inline else => |dynsym, class| { |
| 295 | const dsym = &dynsym[dsi]; |
| 296 | dsym.* = .{ |
| 297 | .name = name_dynstr_entry, |
| 298 | .value = @intCast(opts.value), |
| 299 | .size = @intCast(opts.size), |
| 300 | .info = .{ .type = opts.type, .bind = opts.bind }, |
| 301 | .other = .{ .visibility = opts.visibility }, |
| 302 | .shndx = opts.shndx, |
| 303 | }; |
| 304 | if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, dsym); |
| 224 | 305 | }, |
| 225 | 306 | } |
| 226 | 307 | } |
| 227 | 308 | |
| 228 | | pub fn flushMoved(si: Symbol.Index, elf: *Elf) void { |
| 229 | | const value = elf.computeNodeVAddr(si.node(elf)); |
| 309 | pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void { |
| 230 | 310 | switch (elf.symPtr(si)) { |
| 231 | 311 | inline else => |sym, class| { |
| 232 | 312 | elf.targetStore(&sym.value, @intCast(value)); |
| ... | ... | @@ -241,9 +321,12 @@ pub const Symbol = struct { |
| 241 | 321 | } |
| 242 | 322 | |
| 243 | 323 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { |
| 244 | | for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| { |
| 245 | | if (reloc.loc != si) break; |
| 246 | | reloc.apply(elf); |
| 324 | switch (si.get(elf).loc_relocs) { |
| 325 | .none => {}, |
| 326 | else => |loc_relocs| for (elf.relocs.items[@intFromEnum(loc_relocs)..]) |*reloc| { |
| 327 | if (reloc.loc != si) break; |
| 328 | reloc.apply(elf); |
| 329 | }, |
| 247 | 330 | } |
| 248 | 331 | } |
| 249 | 332 | |
| ... | ... | @@ -267,6 +350,19 @@ pub const Symbol = struct { |
| 267 | 350 | } |
| 268 | 351 | }; |
| 269 | 352 | |
| 353 | pub const Known = struct { |
| 354 | comptime symtab: Symbol.Index = .symtab, |
| 355 | comptime shstrtab: Symbol.Index = .shstrtab, |
| 356 | comptime strtab: Symbol.Index = .strtab, |
| 357 | comptime rodata: Symbol.Index = .rodata, |
| 358 | comptime text: Symbol.Index = .text, |
| 359 | comptime data: Symbol.Index = .data, |
| 360 | dynsym: Symbol.Index, |
| 361 | dynstr: Symbol.Index, |
| 362 | dynamic: Symbol.Index, |
| 363 | tdata: Symbol.Index, |
| 364 | }; |
| 365 | |
| 270 | 366 | comptime { |
| 271 | 367 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16); |
| 272 | 368 | } |
| ... | ... | @@ -287,6 +383,22 @@ pub const Reloc = extern struct { |
| 287 | 383 | AARCH64: std.elf.R_AARCH64, |
| 288 | 384 | RISCV: std.elf.R_RISCV, |
| 289 | 385 | PPC64: std.elf.R_PPC64, |
| 386 | |
| 387 | pub fn absAddr(elf: *Elf) Reloc.Type { |
| 388 | return switch (elf.ehdrField(.machine)) { |
| 389 | else => unreachable, |
| 390 | .AARCH64 => .{ .AARCH64 = .ABS64 }, |
| 391 | .PPC64 => .{ .PPC64 = .ADDR64 }, |
| 392 | .RISCV => .{ .RISCV = .@"64" }, |
| 393 | .X86_64 => .{ .X86_64 = .@"64" }, |
| 394 | }; |
| 395 | } |
| 396 | pub fn sizeAddr(elf: *Elf) Reloc.Type { |
| 397 | return switch (elf.ehdrField(.machine)) { |
| 398 | else => unreachable, |
| 399 | .X86_64 => .{ .X86_64 = .SIZE64 }, |
| 400 | }; |
| 401 | } |
| 290 | 402 | }; |
| 291 | 403 | |
| 292 | 404 | pub const Index = enum(u32) { |
| ... | ... | @@ -329,7 +441,7 @@ pub const Reloc = extern struct { |
| 329 | 441 | target_value, |
| 330 | 442 | target_endian, |
| 331 | 443 | ), |
| 332 | | .PC32 => std.mem.writeInt( |
| 444 | .PC32, .PLT32 => std.mem.writeInt( |
| 333 | 445 | i32, |
| 334 | 446 | loc_slice[0..4], |
| 335 | 447 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), |
| ... | ... | @@ -341,9 +453,15 @@ pub const Reloc = extern struct { |
| 341 | 453 | @intCast(target_value), |
| 342 | 454 | target_endian, |
| 343 | 455 | ), |
| 456 | .@"32S" => std.mem.writeInt( |
| 457 | i32, |
| 458 | loc_slice[0..4], |
| 459 | @intCast(@as(i64, @bitCast(target_value))), |
| 460 | target_endian, |
| 461 | ), |
| 344 | 462 | .TPOFF32 => { |
| 345 | 463 | const phdr = @field(elf.phdrSlice(), @tagName(class)); |
| 346 | | const ph = &phdr[elf.getNode(elf.known.tls).segment]; |
| 464 | const ph = &phdr[elf.getNode(elf.ni.tls).segment]; |
| 347 | 465 | assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS); |
| 348 | 466 | std.mem.writeInt( |
| 349 | 467 | i32, |
| ... | ... | @@ -352,6 +470,18 @@ pub const Reloc = extern struct { |
| 352 | 470 | target_endian, |
| 353 | 471 | ); |
| 354 | 472 | }, |
| 473 | .SIZE32 => std.mem.writeInt( |
| 474 | u32, |
| 475 | loc_slice[0..4], |
| 476 | @intCast(elf.targetLoad(&target_sym.size)), |
| 477 | target_endian, |
| 478 | ), |
| 479 | .SIZE64 => std.mem.writeInt( |
| 480 | u64, |
| 481 | loc_slice[0..8], |
| 482 | @intCast(elf.targetLoad(&target_sym.size)), |
| 483 | target_endian, |
| 484 | ), |
| 355 | 485 | }, |
| 356 | 486 | } |
| 357 | 487 | }, |
| ... | ... | @@ -401,7 +531,6 @@ fn create( |
| 401 | 531 | path: std.Build.Cache.Path, |
| 402 | 532 | options: link.File.OpenOptions, |
| 403 | 533 | ) !*Elf { |
| 404 | | _ = options; |
| 405 | 534 | const target = &comp.root_mod.resolved_target.result; |
| 406 | 535 | assert(target.ofmt == .elf); |
| 407 | 536 | const class: std.elf.CLASS = switch (target.ptrBitWidth()) { |
| ... | ... | @@ -434,20 +563,24 @@ fn create( |
| 434 | 563 | .Obj => .REL, |
| 435 | 564 | }; |
| 436 | 565 | const machine = target.toElfMachine(); |
| 437 | | const maybe_interp = switch (comp.config.output_mode) { |
| 438 | | .Exe, .Lib => switch (comp.config.link_mode) { |
| 439 | | .static => null, |
| 440 | | .dynamic => target.dynamic_linker.get(), |
| 566 | const maybe_interp = switch (comp.config.link_mode) { |
| 567 | .static => null, |
| 568 | .dynamic => switch (comp.config.output_mode) { |
| 569 | .Exe => target.dynamic_linker.get(), |
| 570 | .Lib => if (comp.root_mod.resolved_target.is_explicit_dynamic_linker) |
| 571 | target.dynamic_linker.get() |
| 572 | else |
| 573 | null, |
| 574 | .Obj => null, |
| 441 | 575 | }, |
| 442 | | .Obj => null, |
| 443 | 576 | }; |
| 444 | 577 | |
| 445 | 578 | const elf = try arena.create(Elf); |
| 446 | | const file = try path.root_dir.handle.createFile(path.sub_path, .{ |
| 579 | const file = try path.root_dir.handle.adaptToNewApi().createFile(comp.io, path.sub_path, .{ |
| 447 | 580 | .read = true, |
| 448 | 581 | .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), |
| 449 | 582 | }); |
| 450 | | errdefer file.close(); |
| 583 | errdefer file.close(comp.io); |
| 451 | 584 | elf.* = .{ |
| 452 | 585 | .base = .{ |
| 453 | 586 | .tag = .elf2, |
| ... | ... | @@ -455,19 +588,26 @@ fn create( |
| 455 | 588 | .comp = comp, |
| 456 | 589 | .emit = path, |
| 457 | 590 | |
| 458 | | .file = file, |
| 591 | .file = .adaptFromNewApi(file), |
| 459 | 592 | .gc_sections = false, |
| 460 | 593 | .print_gc_sections = false, |
| 461 | 594 | .build_id = .none, |
| 462 | 595 | .allow_shlib_undefined = false, |
| 463 | 596 | .stack_size = 0, |
| 464 | 597 | }, |
| 598 | .options = options, |
| 465 | 599 | .mf = try .init(file, comp.gpa), |
| 466 | | .known = .{ |
| 600 | .ni = .{ |
| 467 | 601 | .tls = .none, |
| 468 | 602 | }, |
| 469 | 603 | .nodes = .empty, |
| 470 | 604 | .phdrs = .empty, |
| 605 | .si = .{ |
| 606 | .dynsym = .null, |
| 607 | .dynstr = .null, |
| 608 | .dynamic = .null, |
| 609 | .tdata = .null, |
| 610 | }, |
| 471 | 611 | .symtab = .empty, |
| 472 | 612 | .shstrtab = .{ |
| 473 | 613 | .map = .empty, |
| ... | ... | @@ -477,6 +617,15 @@ fn create( |
| 477 | 617 | .map = .empty, |
| 478 | 618 | .size = 1, |
| 479 | 619 | }, |
| 620 | .dynsym = .empty, |
| 621 | .dynstr = .{ |
| 622 | .map = .empty, |
| 623 | .size = 1, |
| 624 | }, |
| 625 | .needed = .empty, |
| 626 | .inputs = .empty, |
| 627 | .input_sections = .empty, |
| 628 | .input_section_pending_index = 0, |
| 480 | 629 | .globals = .empty, |
| 481 | 630 | .navs = .empty, |
| 482 | 631 | .uavs = .empty, |
| ... | ... | @@ -487,6 +636,9 @@ fn create( |
| 487 | 636 | .pending_uavs = .empty, |
| 488 | 637 | .relocs = .empty, |
| 489 | 638 | .entry_hack = .null, |
| 639 | .const_prog_node = .none, |
| 640 | .synth_prog_node = .none, |
| 641 | .input_prog_node = .none, |
| 490 | 642 | }; |
| 491 | 643 | errdefer elf.deinit(); |
| 492 | 644 | |
| ... | ... | @@ -502,6 +654,12 @@ pub fn deinit(elf: *Elf) void { |
| 502 | 654 | elf.symtab.deinit(gpa); |
| 503 | 655 | elf.shstrtab.map.deinit(gpa); |
| 504 | 656 | elf.strtab.map.deinit(gpa); |
| 657 | elf.dynsym.deinit(gpa); |
| 658 | elf.dynstr.map.deinit(gpa); |
| 659 | elf.needed.deinit(gpa); |
| 660 | for (elf.inputs.items) |input| if (input.member) |m| gpa.free(m); |
| 661 | elf.inputs.deinit(gpa); |
| 662 | elf.input_sections.deinit(gpa); |
| 505 | 663 | elf.globals.deinit(gpa); |
| 506 | 664 | elf.navs.deinit(gpa); |
| 507 | 665 | elf.uavs.deinit(gpa); |
| ... | ... | @@ -522,6 +680,13 @@ fn initHeaders( |
| 522 | 680 | ) !void { |
| 523 | 681 | const comp = elf.base.comp; |
| 524 | 682 | const gpa = comp.gpa; |
| 683 | const have_dynamic_section = switch (@"type") { |
| 684 | .NONE => unreachable, |
| 685 | .REL => false, |
| 686 | .EXEC => comp.config.link_mode == .dynamic, |
| 687 | .DYN => true, |
| 688 | .CORE, _ => unreachable, |
| 689 | }; |
| 525 | 690 | const addr_align: std.mem.Alignment = switch (class) { |
| 526 | 691 | .NONE, _ => unreachable, |
| 527 | 692 | .@"32" => .@"4", |
| ... | ... | @@ -541,42 +706,32 @@ fn initHeaders( |
| 541 | 706 | phnum += 1; |
| 542 | 707 | const data_phndx = phnum; |
| 543 | 708 | phnum += 1; |
| 709 | const dynamic_phndx = if (have_dynamic_section) phndx: { |
| 710 | defer phnum += 1; |
| 711 | break :phndx phnum; |
| 712 | } else undefined; |
| 544 | 713 | const tls_phndx = if (comp.config.any_non_single_threaded) phndx: { |
| 545 | 714 | defer phnum += 1; |
| 546 | 715 | break :phndx phnum; |
| 547 | 716 | } else undefined; |
| 548 | 717 | |
| 549 | | const expected_nodes_len = 5 + phnum * 2; |
| 718 | const expected_nodes_len = 5 + phnum * 2 + @as(usize, 2) * @intFromBool(have_dynamic_section); |
| 550 | 719 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); |
| 551 | 720 | try elf.phdrs.resize(gpa, phnum); |
| 552 | 721 | elf.nodes.appendAssumeCapacity(.file); |
| 553 | 722 | |
| 554 | | assert(Node.Known.rodata == try elf.mf.addOnlyChildNode(gpa, .root, .{ |
| 555 | | .alignment = elf.mf.flags.block_size, |
| 556 | | .fixed = true, |
| 557 | | .moved = true, |
| 558 | | .bubbles_moved = false, |
| 559 | | })); |
| 560 | | elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx }); |
| 561 | | elf.phdrs.items[rodata_phndx] = Node.Known.rodata; |
| 562 | | |
| 563 | 723 | switch (class) { |
| 564 | 724 | .NONE, _ => unreachable, |
| 565 | 725 | inline else => |ct_class| { |
| 566 | | const ElfN = switch (ct_class) { |
| 567 | | .NONE, _ => comptime unreachable, |
| 568 | | .@"32" => std.elf.Elf32, |
| 569 | | .@"64" => std.elf.Elf64, |
| 570 | | }; |
| 571 | | |
| 572 | | assert(Node.Known.ehdr == try elf.mf.addOnlyChildNode(gpa, Node.Known.rodata, .{ |
| 726 | const ElfN = ct_class.ElfN(); |
| 727 | assert(elf.ni.ehdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.file, .{ |
| 573 | 728 | .size = @sizeOf(ElfN.Ehdr), |
| 574 | 729 | .alignment = addr_align, |
| 575 | 730 | .fixed = true, |
| 576 | 731 | })); |
| 577 | 732 | elf.nodes.appendAssumeCapacity(.ehdr); |
| 578 | 733 | |
| 579 | | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(Node.Known.ehdr.slice(&elf.mf))); |
| 734 | const ehdr: *ElfN.Ehdr = @ptrCast(@alignCast(elf.ni.ehdr.slice(&elf.mf))); |
| 580 | 735 | const EI = std.elf.EI; |
| 581 | 736 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); |
| 582 | 737 | ehdr.ident[EI.CLASS] = @intFromEnum(class); |
| ... | ... | @@ -602,37 +757,47 @@ fn initHeaders( |
| 602 | 757 | }, |
| 603 | 758 | } |
| 604 | 759 | |
| 605 | | assert(Node.Known.phdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ |
| 606 | | .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum), |
| 760 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 761 | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), |
| 607 | 762 | .alignment = addr_align, |
| 608 | 763 | .moved = true, |
| 609 | 764 | .resized = true, |
| 765 | })); |
| 766 | elf.nodes.appendAssumeCapacity(.shdr); |
| 767 | |
| 768 | assert(elf.ni.rodata == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 769 | .alignment = elf.mf.flags.block_size, |
| 770 | .moved = true, |
| 610 | 771 | .bubbles_moved = false, |
| 611 | 772 | })); |
| 612 | | elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx }); |
| 613 | | elf.phdrs.items[phdr_phndx] = Node.Known.phdr; |
| 773 | elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx }); |
| 774 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; |
| 614 | 775 | |
| 615 | | assert(Node.Known.shdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ |
| 616 | | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), |
| 776 | assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ |
| 777 | .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum), |
| 617 | 778 | .alignment = addr_align, |
| 779 | .moved = true, |
| 780 | .resized = true, |
| 781 | .bubbles_moved = false, |
| 618 | 782 | })); |
| 619 | | elf.nodes.appendAssumeCapacity(.shdr); |
| 783 | elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx }); |
| 784 | elf.phdrs.items[phdr_phndx] = elf.ni.phdr; |
| 620 | 785 | |
| 621 | | assert(Node.Known.text == try elf.mf.addLastChildNode(gpa, .root, .{ |
| 786 | assert(elf.ni.text == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 622 | 787 | .alignment = elf.mf.flags.block_size, |
| 623 | 788 | .moved = true, |
| 624 | 789 | .bubbles_moved = false, |
| 625 | 790 | })); |
| 626 | 791 | elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx }); |
| 627 | | elf.phdrs.items[text_phndx] = Node.Known.text; |
| 792 | elf.phdrs.items[text_phndx] = elf.ni.text; |
| 628 | 793 | |
| 629 | | assert(Node.Known.data == try elf.mf.addLastChildNode(gpa, .root, .{ |
| 794 | assert(elf.ni.data == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 630 | 795 | .alignment = elf.mf.flags.block_size, |
| 631 | 796 | .moved = true, |
| 632 | 797 | .bubbles_moved = false, |
| 633 | 798 | })); |
| 634 | 799 | elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx }); |
| 635 | | elf.phdrs.items[data_phndx] = Node.Known.data; |
| 800 | elf.phdrs.items[data_phndx] = elf.ni.data; |
| 636 | 801 | |
| 637 | 802 | var ph_vaddr: u32 = switch (elf.ehdrField(.type)) { |
| 638 | 803 | else => 0, |
| ... | ... | @@ -648,14 +813,10 @@ fn initHeaders( |
| 648 | 813 | switch (class) { |
| 649 | 814 | .NONE, _ => unreachable, |
| 650 | 815 | inline else => |ct_class| { |
| 651 | | const ElfN = switch (ct_class) { |
| 652 | | .NONE, _ => comptime unreachable, |
| 653 | | .@"32" => std.elf.Elf32, |
| 654 | | .@"64" => std.elf.Elf64, |
| 655 | | }; |
| 816 | const ElfN = ct_class.ElfN(); |
| 656 | 817 | const target_endian = elf.targetEndian(); |
| 657 | 818 | |
| 658 | | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(Node.Known.phdr.slice(&elf.mf))); |
| 819 | const phdr: []ElfN.Phdr = @ptrCast(@alignCast(elf.ni.phdr.slice(&elf.mf))); |
| 659 | 820 | const ph_phdr = &phdr[phdr_phndx]; |
| 660 | 821 | ph_phdr.* = .{ |
| 661 | 822 | .type = std.elf.PT_PHDR, |
| ... | ... | @@ -665,7 +826,7 @@ fn initHeaders( |
| 665 | 826 | .filesz = 0, |
| 666 | 827 | .memsz = 0, |
| 667 | 828 | .flags = .{ .R = true }, |
| 668 | | .@"align" = @intCast(Node.Known.phdr.alignment(&elf.mf).toByteUnits()), |
| 829 | .@"align" = @intCast(elf.ni.phdr.alignment(&elf.mf).toByteUnits()), |
| 669 | 830 | }; |
| 670 | 831 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); |
| 671 | 832 | |
| ... | ... | @@ -684,7 +845,7 @@ fn initHeaders( |
| 684 | 845 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp); |
| 685 | 846 | } |
| 686 | 847 | |
| 687 | | _, const rodata_size = Node.Known.rodata.location(&elf.mf).resolve(&elf.mf); |
| 848 | _, const rodata_size = elf.ni.rodata.location(&elf.mf).resolve(&elf.mf); |
| 688 | 849 | const ph_rodata = &phdr[rodata_phndx]; |
| 689 | 850 | ph_rodata.* = .{ |
| 690 | 851 | .type = std.elf.PT_NULL, |
| ... | ... | @@ -694,12 +855,12 @@ fn initHeaders( |
| 694 | 855 | .filesz = @intCast(rodata_size), |
| 695 | 856 | .memsz = @intCast(rodata_size), |
| 696 | 857 | .flags = .{ .R = true }, |
| 697 | | .@"align" = @intCast(Node.Known.rodata.alignment(&elf.mf).toByteUnits()), |
| 858 | .@"align" = @intCast(elf.ni.rodata.alignment(&elf.mf).toByteUnits()), |
| 698 | 859 | }; |
| 699 | 860 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); |
| 700 | 861 | ph_vaddr += @intCast(rodata_size); |
| 701 | 862 | |
| 702 | | _, const text_size = Node.Known.text.location(&elf.mf).resolve(&elf.mf); |
| 863 | _, const text_size = elf.ni.text.location(&elf.mf).resolve(&elf.mf); |
| 703 | 864 | const ph_text = &phdr[text_phndx]; |
| 704 | 865 | ph_text.* = .{ |
| 705 | 866 | .type = std.elf.PT_NULL, |
| ... | ... | @@ -709,12 +870,12 @@ fn initHeaders( |
| 709 | 870 | .filesz = @intCast(text_size), |
| 710 | 871 | .memsz = @intCast(text_size), |
| 711 | 872 | .flags = .{ .R = true, .X = true }, |
| 712 | | .@"align" = @intCast(Node.Known.text.alignment(&elf.mf).toByteUnits()), |
| 873 | .@"align" = @intCast(elf.ni.text.alignment(&elf.mf).toByteUnits()), |
| 713 | 874 | }; |
| 714 | 875 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); |
| 715 | 876 | ph_vaddr += @intCast(text_size); |
| 716 | 877 | |
| 717 | | _, const data_size = Node.Known.data.location(&elf.mf).resolve(&elf.mf); |
| 878 | _, const data_size = elf.ni.data.location(&elf.mf).resolve(&elf.mf); |
| 718 | 879 | const ph_data = &phdr[data_phndx]; |
| 719 | 880 | ph_data.* = .{ |
| 720 | 881 | .type = std.elf.PT_NULL, |
| ... | ... | @@ -724,11 +885,26 @@ fn initHeaders( |
| 724 | 885 | .filesz = @intCast(data_size), |
| 725 | 886 | .memsz = @intCast(data_size), |
| 726 | 887 | .flags = .{ .R = true, .W = true }, |
| 727 | | .@"align" = @intCast(Node.Known.data.alignment(&elf.mf).toByteUnits()), |
| 888 | .@"align" = @intCast(elf.ni.data.alignment(&elf.mf).toByteUnits()), |
| 728 | 889 | }; |
| 729 | 890 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); |
| 730 | 891 | ph_vaddr += @intCast(data_size); |
| 731 | 892 | |
| 893 | if (have_dynamic_section) { |
| 894 | const ph_dynamic = &phdr[dynamic_phndx]; |
| 895 | ph_dynamic.* = .{ |
| 896 | .type = std.elf.PT_DYNAMIC, |
| 897 | .offset = 0, |
| 898 | .vaddr = 0, |
| 899 | .paddr = 0, |
| 900 | .filesz = 0, |
| 901 | .memsz = 0, |
| 902 | .flags = .{ .R = true, .W = true }, |
| 903 | .@"align" = @intCast(addr_align.toByteUnits()), |
| 904 | }; |
| 905 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_dynamic); |
| 906 | } |
| 907 | |
| 732 | 908 | if (comp.config.any_non_single_threaded) { |
| 733 | 909 | const ph_tls = &phdr[tls_phndx]; |
| 734 | 910 | ph_tls.* = .{ |
| ... | ... | @@ -744,7 +920,7 @@ fn initHeaders( |
| 744 | 920 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); |
| 745 | 921 | } |
| 746 | 922 | |
| 747 | | const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(Node.Known.shdr.slice(&elf.mf))); |
| 923 | const sh_null: *ElfN.Shdr = @ptrCast(@alignCast(elf.ni.shdr.slice(&elf.mf))); |
| 748 | 924 | sh_null.* = .{ |
| 749 | 925 | .name = try elf.string(.shstrtab, ""), |
| 750 | 926 | .type = std.elf.SHT_NULL, |
| ... | ... | @@ -766,114 +942,187 @@ fn initHeaders( |
| 766 | 942 | .target_relocs = .none, |
| 767 | 943 | .unused = 0, |
| 768 | 944 | }; |
| 769 | | assert(try elf.addSection(Node.Known.rodata, .{ |
| 945 | assert(elf.si.symtab == try elf.addSection(elf.ni.file, .{ |
| 770 | 946 | .type = std.elf.SHT_SYMTAB, |
| 947 | .size = @sizeOf(ElfN.Sym) * 1, |
| 771 | 948 | .addralign = addr_align, |
| 772 | 949 | .entsize = @sizeOf(ElfN.Sym), |
| 773 | | }) == .symtab); |
| 774 | | |
| 775 | | const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf))); |
| 776 | | symtab.* = .{ |
| 950 | })); |
| 951 | const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class)); |
| 952 | symtab_null.* = .{ |
| 777 | 953 | .name = try elf.string(.strtab, ""), |
| 778 | 954 | .value = 0, |
| 779 | 955 | .size = 0, |
| 780 | | .info = .{ |
| 781 | | .type = .NOTYPE, |
| 782 | | .bind = .LOCAL, |
| 783 | | }, |
| 784 | | .other = .{ |
| 785 | | .visibility = .DEFAULT, |
| 786 | | }, |
| 956 | .info = .{ .type = .NOTYPE, .bind = .LOCAL }, |
| 957 | .other = .{ .visibility = .DEFAULT }, |
| 787 | 958 | .shndx = std.elf.SHN_UNDEF, |
| 788 | 959 | }; |
| 960 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null); |
| 789 | 961 | |
| 790 | 962 | const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class)); |
| 791 | 963 | ehdr.shstrndx = ehdr.shnum; |
| 792 | 964 | }, |
| 793 | 965 | } |
| 794 | | assert(try elf.addSection(Node.Known.rodata, .{ |
| 966 | assert(elf.si.shstrtab == try elf.addSection(elf.ni.file, .{ |
| 795 | 967 | .type = std.elf.SHT_STRTAB, |
| 796 | 968 | .addralign = elf.mf.flags.block_size, |
| 797 | 969 | .entsize = 1, |
| 798 | | }) == .shstrtab); |
| 799 | | assert(try elf.addSection(Node.Known.rodata, .{ |
| 970 | })); |
| 971 | try elf.renameSection(.symtab, ".symtab"); |
| 972 | try elf.renameSection(.shstrtab, ".shstrtab"); |
| 973 | elf.si.shstrtab.node(elf).slice(&elf.mf)[0] = 0; |
| 974 | |
| 975 | assert(elf.si.strtab == try elf.addSection(elf.ni.file, .{ |
| 976 | .name = ".strtab", |
| 800 | 977 | .type = std.elf.SHT_STRTAB, |
| 978 | .size = 1, |
| 801 | 979 | .addralign = elf.mf.flags.block_size, |
| 802 | 980 | .entsize = 1, |
| 803 | | }) == .strtab); |
| 804 | | try elf.renameSection(.symtab, ".symtab"); |
| 805 | | try elf.renameSection(.shstrtab, ".shstrtab"); |
| 806 | | try elf.renameSection(.strtab, ".strtab"); |
| 981 | })); |
| 807 | 982 | try elf.linkSections(.symtab, .strtab); |
| 808 | | Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; |
| 809 | | Symbol.Index.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 983 | elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 810 | 984 | |
| 811 | | assert(try elf.addSection(Node.Known.rodata, .{ |
| 985 | assert(elf.si.rodata == try elf.addSection(elf.ni.rodata, .{ |
| 812 | 986 | .name = ".rodata", |
| 813 | 987 | .flags = .{ .ALLOC = true }, |
| 814 | 988 | .addralign = elf.mf.flags.block_size, |
| 815 | | }) == .rodata); |
| 816 | | assert(try elf.addSection(Node.Known.text, .{ |
| 989 | })); |
| 990 | assert(elf.si.text == try elf.addSection(elf.ni.text, .{ |
| 817 | 991 | .name = ".text", |
| 818 | 992 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 819 | 993 | .addralign = elf.mf.flags.block_size, |
| 820 | | }) == .text); |
| 821 | | assert(try elf.addSection(Node.Known.data, .{ |
| 994 | })); |
| 995 | assert(elf.si.data == try elf.addSection(elf.ni.data, .{ |
| 822 | 996 | .name = ".data", |
| 823 | 997 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 824 | 998 | .addralign = elf.mf.flags.block_size, |
| 825 | | }) == .data); |
| 826 | | if (comp.config.any_non_single_threaded) { |
| 827 | | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 828 | | elf.known.tls = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ |
| 829 | | .alignment = elf.mf.flags.block_size, |
| 830 | | .moved = true, |
| 831 | | }); |
| 832 | | elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx }); |
| 833 | | elf.phdrs.items[tls_phndx] = elf.known.tls; |
| 834 | | |
| 835 | | assert(try elf.addSection(elf.known.tls, .{ |
| 836 | | .name = ".tdata", |
| 837 | | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 838 | | .addralign = elf.mf.flags.block_size, |
| 839 | | }) == .tdata); |
| 840 | | } |
| 999 | })); |
| 841 | 1000 | if (maybe_interp) |interp| { |
| 842 | | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 843 | | const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ |
| 1001 | const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| 844 | 1002 | .size = interp.len + 1, |
| 845 | 1003 | .moved = true, |
| 846 | 1004 | .resized = true, |
| 1005 | .bubbles_moved = false, |
| 847 | 1006 | }); |
| 848 | 1007 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); |
| 849 | 1008 | elf.phdrs.items[interp_phndx] = interp_ni; |
| 850 | 1009 | |
| 851 | 1010 | const sec_interp_si = try elf.addSection(interp_ni, .{ |
| 852 | 1011 | .name = ".interp", |
| 853 | | .size = @intCast(interp.len + 1), |
| 854 | 1012 | .flags = .{ .ALLOC = true }, |
| 1013 | .size = @intCast(interp.len + 1), |
| 855 | 1014 | }); |
| 856 | 1015 | const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); |
| 857 | 1016 | @memcpy(sec_interp[0..interp.len], interp); |
| 858 | 1017 | sec_interp[interp.len] = 0; |
| 859 | 1018 | } |
| 1019 | if (have_dynamic_section) { |
| 1020 | const dynamic_ni = try elf.mf.addLastChildNode(gpa, elf.ni.data, .{ |
| 1021 | .moved = true, |
| 1022 | .bubbles_moved = false, |
| 1023 | }); |
| 1024 | elf.nodes.appendAssumeCapacity(.{ .segment = dynamic_phndx }); |
| 1025 | elf.phdrs.items[dynamic_phndx] = dynamic_ni; |
| 1026 | |
| 1027 | switch (class) { |
| 1028 | .NONE, _ => unreachable, |
| 1029 | inline else => |ct_class| { |
| 1030 | const ElfN = ct_class.ElfN(); |
| 1031 | elf.si.dynsym = try elf.addSection(elf.ni.rodata, .{ |
| 1032 | .name = ".dynsym", |
| 1033 | .type = std.elf.SHT_DYNSYM, |
| 1034 | .size = @sizeOf(ElfN.Sym) * 1, |
| 1035 | .addralign = addr_align, |
| 1036 | .entsize = @sizeOf(ElfN.Sym), |
| 1037 | }); |
| 1038 | const dynsym_null = &@field(elf.dynsymSlice(), @tagName(ct_class))[0]; |
| 1039 | dynsym_null.* = .{ |
| 1040 | .name = try elf.string(.dynstr, ""), |
| 1041 | .value = 0, |
| 1042 | .size = 0, |
| 1043 | .info = .{ .type = .NOTYPE, .bind = .LOCAL }, |
| 1044 | .other = .{ .visibility = .DEFAULT }, |
| 1045 | .shndx = std.elf.SHN_UNDEF, |
| 1046 | }; |
| 1047 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, dynsym_null); |
| 1048 | }, |
| 1049 | } |
| 1050 | elf.si.dynstr = try elf.addSection(elf.ni.rodata, .{ |
| 1051 | .name = ".dynstr", |
| 1052 | .type = std.elf.SHT_STRTAB, |
| 1053 | .size = 1, |
| 1054 | .addralign = elf.mf.flags.block_size, |
| 1055 | .entsize = 1, |
| 1056 | }); |
| 1057 | elf.si.dynamic = try elf.addSection(dynamic_ni, .{ |
| 1058 | .name = ".dynamic", |
| 1059 | .type = std.elf.SHT_DYNAMIC, |
| 1060 | .flags = .{ .ALLOC = true, .WRITE = true }, |
| 1061 | .addralign = addr_align, |
| 1062 | }); |
| 1063 | try elf.linkSections(elf.si.dynamic, elf.si.dynstr); |
| 1064 | try elf.linkSections(elf.si.dynsym, elf.si.dynstr); |
| 1065 | } |
| 1066 | if (comp.config.any_non_single_threaded) { |
| 1067 | elf.ni.tls = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| 1068 | .alignment = elf.mf.flags.block_size, |
| 1069 | .moved = true, |
| 1070 | .bubbles_moved = false, |
| 1071 | }); |
| 1072 | elf.nodes.appendAssumeCapacity(.{ .segment = tls_phndx }); |
| 1073 | elf.phdrs.items[tls_phndx] = elf.ni.tls; |
| 1074 | |
| 1075 | elf.si.tdata = try elf.addSection(elf.ni.tls, .{ |
| 1076 | .name = ".tdata", |
| 1077 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 1078 | .addralign = elf.mf.flags.block_size, |
| 1079 | }); |
| 1080 | } |
| 860 | 1081 | assert(elf.nodes.len == expected_nodes_len); |
| 861 | 1082 | } |
| 862 | 1083 | |
| 1084 | pub fn startProgress(elf: *Elf, prog_node: std.Progress.Node) void { |
| 1085 | prog_node.increaseEstimatedTotalItems(4); |
| 1086 | elf.const_prog_node = prog_node.start("Constants", elf.pending_uavs.count()); |
| 1087 | elf.synth_prog_node = prog_node.start("Synthetics", count: { |
| 1088 | var count: usize = 0; |
| 1089 | for (&elf.lazy.values) |*lazy| count += lazy.map.count() - lazy.pending_index; |
| 1090 | break :count count; |
| 1091 | }); |
| 1092 | elf.mf.update_prog_node = prog_node.start("Relocations", elf.mf.updates.items.len); |
| 1093 | elf.input_prog_node = prog_node.start( |
| 1094 | "Inputs", |
| 1095 | elf.input_sections.items.len - elf.input_section_pending_index, |
| 1096 | ); |
| 1097 | } |
| 1098 | |
| 1099 | pub fn endProgress(elf: *Elf) void { |
| 1100 | elf.input_prog_node.end(); |
| 1101 | elf.input_prog_node = .none; |
| 1102 | elf.mf.update_prog_node.end(); |
| 1103 | elf.mf.update_prog_node = .none; |
| 1104 | elf.synth_prog_node.end(); |
| 1105 | elf.synth_prog_node = .none; |
| 1106 | elf.const_prog_node.end(); |
| 1107 | elf.const_prog_node = .none; |
| 1108 | } |
| 1109 | |
| 863 | 1110 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 864 | 1111 | return elf.nodes.get(@intFromEnum(ni)); |
| 865 | 1112 | } |
| 866 | 1113 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 867 | 1114 | const parent_vaddr = parent_vaddr: { |
| 868 | 1115 | const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) { |
| 869 | | .file, .ehdr, .shdr => unreachable, |
| 1116 | .file => return 0, |
| 1117 | .ehdr, .shdr => unreachable, |
| 870 | 1118 | .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) { |
| 871 | 1119 | inline else => |ph| elf.targetLoad(&ph[phndx].vaddr), |
| 872 | 1120 | }, |
| 873 | 1121 | .section => |si| si, |
| 1122 | .input_section => unreachable, |
| 874 | 1123 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf), |
| 875 | 1124 | }; |
| 876 | | break :parent_vaddr switch (elf.symPtr(parent_si)) { |
| 1125 | break :parent_vaddr if (parent_si == elf.si.tdata) 0 else switch (elf.symPtr(parent_si)) { |
| 877 | 1126 | inline else => |sym| elf.targetLoad(&sym.value), |
| 878 | 1127 | }; |
| 879 | 1128 | }; |
| ... | ... | @@ -928,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) { |
| 928 | 1177 | @"64": *std.elf.Elf64.Ehdr, |
| 929 | 1178 | }; |
| 930 | 1179 | pub fn ehdrPtr(elf: *Elf) EhdrPtr { |
| 931 | | const slice = Node.Known.ehdr.slice(&elf.mf); |
| 1180 | const slice = elf.ni.ehdr.slice(&elf.mf); |
| 932 | 1181 | return switch (elf.identClass()) { |
| 933 | 1182 | .NONE, _ => unreachable, |
| 934 | 1183 | inline else => |class| @unionInit( |
| ... | ... | @@ -953,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) { |
| 953 | 1202 | @"64": []std.elf.Elf64.Phdr, |
| 954 | 1203 | }; |
| 955 | 1204 | pub fn phdrSlice(elf: *Elf) PhdrSlice { |
| 956 | | const slice = Node.Known.phdr.slice(&elf.mf); |
| 1205 | const slice = elf.ni.phdr.slice(&elf.mf); |
| 957 | 1206 | return switch (elf.identClass()) { |
| 958 | 1207 | .NONE, _ => unreachable, |
| 959 | 1208 | inline else => |class| @unionInit( |
| ... | ... | @@ -970,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) { |
| 970 | 1219 | @"64": []std.elf.Elf64.Shdr, |
| 971 | 1220 | }; |
| 972 | 1221 | pub fn shdrSlice(elf: *Elf) ShdrSlice { |
| 973 | | const slice = Node.Known.shdr.slice(&elf.mf); |
| 1222 | const slice = elf.ni.shdr.slice(&elf.mf); |
| 974 | 1223 | return switch (elf.identClass()) { |
| 975 | 1224 | .NONE, _ => unreachable, |
| 976 | 1225 | inline else => |class| @unionInit( |
| ... | ... | @@ -987,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) { |
| 987 | 1236 | @"64": []std.elf.Elf64.Sym, |
| 988 | 1237 | }; |
| 989 | 1238 | pub fn symtabSlice(elf: *Elf) SymtabSlice { |
| 990 | | const slice = Symbol.Index.symtab.node(elf).slice(&elf.mf); |
| 1239 | const slice = elf.si.symtab.node(elf).slice(&elf.mf); |
| 991 | 1240 | return switch (elf.identClass()) { |
| 992 | 1241 | .NONE, _ => unreachable, |
| 993 | 1242 | inline else => |class| @unionInit( |
| ... | ... | @@ -1009,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { |
| 1009 | 1258 | }; |
| 1010 | 1259 | } |
| 1011 | 1260 | |
| 1261 | pub fn dynsymSlice(elf: *Elf) SymtabSlice { |
| 1262 | const slice = elf.si.dynsym.node(elf).slice(&elf.mf); |
| 1263 | return switch (elf.identClass()) { |
| 1264 | .NONE, _ => unreachable, |
| 1265 | inline else => |class| @unionInit( |
| 1266 | SymtabSlice, |
| 1267 | @tagName(class), |
| 1268 | @ptrCast(@alignCast(slice)), |
| 1269 | ), |
| 1270 | }; |
| 1271 | } |
| 1272 | |
| 1012 | 1273 | fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index { |
| 1013 | 1274 | defer elf.symtab.addOneAssumeCapacity().* = .{ |
| 1014 | 1275 | .ni = .none, |
| ... | ... | @@ -1027,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I |
| 1027 | 1288 | |
| 1028 | 1289 | pub fn globalSymbol(elf: *Elf, opts: struct { |
| 1029 | 1290 | name: []const u8, |
| 1291 | lib_name: ?[]const u8 = null, |
| 1030 | 1292 | type: std.elf.STT, |
| 1031 | 1293 | bind: std.elf.STB = .GLOBAL, |
| 1032 | 1294 | visibility: std.elf.STV = .DEFAULT, |
| ... | ... | @@ -1036,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct { |
| 1036 | 1298 | const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); |
| 1037 | 1299 | if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ |
| 1038 | 1300 | .name = opts.name, |
| 1301 | .lib_name = opts.lib_name, |
| 1039 | 1302 | .type = opts.type, |
| 1040 | 1303 | .bind = opts.bind, |
| 1041 | 1304 | .visibility = opts.visibility, |
| ... | ... | @@ -1072,30 +1335,33 @@ fn navType( |
| 1072 | 1335 | }, |
| 1073 | 1336 | }; |
| 1074 | 1337 | } |
| 1338 | fn namedSection(elf: *const Elf, name: []const u8) ?Symbol.Index { |
| 1339 | if (std.mem.eql(u8, name, ".rodata") or |
| 1340 | std.mem.startsWith(u8, name, ".rodata.")) return elf.si.rodata; |
| 1341 | if (std.mem.eql(u8, name, ".text") or |
| 1342 | std.mem.startsWith(u8, name, ".text.")) return elf.si.text; |
| 1343 | if (std.mem.eql(u8, name, ".data") or |
| 1344 | std.mem.startsWith(u8, name, ".data.")) return elf.si.data; |
| 1345 | if (std.mem.eql(u8, name, ".tdata") or |
| 1346 | std.mem.startsWith(u8, name, ".tdata.")) return elf.si.tdata; |
| 1347 | return null; |
| 1348 | } |
| 1075 | 1349 | fn navSection( |
| 1076 | 1350 | elf: *Elf, |
| 1077 | 1351 | ip: *const InternPool, |
| 1078 | 1352 | nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"), |
| 1079 | 1353 | ) Symbol.Index { |
| 1080 | | if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| { |
| 1081 | | if (std.mem.eql(u8, @"linksection", ".rodata") or |
| 1082 | | std.mem.startsWith(u8, @"linksection", ".rodata.")) return .rodata; |
| 1083 | | if (std.mem.eql(u8, @"linksection", ".text") or |
| 1084 | | std.mem.startsWith(u8, @"linksection", ".text.")) return .text; |
| 1085 | | if (std.mem.eql(u8, @"linksection", ".data") or |
| 1086 | | std.mem.startsWith(u8, @"linksection", ".data.")) return .data; |
| 1087 | | if (std.mem.eql(u8, @"linksection", ".tdata") or |
| 1088 | | std.mem.startsWith(u8, @"linksection", ".tdata.")) return .tdata; |
| 1089 | | } |
| 1354 | if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| |
| 1355 | if (elf.namedSection(@"linksection")) |si| return si; |
| 1090 | 1356 | return switch (navType( |
| 1091 | 1357 | ip, |
| 1092 | 1358 | .{ .fully_resolved = nav_fr }, |
| 1093 | 1359 | elf.base.comp.config.any_non_single_threaded, |
| 1094 | 1360 | )) { |
| 1095 | 1361 | else => unreachable, |
| 1096 | | .FUNC => .text, |
| 1097 | | .OBJECT => .data, |
| 1098 | | .TLS => .tdata, |
| 1362 | .FUNC => elf.si.text, |
| 1363 | .OBJECT => elf.si.data, |
| 1364 | .TLS => elf.si.tdata, |
| 1099 | 1365 | }; |
| 1100 | 1366 | } |
| 1101 | 1367 | fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { |
| ... | ... | @@ -1115,6 +1381,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol. |
| 1115 | 1381 | const nav = ip.getNav(nav_index); |
| 1116 | 1382 | if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ |
| 1117 | 1383 | .name = @"extern".name.toSlice(ip), |
| 1384 | .lib_name = @"extern".lib_name.toSlice(ip), |
| 1118 | 1385 | .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), |
| 1119 | 1386 | .bind = switch (@"extern".linkage) { |
| 1120 | 1387 | .internal => .LOCAL, |
| ... | ... | @@ -1156,11 +1423,523 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { |
| 1156 | 1423 | .const_data => .OBJECT, |
| 1157 | 1424 | }, |
| 1158 | 1425 | }); |
| 1159 | | elf.base.comp.link_synth_prog_node.increaseEstimatedTotalItems(1); |
| 1426 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1160 | 1427 | } |
| 1161 | 1428 | return lazy_gop.value_ptr.*; |
| 1162 | 1429 | } |
| 1163 | 1430 | |
| 1431 | pub fn loadInput(elf: *Elf, input: link.Input) (std.fs.File.Reader.SizeError || |
| 1432 | std.Io.File.Reader.Error || MappedFile.Error || error{ EndOfStream, LinkFailure })!void { |
| 1433 | const io = elf.base.comp.io; |
| 1434 | var buf: [4096]u8 = undefined; |
| 1435 | switch (input) { |
| 1436 | .object => |object| { |
| 1437 | var fr = object.file.reader(io, &buf); |
| 1438 | elf.loadObject(object.path, null, &fr, .{ |
| 1439 | .offset = fr.logicalPos(), |
| 1440 | .size = try fr.getSize(), |
| 1441 | }) catch |err| switch (err) { |
| 1442 | error.ReadFailed => return fr.err.?, |
| 1443 | else => |e| return e, |
| 1444 | }; |
| 1445 | }, |
| 1446 | .archive => |archive| { |
| 1447 | var fr = archive.file.reader(io, &buf); |
| 1448 | elf.loadArchive(archive.path, &fr) catch |err| switch (err) { |
| 1449 | error.ReadFailed => return fr.err.?, |
| 1450 | else => |e| return e, |
| 1451 | }; |
| 1452 | }, |
| 1453 | .res => unreachable, |
| 1454 | .dso => |dso| { |
| 1455 | try elf.needed.ensureUnusedCapacity(elf.base.comp.gpa, 1); |
| 1456 | var fr = dso.file.reader(io, &buf); |
| 1457 | elf.loadDso(dso.path, &fr) catch |err| switch (err) { |
| 1458 | error.ReadFailed => return fr.err.?, |
| 1459 | else => |e| return e, |
| 1460 | }; |
| 1461 | }, |
| 1462 | .dso_exact => |dso_exact| try elf.loadDsoExact(dso_exact.name), |
| 1463 | } |
| 1464 | } |
| 1465 | fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void { |
| 1466 | const comp = elf.base.comp; |
| 1467 | const gpa = comp.gpa; |
| 1468 | const diags = &comp.link_diags; |
| 1469 | const r = &fr.interface; |
| 1470 | |
| 1471 | log.debug("loadArchive({f})", .{path.fmtEscapeString()}); |
| 1472 | if (!std.mem.eql(u8, try r.take(std.elf.ARMAG.len), std.elf.ARMAG)) |
| 1473 | return diags.failParse(path, "bad magic", .{}); |
| 1474 | var strtab: std.Io.Writer.Allocating = .init(gpa); |
| 1475 | defer strtab.deinit(); |
| 1476 | while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| { |
| 1477 | if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG)) |
| 1478 | return diags.failParse(path, "bad file magic", .{}); |
| 1479 | const offset = fr.logicalPos(); |
| 1480 | const size = header.size() catch |
| 1481 | return diags.failParse(path, "bad member size", .{}); |
| 1482 | if (std.mem.eql(u8, &header.ar_name, std.elf.STRNAME)) { |
| 1483 | strtab.clearRetainingCapacity(); |
| 1484 | try strtab.ensureTotalCapacityPrecise(size); |
| 1485 | r.streamExact(&strtab.writer, size) catch |err| switch (err) { |
| 1486 | error.WriteFailed => return error.OutOfMemory, |
| 1487 | else => |e| return e, |
| 1488 | }; |
| 1489 | continue; |
| 1490 | } |
| 1491 | load_object: { |
| 1492 | const member = header.name() orelse member: { |
| 1493 | const strtab_offset = header.nameOffset() catch |err| switch (err) { |
| 1494 | error.Overflow => break :member error.Overflow, |
| 1495 | error.InvalidCharacter => break :load_object, |
| 1496 | } orelse break :load_object; |
| 1497 | const strtab_written = strtab.written(); |
| 1498 | if (strtab_offset > strtab_written.len) break :member error.Overflow; |
| 1499 | const member = std.mem.sliceTo(strtab_written[strtab_offset..], '\n'); |
| 1500 | break :member if (std.mem.endsWith(u8, member, "/")) |
| 1501 | member[0 .. member.len - "/".len] |
| 1502 | else |
| 1503 | member; |
| 1504 | } catch |err| switch (err) { |
| 1505 | error.Overflow => return diags.failParse(path, "bad member name offset", .{}), |
| 1506 | }; |
| 1507 | if (!std.mem.endsWith(u8, member, ".o")) break :load_object; |
| 1508 | try elf.loadObject(path, member, fr, .{ .offset = offset, .size = size }); |
| 1509 | } |
| 1510 | try fr.seekTo(std.mem.alignForward(u64, offset + size, 2)); |
| 1511 | } else |err| switch (err) { |
| 1512 | error.EndOfStream => if (!fr.atEnd()) return error.EndOfStream, |
| 1513 | else => |e| return e, |
| 1514 | } |
| 1515 | } |
| 1516 | fn fmtMemberString(member: ?[]const u8) std.fmt.Alt(?[]const u8, memberStringEscape) { |
| 1517 | return .{ .data = member }; |
| 1518 | } |
| 1519 | fn memberStringEscape(member: ?[]const u8, w: *std.Io.Writer) std.Io.Writer.Error!void { |
| 1520 | try w.print("({f})", .{std.zig.fmtString(member orelse return)}); |
| 1521 | } |
| 1522 | fn loadObject( |
| 1523 | elf: *Elf, |
| 1524 | path: std.Build.Cache.Path, |
| 1525 | member: ?[]const u8, |
| 1526 | fr: *std.Io.File.Reader, |
| 1527 | fl: MappedFile.Node.FileLocation, |
| 1528 | ) !void { |
| 1529 | const comp = elf.base.comp; |
| 1530 | const gpa = comp.gpa; |
| 1531 | const diags = &comp.link_diags; |
| 1532 | const r = &fr.interface; |
| 1533 | |
| 1534 | const ii: Node.InputIndex = @enumFromInt(elf.inputs.items.len); |
| 1535 | log.debug("loadObject({f}{f})", .{ path.fmtEscapeString(), fmtMemberString(member) }); |
| 1536 | const ident = try r.peek(std.elf.EI.NIDENT); |
| 1537 | if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT])) |
| 1538 | return diags.failParse(path, "bad ident", .{}); |
| 1539 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1540 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 1541 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 1542 | .path = path, |
| 1543 | .member = if (member) |m| try gpa.dupe(u8, m) else null, |
| 1544 | .si = try elf.initSymbolAssumeCapacity(.{ |
| 1545 | .name = std.fs.path.stem(member orelse path.sub_path), |
| 1546 | .type = .FILE, |
| 1547 | .shndx = std.elf.SHN_ABS, |
| 1548 | }), |
| 1549 | }; |
| 1550 | const target_endian = elf.targetEndian(); |
| 1551 | switch (elf.identClass()) { |
| 1552 | .NONE, _ => unreachable, |
| 1553 | inline else => |class| { |
| 1554 | const ElfN = class.ElfN(); |
| 1555 | const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian); |
| 1556 | if (ehdr.type != .REL) return diags.failParse(path, "unsupported object type", .{}); |
| 1557 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 1558 | return diags.failParse(path, "bad machine", .{}); |
| 1559 | if (ehdr.shoff == 0 or ehdr.shnum <= 1) return; |
| 1560 | if (ehdr.shoff + ehdr.shentsize * ehdr.shnum > fl.size) |
| 1561 | return diags.failParse(path, "bad section header location", .{}); |
| 1562 | if (ehdr.shentsize < @sizeOf(ElfN.Shdr)) |
| 1563 | return diags.failParse(path, "unsupported shentsize", .{}); |
| 1564 | const sections = try gpa.alloc(struct { shdr: ElfN.Shdr, si: Symbol.Index }, ehdr.shnum); |
| 1565 | defer gpa.free(sections); |
| 1566 | try fr.seekTo(fl.offset + ehdr.shoff); |
| 1567 | for (sections) |*section| { |
| 1568 | section.* = .{ |
| 1569 | .shdr = try r.peekStruct(ElfN.Shdr, target_endian), |
| 1570 | .si = .null, |
| 1571 | }; |
| 1572 | try r.discardAll(ehdr.shentsize); |
| 1573 | switch (section.shdr.type) { |
| 1574 | std.elf.SHT_NULL, std.elf.SHT_NOBITS => {}, |
| 1575 | else => if (section.shdr.offset + section.shdr.size > fl.size) |
| 1576 | return diags.failParse(path, "bad section location", .{}), |
| 1577 | } |
| 1578 | } |
| 1579 | const shstrtab = shstrtab: { |
| 1580 | if (ehdr.shstrndx == std.elf.SHN_UNDEF or ehdr.shstrndx >= ehdr.shnum) |
| 1581 | return diags.failParse(path, "missing section names", .{}); |
| 1582 | const shdr = &sections[ehdr.shstrndx].shdr; |
| 1583 | if (shdr.type != std.elf.SHT_STRTAB) |
| 1584 | return diags.failParse(path, "invalid shstrtab type", .{}); |
| 1585 | const shstrtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1586 | errdefer gpa.free(shstrtab); |
| 1587 | try fr.seekTo(fl.offset + shdr.offset); |
| 1588 | try r.readSliceAll(shstrtab); |
| 1589 | break :shstrtab shstrtab; |
| 1590 | }; |
| 1591 | defer gpa.free(shstrtab); |
| 1592 | try elf.nodes.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1593 | try elf.symtab.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1594 | try elf.input_sections.ensureUnusedCapacity(gpa, ehdr.shnum - 1); |
| 1595 | for (sections[1..]) |*section| switch (section.shdr.type) { |
| 1596 | else => {}, |
| 1597 | std.elf.SHT_PROGBITS, std.elf.SHT_NOBITS => { |
| 1598 | if (section.shdr.name >= shstrtab.len) continue; |
| 1599 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); |
| 1600 | const parent_si = elf.namedSection(name) orelse continue; |
| 1601 | const ni = try elf.mf.addLastChildNode(gpa, parent_si.node(elf), .{ |
| 1602 | .size = section.shdr.size, |
| 1603 | .alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert( |
| 1604 | usize, |
| 1605 | @intCast(@max(section.shdr.addralign, 1)), |
| 1606 | )), |
| 1607 | .moved = true, |
| 1608 | }); |
| 1609 | elf.nodes.appendAssumeCapacity(.{ |
| 1610 | .input_section = @enumFromInt(elf.input_sections.items.len), |
| 1611 | }); |
| 1612 | section.si = try elf.initSymbolAssumeCapacity(.{ |
| 1613 | .type = .SECTION, |
| 1614 | .shndx = elf.targetLoad(&@field(elf.symPtr(parent_si), @tagName(class)).shndx), |
| 1615 | }); |
| 1616 | section.si.get(elf).ni = ni; |
| 1617 | elf.input_sections.addOneAssumeCapacity().* = .{ |
| 1618 | .ii = ii, |
| 1619 | .si = section.si, |
| 1620 | .file_location = .{ |
| 1621 | .offset = fl.offset + section.shdr.offset, |
| 1622 | .size = section.shdr.size, |
| 1623 | }, |
| 1624 | }; |
| 1625 | elf.synth_prog_node.increaseEstimatedTotalItems(1); |
| 1626 | }, |
| 1627 | }; |
| 1628 | var symmap: std.ArrayList(Symbol.Index) = .empty; |
| 1629 | defer symmap.deinit(gpa); |
| 1630 | for (sections[1..], 1..) |*symtab, symtab_shndx| switch (symtab.shdr.type) { |
| 1631 | else => {}, |
| 1632 | std.elf.SHT_SYMTAB => { |
| 1633 | if (symtab.shdr.entsize < @sizeOf(ElfN.Sym)) |
| 1634 | return diags.failParse(path, "unsupported symtab entsize", .{}); |
| 1635 | const strtab = strtab: { |
| 1636 | if (symtab.shdr.link == std.elf.SHN_UNDEF or symtab.shdr.link >= ehdr.shnum) |
| 1637 | return diags.failParse(path, "missing symbol names", .{}); |
| 1638 | const shdr = &sections[symtab.shdr.link].shdr; |
| 1639 | if (shdr.type != std.elf.SHT_STRTAB) |
| 1640 | return diags.failParse(path, "invalid strtab type", .{}); |
| 1641 | const strtab = try gpa.alloc(u8, @intCast(shdr.size)); |
| 1642 | errdefer gpa.free(strtab); |
| 1643 | try fr.seekTo(fl.offset + shdr.offset); |
| 1644 | try r.readSliceAll(strtab); |
| 1645 | break :strtab strtab; |
| 1646 | }; |
| 1647 | defer gpa.free(strtab); |
| 1648 | const symnum = std.math.divExact( |
| 1649 | u32, |
| 1650 | @intCast(symtab.shdr.size), |
| 1651 | @intCast(symtab.shdr.entsize), |
| 1652 | ) catch return diags.failParse( |
| 1653 | path, |
| 1654 | "symtab section size (0x{x}) is not a multiple of entsize (0x{x})", |
| 1655 | .{ symtab.shdr.size, symtab.shdr.entsize }, |
| 1656 | ); |
| 1657 | symmap.clearRetainingCapacity(); |
| 1658 | try symmap.resize(gpa, std.math.sub(u32, symnum, 1) catch continue); |
| 1659 | try elf.symtab.ensureUnusedCapacity(gpa, symnum); |
| 1660 | try elf.globals.ensureUnusedCapacity(gpa, symnum); |
| 1661 | try fr.seekTo(fl.offset + symtab.shdr.offset + symtab.shdr.entsize); |
| 1662 | for (symmap.items) |*si| { |
| 1663 | si.* = .null; |
| 1664 | const input_sym = try r.peekStruct(ElfN.Sym, target_endian); |
| 1665 | try r.discardAll64(symtab.shdr.entsize); |
| 1666 | if (input_sym.name >= strtab.len or input_sym.shndx == std.elf.SHN_UNDEF or |
| 1667 | input_sym.shndx >= ehdr.shnum) continue; |
| 1668 | switch (input_sym.info.type) { |
| 1669 | else => continue, |
| 1670 | .SECTION => { |
| 1671 | const section = &sections[input_sym.shndx]; |
| 1672 | if (input_sym.value == section.shdr.addr) si.* = section.si; |
| 1673 | continue; |
| 1674 | }, |
| 1675 | .OBJECT, .FUNC => {}, |
| 1676 | } |
| 1677 | const name = std.mem.sliceTo(strtab[input_sym.name..], 0); |
| 1678 | const parent_si = sections[input_sym.shndx].si; |
| 1679 | si.* = try elf.initSymbolAssumeCapacity(.{ |
| 1680 | .name = name, |
| 1681 | .value = input_sym.value, |
| 1682 | .size = input_sym.size, |
| 1683 | .type = input_sym.info.type, |
| 1684 | .bind = input_sym.info.bind, |
| 1685 | .visibility = input_sym.other.visibility, |
| 1686 | .shndx = elf.targetLoad(switch (elf.symPtr(parent_si)) { |
| 1687 | inline else => |parent_sym| &parent_sym.shndx, |
| 1688 | }), |
| 1689 | }); |
| 1690 | si.get(elf).ni = parent_si.get(elf).ni; |
| 1691 | switch (input_sym.info.bind) { |
| 1692 | else => {}, |
| 1693 | .GLOBAL => { |
| 1694 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| 1695 | &@field(elf.symPtr(si.*), @tagName(class)).name, |
| 1696 | )); |
| 1697 | if (gop.found_existing) switch (elf.targetLoad( |
| 1698 | switch (elf.symPtr(gop.value_ptr.*)) { |
| 1699 | inline else => |sym| &sym.info, |
| 1700 | }, |
| 1701 | ).bind) { |
| 1702 | else => unreachable, |
| 1703 | .GLOBAL => return diags.failParse( |
| 1704 | path, |
| 1705 | "multiple definitions of '{s}'", |
| 1706 | .{name}, |
| 1707 | ), |
| 1708 | .WEAK => {}, |
| 1709 | }; |
| 1710 | gop.value_ptr.* = si.*; |
| 1711 | }, |
| 1712 | .WEAK => { |
| 1713 | const gop = elf.globals.getOrPutAssumeCapacity(elf.targetLoad( |
| 1714 | &@field(elf.symPtr(si.*), @tagName(class)).name, |
| 1715 | )); |
| 1716 | if (!gop.found_existing) gop.value_ptr.* = si.*; |
| 1717 | }, |
| 1718 | } |
| 1719 | } |
| 1720 | for (sections[1..]) |*rels| switch (rels.shdr.type) { |
| 1721 | else => {}, |
| 1722 | inline std.elf.SHT_REL, std.elf.SHT_RELA => |sht| { |
| 1723 | if (rels.shdr.link != symtab_shndx or rels.shdr.info == std.elf.SHN_UNDEF or |
| 1724 | rels.shdr.info >= ehdr.shnum) continue; |
| 1725 | const Rel = switch (sht) { |
| 1726 | else => comptime unreachable, |
| 1727 | std.elf.SHT_REL => ElfN.Rel, |
| 1728 | std.elf.SHT_RELA => ElfN.Rela, |
| 1729 | }; |
| 1730 | if (rels.shdr.entsize < @sizeOf(Rel)) |
| 1731 | return diags.failParse(path, "unsupported rel entsize", .{}); |
| 1732 | const loc_sec = &sections[rels.shdr.info]; |
| 1733 | if (loc_sec.si == .null) continue; |
| 1734 | const relnum = std.math.divExact( |
| 1735 | u32, |
| 1736 | @intCast(rels.shdr.size), |
| 1737 | @intCast(rels.shdr.entsize), |
| 1738 | ) catch return diags.failParse( |
| 1739 | path, |
| 1740 | "relocation section size (0x{x}) is not a multiple of entsize (0x{x})", |
| 1741 | .{ rels.shdr.size, rels.shdr.entsize }, |
| 1742 | ); |
| 1743 | try elf.relocs.ensureUnusedCapacity(gpa, relnum); |
| 1744 | try fr.seekTo(fl.offset + rels.shdr.offset); |
| 1745 | for (0..relnum) |_| { |
| 1746 | const rel = try r.peekStruct(Rel, target_endian); |
| 1747 | try r.discardAll64(rels.shdr.entsize); |
| 1748 | if (rel.info.sym >= symnum) continue; |
| 1749 | const target_si = symmap.items[rel.info.sym - 1]; |
| 1750 | if (target_si == .null) continue; |
| 1751 | elf.addRelocAssumeCapacity( |
| 1752 | loc_sec.si, |
| 1753 | rel.offset - loc_sec.shdr.addr, |
| 1754 | target_si, |
| 1755 | rel.addend, |
| 1756 | switch (elf.ehdrField(.machine)) { |
| 1757 | else => unreachable, |
| 1758 | inline .AARCH64, |
| 1759 | .PPC64, |
| 1760 | .RISCV, |
| 1761 | .X86_64, |
| 1762 | => |machine| @unionInit( |
| 1763 | Reloc.Type, |
| 1764 | @tagName(machine), |
| 1765 | @enumFromInt(rel.info.type), |
| 1766 | ), |
| 1767 | }, |
| 1768 | ); |
| 1769 | } |
| 1770 | }, |
| 1771 | }; |
| 1772 | }, |
| 1773 | }; |
| 1774 | }, |
| 1775 | } |
| 1776 | } |
| 1777 | fn loadDso(elf: *Elf, path: std.Build.Cache.Path, fr: *std.Io.File.Reader) !void { |
| 1778 | const comp = elf.base.comp; |
| 1779 | const diags = &comp.link_diags; |
| 1780 | const r = &fr.interface; |
| 1781 | |
| 1782 | log.debug("loadDso({f})", .{path.fmtEscapeString()}); |
| 1783 | const ident = try r.peek(std.elf.EI.NIDENT); |
| 1784 | if (!std.mem.eql(u8, ident, elf.mf.contents[0..std.elf.EI.NIDENT])) |
| 1785 | return diags.failParse(path, "bad ident", .{}); |
| 1786 | const target_endian = elf.targetEndian(); |
| 1787 | switch (elf.identClass()) { |
| 1788 | .NONE, _ => unreachable, |
| 1789 | inline else => |class| { |
| 1790 | const ElfN = class.ElfN(); |
| 1791 | const ehdr = try r.peekStruct(ElfN.Ehdr, target_endian); |
| 1792 | if (ehdr.type != .DYN) return diags.failParse(path, "unsupported dso type", .{}); |
| 1793 | if (ehdr.machine != elf.ehdrField(.machine)) |
| 1794 | return diags.failParse(path, "bad machine", .{}); |
| 1795 | if (ehdr.phoff == 0 or ehdr.phnum <= 1) |
| 1796 | return diags.failParse(path, "no program headers", .{}); |
| 1797 | try fr.seekTo(ehdr.phoff); |
| 1798 | const dynamic_ph = for (0..ehdr.phnum) |_| { |
| 1799 | const ph = try r.peekStruct(ElfN.Phdr, target_endian); |
| 1800 | try r.discardAll(ehdr.phentsize); |
| 1801 | switch (ph.type) { |
| 1802 | else => {}, |
| 1803 | std.elf.PT_DYNAMIC => break ph, |
| 1804 | } |
| 1805 | } else return diags.failParse(path, "no dynamic segment", .{}); |
| 1806 | const dynnum = std.math.divExact( |
| 1807 | u32, |
| 1808 | @intCast(dynamic_ph.filesz), |
| 1809 | @sizeOf(ElfN.Addr) * 2, |
| 1810 | ) catch return diags.failParse( |
| 1811 | path, |
| 1812 | "dynamic segment filesz (0x{x}) is not a multiple of entsize (0x{x})", |
| 1813 | .{ dynamic_ph.filesz, @sizeOf(ElfN.Addr) * 2 }, |
| 1814 | ); |
| 1815 | var strtab: ?ElfN.Addr = null; |
| 1816 | var strsz: ?ElfN.Addr = null; |
| 1817 | var soname: ?ElfN.Addr = null; |
| 1818 | try fr.seekTo(dynamic_ph.offset); |
| 1819 | for (0..dynnum) |_| { |
| 1820 | const key = try r.takeInt(ElfN.Addr, target_endian); |
| 1821 | const value = try r.takeInt(ElfN.Addr, target_endian); |
| 1822 | switch (key) { |
| 1823 | else => {}, |
| 1824 | std.elf.DT_STRTAB => strtab = value, |
| 1825 | std.elf.DT_STRSZ => strsz = value, |
| 1826 | std.elf.DT_SONAME => soname = value, |
| 1827 | } |
| 1828 | } |
| 1829 | if (strtab == null or soname == null) |
| 1830 | return elf.loadDsoExact(std.fs.path.basename(path.sub_path)); |
| 1831 | if (strsz) |size| if (soname.? >= size) |
| 1832 | return diags.failParse(path, "bad soname string", .{}); |
| 1833 | try fr.seekTo(ehdr.phoff); |
| 1834 | const ph = for (0..ehdr.phnum) |_| { |
| 1835 | const ph = try r.peekStruct(ElfN.Phdr, target_endian); |
| 1836 | try r.discardAll(ehdr.phentsize); |
| 1837 | switch (ph.type) { |
| 1838 | else => {}, |
| 1839 | std.elf.PT_LOAD => if (strtab.? >= ph.vaddr and |
| 1840 | strtab.? + (strsz orelse 0) <= ph.vaddr + ph.filesz) break ph, |
| 1841 | } |
| 1842 | } else return diags.failParse(path, "strtab not part of a loaded segment", .{}); |
| 1843 | try fr.seekTo(strtab.? + soname.? - ph.vaddr + ph.offset); |
| 1844 | return elf.loadDsoExact(r.peekSentinel(0) catch |err| switch (err) { |
| 1845 | error.StreamTooLong => return diags.failParse(path, "soname too lang", .{}), |
| 1846 | else => |e| return e, |
| 1847 | }); |
| 1848 | }, |
| 1849 | } |
| 1850 | } |
| 1851 | fn loadDsoExact(elf: *Elf, name: []const u8) !void { |
| 1852 | log.debug("loadDsoExact({f})", .{std.zig.fmtString(name)}); |
| 1853 | try elf.needed.put(elf.base.comp.gpa, try elf.string(.dynstr, name), {}); |
| 1854 | } |
| 1855 | |
| 1856 | pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) !void { |
| 1857 | _ = prog_node; |
| 1858 | elf.prelinkInner() catch |err| switch (err) { |
| 1859 | error.OutOfMemory => return error.OutOfMemory, |
| 1860 | else => |e| return elf.base.comp.link_diags.fail("prelink failed: {t}", .{e}), |
| 1861 | }; |
| 1862 | } |
| 1863 | fn prelinkInner(elf: *Elf) !void { |
| 1864 | const gpa = elf.base.comp.gpa; |
| 1865 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| 1866 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| 1867 | const zcu_name = try std.fmt.allocPrint(gpa, "{s}_zcu", .{ |
| 1868 | std.fs.path.stem(elf.base.emit.sub_path), |
| 1869 | }); |
| 1870 | defer gpa.free(zcu_name); |
| 1871 | const si = try elf.initSymbolAssumeCapacity(.{ |
| 1872 | .name = zcu_name, |
| 1873 | .type = .FILE, |
| 1874 | .shndx = std.elf.SHN_ABS, |
| 1875 | }); |
| 1876 | elf.inputs.addOneAssumeCapacity().* = .{ |
| 1877 | .path = elf.base.emit, |
| 1878 | .member = null, |
| 1879 | .si = si, |
| 1880 | }; |
| 1881 | |
| 1882 | if (elf.si.dynamic != .null) switch (elf.identClass()) { |
| 1883 | .NONE, _ => unreachable, |
| 1884 | inline else => |ct_class| { |
| 1885 | const ElfN = ct_class.ElfN(); |
| 1886 | const needed_len = elf.needed.count(); |
| 1887 | const dynamic_len = needed_len + @intFromBool(elf.options.soname != null) + 5; |
| 1888 | const dynamic_size: u32 = @intCast(@sizeOf(ElfN.Addr) * 2 * dynamic_len); |
| 1889 | const dynamic_ni = elf.si.dynamic.node(elf); |
| 1890 | try dynamic_ni.resize(&elf.mf, gpa, dynamic_size); |
| 1891 | const sec_dynamic = dynamic_ni.slice(&elf.mf); |
| 1892 | const dynamic_entries: [][2]ElfN.Addr = @ptrCast(@alignCast(sec_dynamic)); |
| 1893 | var dynamic_index: usize = 0; |
| 1894 | for ( |
| 1895 | dynamic_entries[dynamic_index..][0..needed_len], |
| 1896 | elf.needed.keys(), |
| 1897 | ) |*dynamic_entry, needed| dynamic_entry.* = .{ std.elf.DT_NEEDED, needed }; |
| 1898 | dynamic_index += needed_len; |
| 1899 | if (elf.options.soname) |soname| { |
| 1900 | dynamic_entries[dynamic_index] = .{ std.elf.DT_SONAME, try elf.string(.dynstr, soname) }; |
| 1901 | dynamic_index += 1; |
| 1902 | } |
| 1903 | dynamic_entries[dynamic_index..][0..5].* = .{ |
| 1904 | .{ std.elf.DT_SYMTAB, 0 }, |
| 1905 | .{ std.elf.DT_SYMENT, @sizeOf(ElfN.Sym) }, |
| 1906 | .{ std.elf.DT_STRTAB, 0 }, |
| 1907 | .{ std.elf.DT_STRSZ, 0 }, |
| 1908 | .{ std.elf.DT_NULL, 0 }, |
| 1909 | }; |
| 1910 | dynamic_index += 5; |
| 1911 | assert(dynamic_index == dynamic_len); |
| 1912 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| |
| 1913 | std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry); |
| 1914 | |
| 1915 | const dynamic_sym = elf.si.dynamic.get(elf); |
| 1916 | assert(dynamic_sym.loc_relocs == .none); |
| 1917 | dynamic_sym.loc_relocs = @enumFromInt(elf.relocs.items.len); |
| 1918 | try elf.addReloc( |
| 1919 | elf.si.dynamic, |
| 1920 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 5) + 1), |
| 1921 | elf.si.dynsym, |
| 1922 | 0, |
| 1923 | .absAddr(elf), |
| 1924 | ); |
| 1925 | try elf.addReloc( |
| 1926 | elf.si.dynamic, |
| 1927 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 3) + 1), |
| 1928 | elf.si.dynstr, |
| 1929 | 0, |
| 1930 | .absAddr(elf), |
| 1931 | ); |
| 1932 | try elf.addReloc( |
| 1933 | elf.si.dynamic, |
| 1934 | @sizeOf(ElfN.Addr) * (2 * (dynamic_len - 2) + 1), |
| 1935 | elf.si.dynstr, |
| 1936 | 0, |
| 1937 | .sizeAddr(elf), |
| 1938 | ); |
| 1939 | }, |
| 1940 | }; |
| 1941 | } |
| 1942 | |
| 1164 | 1943 | pub fn getNavVAddr( |
| 1165 | 1944 | elf: *Elf, |
| 1166 | 1945 | pt: Zcu.PerThread, |
| ... | ... | @@ -1184,14 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In |
| 1184 | 1963 | reloc_info.offset, |
| 1185 | 1964 | target_si, |
| 1186 | 1965 | reloc_info.addend, |
| 1187 | | switch (elf.ehdrField(.machine)) { |
| 1188 | | else => unreachable, |
| 1189 | | .X86_64 => .{ .X86_64 = switch (elf.identClass()) { |
| 1190 | | .NONE, _ => unreachable, |
| 1191 | | .@"32" => .@"32", |
| 1192 | | .@"64" => .@"64", |
| 1193 | | } }, |
| 1194 | | }, |
| 1966 | .absAddr(elf), |
| 1195 | 1967 | ); |
| 1196 | 1968 | return switch (elf.symPtr(target_si)) { |
| 1197 | 1969 | inline else => |sym| elf.targetLoad(&sym.value), |
| ... | ... | @@ -1201,11 +1973,16 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In |
| 1201 | 1973 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1202 | 1974 | name: []const u8 = "", |
| 1203 | 1975 | type: std.elf.Word = std.elf.SHT_NULL, |
| 1204 | | size: std.elf.Word = 0, |
| 1205 | 1976 | flags: std.elf.SHF = .{}, |
| 1977 | size: std.elf.Word = 0, |
| 1206 | 1978 | addralign: std.mem.Alignment = .@"1", |
| 1207 | 1979 | entsize: std.elf.Word = 0, |
| 1208 | 1980 | }) !Symbol.Index { |
| 1981 | switch (opts.type) { |
| 1982 | std.elf.SHT_NULL => assert(opts.size == 0), |
| 1983 | std.elf.SHT_PROGBITS => assert(opts.size > 0), |
| 1984 | else => {}, |
| 1985 | } |
| 1209 | 1986 | const gpa = elf.base.comp.gpa; |
| 1210 | 1987 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1211 | 1988 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -1219,17 +1996,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1219 | 1996 | break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum }; |
| 1220 | 1997 | }, |
| 1221 | 1998 | }; |
| 1222 | | try Node.Known.shdr.resize(&elf.mf, gpa, shdr_size); |
| 1999 | try elf.ni.shdr.resize(&elf.mf, gpa, shdr_size); |
| 1223 | 2000 | const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{ |
| 1224 | 2001 | .alignment = opts.addralign, |
| 1225 | 2002 | .size = opts.size, |
| 1226 | | .moved = true, |
| 2003 | .resized = opts.size > 0, |
| 1227 | 2004 | }); |
| 1228 | 2005 | const si = elf.addSymbolAssumeCapacity(); |
| 1229 | 2006 | elf.nodes.appendAssumeCapacity(.{ .section = si }); |
| 1230 | 2007 | si.get(elf).ni = ni; |
| 2008 | const addr = elf.computeNodeVAddr(ni); |
| 2009 | const offset = ni.fileLocation(&elf.mf, false).offset; |
| 1231 | 2010 | try si.init(elf, .{ |
| 1232 | | .name = opts.name, |
| 2011 | .value = addr, |
| 1233 | 2012 | .size = opts.size, |
| 1234 | 2013 | .type = .SECTION, |
| 1235 | 2014 | .shndx = shndx, |
| ... | ... | @@ -1241,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1241 | 2020 | .name = shstrtab_entry, |
| 1242 | 2021 | .type = opts.type, |
| 1243 | 2022 | .flags = .{ .shf = opts.flags }, |
| 1244 | | .addr = 0, |
| 1245 | | .offset = 0, |
| 2023 | .addr = @intCast(addr), |
| 2024 | .offset = @intCast(offset), |
| 1246 | 2025 | .size = opts.size, |
| 1247 | 2026 | .link = 0, |
| 1248 | 2027 | .info = 0, |
| ... | ... | @@ -1256,15 +2035,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1256 | 2035 | } |
| 1257 | 2036 | |
| 1258 | 2037 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 1259 | | const strtab_entry = try elf.string(.strtab, name); |
| 1260 | 2038 | const shstrtab_entry = try elf.string(.shstrtab, name); |
| 1261 | 2039 | switch (elf.shdrSlice()) { |
| 1262 | | inline else => |shdr, class| { |
| 1263 | | const sym = @field(elf.symPtr(si), @tagName(class)); |
| 1264 | | elf.targetStore(&sym.name, strtab_entry); |
| 1265 | | const sh = &shdr[elf.targetLoad(&sym.shndx)]; |
| 1266 | | elf.targetStore(&sh.name, shstrtab_entry); |
| 1267 | | }, |
| 2040 | inline else => |shdr, class| elf.targetStore( |
| 2041 | &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name, |
| 2042 | shstrtab_entry, |
| 2043 | ), |
| 1268 | 2044 | } |
| 1269 | 2045 | } |
| 1270 | 2046 | |
| ... | ... | @@ -1277,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { |
| 1277 | 2053 | } |
| 1278 | 2054 | |
| 1279 | 2055 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { |
| 1280 | | const name = Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) { |
| 2056 | const name = elf.si.shstrtab.node(elf).slice(&elf.mf)[switch (elf.shdrSlice()) { |
| 1281 | 2057 | inline else => |shndx, class| elf.targetLoad( |
| 1282 | 2058 | &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name, |
| 1283 | 2059 | ), |
| ... | ... | @@ -1285,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { |
| 1285 | 2061 | return name[0..std.mem.indexOfScalar(u8, name, 0).? :0]; |
| 1286 | 2062 | } |
| 1287 | 2063 | |
| 1288 | | fn string(elf: *Elf, comptime section: enum { shstrtab, strtab }, key: []const u8) !u32 { |
| 2064 | fn string(elf: *Elf, comptime section: enum { shstrtab, strtab, dynstr }, key: []const u8) !u32 { |
| 1289 | 2065 | if (key.len == 0) return 0; |
| 1290 | 2066 | return @field(elf, @tagName(section)).get( |
| 1291 | 2067 | elf.base.comp.gpa, |
| 1292 | 2068 | &elf.mf, |
| 1293 | | @field(Symbol.Index, @tagName(section)).node(elf), |
| 2069 | @field(elf.si, @tagName(section)).node(elf), |
| 1294 | 2070 | key, |
| 1295 | 2071 | ); |
| 1296 | 2072 | } |
| ... | ... | @@ -1303,10 +2079,20 @@ pub fn addReloc( |
| 1303 | 2079 | addend: i64, |
| 1304 | 2080 | @"type": Reloc.Type, |
| 1305 | 2081 | ) !void { |
| 1306 | | const gpa = elf.base.comp.gpa; |
| 2082 | try elf.relocs.ensureUnusedCapacity(elf.base.comp.gpa, 1); |
| 2083 | elf.addRelocAssumeCapacity(loc_si, offset, target_si, addend, @"type"); |
| 2084 | } |
| 2085 | pub fn addRelocAssumeCapacity( |
| 2086 | elf: *Elf, |
| 2087 | loc_si: Symbol.Index, |
| 2088 | offset: u64, |
| 2089 | target_si: Symbol.Index, |
| 2090 | addend: i64, |
| 2091 | @"type": Reloc.Type, |
| 2092 | ) void { |
| 1307 | 2093 | const target = target_si.get(elf); |
| 1308 | 2094 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); |
| 1309 | | (try elf.relocs.addOne(gpa)).* = .{ |
| 2095 | elf.relocs.addOneAssumeCapacity().* = .{ |
| 1310 | 2096 | .type = @"type", |
| 1311 | 2097 | .prev = .none, |
| 1312 | 2098 | .next = target.target_relocs, |
| ... | ... | @@ -1323,11 +2109,6 @@ pub fn addReloc( |
| 1323 | 2109 | target.target_relocs = ri; |
| 1324 | 2110 | } |
| 1325 | 2111 | |
| 1326 | | pub fn prelink(elf: *Elf, prog_node: std.Progress.Node) void { |
| 1327 | | _ = elf; |
| 1328 | | _ = prog_node; |
| 1329 | | } |
| 1330 | | |
| 1331 | 2112 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { |
| 1332 | 2113 | elf.updateNavInner(pt, nav_index) catch |err| switch (err) { |
| 1333 | 2114 | error.OutOfMemory, |
| ... | ... | @@ -1430,7 +2211,7 @@ pub fn lowerUav( |
| 1430 | 2211 | .alignment = uav_align, |
| 1431 | 2212 | .src_loc = src_loc, |
| 1432 | 2213 | }; |
| 1433 | | elf.base.comp.link_const_prog_node.increaseEstimatedTotalItems(1); |
| 2214 | elf.const_prog_node.increaseEstimatedTotalItems(1); |
| 1434 | 2215 | } |
| 1435 | 2216 | } |
| 1436 | 2217 | return .{ .sym_index = @intFromEnum(si) }; |
| ... | ... | @@ -1534,7 +2315,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { |
| 1534 | 2315 | }) catch |err| switch (err) { |
| 1535 | 2316 | error.OutOfMemory => return error.OutOfMemory, |
| 1536 | 2317 | error.CodegenFail => return error.LinkFailure, |
| 1537 | | else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed {t}", .{e}), |
| 2318 | else => |e| return elf.base.comp.link_diags.fail("updateErrorData failed: {t}", .{e}), |
| 1538 | 2319 | }; |
| 1539 | 2320 | } |
| 1540 | 2321 | |
| ... | ... | @@ -1553,20 +2334,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1553 | 2334 | const comp = elf.base.comp; |
| 1554 | 2335 | task: { |
| 1555 | 2336 | while (elf.pending_uavs.pop()) |pending_uav| { |
| 1556 | | const sub_prog_node = elf.idleProgNode( |
| 1557 | | tid, |
| 1558 | | comp.link_const_prog_node, |
| 1559 | | .{ .uav = pending_uav.key }, |
| 1560 | | ); |
| 2337 | const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key }); |
| 1561 | 2338 | defer sub_prog_node.end(); |
| 1562 | 2339 | elf.flushUav( |
| 1563 | | .{ .zcu = elf.base.comp.zcu.?, .tid = tid }, |
| 2340 | .{ .zcu = comp.zcu.?, .tid = tid }, |
| 1564 | 2341 | pending_uav.key, |
| 1565 | 2342 | pending_uav.value.alignment, |
| 1566 | 2343 | pending_uav.value.src_loc, |
| 1567 | 2344 | ) catch |err| switch (err) { |
| 1568 | 2345 | error.OutOfMemory => return error.OutOfMemory, |
| 1569 | | else => |e| return elf.base.comp.link_diags.fail( |
| 2346 | else => |e| return comp.link_diags.fail( |
| 1570 | 2347 | "linker failed to lower constant: {t}", |
| 1571 | 2348 | .{e}, |
| 1572 | 2349 | ), |
| ... | ... | @@ -1575,7 +2352,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1575 | 2352 | } |
| 1576 | 2353 | var lazy_it = elf.lazy.iterator(); |
| 1577 | 2354 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { |
| 1578 | | const pt: Zcu.PerThread = .{ .zcu = elf.base.comp.zcu.?, .tid = tid }; |
| 2355 | const pt: Zcu.PerThread = .{ .zcu = comp.zcu.?, .tid = tid }; |
| 1579 | 2356 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; |
| 1580 | 2357 | lazy.value.pending_index += 1; |
| 1581 | 2358 | const kind = switch (lmr.kind) { |
| ... | ... | @@ -1583,7 +2360,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1583 | 2360 | .const_data => "data", |
| 1584 | 2361 | }; |
| 1585 | 2362 | var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 1586 | | const sub_prog_node = comp.link_synth_prog_node.start( |
| 2363 | const sub_prog_node = elf.synth_prog_node.start( |
| 1587 | 2364 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ |
| 1588 | 2365 | kind, |
| 1589 | 2366 | Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt), |
| ... | ... | @@ -1593,13 +2370,36 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1593 | 2370 | defer sub_prog_node.end(); |
| 1594 | 2371 | elf.flushLazy(pt, lmr) catch |err| switch (err) { |
| 1595 | 2372 | error.OutOfMemory => return error.OutOfMemory, |
| 1596 | | else => |e| return elf.base.comp.link_diags.fail( |
| 2373 | else => |e| return comp.link_diags.fail( |
| 1597 | 2374 | "linker failed to lower lazy {s}: {t}", |
| 1598 | 2375 | .{ kind, e }, |
| 1599 | 2376 | ), |
| 1600 | 2377 | }; |
| 1601 | 2378 | break :task; |
| 1602 | 2379 | }; |
| 2380 | if (elf.input_section_pending_index < elf.input_sections.items.len) { |
| 2381 | const isi: Node.InputSectionIndex = @enumFromInt(elf.input_section_pending_index); |
| 2382 | elf.input_section_pending_index += 1; |
| 2383 | const sub_prog_node = elf.idleProgNode(tid, elf.input_prog_node, elf.getNode(isi.symbol(elf).node(elf))); |
| 2384 | defer sub_prog_node.end(); |
| 2385 | elf.flushInputSection(isi) catch |err| switch (err) { |
| 2386 | else => |e| { |
| 2387 | const ii = isi.input(elf); |
| 2388 | return comp.link_diags.fail( |
| 2389 | "linker failed to read input section '{s}' from \"{f}{f}\": {t}", |
| 2390 | .{ |
| 2391 | elf.sectionName( |
| 2392 | elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section, |
| 2393 | ), |
| 2394 | ii.path(elf).fmtEscapeString(), |
| 2395 | fmtMemberString(ii.member(elf)), |
| 2396 | e, |
| 2397 | }, |
| 2398 | ); |
| 2399 | }, |
| 2400 | }; |
| 2401 | break :task; |
| 2402 | } |
| 1603 | 2403 | while (elf.mf.updates.pop()) |ni| { |
| 1604 | 2404 | const clean_moved = ni.cleanMoved(&elf.mf); |
| 1605 | 2405 | const clean_resized = ni.cleanResized(&elf.mf); |
| ... | ... | @@ -1614,6 +2414,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1614 | 2414 | } |
| 1615 | 2415 | if (elf.pending_uavs.count() > 0) return true; |
| 1616 | 2416 | for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; |
| 2417 | if (elf.input_sections.items.len > elf.input_section_pending_index) return true; |
| 1617 | 2418 | if (elf.mf.updates.items.len > 0) return true; |
| 1618 | 2419 | return false; |
| 1619 | 2420 | } |
| ... | ... | @@ -1628,6 +2429,14 @@ fn idleProgNode( |
| 1628 | 2429 | return prog_node.start(name: switch (node) { |
| 1629 | 2430 | else => |tag| @tagName(tag), |
| 1630 | 2431 | .section => |si| elf.sectionName(si), |
| 2432 | .input_section => |isi| { |
| 2433 | const ii = isi.input(elf); |
| 2434 | break :name std.fmt.bufPrint(&name, "{f}{f} {s}", .{ |
| 2435 | ii.path(elf).fmtEscapeString(), |
| 2436 | fmtMemberString(ii.member(elf)), |
| 2437 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), |
| 2438 | }) catch &name; |
| 2439 | }, |
| 1631 | 2440 | .nav => |nmi| { |
| 1632 | 2441 | const ip = &elf.base.comp.zcu.?.intern_pool; |
| 1633 | 2442 | break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip); |
| ... | ... | @@ -1655,7 +2464,7 @@ fn flushUav( |
| 1655 | 2464 | switch (sym.ni) { |
| 1656 | 2465 | .none => { |
| 1657 | 2466 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1658 | | const ni = try elf.mf.addLastChildNode(gpa, Symbol.Index.data.node(elf), .{ |
| 2467 | const ni = try elf.mf.addLastChildNode(gpa, elf.si.data.node(elf), .{ |
| 1659 | 2468 | .alignment = uav_align.toStdMem(), |
| 1660 | 2469 | .moved = true, |
| 1661 | 2470 | }); |
| ... | ... | @@ -1749,9 +2558,27 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 1749 | 2558 | si.applyLocationRelocs(elf); |
| 1750 | 2559 | } |
| 1751 | 2560 | |
| 1752 | | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 2561 | fn flushInputSection(elf: *Elf, isi: Node.InputSectionIndex) !void { |
| 2562 | const file_loc = isi.fileLocation(elf); |
| 2563 | if (file_loc.size == 0) return; |
| 2564 | const comp = elf.base.comp; |
| 2565 | const gpa = comp.gpa; |
| 2566 | const ii = isi.input(elf); |
| 2567 | const path = ii.path(elf); |
| 2568 | const file = try path.root_dir.handle.adaptToNewApi().openFile(comp.io, path.sub_path, .{}); |
| 2569 | defer file.close(comp.io); |
| 2570 | var fr = file.reader(comp.io, &.{}); |
| 2571 | try fr.seekTo(file_loc.offset); |
| 2572 | var nw: MappedFile.Node.Writer = undefined; |
| 2573 | isi.symbol(elf).node(elf).writer(&elf.mf, gpa, &nw); |
| 2574 | defer nw.deinit(); |
| 2575 | if (try nw.interface.sendFileAll(&fr, .limited(@intCast(file_loc.size))) != file_loc.size) |
| 2576 | return error.EndOfStream; |
| 2577 | } |
| 2578 | |
| 2579 | fn flushFileOffset(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1753 | 2580 | switch (elf.getNode(ni)) { |
| 1754 | | .file => unreachable, |
| 2581 | else => unreachable, |
| 1755 | 2582 | .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0), |
| 1756 | 2583 | .shdr => switch (elf.ehdrPtr()) { |
| 1757 | 2584 | inline else => |ehdr| elf.targetStore( |
| ... | ... | @@ -1759,34 +2586,84 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1759 | 2586 | @intCast(ni.fileLocation(&elf.mf, false).offset), |
| 1760 | 2587 | ), |
| 1761 | 2588 | }, |
| 1762 | | .segment => |phndx| switch (elf.phdrSlice()) { |
| 1763 | | inline else => |phdr, class| { |
| 1764 | | const ph = &phdr[phndx]; |
| 1765 | | elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); |
| 1766 | | switch (elf.targetLoad(&ph.type)) { |
| 1767 | | else => unreachable, |
| 1768 | | std.elf.PT_NULL, std.elf.PT_LOAD => return, |
| 1769 | | std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {}, |
| 1770 | | std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset, |
| 1771 | | std.elf.PT_TLS => {}, |
| 1772 | | } |
| 1773 | | elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni))); |
| 1774 | | ph.paddr = ph.vaddr; |
| 1775 | | }, |
| 2589 | .segment => |phndx| { |
| 2590 | switch (elf.phdrSlice()) { |
| 2591 | inline else => |phdr| elf.targetStore( |
| 2592 | &phdr[phndx].offset, |
| 2593 | @intCast(ni.fileLocation(&elf.mf, false).offset), |
| 2594 | ), |
| 2595 | } |
| 2596 | var child_it = ni.children(&elf.mf); |
| 2597 | while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni); |
| 1776 | 2598 | }, |
| 1777 | 2599 | .section => |si| switch (elf.shdrSlice()) { |
| 1778 | | inline else => |shdr, class| { |
| 1779 | | const sym = @field(elf.symPtr(si), @tagName(class)); |
| 1780 | | const sh = &shdr[elf.targetLoad(&sym.shndx)]; |
| 1781 | | elf.targetStore(&sh.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); |
| 1782 | | const flags = elf.targetLoad(&sh.flags).shf; |
| 1783 | | if (flags.ALLOC) { |
| 1784 | | elf.targetStore(&sh.addr, @intCast(elf.computeNodeVAddr(ni))); |
| 1785 | | if (!flags.TLS) sym.value = sh.addr; |
| 1786 | | } |
| 1787 | | }, |
| 2600 | inline else => |shdr, class| elf.targetStore( |
| 2601 | &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset, |
| 2602 | @intCast(ni.fileLocation(&elf.mf, false).offset), |
| 2603 | ), |
| 1788 | 2604 | }, |
| 1789 | | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved(elf), |
| 2605 | } |
| 2606 | } |
| 2607 | |
| 2608 | fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 2609 | switch (elf.getNode(ni)) { |
| 2610 | .file => unreachable, |
| 2611 | .ehdr, .shdr => try elf.flushFileOffset(ni), |
| 2612 | .segment => |phndx| { |
| 2613 | try elf.flushFileOffset(ni); |
| 2614 | switch (elf.phdrSlice()) { |
| 2615 | inline else => |phdr, class| { |
| 2616 | const ph = &phdr[phndx]; |
| 2617 | switch (elf.targetLoad(&ph.type)) { |
| 2618 | else => unreachable, |
| 2619 | std.elf.PT_NULL, std.elf.PT_LOAD => return, |
| 2620 | std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {}, |
| 2621 | std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset, |
| 2622 | std.elf.PT_TLS => {}, |
| 2623 | } |
| 2624 | elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni))); |
| 2625 | ph.paddr = ph.vaddr; |
| 2626 | }, |
| 2627 | } |
| 2628 | }, |
| 2629 | .section => |si| { |
| 2630 | try elf.flushFileOffset(ni); |
| 2631 | const addr = elf.computeNodeVAddr(ni); |
| 2632 | switch (elf.shdrSlice()) { |
| 2633 | inline else => |shdr, class| { |
| 2634 | const sym = @field(elf.symPtr(si), @tagName(class)); |
| 2635 | const sh = &shdr[elf.targetLoad(&sym.shndx)]; |
| 2636 | const flags = elf.targetLoad(&sh.flags).shf; |
| 2637 | if (flags.ALLOC) { |
| 2638 | elf.targetStore(&sh.addr, @intCast(addr)); |
| 2639 | sym.value = sh.addr; |
| 2640 | } |
| 2641 | }, |
| 2642 | } |
| 2643 | si.flushMoved(elf, addr); |
| 2644 | }, |
| 2645 | .input_section => |isi| { |
| 2646 | const old_addr = switch (elf.symPtr(isi.symbol(elf))) { |
| 2647 | inline else => |sym| elf.targetLoad(&sym.value), |
| 2648 | }; |
| 2649 | const new_addr = elf.computeNodeVAddr(ni); |
| 2650 | const ii = isi.input(elf); |
| 2651 | var si = ii.symbol(elf); |
| 2652 | const end_si = ii.endSymbol(elf); |
| 2653 | while (cond: { |
| 2654 | si = si.next(); |
| 2655 | break :cond si != end_si; |
| 2656 | }) { |
| 2657 | if (si.get(elf).ni != ni) continue; |
| 2658 | si.flushMoved(elf, switch (elf.symPtr(si)) { |
| 2659 | inline else => |sym| elf.targetLoad(&sym.value), |
| 2660 | } - old_addr + new_addr); |
| 2661 | } |
| 2662 | }, |
| 2663 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf).flushMoved( |
| 2664 | elf, |
| 2665 | elf.computeNodeVAddr(ni), |
| 2666 | ), |
| 1790 | 2667 | } |
| 1791 | 2668 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 1792 | 2669 | } |
| ... | ... | @@ -1852,14 +2729,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1852 | 2729 | else => unreachable, |
| 1853 | 2730 | std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS), |
| 1854 | 2731 | std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL), |
| 1855 | | std.elf.SHT_SYMTAB => elf.targetStore( |
| 2732 | std.elf.SHT_SYMTAB, std.elf.SHT_DYNSYM => elf.targetStore( |
| 1856 | 2733 | &sh.info, |
| 1857 | 2734 | @intCast(@divExact(size, elf.targetLoad(&sh.entsize))), |
| 1858 | 2735 | ), |
| 1859 | | std.elf.SHT_STRTAB => {}, |
| 2736 | std.elf.SHT_STRTAB, std.elf.SHT_DYNAMIC => {}, |
| 1860 | 2737 | } |
| 1861 | 2738 | }, |
| 1862 | 2739 | }, |
| 2740 | .input_section => {}, |
| 1863 | 2741 | .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 1864 | 2742 | } |
| 1865 | 2743 | } |
| ... | ... | @@ -1983,6 +2861,14 @@ pub fn printNode( |
| 1983 | 2861 | switch (node) { |
| 1984 | 2862 | else => {}, |
| 1985 | 2863 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), |
| 2864 | .input_section => |isi| { |
| 2865 | const ii = isi.input(elf); |
| 2866 | try w.print("({f}{f}, {s})", .{ |
| 2867 | ii.path(elf).fmtEscapeString(), |
| 2868 | fmtMemberString(ii.member(elf)), |
| 2869 | elf.sectionName(elf.getNode(isi.symbol(elf).node(elf).parent(&elf.mf)).section), |
| 2870 | }); |
| 2871 | }, |
| 1986 | 2872 | .nav => |nmi| { |
| 1987 | 2873 | const zcu = elf.base.comp.zcu.?; |
| 1988 | 2874 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -2027,25 +2913,28 @@ pub fn printNode( |
| 2027 | 2913 | leaf = false; |
| 2028 | 2914 | try elf.printNode(tid, w, child_ni, indent + 1); |
| 2029 | 2915 | } |
| 2030 | | if (leaf) { |
| 2031 | | const file_loc = ni.fileLocation(&elf.mf, false); |
| 2032 | | if (file_loc.size == 0) return; |
| 2033 | | var address = file_loc.offset; |
| 2034 | | const line_len = 0x10; |
| 2035 | | var line_it = std.mem.window( |
| 2036 | | u8, |
| 2037 | | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], |
| 2038 | | line_len, |
| 2039 | | line_len, |
| 2040 | | ); |
| 2041 | | while (line_it.next()) |line_bytes| : (address += line_len) { |
| 2042 | | try w.splatByteAll(' ', indent + 1); |
| 2043 | | try w.print("{x:0>8} ", .{address}); |
| 2044 | | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); |
| 2045 | | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); |
| 2046 | | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); |
| 2047 | | try w.writeByte('\n'); |
| 2048 | | } |
| 2916 | if (!leaf) return; |
| 2917 | const file_loc = ni.fileLocation(&elf.mf, false); |
| 2918 | var address = file_loc.offset; |
| 2919 | if (file_loc.size == 0) { |
| 2920 | try w.splatByteAll(' ', indent + 1); |
| 2921 | try w.print("{x:0>8}\n", .{address}); |
| 2922 | return; |
| 2923 | } |
| 2924 | const line_len = 0x10; |
| 2925 | var line_it = std.mem.window( |
| 2926 | u8, |
| 2927 | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], |
| 2928 | line_len, |
| 2929 | line_len, |
| 2930 | ); |
| 2931 | while (line_it.next()) |line_bytes| : (address += line_len) { |
| 2932 | try w.splatByteAll(' ', indent + 1); |
| 2933 | try w.print("{x:0>8} ", .{address}); |
| 2934 | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); |
| 2935 | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); |
| 2936 | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); |
| 2937 | try w.writeByte('\n'); |
| 2049 | 2938 | } |
| 2050 | 2939 | } |
| 2051 | 2940 | |