| ... | @@ -1,11 +1,27 @@ | ... | @@ -1,11 +1,27 @@ |
| 1 | base: link.File, | 1 | base: link.File, |
| | 2 | options: link.File.OpenOptions, |
| 2 | mf: MappedFile, | 3 | mf: MappedFile, |
| 3 | known: Node.Known, | 4 | ni: Node.Known, |
| 4 | nodes: std.MultiArrayList(Node), | 5 | nodes: std.MultiArrayList(Node), |
| 5 | phdrs: std.ArrayList(MappedFile.Node.Index), | 6 | phdrs: std.ArrayList(MappedFile.Node.Index), |
| | 7 | si: Symbol.Known, |
| 6 | symtab: std.ArrayList(Symbol), | 8 | symtab: std.ArrayList(Symbol), |
| 7 | shstrtab: StringTable, | 9 | shstrtab: StringTable, |
| 8 | strtab: StringTable, | 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 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), | 25 | globals: std.AutoArrayHashMapUnmanaged(u32, Symbol.Index), |
| 10 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), | 26 | navs: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, Symbol.Index), |
| 11 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), | 27 | uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Symbol.Index), |
| ... | @@ -20,6 +36,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { | ... | @@ -20,6 +36,9 @@ pending_uavs: std.AutoArrayHashMapUnmanaged(Node.UavMapIndex, struct { |
| 20 | relocs: std.ArrayList(Reloc), | 36 | relocs: std.ArrayList(Reloc), |
| 21 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. | 37 | /// This is hiding actual bugs with global symbols! Reconsider once they are implemented correctly. |
| 22 | entry_hack: Symbol.Index, | 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 | pub const Node = union(enum) { | 43 | pub const Node = union(enum) { |
| 25 | file, | 44 | file, |
| ... | @@ -27,11 +46,52 @@ pub const Node = union(enum) { | ... | @@ -27,11 +46,52 @@ pub const Node = union(enum) { |
| 27 | shdr, | 46 | shdr, |
| 28 | segment: u32, | 47 | segment: u32, |
| 29 | section: Symbol.Index, | 48 | section: Symbol.Index, |
| | 49 | input_section: InputSectionIndex, |
| 30 | nav: NavMapIndex, | 50 | nav: NavMapIndex, |
| 31 | uav: UavMapIndex, | 51 | uav: UavMapIndex, |
| 32 | lazy_code: LazyMapRef.Index(.code), | 52 | lazy_code: LazyMapRef.Index(.code), |
| 33 | lazy_const_data: LazyMapRef.Index(.const_data), | 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 | pub const NavMapIndex = enum(u32) { | 95 | pub const NavMapIndex = enum(u32) { |
| 36 | _, | 96 | _, |
| 37 | | 97 | |
| ... | @@ -88,13 +148,13 @@ pub const Node = union(enum) { | ... | @@ -88,13 +148,13 @@ pub const Node = union(enum) { |
| 88 | }; | 148 | }; |
| 89 | | 149 | |
| 90 | pub const Known = struct { | 150 | pub const Known = struct { |
| 91 | pub const rodata: MappedFile.Node.Index = @enumFromInt(1); | 151 | comptime file: MappedFile.Node.Index = .root, |
| 92 | pub const ehdr: MappedFile.Node.Index = @enumFromInt(2); | 152 | comptime ehdr: MappedFile.Node.Index = @enumFromInt(1), |
| 93 | pub const phdr: MappedFile.Node.Index = @enumFromInt(3); | 153 | comptime shdr: MappedFile.Node.Index = @enumFromInt(2), |
| 94 | pub const shdr: MappedFile.Node.Index = @enumFromInt(4); | 154 | comptime rodata: MappedFile.Node.Index = @enumFromInt(3), |
| 95 | pub const text: MappedFile.Node.Index = @enumFromInt(5); | 155 | comptime phdr: MappedFile.Node.Index = @enumFromInt(4), |
| 96 | pub const data: MappedFile.Node.Index = @enumFromInt(6); | 156 | comptime text: MappedFile.Node.Index = @enumFromInt(5), |
| 97 | | 157 | comptime data: MappedFile.Node.Index = @enumFromInt(6), |
| 98 | tls: MappedFile.Node.Index, | 158 | tls: MappedFile.Node.Index, |
| 99 | }; | 159 | }; |
| 100 | | 160 | |
| ... | @@ -176,7 +236,6 @@ pub const Symbol = struct { | ... | @@ -176,7 +236,6 @@ pub const Symbol = struct { |
| 176 | rodata, | 236 | rodata, |
| 177 | text, | 237 | text, |
| 178 | data, | 238 | data, |
| 179 | tdata, | | |
| 180 | _, | 239 | _, |
| 181 | | 240 | |
| 182 | pub fn get(si: Symbol.Index, elf: *Elf) *Symbol { | 241 | pub fn get(si: Symbol.Index, elf: *Elf) *Symbol { |
| ... | @@ -189,44 +248,65 @@ pub const Symbol = struct { | ... | @@ -189,44 +248,65 @@ pub const Symbol = struct { |
| 189 | return ni; | 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 | pub const InitOptions = struct { | 255 | pub const InitOptions = struct { |
| 193 | name: []const u8 = "", | 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 | type: std.elf.STT, | 260 | type: std.elf.STT, |
| 196 | bind: std.elf.STB = .LOCAL, | 261 | bind: std.elf.STB = .LOCAL, |
| 197 | visibility: std.elf.STV = .DEFAULT, | 262 | visibility: std.elf.STV = .DEFAULT, |
| 198 | shndx: std.elf.Section = std.elf.SHN_UNDEF, | 263 | shndx: std.elf.Section = std.elf.SHN_UNDEF, |
| 199 | }; | 264 | }; |
| 200 | pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void { | 265 | pub fn init(si: Symbol.Index, elf: *Elf, opts: InitOptions) !void { |
| 201 | const name_entry = try elf.string(.strtab, opts.name); | 266 | const gpa = elf.base.comp.gpa; |
| 202 | try Symbol.Index.symtab.node(elf).resize( | 267 | const target_endian = elf.targetEndian(); |
| 203 | &elf.mf, | 268 | const sym_size: usize = switch (elf.identClass()) { |
| 204 | elf.base.comp.gpa, | 269 | .NONE, _ => unreachable, |
| 205 | @as(usize, switch (elf.identClass()) { | 270 | inline else => |class| @sizeOf(class.ElfN().Sym), |
| 206 | .NONE, _ => unreachable, | 271 | }; |
| 207 | .@"32" => @sizeOf(std.elf.Elf32.Sym), | 272 | const name_strtab_entry = try elf.string(.strtab, opts.name); |
| 208 | .@"64" => @sizeOf(std.elf.Elf64.Sym), | 273 | try elf.si.symtab.node(elf).resize(&elf.mf, gpa, sym_size * elf.symtab.items.len); |
| 209 | }) * elf.symtab.items.len, | | |
| 210 | ); | | |
| 211 | switch (elf.symPtr(si)) { | 274 | switch (elf.symPtr(si)) { |
| 212 | inline else => |sym| sym.* = .{ | 275 | inline else => |sym, class| { |
| 213 | .name = name_entry, | 276 | sym.* = .{ |
| 214 | .value = 0, | 277 | .name = name_strtab_entry, |
| 215 | .size = opts.size, | 278 | .value = @intCast(opts.value), |
| 216 | .info = .{ | 279 | .size = @intCast(opts.size), |
| 217 | .type = opts.type, | 280 | .info = .{ .type = opts.type, .bind = opts.bind }, |
| 218 | .bind = opts.bind, | 281 | .other = .{ .visibility = opts.visibility }, |
| 219 | }, | 282 | .shndx = opts.shndx, |
| 220 | .other = .{ | 283 | }; |
| 221 | .visibility = opts.visibility, | 284 | if (target_endian != native_endian) std.mem.byteSwapAllFields(class.ElfN().Sym, sym); |
| 222 | }, | 285 | }, |
| 223 | .shndx = opts.shndx, | 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 { | 309 | pub fn flushMoved(si: Symbol.Index, elf: *Elf, value: u64) void { |
| 229 | const value = elf.computeNodeVAddr(si.node(elf)); | | |
| 230 | switch (elf.symPtr(si)) { | 310 | switch (elf.symPtr(si)) { |
| 231 | inline else => |sym, class| { | 311 | inline else => |sym, class| { |
| 232 | elf.targetStore(&sym.value, @intCast(value)); | 312 | elf.targetStore(&sym.value, @intCast(value)); |
| ... | @@ -241,9 +321,12 @@ pub const Symbol = struct { | ... | @@ -241,9 +321,12 @@ pub const Symbol = struct { |
| 241 | } | 321 | } |
| 242 | | 322 | |
| 243 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { | 323 | pub fn applyLocationRelocs(si: Symbol.Index, elf: *Elf) void { |
| 244 | for (elf.relocs.items[@intFromEnum(si.get(elf).loc_relocs)..]) |*reloc| { | 324 | switch (si.get(elf).loc_relocs) { |
| 245 | if (reloc.loc != si) break; | 325 | .none => {}, |
| 246 | reloc.apply(elf); | 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,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 | comptime { | 366 | comptime { |
| 271 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16); | 367 | if (!std.debug.runtime_safety) std.debug.assert(@sizeOf(Symbol) == 16); |
| 272 | } | 368 | } |
| ... | @@ -287,6 +383,22 @@ pub const Reloc = extern struct { | ... | @@ -287,6 +383,22 @@ pub const Reloc = extern struct { |
| 287 | AARCH64: std.elf.R_AARCH64, | 383 | AARCH64: std.elf.R_AARCH64, |
| 288 | RISCV: std.elf.R_RISCV, | 384 | RISCV: std.elf.R_RISCV, |
| 289 | PPC64: std.elf.R_PPC64, | 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 | pub const Index = enum(u32) { | 404 | pub const Index = enum(u32) { |
| ... | @@ -329,7 +441,7 @@ pub const Reloc = extern struct { | ... | @@ -329,7 +441,7 @@ pub const Reloc = extern struct { |
| 329 | target_value, | 441 | target_value, |
| 330 | target_endian, | 442 | target_endian, |
| 331 | ), | 443 | ), |
| 332 | .PC32 => std.mem.writeInt( | 444 | .PC32, .PLT32 => std.mem.writeInt( |
| 333 | i32, | 445 | i32, |
| 334 | loc_slice[0..4], | 446 | loc_slice[0..4], |
| 335 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), | 447 | @intCast(@as(i64, @bitCast(target_value -% loc_value))), |
| ... | @@ -341,9 +453,15 @@ pub const Reloc = extern struct { | ... | @@ -341,9 +453,15 @@ pub const Reloc = extern struct { |
| 341 | @intCast(target_value), | 453 | @intCast(target_value), |
| 342 | target_endian, | 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 | .TPOFF32 => { | 462 | .TPOFF32 => { |
| 345 | const phdr = @field(elf.phdrSlice(), @tagName(class)); | 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 | assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS); | 465 | assert(elf.targetLoad(&ph.type) == std.elf.PT_TLS); |
| 348 | std.mem.writeInt( | 466 | std.mem.writeInt( |
| 349 | i32, | 467 | i32, |
| ... | @@ -352,6 +470,18 @@ pub const Reloc = extern struct { | ... | @@ -352,6 +470,18 @@ pub const Reloc = extern struct { |
| 352 | target_endian, | 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,7 +531,6 @@ fn create( |
| 401 | path: std.Build.Cache.Path, | 531 | path: std.Build.Cache.Path, |
| 402 | options: link.File.OpenOptions, | 532 | options: link.File.OpenOptions, |
| 403 | ) !*Elf { | 533 | ) !*Elf { |
| 404 | _ = options; | | |
| 405 | const target = &comp.root_mod.resolved_target.result; | 534 | const target = &comp.root_mod.resolved_target.result; |
| 406 | assert(target.ofmt == .elf); | 535 | assert(target.ofmt == .elf); |
| 407 | const class: std.elf.CLASS = switch (target.ptrBitWidth()) { | 536 | const class: std.elf.CLASS = switch (target.ptrBitWidth()) { |
| ... | @@ -434,20 +563,24 @@ fn create( | ... | @@ -434,20 +563,24 @@ fn create( |
| 434 | .Obj => .REL, | 563 | .Obj => .REL, |
| 435 | }; | 564 | }; |
| 436 | const machine = target.toElfMachine(); | 565 | const machine = target.toElfMachine(); |
| 437 | const maybe_interp = switch (comp.config.output_mode) { | 566 | const maybe_interp = switch (comp.config.link_mode) { |
| 438 | .Exe, .Lib => switch (comp.config.link_mode) { | 567 | .static => null, |
| 439 | .static => null, | 568 | .dynamic => switch (comp.config.output_mode) { |
| 440 | .dynamic => target.dynamic_linker.get(), | 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 | const elf = try arena.create(Elf); | 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 | .read = true, | 580 | .read = true, |
| 448 | .mode = link.File.determineMode(comp.config.output_mode, comp.config.link_mode), | 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 | elf.* = .{ | 584 | elf.* = .{ |
| 452 | .base = .{ | 585 | .base = .{ |
| 453 | .tag = .elf2, | 586 | .tag = .elf2, |
| ... | @@ -455,19 +588,26 @@ fn create( | ... | @@ -455,19 +588,26 @@ fn create( |
| 455 | .comp = comp, | 588 | .comp = comp, |
| 456 | .emit = path, | 589 | .emit = path, |
| 457 | | 590 | |
| 458 | .file = file, | 591 | .file = .adaptFromNewApi(file), |
| 459 | .gc_sections = false, | 592 | .gc_sections = false, |
| 460 | .print_gc_sections = false, | 593 | .print_gc_sections = false, |
| 461 | .build_id = .none, | 594 | .build_id = .none, |
| 462 | .allow_shlib_undefined = false, | 595 | .allow_shlib_undefined = false, |
| 463 | .stack_size = 0, | 596 | .stack_size = 0, |
| 464 | }, | 597 | }, |
| | 598 | .options = options, |
| 465 | .mf = try .init(file, comp.gpa), | 599 | .mf = try .init(file, comp.gpa), |
| 466 | .known = .{ | 600 | .ni = .{ |
| 467 | .tls = .none, | 601 | .tls = .none, |
| 468 | }, | 602 | }, |
| 469 | .nodes = .empty, | 603 | .nodes = .empty, |
| 470 | .phdrs = .empty, | 604 | .phdrs = .empty, |
| | 605 | .si = .{ |
| | 606 | .dynsym = .null, |
| | 607 | .dynstr = .null, |
| | 608 | .dynamic = .null, |
| | 609 | .tdata = .null, |
| | 610 | }, |
| 471 | .symtab = .empty, | 611 | .symtab = .empty, |
| 472 | .shstrtab = .{ | 612 | .shstrtab = .{ |
| 473 | .map = .empty, | 613 | .map = .empty, |
| ... | @@ -477,6 +617,15 @@ fn create( | ... | @@ -477,6 +617,15 @@ fn create( |
| 477 | .map = .empty, | 617 | .map = .empty, |
| 478 | .size = 1, | 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 | .globals = .empty, | 629 | .globals = .empty, |
| 481 | .navs = .empty, | 630 | .navs = .empty, |
| 482 | .uavs = .empty, | 631 | .uavs = .empty, |
| ... | @@ -487,6 +636,9 @@ fn create( | ... | @@ -487,6 +636,9 @@ fn create( |
| 487 | .pending_uavs = .empty, | 636 | .pending_uavs = .empty, |
| 488 | .relocs = .empty, | 637 | .relocs = .empty, |
| 489 | .entry_hack = .null, | 638 | .entry_hack = .null, |
| | 639 | .const_prog_node = .none, |
| | 640 | .synth_prog_node = .none, |
| | 641 | .input_prog_node = .none, |
| 490 | }; | 642 | }; |
| 491 | errdefer elf.deinit(); | 643 | errdefer elf.deinit(); |
| 492 | | 644 | |
| ... | @@ -502,6 +654,12 @@ pub fn deinit(elf: *Elf) void { | ... | @@ -502,6 +654,12 @@ pub fn deinit(elf: *Elf) void { |
| 502 | elf.symtab.deinit(gpa); | 654 | elf.symtab.deinit(gpa); |
| 503 | elf.shstrtab.map.deinit(gpa); | 655 | elf.shstrtab.map.deinit(gpa); |
| 504 | elf.strtab.map.deinit(gpa); | 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 | elf.globals.deinit(gpa); | 663 | elf.globals.deinit(gpa); |
| 506 | elf.navs.deinit(gpa); | 664 | elf.navs.deinit(gpa); |
| 507 | elf.uavs.deinit(gpa); | 665 | elf.uavs.deinit(gpa); |
| ... | @@ -522,6 +680,13 @@ fn initHeaders( | ... | @@ -522,6 +680,13 @@ fn initHeaders( |
| 522 | ) !void { | 680 | ) !void { |
| 523 | const comp = elf.base.comp; | 681 | const comp = elf.base.comp; |
| 524 | const gpa = comp.gpa; | 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 | const addr_align: std.mem.Alignment = switch (class) { | 690 | const addr_align: std.mem.Alignment = switch (class) { |
| 526 | .NONE, _ => unreachable, | 691 | .NONE, _ => unreachable, |
| 527 | .@"32" => .@"4", | 692 | .@"32" => .@"4", |
| ... | @@ -541,42 +706,32 @@ fn initHeaders( | ... | @@ -541,42 +706,32 @@ fn initHeaders( |
| 541 | phnum += 1; | 706 | phnum += 1; |
| 542 | const data_phndx = phnum; | 707 | const data_phndx = phnum; |
| 543 | phnum += 1; | 708 | phnum += 1; |
| | 709 | const dynamic_phndx = if (have_dynamic_section) phndx: { |
| | 710 | defer phnum += 1; |
| | 711 | break :phndx phnum; |
| | 712 | } else undefined; |
| 544 | const tls_phndx = if (comp.config.any_non_single_threaded) phndx: { | 713 | const tls_phndx = if (comp.config.any_non_single_threaded) phndx: { |
| 545 | defer phnum += 1; | 714 | defer phnum += 1; |
| 546 | break :phndx phnum; | 715 | break :phndx phnum; |
| 547 | } else undefined; | 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 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); | 719 | try elf.nodes.ensureTotalCapacity(gpa, expected_nodes_len); |
| 551 | try elf.phdrs.resize(gpa, phnum); | 720 | try elf.phdrs.resize(gpa, phnum); |
| 552 | elf.nodes.appendAssumeCapacity(.file); | 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 | switch (class) { | 723 | switch (class) { |
| 564 | .NONE, _ => unreachable, | 724 | .NONE, _ => unreachable, |
| 565 | inline else => |ct_class| { | 725 | inline else => |ct_class| { |
| 566 | const ElfN = switch (ct_class) { | 726 | const ElfN = ct_class.ElfN(); |
| 567 | .NONE, _ => comptime unreachable, | 727 | assert(elf.ni.ehdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.file, .{ |
| 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, .{ | | |
| 573 | .size = @sizeOf(ElfN.Ehdr), | 728 | .size = @sizeOf(ElfN.Ehdr), |
| 574 | .alignment = addr_align, | 729 | .alignment = addr_align, |
| 575 | .fixed = true, | 730 | .fixed = true, |
| 576 | })); | 731 | })); |
| 577 | elf.nodes.appendAssumeCapacity(.ehdr); | 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 | const EI = std.elf.EI; | 735 | const EI = std.elf.EI; |
| 581 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); | 736 | @memcpy(ehdr.ident[0..std.elf.MAGIC.len], std.elf.MAGIC); |
| 582 | ehdr.ident[EI.CLASS] = @intFromEnum(class); | 737 | ehdr.ident[EI.CLASS] = @intFromEnum(class); |
| ... | @@ -602,37 +757,47 @@ fn initHeaders( | ... | @@ -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, .{ | 760 | assert(elf.ni.shdr == try elf.mf.addLastChildNode(gpa, elf.ni.file, .{ |
| 606 | .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum), | 761 | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), |
| 607 | .alignment = addr_align, | 762 | .alignment = addr_align, |
| 608 | .moved = true, | 763 | .moved = true, |
| 609 | .resized = true, | 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 | .bubbles_moved = false, | 771 | .bubbles_moved = false, |
| 611 | })); | 772 | })); |
| 612 | elf.nodes.appendAssumeCapacity(.{ .segment = phdr_phndx }); | 773 | elf.nodes.appendAssumeCapacity(.{ .segment = rodata_phndx }); |
| 613 | elf.phdrs.items[phdr_phndx] = Node.Known.phdr; | 774 | elf.phdrs.items[rodata_phndx] = elf.ni.rodata; |
| 614 | | 775 | |
| 615 | assert(Node.Known.shdr == try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ | 776 | assert(elf.ni.phdr == try elf.mf.addOnlyChildNode(gpa, elf.ni.rodata, .{ |
| 616 | .size = elf.ehdrField(.shentsize) * elf.ehdrField(.shnum), | 777 | .size = elf.ehdrField(.phentsize) * elf.ehdrField(.phnum), |
| 617 | .alignment = addr_align, | 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 | .alignment = elf.mf.flags.block_size, | 787 | .alignment = elf.mf.flags.block_size, |
| 623 | .moved = true, | 788 | .moved = true, |
| 624 | .bubbles_moved = false, | 789 | .bubbles_moved = false, |
| 625 | })); | 790 | })); |
| 626 | elf.nodes.appendAssumeCapacity(.{ .segment = text_phndx }); | 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 | .alignment = elf.mf.flags.block_size, | 795 | .alignment = elf.mf.flags.block_size, |
| 631 | .moved = true, | 796 | .moved = true, |
| 632 | .bubbles_moved = false, | 797 | .bubbles_moved = false, |
| 633 | })); | 798 | })); |
| 634 | elf.nodes.appendAssumeCapacity(.{ .segment = data_phndx }); | 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 | var ph_vaddr: u32 = switch (elf.ehdrField(.type)) { | 802 | var ph_vaddr: u32 = switch (elf.ehdrField(.type)) { |
| 638 | else => 0, | 803 | else => 0, |
| ... | @@ -648,14 +813,10 @@ fn initHeaders( | ... | @@ -648,14 +813,10 @@ fn initHeaders( |
| 648 | switch (class) { | 813 | switch (class) { |
| 649 | .NONE, _ => unreachable, | 814 | .NONE, _ => unreachable, |
| 650 | inline else => |ct_class| { | 815 | inline else => |ct_class| { |
| 651 | const ElfN = switch (ct_class) { | 816 | const ElfN = ct_class.ElfN(); |
| 652 | .NONE, _ => comptime unreachable, | | |
| 653 | .@"32" => std.elf.Elf32, | | |
| 654 | .@"64" => std.elf.Elf64, | | |
| 655 | }; | | |
| 656 | const target_endian = elf.targetEndian(); | 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 | const ph_phdr = &phdr[phdr_phndx]; | 820 | const ph_phdr = &phdr[phdr_phndx]; |
| 660 | ph_phdr.* = .{ | 821 | ph_phdr.* = .{ |
| 661 | .type = std.elf.PT_PHDR, | 822 | .type = std.elf.PT_PHDR, |
| ... | @@ -665,7 +826,7 @@ fn initHeaders( | ... | @@ -665,7 +826,7 @@ fn initHeaders( |
| 665 | .filesz = 0, | 826 | .filesz = 0, |
| 666 | .memsz = 0, | 827 | .memsz = 0, |
| 667 | .flags = .{ .R = true }, | 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 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); | 831 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_phdr); |
| 671 | | 832 | |
| ... | @@ -684,7 +845,7 @@ fn initHeaders( | ... | @@ -684,7 +845,7 @@ fn initHeaders( |
| 684 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_interp); | 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 | const ph_rodata = &phdr[rodata_phndx]; | 849 | const ph_rodata = &phdr[rodata_phndx]; |
| 689 | ph_rodata.* = .{ | 850 | ph_rodata.* = .{ |
| 690 | .type = std.elf.PT_NULL, | 851 | .type = std.elf.PT_NULL, |
| ... | @@ -694,12 +855,12 @@ fn initHeaders( | ... | @@ -694,12 +855,12 @@ fn initHeaders( |
| 694 | .filesz = @intCast(rodata_size), | 855 | .filesz = @intCast(rodata_size), |
| 695 | .memsz = @intCast(rodata_size), | 856 | .memsz = @intCast(rodata_size), |
| 696 | .flags = .{ .R = true }, | 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 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); | 860 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_rodata); |
| 700 | ph_vaddr += @intCast(rodata_size); | 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 | const ph_text = &phdr[text_phndx]; | 864 | const ph_text = &phdr[text_phndx]; |
| 704 | ph_text.* = .{ | 865 | ph_text.* = .{ |
| 705 | .type = std.elf.PT_NULL, | 866 | .type = std.elf.PT_NULL, |
| ... | @@ -709,12 +870,12 @@ fn initHeaders( | ... | @@ -709,12 +870,12 @@ fn initHeaders( |
| 709 | .filesz = @intCast(text_size), | 870 | .filesz = @intCast(text_size), |
| 710 | .memsz = @intCast(text_size), | 871 | .memsz = @intCast(text_size), |
| 711 | .flags = .{ .R = true, .X = true }, | 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 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); | 875 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_text); |
| 715 | ph_vaddr += @intCast(text_size); | 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 | const ph_data = &phdr[data_phndx]; | 879 | const ph_data = &phdr[data_phndx]; |
| 719 | ph_data.* = .{ | 880 | ph_data.* = .{ |
| 720 | .type = std.elf.PT_NULL, | 881 | .type = std.elf.PT_NULL, |
| ... | @@ -724,11 +885,26 @@ fn initHeaders( | ... | @@ -724,11 +885,26 @@ fn initHeaders( |
| 724 | .filesz = @intCast(data_size), | 885 | .filesz = @intCast(data_size), |
| 725 | .memsz = @intCast(data_size), | 886 | .memsz = @intCast(data_size), |
| 726 | .flags = .{ .R = true, .W = true }, | 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 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); | 890 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_data); |
| 730 | ph_vaddr += @intCast(data_size); | 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 | if (comp.config.any_non_single_threaded) { | 908 | if (comp.config.any_non_single_threaded) { |
| 733 | const ph_tls = &phdr[tls_phndx]; | 909 | const ph_tls = &phdr[tls_phndx]; |
| 734 | ph_tls.* = .{ | 910 | ph_tls.* = .{ |
| ... | @@ -744,7 +920,7 @@ fn initHeaders( | ... | @@ -744,7 +920,7 @@ fn initHeaders( |
| 744 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Phdr, ph_tls); | 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 | sh_null.* = .{ | 924 | sh_null.* = .{ |
| 749 | .name = try elf.string(.shstrtab, ""), | 925 | .name = try elf.string(.shstrtab, ""), |
| 750 | .type = std.elf.SHT_NULL, | 926 | .type = std.elf.SHT_NULL, |
| ... | @@ -766,114 +942,187 @@ fn initHeaders( | ... | @@ -766,114 +942,187 @@ fn initHeaders( |
| 766 | .target_relocs = .none, | 942 | .target_relocs = .none, |
| 767 | .unused = 0, | 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 | .type = std.elf.SHT_SYMTAB, | 946 | .type = std.elf.SHT_SYMTAB, |
| | 947 | .size = @sizeOf(ElfN.Sym) * 1, |
| 771 | .addralign = addr_align, | 948 | .addralign = addr_align, |
| 772 | .entsize = @sizeOf(ElfN.Sym), | 949 | .entsize = @sizeOf(ElfN.Sym), |
| 773 | }) == .symtab); | 950 | })); |
| 774 | | 951 | const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class)); |
| 775 | const symtab: *ElfN.Sym = @ptrCast(@alignCast(Symbol.Index.symtab.node(elf).slice(&elf.mf))); | 952 | symtab_null.* = .{ |
| 776 | symtab.* = .{ | | |
| 777 | .name = try elf.string(.strtab, ""), | 953 | .name = try elf.string(.strtab, ""), |
| 778 | .value = 0, | 954 | .value = 0, |
| 779 | .size = 0, | 955 | .size = 0, |
| 780 | .info = .{ | 956 | .info = .{ .type = .NOTYPE, .bind = .LOCAL }, |
| 781 | .type = .NOTYPE, | 957 | .other = .{ .visibility = .DEFAULT }, |
| 782 | .bind = .LOCAL, | | |
| 783 | }, | | |
| 784 | .other = .{ | | |
| 785 | .visibility = .DEFAULT, | | |
| 786 | }, | | |
| 787 | .shndx = std.elf.SHN_UNDEF, | 958 | .shndx = std.elf.SHN_UNDEF, |
| 788 | }; | 959 | }; |
| | 960 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null); |
| 789 | | 961 | |
| 790 | const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class)); | 962 | const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class)); |
| 791 | ehdr.shstrndx = ehdr.shnum; | 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 | .type = std.elf.SHT_STRTAB, | 967 | .type = std.elf.SHT_STRTAB, |
| 796 | .addralign = elf.mf.flags.block_size, | 968 | .addralign = elf.mf.flags.block_size, |
| 797 | .entsize = 1, | 969 | .entsize = 1, |
| 798 | }) == .shstrtab); | 970 | })); |
| 799 | assert(try elf.addSection(Node.Known.rodata, .{ | 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 | .type = std.elf.SHT_STRTAB, | 977 | .type = std.elf.SHT_STRTAB, |
| | 978 | .size = 1, |
| 801 | .addralign = elf.mf.flags.block_size, | 979 | .addralign = elf.mf.flags.block_size, |
| 802 | .entsize = 1, | 980 | .entsize = 1, |
| 803 | }) == .strtab); | 981 | })); |
| 804 | try elf.renameSection(.symtab, ".symtab"); | | |
| 805 | try elf.renameSection(.shstrtab, ".shstrtab"); | | |
| 806 | try elf.renameSection(.strtab, ".strtab"); | | |
| 807 | try elf.linkSections(.symtab, .strtab); | 982 | try elf.linkSections(.symtab, .strtab); |
| 808 | Symbol.Index.shstrtab.node(elf).slice(&elf.mf)[0] = 0; | 983 | elf.si.strtab.node(elf).slice(&elf.mf)[0] = 0; |
| 809 | Symbol.Index.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 | .name = ".rodata", | 986 | .name = ".rodata", |
| 813 | .flags = .{ .ALLOC = true }, | 987 | .flags = .{ .ALLOC = true }, |
| 814 | .addralign = elf.mf.flags.block_size, | 988 | .addralign = elf.mf.flags.block_size, |
| 815 | }) == .rodata); | 989 | })); |
| 816 | assert(try elf.addSection(Node.Known.text, .{ | 990 | assert(elf.si.text == try elf.addSection(elf.ni.text, .{ |
| 817 | .name = ".text", | 991 | .name = ".text", |
| 818 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, | 992 | .flags = .{ .ALLOC = true, .EXECINSTR = true }, |
| 819 | .addralign = elf.mf.flags.block_size, | 993 | .addralign = elf.mf.flags.block_size, |
| 820 | }) == .text); | 994 | })); |
| 821 | assert(try elf.addSection(Node.Known.data, .{ | 995 | assert(elf.si.data == try elf.addSection(elf.ni.data, .{ |
| 822 | .name = ".data", | 996 | .name = ".data", |
| 823 | .flags = .{ .WRITE = true, .ALLOC = true }, | 997 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 824 | .addralign = elf.mf.flags.block_size, | 998 | .addralign = elf.mf.flags.block_size, |
| 825 | }) == .data); | 999 | })); |
| 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 | } | | |
| 841 | if (maybe_interp) |interp| { | 1000 | if (maybe_interp) |interp| { |
| 842 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 1001 | const interp_ni = try elf.mf.addLastChildNode(gpa, elf.ni.rodata, .{ |
| 843 | const interp_ni = try elf.mf.addLastChildNode(gpa, Node.Known.rodata, .{ | | |
| 844 | .size = interp.len + 1, | 1002 | .size = interp.len + 1, |
| 845 | .moved = true, | 1003 | .moved = true, |
| 846 | .resized = true, | 1004 | .resized = true, |
| | 1005 | .bubbles_moved = false, |
| 847 | }); | 1006 | }); |
| 848 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); | 1007 | elf.nodes.appendAssumeCapacity(.{ .segment = interp_phndx }); |
| 849 | elf.phdrs.items[interp_phndx] = interp_ni; | 1008 | elf.phdrs.items[interp_phndx] = interp_ni; |
| 850 | | 1009 | |
| 851 | const sec_interp_si = try elf.addSection(interp_ni, .{ | 1010 | const sec_interp_si = try elf.addSection(interp_ni, .{ |
| 852 | .name = ".interp", | 1011 | .name = ".interp", |
| 853 | .size = @intCast(interp.len + 1), | | |
| 854 | .flags = .{ .ALLOC = true }, | 1012 | .flags = .{ .ALLOC = true }, |
| | 1013 | .size = @intCast(interp.len + 1), |
| 855 | }); | 1014 | }); |
| 856 | const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); | 1015 | const sec_interp = sec_interp_si.node(elf).slice(&elf.mf); |
| 857 | @memcpy(sec_interp[0..interp.len], interp); | 1016 | @memcpy(sec_interp[0..interp.len], interp); |
| 858 | sec_interp[interp.len] = 0; | 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 | assert(elf.nodes.len == expected_nodes_len); | 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 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { | 1110 | fn getNode(elf: *const Elf, ni: MappedFile.Node.Index) Node { |
| 864 | return elf.nodes.get(@intFromEnum(ni)); | 1111 | return elf.nodes.get(@intFromEnum(ni)); |
| 865 | } | 1112 | } |
| 866 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { | 1113 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 867 | const parent_vaddr = parent_vaddr: { | 1114 | const parent_vaddr = parent_vaddr: { |
| 868 | const parent_si = switch (elf.getNode(ni.parent(&elf.mf))) { | 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 | .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) { | 1118 | .segment => |phndx| break :parent_vaddr switch (elf.phdrSlice()) { |
| 871 | inline else => |ph| elf.targetLoad(&ph[phndx].vaddr), | 1119 | inline else => |ph| elf.targetLoad(&ph[phndx].vaddr), |
| 872 | }, | 1120 | }, |
| 873 | .section => |si| si, | 1121 | .section => |si| si, |
| | 1122 | .input_section => unreachable, |
| 874 | inline .nav, .uav, .lazy_code, .lazy_const_data => |mi| mi.symbol(elf), | 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 | inline else => |sym| elf.targetLoad(&sym.value), | 1126 | inline else => |sym| elf.targetLoad(&sym.value), |
| 878 | }; | 1127 | }; |
| 879 | }; | 1128 | }; |
| ... | @@ -928,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) { | ... | @@ -928,7 +1177,7 @@ pub const EhdrPtr = union(std.elf.CLASS) { |
| 928 | @"64": *std.elf.Elf64.Ehdr, | 1177 | @"64": *std.elf.Elf64.Ehdr, |
| 929 | }; | 1178 | }; |
| 930 | pub fn ehdrPtr(elf: *Elf) EhdrPtr { | 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 | return switch (elf.identClass()) { | 1181 | return switch (elf.identClass()) { |
| 933 | .NONE, _ => unreachable, | 1182 | .NONE, _ => unreachable, |
| 934 | inline else => |class| @unionInit( | 1183 | inline else => |class| @unionInit( |
| ... | @@ -953,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) { | ... | @@ -953,7 +1202,7 @@ pub const PhdrSlice = union(std.elf.CLASS) { |
| 953 | @"64": []std.elf.Elf64.Phdr, | 1202 | @"64": []std.elf.Elf64.Phdr, |
| 954 | }; | 1203 | }; |
| 955 | pub fn phdrSlice(elf: *Elf) PhdrSlice { | 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 | return switch (elf.identClass()) { | 1206 | return switch (elf.identClass()) { |
| 958 | .NONE, _ => unreachable, | 1207 | .NONE, _ => unreachable, |
| 959 | inline else => |class| @unionInit( | 1208 | inline else => |class| @unionInit( |
| ... | @@ -970,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) { | ... | @@ -970,7 +1219,7 @@ pub const ShdrSlice = union(std.elf.CLASS) { |
| 970 | @"64": []std.elf.Elf64.Shdr, | 1219 | @"64": []std.elf.Elf64.Shdr, |
| 971 | }; | 1220 | }; |
| 972 | pub fn shdrSlice(elf: *Elf) ShdrSlice { | 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 | return switch (elf.identClass()) { | 1223 | return switch (elf.identClass()) { |
| 975 | .NONE, _ => unreachable, | 1224 | .NONE, _ => unreachable, |
| 976 | inline else => |class| @unionInit( | 1225 | inline else => |class| @unionInit( |
| ... | @@ -987,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) { | ... | @@ -987,7 +1236,7 @@ pub const SymtabSlice = union(std.elf.CLASS) { |
| 987 | @"64": []std.elf.Elf64.Sym, | 1236 | @"64": []std.elf.Elf64.Sym, |
| 988 | }; | 1237 | }; |
| 989 | pub fn symtabSlice(elf: *Elf) SymtabSlice { | 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 | return switch (elf.identClass()) { | 1240 | return switch (elf.identClass()) { |
| 992 | .NONE, _ => unreachable, | 1241 | .NONE, _ => unreachable, |
| 993 | inline else => |class| @unionInit( | 1242 | inline else => |class| @unionInit( |
| ... | @@ -1009,6 +1258,18 @@ pub fn symPtr(elf: *Elf, si: Symbol.Index) SymPtr { | ... | @@ -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 | fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index { | 1273 | fn addSymbolAssumeCapacity(elf: *Elf) Symbol.Index { |
| 1013 | defer elf.symtab.addOneAssumeCapacity().* = .{ | 1274 | defer elf.symtab.addOneAssumeCapacity().* = .{ |
| 1014 | .ni = .none, | 1275 | .ni = .none, |
| ... | @@ -1027,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I | ... | @@ -1027,6 +1288,7 @@ fn initSymbolAssumeCapacity(elf: *Elf, opts: Symbol.Index.InitOptions) !Symbol.I |
| 1027 | | 1288 | |
| 1028 | pub fn globalSymbol(elf: *Elf, opts: struct { | 1289 | pub fn globalSymbol(elf: *Elf, opts: struct { |
| 1029 | name: []const u8, | 1290 | name: []const u8, |
| | 1291 | lib_name: ?[]const u8 = null, |
| 1030 | type: std.elf.STT, | 1292 | type: std.elf.STT, |
| 1031 | bind: std.elf.STB = .GLOBAL, | 1293 | bind: std.elf.STB = .GLOBAL, |
| 1032 | visibility: std.elf.STV = .DEFAULT, | 1294 | visibility: std.elf.STV = .DEFAULT, |
| ... | @@ -1036,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct { | ... | @@ -1036,6 +1298,7 @@ pub fn globalSymbol(elf: *Elf, opts: struct { |
| 1036 | const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); | 1298 | const global_gop = try elf.globals.getOrPut(gpa, try elf.string(.strtab, opts.name)); |
| 1037 | if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ | 1299 | if (!global_gop.found_existing) global_gop.value_ptr.* = try elf.initSymbolAssumeCapacity(.{ |
| 1038 | .name = opts.name, | 1300 | .name = opts.name, |
| | 1301 | .lib_name = opts.lib_name, |
| 1039 | .type = opts.type, | 1302 | .type = opts.type, |
| 1040 | .bind = opts.bind, | 1303 | .bind = opts.bind, |
| 1041 | .visibility = opts.visibility, | 1304 | .visibility = opts.visibility, |
| ... | @@ -1072,30 +1335,33 @@ fn navType( | ... | @@ -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 | fn navSection( | 1349 | fn navSection( |
| 1076 | elf: *Elf, | 1350 | elf: *Elf, |
| 1077 | ip: *const InternPool, | 1351 | ip: *const InternPool, |
| 1078 | nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"), | 1352 | nav_fr: @FieldType(@FieldType(InternPool.Nav, "status"), "fully_resolved"), |
| 1079 | ) Symbol.Index { | 1353 | ) Symbol.Index { |
| 1080 | if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| { | 1354 | if (nav_fr.@"linksection".toSlice(ip)) |@"linksection"| |
| 1081 | if (std.mem.eql(u8, @"linksection", ".rodata") or | 1355 | if (elf.namedSection(@"linksection")) |si| return si; |
| 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 | } | | |
| 1090 | return switch (navType( | 1356 | return switch (navType( |
| 1091 | ip, | 1357 | ip, |
| 1092 | .{ .fully_resolved = nav_fr }, | 1358 | .{ .fully_resolved = nav_fr }, |
| 1093 | elf.base.comp.config.any_non_single_threaded, | 1359 | elf.base.comp.config.any_non_single_threaded, |
| 1094 | )) { | 1360 | )) { |
| 1095 | else => unreachable, | 1361 | else => unreachable, |
| 1096 | .FUNC => .text, | 1362 | .FUNC => elf.si.text, |
| 1097 | .OBJECT => .data, | 1363 | .OBJECT => elf.si.data, |
| 1098 | .TLS => .tdata, | 1364 | .TLS => elf.si.tdata, |
| 1099 | }; | 1365 | }; |
| 1100 | } | 1366 | } |
| 1101 | fn navMapIndex(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Node.NavMapIndex { | 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,6 +1381,7 @@ pub fn navSymbol(elf: *Elf, zcu: *Zcu, nav_index: InternPool.Nav.Index) !Symbol. |
| 1115 | const nav = ip.getNav(nav_index); | 1381 | const nav = ip.getNav(nav_index); |
| 1116 | if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ | 1382 | if (nav.getExtern(ip)) |@"extern"| return elf.globalSymbol(.{ |
| 1117 | .name = @"extern".name.toSlice(ip), | 1383 | .name = @"extern".name.toSlice(ip), |
| | 1384 | .lib_name = @"extern".lib_name.toSlice(ip), |
| 1118 | .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), | 1385 | .type = navType(ip, nav.status, elf.base.comp.config.any_non_single_threaded), |
| 1119 | .bind = switch (@"extern".linkage) { | 1386 | .bind = switch (@"extern".linkage) { |
| 1120 | .internal => .LOCAL, | 1387 | .internal => .LOCAL, |
| ... | @@ -1156,11 +1423,523 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { | ... | @@ -1156,11 +1423,523 @@ pub fn lazySymbol(elf: *Elf, lazy: link.File.LazySymbol) !Symbol.Index { |
| 1156 | .const_data => .OBJECT, | 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 | return lazy_gop.value_ptr.*; | 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 | pub fn getNavVAddr( | 1943 | pub fn getNavVAddr( |
| 1165 | elf: *Elf, | 1944 | elf: *Elf, |
| 1166 | pt: Zcu.PerThread, | 1945 | pt: Zcu.PerThread, |
| ... | @@ -1184,14 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In | ... | @@ -1184,14 +1963,7 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In |
| 1184 | reloc_info.offset, | 1963 | reloc_info.offset, |
| 1185 | target_si, | 1964 | target_si, |
| 1186 | reloc_info.addend, | 1965 | reloc_info.addend, |
| 1187 | switch (elf.ehdrField(.machine)) { | 1966 | .absAddr(elf), |
| 1188 | else => unreachable, | | |
| 1189 | .X86_64 => .{ .X86_64 = switch (elf.identClass()) { | | |
| 1190 | .NONE, _ => unreachable, | | |
| 1191 | .@"32" => .@"32", | | |
| 1192 | .@"64" => .@"64", | | |
| 1193 | } }, | | |
| 1194 | }, | | |
| 1195 | ); | 1967 | ); |
| 1196 | return switch (elf.symPtr(target_si)) { | 1968 | return switch (elf.symPtr(target_si)) { |
| 1197 | inline else => |sym| elf.targetLoad(&sym.value), | 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,11 +1973,16 @@ pub fn getVAddr(elf: *Elf, reloc_info: link.File.RelocInfo, target_si: Symbol.In |
| 1201 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | 1973 | fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1202 | name: []const u8 = "", | 1974 | name: []const u8 = "", |
| 1203 | type: std.elf.Word = std.elf.SHT_NULL, | 1975 | type: std.elf.Word = std.elf.SHT_NULL, |
| 1204 | size: std.elf.Word = 0, | | |
| 1205 | flags: std.elf.SHF = .{}, | 1976 | flags: std.elf.SHF = .{}, |
| | 1977 | size: std.elf.Word = 0, |
| 1206 | addralign: std.mem.Alignment = .@"1", | 1978 | addralign: std.mem.Alignment = .@"1", |
| 1207 | entsize: std.elf.Word = 0, | 1979 | entsize: std.elf.Word = 0, |
| 1208 | }) !Symbol.Index { | 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 | const gpa = elf.base.comp.gpa; | 1986 | const gpa = elf.base.comp.gpa; |
| 1210 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 1987 | try elf.nodes.ensureUnusedCapacity(gpa, 1); |
| 1211 | try elf.symtab.ensureUnusedCapacity(gpa, 1); | 1988 | try elf.symtab.ensureUnusedCapacity(gpa, 1); |
| ... | @@ -1219,17 +1996,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -1219,17 +1996,19 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1219 | break :shndx .{ shndx, elf.targetLoad(&ehdr.shentsize) * shnum }; | 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 | const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{ | 2000 | const ni = try elf.mf.addLastChildNode(gpa, segment_ni, .{ |
| 1224 | .alignment = opts.addralign, | 2001 | .alignment = opts.addralign, |
| 1225 | .size = opts.size, | 2002 | .size = opts.size, |
| 1226 | .moved = true, | 2003 | .resized = opts.size > 0, |
| 1227 | }); | 2004 | }); |
| 1228 | const si = elf.addSymbolAssumeCapacity(); | 2005 | const si = elf.addSymbolAssumeCapacity(); |
| 1229 | elf.nodes.appendAssumeCapacity(.{ .section = si }); | 2006 | elf.nodes.appendAssumeCapacity(.{ .section = si }); |
| 1230 | si.get(elf).ni = ni; | 2007 | si.get(elf).ni = ni; |
| | 2008 | const addr = elf.computeNodeVAddr(ni); |
| | 2009 | const offset = ni.fileLocation(&elf.mf, false).offset; |
| 1231 | try si.init(elf, .{ | 2010 | try si.init(elf, .{ |
| 1232 | .name = opts.name, | 2011 | .value = addr, |
| 1233 | .size = opts.size, | 2012 | .size = opts.size, |
| 1234 | .type = .SECTION, | 2013 | .type = .SECTION, |
| 1235 | .shndx = shndx, | 2014 | .shndx = shndx, |
| ... | @@ -1241,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -1241,8 +2020,8 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1241 | .name = shstrtab_entry, | 2020 | .name = shstrtab_entry, |
| 1242 | .type = opts.type, | 2021 | .type = opts.type, |
| 1243 | .flags = .{ .shf = opts.flags }, | 2022 | .flags = .{ .shf = opts.flags }, |
| 1244 | .addr = 0, | 2023 | .addr = @intCast(addr), |
| 1245 | .offset = 0, | 2024 | .offset = @intCast(offset), |
| 1246 | .size = opts.size, | 2025 | .size = opts.size, |
| 1247 | .link = 0, | 2026 | .link = 0, |
| 1248 | .info = 0, | 2027 | .info = 0, |
| ... | @@ -1256,15 +2035,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { | ... | @@ -1256,15 +2035,12 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 1256 | } | 2035 | } |
| 1257 | | 2036 | |
| 1258 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { | 2037 | fn renameSection(elf: *Elf, si: Symbol.Index, name: []const u8) !void { |
| 1259 | const strtab_entry = try elf.string(.strtab, name); | | |
| 1260 | const shstrtab_entry = try elf.string(.shstrtab, name); | 2038 | const shstrtab_entry = try elf.string(.shstrtab, name); |
| 1261 | switch (elf.shdrSlice()) { | 2039 | switch (elf.shdrSlice()) { |
| 1262 | inline else => |shdr, class| { | 2040 | inline else => |shdr, class| elf.targetStore( |
| 1263 | const sym = @field(elf.symPtr(si), @tagName(class)); | 2041 | &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name, |
| 1264 | elf.targetStore(&sym.name, strtab_entry); | 2042 | shstrtab_entry, |
| 1265 | const sh = &shdr[elf.targetLoad(&sym.shndx)]; | 2043 | ), |
| 1266 | elf.targetStore(&sh.name, shstrtab_entry); | | |
| 1267 | }, | | |
| 1268 | } | 2044 | } |
| 1269 | } | 2045 | } |
| 1270 | | 2046 | |
| ... | @@ -1277,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { | ... | @@ -1277,7 +2053,7 @@ fn linkSections(elf: *Elf, si: Symbol.Index, link_si: Symbol.Index) !void { |
| 1277 | } | 2053 | } |
| 1278 | | 2054 | |
| 1279 | fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { | 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 | inline else => |shndx, class| elf.targetLoad( | 2057 | inline else => |shndx, class| elf.targetLoad( |
| 1282 | &shndx[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].name, | 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,12 +2061,12 @@ fn sectionName(elf: *Elf, si: Symbol.Index) [:0]const u8 { |
| 1285 | return name[0..std.mem.indexOfScalar(u8, name, 0).? :0]; | 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 | if (key.len == 0) return 0; | 2065 | if (key.len == 0) return 0; |
| 1290 | return @field(elf, @tagName(section)).get( | 2066 | return @field(elf, @tagName(section)).get( |
| 1291 | elf.base.comp.gpa, | 2067 | elf.base.comp.gpa, |
| 1292 | &elf.mf, | 2068 | &elf.mf, |
| 1293 | @field(Symbol.Index, @tagName(section)).node(elf), | 2069 | @field(elf.si, @tagName(section)).node(elf), |
| 1294 | key, | 2070 | key, |
| 1295 | ); | 2071 | ); |
| 1296 | } | 2072 | } |
| ... | @@ -1303,10 +2079,20 @@ pub fn addReloc( | ... | @@ -1303,10 +2079,20 @@ pub fn addReloc( |
| 1303 | addend: i64, | 2079 | addend: i64, |
| 1304 | @"type": Reloc.Type, | 2080 | @"type": Reloc.Type, |
| 1305 | ) !void { | 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 | const target = target_si.get(elf); | 2093 | const target = target_si.get(elf); |
| 1308 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); | 2094 | const ri: Reloc.Index = @enumFromInt(elf.relocs.items.len); |
| 1309 | (try elf.relocs.addOne(gpa)).* = .{ | 2095 | elf.relocs.addOneAssumeCapacity().* = .{ |
| 1310 | .type = @"type", | 2096 | .type = @"type", |
| 1311 | .prev = .none, | 2097 | .prev = .none, |
| 1312 | .next = target.target_relocs, | 2098 | .next = target.target_relocs, |
| ... | @@ -1323,11 +2109,6 @@ pub fn addReloc( | ... | @@ -1323,11 +2109,6 @@ pub fn addReloc( |
| 1323 | target.target_relocs = ri; | 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 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { | 2112 | pub fn updateNav(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) !void { |
| 1332 | elf.updateNavInner(pt, nav_index) catch |err| switch (err) { | 2113 | elf.updateNavInner(pt, nav_index) catch |err| switch (err) { |
| 1333 | error.OutOfMemory, | 2114 | error.OutOfMemory, |
| ... | @@ -1430,7 +2211,7 @@ pub fn lowerUav( | ... | @@ -1430,7 +2211,7 @@ pub fn lowerUav( |
| 1430 | .alignment = uav_align, | 2211 | .alignment = uav_align, |
| 1431 | .src_loc = src_loc, | 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 | return .{ .sym_index = @intFromEnum(si) }; | 2217 | return .{ .sym_index = @intFromEnum(si) }; |
| ... | @@ -1534,7 +2315,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { | ... | @@ -1534,7 +2315,7 @@ pub fn updateErrorData(elf: *Elf, pt: Zcu.PerThread) !void { |
| 1534 | }) catch |err| switch (err) { | 2315 | }) catch |err| switch (err) { |
| 1535 | error.OutOfMemory => return error.OutOfMemory, | 2316 | error.OutOfMemory => return error.OutOfMemory, |
| 1536 | error.CodegenFail => return error.LinkFailure, | 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,20 +2334,16 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1553 | const comp = elf.base.comp; | 2334 | const comp = elf.base.comp; |
| 1554 | task: { | 2335 | task: { |
| 1555 | while (elf.pending_uavs.pop()) |pending_uav| { | 2336 | while (elf.pending_uavs.pop()) |pending_uav| { |
| 1556 | const sub_prog_node = elf.idleProgNode( | 2337 | const sub_prog_node = elf.idleProgNode(tid, elf.const_prog_node, .{ .uav = pending_uav.key }); |
| 1557 | tid, | | |
| 1558 | comp.link_const_prog_node, | | |
| 1559 | .{ .uav = pending_uav.key }, | | |
| 1560 | ); | | |
| 1561 | defer sub_prog_node.end(); | 2338 | defer sub_prog_node.end(); |
| 1562 | elf.flushUav( | 2339 | elf.flushUav( |
| 1563 | .{ .zcu = elf.base.comp.zcu.?, .tid = tid }, | 2340 | .{ .zcu = comp.zcu.?, .tid = tid }, |
| 1564 | pending_uav.key, | 2341 | pending_uav.key, |
| 1565 | pending_uav.value.alignment, | 2342 | pending_uav.value.alignment, |
| 1566 | pending_uav.value.src_loc, | 2343 | pending_uav.value.src_loc, |
| 1567 | ) catch |err| switch (err) { | 2344 | ) catch |err| switch (err) { |
| 1568 | error.OutOfMemory => return error.OutOfMemory, | 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 | "linker failed to lower constant: {t}", | 2347 | "linker failed to lower constant: {t}", |
| 1571 | .{e}, | 2348 | .{e}, |
| 1572 | ), | 2349 | ), |
| ... | @@ -1575,7 +2352,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -1575,7 +2352,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1575 | } | 2352 | } |
| 1576 | var lazy_it = elf.lazy.iterator(); | 2353 | var lazy_it = elf.lazy.iterator(); |
| 1577 | while (lazy_it.next()) |lazy| if (lazy.value.pending_index < lazy.value.map.count()) { | 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 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; | 2356 | const lmr: Node.LazyMapRef = .{ .kind = lazy.key, .index = lazy.value.pending_index }; |
| 1580 | lazy.value.pending_index += 1; | 2357 | lazy.value.pending_index += 1; |
| 1581 | const kind = switch (lmr.kind) { | 2358 | const kind = switch (lmr.kind) { |
| ... | @@ -1583,7 +2360,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -1583,7 +2360,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1583 | .const_data => "data", | 2360 | .const_data => "data", |
| 1584 | }; | 2361 | }; |
| 1585 | var name: [std.Progress.Node.max_name_len]u8 = undefined; | 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 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ | 2364 | std.fmt.bufPrint(&name, "lazy {s} for {f}", .{ |
| 1588 | kind, | 2365 | kind, |
| 1589 | Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt), | 2366 | Type.fromInterned(lmr.lazySymbol(elf).ty).fmt(pt), |
| ... | @@ -1593,13 +2370,36 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -1593,13 +2370,36 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1593 | defer sub_prog_node.end(); | 2370 | defer sub_prog_node.end(); |
| 1594 | elf.flushLazy(pt, lmr) catch |err| switch (err) { | 2371 | elf.flushLazy(pt, lmr) catch |err| switch (err) { |
| 1595 | error.OutOfMemory => return error.OutOfMemory, | 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 | "linker failed to lower lazy {s}: {t}", | 2374 | "linker failed to lower lazy {s}: {t}", |
| 1598 | .{ kind, e }, | 2375 | .{ kind, e }, |
| 1599 | ), | 2376 | ), |
| 1600 | }; | 2377 | }; |
| 1601 | break :task; | 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 | while (elf.mf.updates.pop()) |ni| { | 2403 | while (elf.mf.updates.pop()) |ni| { |
| 1604 | const clean_moved = ni.cleanMoved(&elf.mf); | 2404 | const clean_moved = ni.cleanMoved(&elf.mf); |
| 1605 | const clean_resized = ni.cleanResized(&elf.mf); | 2405 | const clean_resized = ni.cleanResized(&elf.mf); |
| ... | @@ -1614,6 +2414,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { | ... | @@ -1614,6 +2414,7 @@ pub fn idle(elf: *Elf, tid: Zcu.PerThread.Id) !bool { |
| 1614 | } | 2414 | } |
| 1615 | if (elf.pending_uavs.count() > 0) return true; | 2415 | if (elf.pending_uavs.count() > 0) return true; |
| 1616 | for (&elf.lazy.values) |lazy| if (lazy.map.count() > lazy.pending_index) return true; | 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 | if (elf.mf.updates.items.len > 0) return true; | 2418 | if (elf.mf.updates.items.len > 0) return true; |
| 1618 | return false; | 2419 | return false; |
| 1619 | } | 2420 | } |
| ... | @@ -1628,6 +2429,14 @@ fn idleProgNode( | ... | @@ -1628,6 +2429,14 @@ fn idleProgNode( |
| 1628 | return prog_node.start(name: switch (node) { | 2429 | return prog_node.start(name: switch (node) { |
| 1629 | else => |tag| @tagName(tag), | 2430 | else => |tag| @tagName(tag), |
| 1630 | .section => |si| elf.sectionName(si), | 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 | .nav => |nmi| { | 2440 | .nav => |nmi| { |
| 1632 | const ip = &elf.base.comp.zcu.?.intern_pool; | 2441 | const ip = &elf.base.comp.zcu.?.intern_pool; |
| 1633 | break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip); | 2442 | break :name ip.getNav(nmi.navIndex(elf)).fqn.toSlice(ip); |
| ... | @@ -1655,7 +2464,7 @@ fn flushUav( | ... | @@ -1655,7 +2464,7 @@ fn flushUav( |
| 1655 | switch (sym.ni) { | 2464 | switch (sym.ni) { |
| 1656 | .none => { | 2465 | .none => { |
| 1657 | try elf.nodes.ensureUnusedCapacity(gpa, 1); | 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 | .alignment = uav_align.toStdMem(), | 2468 | .alignment = uav_align.toStdMem(), |
| 1660 | .moved = true, | 2469 | .moved = true, |
| 1661 | }); | 2470 | }); |
| ... | @@ -1749,9 +2558,27 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { | ... | @@ -1749,9 +2558,27 @@ fn flushLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) !void { |
| 1749 | si.applyLocationRelocs(elf); | 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 | switch (elf.getNode(ni)) { | 2580 | switch (elf.getNode(ni)) { |
| 1754 | .file => unreachable, | 2581 | else => unreachable, |
| 1755 | .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0), | 2582 | .ehdr => assert(ni.fileLocation(&elf.mf, false).offset == 0), |
| 1756 | .shdr => switch (elf.ehdrPtr()) { | 2583 | .shdr => switch (elf.ehdrPtr()) { |
| 1757 | inline else => |ehdr| elf.targetStore( | 2584 | inline else => |ehdr| elf.targetStore( |
| ... | @@ -1759,34 +2586,84 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { | ... | @@ -1759,34 +2586,84 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1759 | @intCast(ni.fileLocation(&elf.mf, false).offset), | 2586 | @intCast(ni.fileLocation(&elf.mf, false).offset), |
| 1760 | ), | 2587 | ), |
| 1761 | }, | 2588 | }, |
| 1762 | .segment => |phndx| switch (elf.phdrSlice()) { | 2589 | .segment => |phndx| { |
| 1763 | inline else => |phdr, class| { | 2590 | switch (elf.phdrSlice()) { |
| 1764 | const ph = &phdr[phndx]; | 2591 | inline else => |phdr| elf.targetStore( |
| 1765 | elf.targetStore(&ph.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); | 2592 | &phdr[phndx].offset, |
| 1766 | switch (elf.targetLoad(&ph.type)) { | 2593 | @intCast(ni.fileLocation(&elf.mf, false).offset), |
| 1767 | else => unreachable, | 2594 | ), |
| 1768 | std.elf.PT_NULL, std.elf.PT_LOAD => return, | 2595 | } |
| 1769 | std.elf.PT_DYNAMIC, std.elf.PT_INTERP => {}, | 2596 | var child_it = ni.children(&elf.mf); |
| 1770 | std.elf.PT_PHDR => @field(elf.ehdrPtr(), @tagName(class)).phoff = ph.offset, | 2597 | while (child_it.next()) |child_ni| try elf.flushFileOffset(child_ni); |
| 1771 | std.elf.PT_TLS => {}, | | |
| 1772 | } | | |
| 1773 | elf.targetStore(&ph.vaddr, @intCast(elf.computeNodeVAddr(ni))); | | |
| 1774 | ph.paddr = ph.vaddr; | | |
| 1775 | }, | | |
| 1776 | }, | 2598 | }, |
| 1777 | .section => |si| switch (elf.shdrSlice()) { | 2599 | .section => |si| switch (elf.shdrSlice()) { |
| 1778 | inline else => |shdr, class| { | 2600 | inline else => |shdr, class| elf.targetStore( |
| 1779 | const sym = @field(elf.symPtr(si), @tagName(class)); | 2601 | &shdr[elf.targetLoad(&@field(elf.symPtr(si), @tagName(class)).shndx)].offset, |
| 1780 | const sh = &shdr[elf.targetLoad(&sym.shndx)]; | 2602 | @intCast(ni.fileLocation(&elf.mf, false).offset), |
| 1781 | elf.targetStore(&sh.offset, @intCast(ni.fileLocation(&elf.mf, false).offset)); | 2603 | ), |
| 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 | }, | | |
| 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 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); | 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,14 +2729,15 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) !void { |
| 1852 | else => unreachable, | 2729 | else => unreachable, |
| 1853 | std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS), | 2730 | std.elf.SHT_NULL => if (size > 0) elf.targetStore(&sh.type, std.elf.SHT_PROGBITS), |
| 1854 | std.elf.SHT_PROGBITS => if (size == 0) elf.targetStore(&sh.type, std.elf.SHT_NULL), | 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 | &sh.info, | 2733 | &sh.info, |
| 1857 | @intCast(@divExact(size, elf.targetLoad(&sh.entsize))), | 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 | .nav, .uav, .lazy_code, .lazy_const_data => {}, | 2741 | .nav, .uav, .lazy_code, .lazy_const_data => {}, |
| 1864 | } | 2742 | } |
| 1865 | } | 2743 | } |
| ... | @@ -1983,6 +2861,14 @@ pub fn printNode( | ... | @@ -1983,6 +2861,14 @@ pub fn printNode( |
| 1983 | switch (node) { | 2861 | switch (node) { |
| 1984 | else => {}, | 2862 | else => {}, |
| 1985 | .section => |si| try w.print("({s})", .{elf.sectionName(si)}), | 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 | .nav => |nmi| { | 2872 | .nav => |nmi| { |
| 1987 | const zcu = elf.base.comp.zcu.?; | 2873 | const zcu = elf.base.comp.zcu.?; |
| 1988 | const ip = &zcu.intern_pool; | 2874 | const ip = &zcu.intern_pool; |
| ... | @@ -2027,25 +2913,28 @@ pub fn printNode( | ... | @@ -2027,25 +2913,28 @@ pub fn printNode( |
| 2027 | leaf = false; | 2913 | leaf = false; |
| 2028 | try elf.printNode(tid, w, child_ni, indent + 1); | 2914 | try elf.printNode(tid, w, child_ni, indent + 1); |
| 2029 | } | 2915 | } |
| 2030 | if (leaf) { | 2916 | if (!leaf) return; |
| 2031 | const file_loc = ni.fileLocation(&elf.mf, false); | 2917 | const file_loc = ni.fileLocation(&elf.mf, false); |
| 2032 | if (file_loc.size == 0) return; | 2918 | var address = file_loc.offset; |
| 2033 | var address = file_loc.offset; | 2919 | if (file_loc.size == 0) { |
| 2034 | const line_len = 0x10; | 2920 | try w.splatByteAll(' ', indent + 1); |
| 2035 | var line_it = std.mem.window( | 2921 | try w.print("{x:0>8}\n", .{address}); |
| 2036 | u8, | 2922 | return; |
| 2037 | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], | 2923 | } |
| 2038 | line_len, | 2924 | const line_len = 0x10; |
| 2039 | line_len, | 2925 | var line_it = std.mem.window( |
| 2040 | ); | 2926 | u8, |
| 2041 | while (line_it.next()) |line_bytes| : (address += line_len) { | 2927 | elf.mf.contents[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)], |
| 2042 | try w.splatByteAll(' ', indent + 1); | 2928 | line_len, |
| 2043 | try w.print("{x:0>8} ", .{address}); | 2929 | line_len, |
| 2044 | for (line_bytes) |byte| try w.print("{x:0>2} ", .{byte}); | 2930 | ); |
| 2045 | try w.splatByteAll(' ', 3 * (line_len - line_bytes.len) + 1); | 2931 | while (line_it.next()) |line_bytes| : (address += line_len) { |
| 2046 | for (line_bytes) |byte| try w.writeByte(if (std.ascii.isPrint(byte)) byte else '.'); | 2932 | try w.splatByteAll(' ', indent + 1); |
| 2047 | try w.writeByte('\n'); | 2933 | try w.print("{x:0>8} ", .{address}); |
| 2048 | } | 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 | |