| author | |
| committer | |
| log | 79bb28aa57b3712116dc75288d60f2d29ba31cfb |
| tree | 7ee962f502f1c03c23189a416d0b4c234b564d3b |
| parent | e78ea8f2cb3677c0a104319b8aa5e37ea64d9cfa |
Other debug info is still in progress.
Closes #2542121 files changed, 4429 insertions(+), 853 deletions(-)
CMakeLists.txt+1| ... | ... | @@ -383,6 +383,7 @@ set(ZIG_STAGE2_SOURCES |
| 383 | 383 | src/link/ConstPool.zig |
| 384 | 384 | src/link/Coff.zig |
| 385 | 385 | src/link/Dwarf.zig |
| 386 | src/link/Dwarf2.zig | |
| 386 | 387 | src/link/Elf.zig |
| 387 | 388 | src/link/Elf/Archive.zig |
| 388 | 389 | src/link/Elf/Atom.zig |
lib/std/debug/Dwarf/Unwind.zig+16-7| ... | ... | @@ -362,8 +362,7 @@ pub const CommonInformationEntry = struct { |
| 362 | 362 | if (aug_str.len == 0) break :aug .none; |
| 363 | 363 | if (aug_str[0] == 'z') break :aug .lsb_z; |
| 364 | 364 | if (std.mem.eql(u8, aug_str, "eh")) break :aug .gcc_eh; |
| 365 | // We can't finish parsing the CIE if we don't know what its augmentation means. | |
| 366 | return bad(); | |
| 365 | return error.UnsupportedAugmentation; | |
| 367 | 366 | }; |
| 368 | 367 | |
| 369 | 368 | switch (aug_kind) { |
| ... | ... | @@ -396,7 +395,7 @@ pub const CommonInformationEntry = struct { |
| 396 | 395 | 'R' => fde_pointer_enc = @bitCast(try aug_data.takeByte()), |
| 397 | 396 | 'S' => is_signal_frame = true, |
| 398 | 397 | 'B', 'G' => {}, |
| 399 | else => return bad(), | |
| 398 | else => return error.UnsupportedAugmentation, | |
| 400 | 399 | }; |
| 401 | 400 | break :aug .{ fde_pointer_enc, is_signal_frame }; |
| 402 | 401 | }; |
| ... | ... | @@ -502,7 +501,15 @@ pub fn prepare( |
| 502 | 501 | const idx = unwind.cie_list.len; |
| 503 | 502 | try unwind.cie_list.append(gpa, .{ |
| 504 | 503 | .offset = entry_offset, |
| 505 | .cie = try .parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes), | |
| 504 | .cie = CommonInformationEntry.parse(cie_info.format, try r.take(bytes_len), section.id, addr_size_bytes) catch |err| switch (err) { | |
| 505 | error.UnsupportedDwarfVersion, | |
| 506 | error.UnsupportedAugmentation, | |
| 507 | => { | |
| 508 | // These are recoverable by just skipping the CIE. | |
| 509 | continue; | |
| 510 | }, | |
| 511 | else => |e| return e, | |
| 512 | }, | |
| 506 | 513 | }); |
| 507 | 514 | errdefer _ = unwind.cie_list.pop().?; |
| 508 | 515 | try VirtualMachine.populateCieLastRow(gpa, &unwind.cie_list.items(.cie)[idx], addr_size_bytes, endian); |
| ... | ... | @@ -514,8 +521,10 @@ pub fn prepare( |
| 514 | 521 | try r.discardAll(bytes_len); |
| 515 | 522 | continue; |
| 516 | 523 | } |
| 517 | const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo; | |
| 518 | const fde: FrameDescriptionEntry = try .parse(section.vaddr + r.seek, try r.take(bytes_len), cie, endian); | |
| 524 | const fde_vaddr = section.vaddr + r.seek; | |
| 525 | const fde_bytes = try r.take(bytes_len); | |
| 526 | const cie = unwind.findCie(fde_info.cie_offset) orelse continue; | |
| 527 | const fde: FrameDescriptionEntry = try .parse(fde_vaddr, fde_bytes, cie, endian); | |
| 519 | 528 | try fde_list.append(gpa, .{ |
| 520 | 529 | .pc_begin = fde.pc_begin, |
| 521 | 530 | .fde_offset = entry_offset, |
| ... | ... | @@ -612,7 +621,7 @@ pub fn getFde(unwind: *const Unwind, fde_offset: u64, endian: Endian) !struct { |
| 612 | 621 | .cie, .terminator => return bad(), // This is meant to be an FDE |
| 613 | 622 | }; |
| 614 | 623 | |
| 615 | const cie = unwind.findCie(fde_info.cie_offset) orelse return error.InvalidDebugInfo; | |
| 624 | const cie = unwind.findCie(fde_info.cie_offset) orelse return bad(); | |
| 616 | 625 | const fde: FrameDescriptionEntry = try .parse( |
| 617 | 626 | section.vaddr + fde_offset + fde_reader.seek, |
| 618 | 627 | try fde_reader.take(cast(usize, fde_info.bytes_len) orelse return error.EndOfStream), |
lib/std/debug/SelfInfo/Elf.zig-1| ... | ... | @@ -340,7 +340,6 @@ const Module = struct { |
| 340 | 340 | error.InvalidOperation, |
| 341 | 341 | => return error.InvalidDebugInfo, |
| 342 | 342 | error.UnsupportedAddrSize, |
| 343 | error.UnsupportedDwarfVersion, | |
| 344 | 343 | error.UnimplementedUserOpcode, |
| 345 | 344 | => return error.UnsupportedDebugInfo, |
| 346 | 345 | }; |
lib/std/debug/SelfInfo/MachO.zig-1| ... | ... | @@ -578,7 +578,6 @@ const Module = struct { |
| 578 | 578 | error.InvalidOperation, |
| 579 | 579 | => return error.InvalidDebugInfo, |
| 580 | 580 | error.UnsupportedAddrSize, |
| 581 | error.UnsupportedDwarfVersion, | |
| 582 | 581 | error.UnimplementedUserOpcode, |
| 583 | 582 | => return error.UnsupportedDebugInfo, |
| 584 | 583 | }; |
src/codegen.zig+4-3| ... | ... | @@ -26,6 +26,7 @@ pub const aarch64 = @import("codegen/aarch64.zig"); |
| 26 | 26 | pub const loongarch = @import("codegen/loongarch.zig"); |
| 27 | 27 | |
| 28 | 28 | pub const Error = link.Error; |
| 29 | pub const EmitError = Error || std.Io.Writer.Error || error{MappedFileIo}; | |
| 29 | 30 | |
| 30 | 31 | fn devFeatureForBackend(backend: std.lang.CompilerBackend) dev.Feature { |
| 31 | 32 | return switch (backend) { |
| ... | ... | @@ -196,7 +197,7 @@ pub fn emitFunction( |
| 196 | 197 | any_mir: *const AnyMir, |
| 197 | 198 | w: *std.Io.Writer, |
| 198 | 199 | debug_output: link.File.DebugInfoOutput, |
| 199 | ) (Error || std.Io.Writer.Error)!void { | |
| 200 | ) EmitError!void { | |
| 200 | 201 | const zcu = pt.zcu; |
| 201 | 202 | const func = zcu.funcInfo(func_index); |
| 202 | 203 | const target = &zcu.navFileScope(func.owner_nav).mod.?.resolved_target.result; |
| ... | ... | @@ -228,7 +229,7 @@ pub fn generateLazyFunction( |
| 228 | 229 | atom_id: link.File.AtomId, |
| 229 | 230 | w: *std.Io.Writer, |
| 230 | 231 | debug_output: link.File.DebugInfoOutput, |
| 231 | ) (Error || std.Io.Writer.Error)!void { | |
| 232 | ) EmitError!void { | |
| 232 | 233 | const zcu = pt.zcu; |
| 233 | 234 | const target = if (Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu)) |inst_index| |
| 234 | 235 | &zcu.fileByIndex(inst_index.resolveFile(&zcu.intern_pool)).mod.?.resolved_target.result |
| ... | ... | @@ -252,7 +253,7 @@ pub fn generateLazySymbol( |
| 252 | 253 | w: *std.Io.Writer, |
| 253 | 254 | debug_output: link.File.DebugInfoOutput, |
| 254 | 255 | reloc_parent: link.File.RelocInfo.Parent, |
| 255 | ) (Error || std.Io.Writer.Error)!void { | |
| 256 | ) EmitError!void { | |
| 256 | 257 | const tracy = trace(@src()); |
| 257 | 258 | defer tracy.end(); |
| 258 | 259 | tracy.addTextFmt("{t}, {f}", .{ lazy_sym.kind, Type.fromInterned(lazy_sym.ty).fmt(pt) }); |
src/codegen/riscv64/CodeGen.zig+1-1| ... | ... | @@ -856,7 +856,7 @@ pub fn generateLazy( |
| 856 | 856 | atom_index: link.File.AtomId, |
| 857 | 857 | w: *std.Io.Writer, |
| 858 | 858 | debug_output: link.File.DebugInfoOutput, |
| 859 | ) (codegen.Error || std.Io.Writer.Error)!void { | |
| 859 | ) codegen.EmitError!void { | |
| 860 | 860 | _ = atom_index; |
| 861 | 861 | const comp = bin_file.comp; |
| 862 | 862 | const gpa = comp.gpa; |
src/codegen/riscv64/Emit.zig+9-8| ... | ... | @@ -13,7 +13,7 @@ prev_di_pc: usize, |
| 13 | 13 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, |
| 14 | 14 | relocs: std.ArrayList(Reloc) = .empty, |
| 15 | 15 | |
| 16 | pub const Error = Lower.Error || std.Io.Writer.Error || error{ | |
| 16 | pub const Error = Lower.Error || codegen.EmitError || error{ | |
| 17 | 17 | EmitFail, |
| 18 | 18 | }; |
| 19 | 19 | |
| ... | ... | @@ -118,14 +118,14 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 118 | 118 | else => unreachable, |
| 119 | 119 | .pseudo_dbg_prologue_end => { |
| 120 | 120 | switch (emit.debug_output) { |
| 121 | .dwarf => |dw| { | |
| 121 | inline .dwarf, .dwarf2 => |dw| { | |
| 122 | 122 | try dw.setPrologueEnd(); |
| 123 | 123 | log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ |
| 124 | 124 | emit.prev_di_line, emit.prev_di_column, |
| 125 | 125 | }); |
| 126 | 126 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); |
| 127 | 127 | }, |
| 128 | .none => {}, | |
| 128 | .eh_frame, .none => {}, | |
| 129 | 129 | } |
| 130 | 130 | }, |
| 131 | 131 | .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine( |
| ... | ... | @@ -134,14 +134,14 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 134 | 134 | ), |
| 135 | 135 | .pseudo_dbg_epilogue_begin => { |
| 136 | 136 | switch (emit.debug_output) { |
| 137 | .dwarf => |dw| { | |
| 137 | inline .dwarf, .dwarf2 => |dw| { | |
| 138 | 138 | try dw.setEpilogueBegin(); |
| 139 | 139 | log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ |
| 140 | 140 | emit.prev_di_line, emit.prev_di_column, |
| 141 | 141 | }); |
| 142 | 142 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); |
| 143 | 143 | }, |
| 144 | .none => {}, | |
| 144 | .eh_frame, .none => {}, | |
| 145 | 145 | } |
| 146 | 146 | }, |
| 147 | 147 | .pseudo_dead => {}, |
| ... | ... | @@ -190,15 +190,15 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) Error!void { |
| 190 | 190 | const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 191 | 191 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); |
| 192 | 192 | switch (emit.debug_output) { |
| 193 | .dwarf => |dw| { | |
| 193 | inline .dwarf, .dwarf2 => |dw| { | |
| 194 | 194 | if (column != emit.prev_di_column) try dw.setColumn(column); |
| 195 | 195 | if (delta_line == 0) return; // TODO: fix these edge cases. |
| 196 | try dw.advancePCAndLine(delta_line, delta_pc); | |
| 196 | try dw.advancePcAndLine(delta_line, delta_pc); | |
| 197 | 197 | emit.prev_di_line = line; |
| 198 | 198 | emit.prev_di_column = column; |
| 199 | 199 | emit.prev_di_pc = emit.w.end; |
| 200 | 200 | }, |
| 201 | .none => {}, | |
| 201 | .eh_frame, .none => {}, | |
| 202 | 202 | } |
| 203 | 203 | } |
| 204 | 204 | |
| ... | ... | @@ -209,6 +209,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) Error { |
| 209 | 209 | }; |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | const codegen = @import("../../codegen.zig"); | |
| 212 | 213 | const link = @import("../../link.zig"); |
| 213 | 214 | const log = std.log.scoped(.emit); |
| 214 | 215 | const mem = std.mem; |
src/codegen/riscv64/Mir.zig+1-1| ... | ... | @@ -111,7 +111,7 @@ pub fn emit( |
| 111 | 111 | atom_index: link.File.AtomId, |
| 112 | 112 | w: *std.Io.Writer, |
| 113 | 113 | debug_output: link.File.DebugInfoOutput, |
| 114 | ) (codegen.Error || std.Io.Writer.Error)!void { | |
| 114 | ) codegen.EmitError!void { | |
| 115 | 115 | _ = atom_index; |
| 116 | 116 | const zcu = pt.zcu; |
| 117 | 117 | const comp = zcu.comp; |
src/codegen/sparc64/Emit.zig+9-9| ... | ... | @@ -4,6 +4,7 @@ |
| 4 | 4 | const std = @import("std"); |
| 5 | 5 | const Endian = std.lang.Endian; |
| 6 | 6 | const assert = std.debug.assert; |
| 7 | const codegen = @import("../../codegen.zig"); | |
| 7 | 8 | const link = @import("../../link.zig"); |
| 8 | 9 | const Zcu = @import("../../Zcu.zig"); |
| 9 | 10 | const ErrorMsg = Zcu.ErrorMsg; |
| ... | ... | @@ -40,8 +41,7 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayList(M |
| 40 | 41 | /// instruction |
| 41 | 42 | code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .empty, |
| 42 | 43 | |
| 43 | const InnerError = std.Io.Writer.Error || error{ | |
| 44 | OutOfMemory, | |
| 44 | const InnerError = codegen.EmitError || error{ | |
| 45 | 45 | EmitFail, |
| 46 | 46 | }; |
| 47 | 47 | |
| ... | ... | @@ -175,21 +175,21 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 175 | 175 | |
| 176 | 176 | fn mirDebugPrologueEnd(emit: *Emit) !void { |
| 177 | 177 | switch (emit.debug_output) { |
| 178 | .dwarf => |dbg_out| { | |
| 178 | inline .dwarf, .dwarf2 => |dbg_out| { | |
| 179 | 179 | try dbg_out.setPrologueEnd(); |
| 180 | 180 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); |
| 181 | 181 | }, |
| 182 | .none => {}, | |
| 182 | .eh_frame, .none => {}, | |
| 183 | 183 | } |
| 184 | 184 | } |
| 185 | 185 | |
| 186 | 186 | fn mirDebugEpilogueBegin(emit: *Emit) !void { |
| 187 | 187 | switch (emit.debug_output) { |
| 188 | .dwarf => |dbg_out| { | |
| 188 | inline .dwarf, .dwarf2 => |dbg_out| { | |
| 189 | 189 | try dbg_out.setEpilogueBegin(); |
| 190 | 190 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); |
| 191 | 191 | }, |
| 192 | .none => {}, | |
| 192 | .eh_frame, .none => {}, | |
| 193 | 193 | } |
| 194 | 194 | } |
| 195 | 195 | |
| ... | ... | @@ -496,13 +496,13 @@ fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { |
| 496 | 496 | const delta_line = @as(i32, @intCast(line)) - @as(i32, @intCast(emit.prev_di_line)); |
| 497 | 497 | const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 498 | 498 | switch (emit.debug_output) { |
| 499 | .dwarf => |dbg_out| { | |
| 500 | try dbg_out.advancePCAndLine(delta_line, delta_pc); | |
| 499 | inline .dwarf, .dwarf2 => |dbg_out| { | |
| 500 | try dbg_out.advancePcAndLine(delta_line, delta_pc); | |
| 501 | 501 | emit.prev_di_line = line; |
| 502 | 502 | emit.prev_di_column = column; |
| 503 | 503 | emit.prev_di_pc = emit.w.end; |
| 504 | 504 | }, |
| 505 | else => {}, | |
| 505 | .eh_frame, .none => {}, | |
| 506 | 506 | } |
| 507 | 507 | } |
| 508 | 508 |
src/codegen/sparc64/Mir.zig+1-1| ... | ... | @@ -382,7 +382,7 @@ pub fn emit( |
| 382 | 382 | atom_index: link.File.AtomId, |
| 383 | 383 | w: *std.Io.Writer, |
| 384 | 384 | debug_output: link.File.DebugInfoOutput, |
| 385 | ) (codegen.Error || std.Io.Writer.Error)!void { | |
| 385 | ) codegen.EmitError!void { | |
| 386 | 386 | _ = atom_index; |
| 387 | 387 | const zcu = pt.zcu; |
| 388 | 388 | const func = zcu.funcInfo(func_index); |
src/codegen/x86_64/CodeGen.zig+1-1| ... | ... | @@ -1120,7 +1120,7 @@ pub fn generateLazy( |
| 1120 | 1120 | atom_id: link.File.AtomId, |
| 1121 | 1121 | w: *std.Io.Writer, |
| 1122 | 1122 | debug_output: link.File.DebugInfoOutput, |
| 1123 | ) codegen.Error!void { | |
| 1123 | ) codegen.EmitError!void { | |
| 1124 | 1124 | const gpa = pt.zcu.gpa; |
| 1125 | 1125 | // This function is for generating global code, so we use the root module. |
| 1126 | 1126 | const mod = pt.zcu.comp.root_mod; |
src/codegen/x86_64/Emit.zig+193-192| ... | ... | @@ -16,10 +16,8 @@ code_offset_mapping: std.ArrayList(u32), |
| 16 | 16 | relocs: std.ArrayList(Reloc), |
| 17 | 17 | table_relocs: std.ArrayList(TableReloc), |
| 18 | 18 | |
| 19 | pub const Error = Lower.Error || error{ | |
| 20 | AlreadyReported, | |
| 19 | pub const Error = Lower.Error || codegen.EmitError || error{ | |
| 21 | 20 | EmitFail, |
| 22 | NotFile, | |
| 23 | 21 | } || std.posix.MMapError || std.posix.MRemapError || link.File.UpdateDebugInfoError; |
| 24 | 22 | |
| 25 | 23 | pub fn emitMir(emit: *Emit) Error!void { |
| ... | ... | @@ -38,7 +36,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 38 | 36 | if (lowered_inst.prefix == .directive) { |
| 39 | 37 | const start_offset: u32 = @intCast(emit.w.end); |
| 40 | 38 | switch (emit.debug_output) { |
| 41 | .dwarf => |dwarf| switch (lowered_inst.encoding.mnemonic) { | |
| 39 | inline .dwarf, .eh_frame, .dwarf2 => |dwarf| switch (lowered_inst.encoding.mnemonic) { | |
| 42 | 40 | .@".cfi_def_cfa" => try dwarf.genDebugFrame(start_offset, .{ .def_cfa = .{ |
| 43 | 41 | .reg = lowered_inst.ops[0].reg.dwarfNum(), |
| 44 | 42 | .off = lowered_inst.ops[1].imm.signed, |
| ... | ... | @@ -460,204 +458,207 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 460 | 458 | |
| 461 | 459 | if (lowered.insts.len == 0) { |
| 462 | 460 | const mir_inst = emit.lower.mir.instructions.get(mir_index); |
| 463 | switch (mir_inst.tag) { | |
| 461 | assert(mir_inst.tag == .pseudo); | |
| 462 | switch (mir_inst.ops) { | |
| 464 | 463 | else => unreachable, |
| 465 | .pseudo => switch (mir_inst.ops) { | |
| 466 | else => unreachable, | |
| 467 | .pseudo_dbg_prologue_end_none => switch (emit.debug_output) { | |
| 468 | .dwarf => |dwarf| try dwarf.setPrologueEnd(), | |
| 469 | .none => {}, | |
| 470 | }, | |
| 471 | .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePCAndLine(.{ | |
| 472 | .line = mir_inst.data.line_column.line, | |
| 473 | .column = mir_inst.data.line_column.column, | |
| 474 | .is_stmt = true, | |
| 475 | }), | |
| 476 | .pseudo_dbg_line_line_column => try emit.dbgAdvancePCAndLine(.{ | |
| 477 | .line = mir_inst.data.line_column.line, | |
| 478 | .column = mir_inst.data.line_column.column, | |
| 479 | .is_stmt = false, | |
| 480 | }), | |
| 481 | .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) { | |
| 482 | .dwarf => |dwarf| { | |
| 483 | try dwarf.setEpilogueBegin(); | |
| 484 | log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ | |
| 485 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 486 | }); | |
| 487 | try emit.dbgAdvancePCAndLine(emit.prev_di_loc); | |
| 488 | }, | |
| 489 | .none => {}, | |
| 464 | .pseudo_dbg_prologue_end_none => switch (emit.debug_output) { | |
| 465 | inline .dwarf, .dwarf2 => |dwarf| try dwarf.setPrologueEnd(), | |
| 466 | .eh_frame, .none => {}, | |
| 467 | }, | |
| 468 | .pseudo_dbg_line_stmt_line_column => try emit.dbgAdvancePcAndLine(.{ | |
| 469 | .line = mir_inst.data.line_column.line, | |
| 470 | .column = mir_inst.data.line_column.column, | |
| 471 | .is_stmt = true, | |
| 472 | }), | |
| 473 | .pseudo_dbg_line_line_column => try emit.dbgAdvancePcAndLine(.{ | |
| 474 | .line = mir_inst.data.line_column.line, | |
| 475 | .column = mir_inst.data.line_column.column, | |
| 476 | .is_stmt = false, | |
| 477 | }), | |
| 478 | .pseudo_dbg_epilogue_begin_none => switch (emit.debug_output) { | |
| 479 | inline .dwarf, .dwarf2 => |dwarf| { | |
| 480 | try dwarf.setEpilogueBegin(); | |
| 481 | log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{ | |
| 482 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 483 | }); | |
| 484 | try emit.dbgAdvancePcAndLine(emit.prev_di_loc); | |
| 490 | 485 | }, |
| 491 | .pseudo_dbg_enter_block_none => switch (emit.debug_output) { | |
| 492 | .dwarf => |dwarf| { | |
| 493 | log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ | |
| 494 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 495 | }); | |
| 496 | try dwarf.enterBlock(emit.w.end); | |
| 497 | }, | |
| 498 | .none => {}, | |
| 486 | .eh_frame, .none => {}, | |
| 487 | }, | |
| 488 | .pseudo_dbg_enter_block_none => switch (emit.debug_output) { | |
| 489 | inline .dwarf, .dwarf2 => |dwarf| { | |
| 490 | log.debug("mirDbgEnterBlock (line={d}, col={d})", .{ | |
| 491 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 492 | }); | |
| 493 | try dwarf.enterBlock(emit.w.end); | |
| 499 | 494 | }, |
| 500 | .pseudo_dbg_leave_block_none => switch (emit.debug_output) { | |
| 501 | .dwarf => |dwarf| { | |
| 502 | log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ | |
| 503 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 504 | }); | |
| 505 | try dwarf.leaveBlock(emit.w.end); | |
| 506 | }, | |
| 507 | .none => {}, | |
| 495 | .eh_frame, .none => {}, | |
| 496 | }, | |
| 497 | .pseudo_dbg_leave_block_none => switch (emit.debug_output) { | |
| 498 | inline .dwarf, .dwarf2 => |dwarf| { | |
| 499 | log.debug("mirDbgLeaveBlock (line={d}, col={d})", .{ | |
| 500 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 501 | }); | |
| 502 | try dwarf.leaveBlock(emit.w.end); | |
| 508 | 503 | }, |
| 509 | .pseudo_dbg_enter_inline_func => switch (emit.debug_output) { | |
| 510 | .dwarf => |dwarf| { | |
| 511 | log.debug("mirDbgEnterInline (line={d}, col={d})", .{ | |
| 512 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 513 | }); | |
| 514 | try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column); | |
| 515 | }, | |
| 516 | .none => {}, | |
| 504 | .eh_frame, .none => {}, | |
| 505 | }, | |
| 506 | .pseudo_dbg_enter_inline_func => switch (emit.debug_output) { | |
| 507 | inline .dwarf, .dwarf2 => |dwarf| { | |
| 508 | log.debug("mirDbgEnterInline (line={d}, col={d})", .{ | |
| 509 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 510 | }); | |
| 511 | try dwarf.enterInlineFunc(mir_inst.data.ip_index, emit.w.end, emit.prev_di_loc.line, emit.prev_di_loc.column); | |
| 517 | 512 | }, |
| 518 | .pseudo_dbg_leave_inline_func => switch (emit.debug_output) { | |
| 519 | .dwarf => |dwarf| { | |
| 520 | log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ | |
| 521 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 522 | }); | |
| 523 | try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end); | |
| 524 | }, | |
| 525 | .none => {}, | |
| 513 | .eh_frame, .none => {}, | |
| 514 | }, | |
| 515 | .pseudo_dbg_leave_inline_func => switch (emit.debug_output) { | |
| 516 | inline .dwarf, .dwarf2 => |dwarf| { | |
| 517 | log.debug("mirDbgLeaveInline (line={d}, col={d})", .{ | |
| 518 | emit.prev_di_loc.line, emit.prev_di_loc.column, | |
| 519 | }); | |
| 520 | try dwarf.leaveInlineFunc(mir_inst.data.ip_index, emit.w.end); | |
| 526 | 521 | }, |
| 527 | .pseudo_dbg_arg_none, | |
| 528 | .pseudo_dbg_arg_i_s, | |
| 529 | .pseudo_dbg_arg_i_u, | |
| 530 | .pseudo_dbg_arg_i_64, | |
| 531 | .pseudo_dbg_arg_ro, | |
| 532 | .pseudo_dbg_arg_fa, | |
| 533 | .pseudo_dbg_arg_m, | |
| 534 | .pseudo_dbg_var_none, | |
| 535 | .pseudo_dbg_var_i_s, | |
| 536 | .pseudo_dbg_var_i_u, | |
| 537 | .pseudo_dbg_var_i_64, | |
| 538 | .pseudo_dbg_var_ro, | |
| 539 | .pseudo_dbg_var_fa, | |
| 540 | .pseudo_dbg_var_m, | |
| 541 | => switch (emit.debug_output) { | |
| 542 | .dwarf => |dwarf| { | |
| 543 | var loc_buf: [2]link.File.Dwarf.Loc = undefined; | |
| 544 | const loc: link.File.Dwarf.Loc = loc: switch (mir_inst.ops) { | |
| 522 | .eh_frame, .none => {}, | |
| 523 | }, | |
| 524 | .pseudo_dbg_arg_none, | |
| 525 | .pseudo_dbg_arg_i_s, | |
| 526 | .pseudo_dbg_arg_i_u, | |
| 527 | .pseudo_dbg_arg_i_64, | |
| 528 | .pseudo_dbg_arg_ro, | |
| 529 | .pseudo_dbg_arg_fa, | |
| 530 | .pseudo_dbg_arg_m, | |
| 531 | .pseudo_dbg_var_none, | |
| 532 | .pseudo_dbg_var_i_s, | |
| 533 | .pseudo_dbg_var_i_u, | |
| 534 | .pseudo_dbg_var_i_64, | |
| 535 | .pseudo_dbg_var_ro, | |
| 536 | .pseudo_dbg_var_fa, | |
| 537 | .pseudo_dbg_var_m, | |
| 538 | => switch (emit.debug_output) { | |
| 539 | inline .dwarf, .dwarf2 => |dwarf, tag| { | |
| 540 | const DwarfLoc = switch (tag) { | |
| 541 | .dwarf => link.File.Dwarf.Loc, | |
| 542 | .dwarf2 => link.File.Dwarf2.Loc, | |
| 543 | .eh_frame, .none => comptime unreachable, | |
| 544 | }; | |
| 545 | var loc_buf: [2]DwarfLoc = undefined; | |
| 546 | const loc: DwarfLoc = loc: switch (mir_inst.ops) { | |
| 547 | else => unreachable, | |
| 548 | .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty, | |
| 549 | .pseudo_dbg_arg_i_s, | |
| 550 | .pseudo_dbg_arg_i_u, | |
| 551 | .pseudo_dbg_var_i_s, | |
| 552 | .pseudo_dbg_var_i_u, | |
| 553 | => .{ .stack_value = stack_value: { | |
| 554 | loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) { | |
| 555 | .signed => |s| .{ .consts = s }, | |
| 556 | .unsigned => |u| .{ .constu = u }, | |
| 557 | }; | |
| 558 | break :stack_value &loc_buf[0]; | |
| 559 | } }, | |
| 560 | .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: { | |
| 561 | loc_buf[0] = .{ .constu = mir_inst.data.i64 }; | |
| 562 | break :stack_value &loc_buf[0]; | |
| 563 | } }, | |
| 564 | .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => { | |
| 565 | const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa); | |
| 566 | break :loc .{ .plus = .{ | |
| 567 | reg: { | |
| 568 | loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() }; | |
| 569 | break :reg &loc_buf[0]; | |
| 570 | }, | |
| 571 | off: { | |
| 572 | loc_buf[1] = .{ .consts = reg_off.off }; | |
| 573 | break :off &loc_buf[1]; | |
| 574 | }, | |
| 575 | } }; | |
| 576 | }, | |
| 577 | .pseudo_dbg_arg_m, .pseudo_dbg_var_m => { | |
| 578 | const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode(); | |
| 579 | break :loc .{ .plus = .{ | |
| 580 | base: { | |
| 581 | loc_buf[0] = switch (mem.base()) { | |
| 582 | .none => .{ .constu = 0 }, | |
| 583 | .reg => |reg| .{ .breg = reg.dwarfNum() }, | |
| 584 | .frame, .table, .rip_inst => unreachable, | |
| 585 | .nav => |nav| .{ .addr_reloc = try codegen.genNavRef( | |
| 586 | emit.bin_file, | |
| 587 | emit.pt, | |
| 588 | nav, | |
| 589 | ) }, | |
| 590 | .uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav( | |
| 591 | emit.pt, | |
| 592 | uav.val, | |
| 593 | Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu), | |
| 594 | ) }, | |
| 595 | .lazy_sym, .extern_func => unreachable, | |
| 596 | }; | |
| 597 | break :base &loc_buf[0]; | |
| 598 | }, | |
| 599 | disp: { | |
| 600 | loc_buf[1] = switch (mem.disp()) { | |
| 601 | .signed => |s| .{ .consts = s }, | |
| 602 | .unsigned => |u| .{ .constu = u }, | |
| 603 | }; | |
| 604 | break :disp &loc_buf[1]; | |
| 605 | }, | |
| 606 | } }; | |
| 607 | }, | |
| 608 | }; | |
| 609 | ||
| 610 | const local = &emit.lower.mir.locals[local_index]; | |
| 611 | local_index += 1; | |
| 612 | try dwarf.genLocalVarDebugInfo( | |
| 613 | switch (mir_inst.ops) { | |
| 545 | 614 | else => unreachable, |
| 546 | .pseudo_dbg_arg_none, .pseudo_dbg_var_none => .empty, | |
| 615 | .pseudo_dbg_arg_none, | |
| 547 | 616 | .pseudo_dbg_arg_i_s, |
| 548 | 617 | .pseudo_dbg_arg_i_u, |
| 618 | .pseudo_dbg_arg_i_64, | |
| 619 | .pseudo_dbg_arg_ro, | |
| 620 | .pseudo_dbg_arg_fa, | |
| 621 | .pseudo_dbg_arg_m, | |
| 622 | .pseudo_dbg_arg_val, | |
| 623 | => .arg, | |
| 624 | .pseudo_dbg_var_none, | |
| 549 | 625 | .pseudo_dbg_var_i_s, |
| 550 | 626 | .pseudo_dbg_var_i_u, |
| 551 | => .{ .stack_value = stack_value: { | |
| 552 | loc_buf[0] = switch (emit.lower.imm(mir_inst.ops, mir_inst.data.i.i)) { | |
| 553 | .signed => |s| .{ .consts = s }, | |
| 554 | .unsigned => |u| .{ .constu = u }, | |
| 555 | }; | |
| 556 | break :stack_value &loc_buf[0]; | |
| 557 | } }, | |
| 558 | .pseudo_dbg_arg_i_64, .pseudo_dbg_var_i_64 => .{ .stack_value = stack_value: { | |
| 559 | loc_buf[0] = .{ .constu = mir_inst.data.i64 }; | |
| 560 | break :stack_value &loc_buf[0]; | |
| 561 | } }, | |
| 562 | .pseudo_dbg_arg_fa, .pseudo_dbg_var_fa => { | |
| 563 | const reg_off = emit.lower.mir.resolveFrameAddr(mir_inst.data.fa); | |
| 564 | break :loc .{ .plus = .{ | |
| 565 | reg: { | |
| 566 | loc_buf[0] = .{ .breg = reg_off.reg.dwarfNum() }; | |
| 567 | break :reg &loc_buf[0]; | |
| 568 | }, | |
| 569 | off: { | |
| 570 | loc_buf[1] = .{ .consts = reg_off.off }; | |
| 571 | break :off &loc_buf[1]; | |
| 572 | }, | |
| 573 | } }; | |
| 574 | }, | |
| 575 | .pseudo_dbg_arg_m, .pseudo_dbg_var_m => { | |
| 576 | const mem = emit.lower.mir.resolveMemoryExtra(mir_inst.data.x.payload).decode(); | |
| 577 | break :loc .{ .plus = .{ | |
| 578 | base: { | |
| 579 | loc_buf[0] = switch (mem.base()) { | |
| 580 | .none => .{ .constu = 0 }, | |
| 581 | .reg => |reg| .{ .breg = reg.dwarfNum() }, | |
| 582 | .frame, .table, .rip_inst => unreachable, | |
| 583 | .nav => |nav| .{ .addr_reloc = try codegen.genNavRef( | |
| 584 | emit.bin_file, | |
| 585 | emit.pt, | |
| 586 | nav, | |
| 587 | ) }, | |
| 588 | .uav => |uav| .{ .addr_reloc = try emit.bin_file.lowerUav( | |
| 589 | emit.pt, | |
| 590 | uav.val, | |
| 591 | Type.fromInterned(uav.orig_ty).ptrAlignment(emit.pt.zcu), | |
| 592 | ) }, | |
| 593 | .lazy_sym, .extern_func => unreachable, | |
| 594 | }; | |
| 595 | break :base &loc_buf[0]; | |
| 596 | }, | |
| 597 | disp: { | |
| 598 | loc_buf[1] = switch (mem.disp()) { | |
| 599 | .signed => |s| .{ .consts = s }, | |
| 600 | .unsigned => |u| .{ .constu = u }, | |
| 601 | }; | |
| 602 | break :disp &loc_buf[1]; | |
| 603 | }, | |
| 604 | } }; | |
| 605 | }, | |
| 606 | }; | |
| 607 | ||
| 608 | const local = &emit.lower.mir.locals[local_index]; | |
| 609 | local_index += 1; | |
| 610 | try dwarf.genLocalVarDebugInfo( | |
| 611 | switch (mir_inst.ops) { | |
| 612 | else => unreachable, | |
| 613 | .pseudo_dbg_arg_none, | |
| 614 | .pseudo_dbg_arg_i_s, | |
| 615 | .pseudo_dbg_arg_i_u, | |
| 616 | .pseudo_dbg_arg_i_64, | |
| 617 | .pseudo_dbg_arg_ro, | |
| 618 | .pseudo_dbg_arg_fa, | |
| 619 | .pseudo_dbg_arg_m, | |
| 620 | .pseudo_dbg_arg_val, | |
| 621 | => .arg, | |
| 622 | .pseudo_dbg_var_none, | |
| 623 | .pseudo_dbg_var_i_s, | |
| 624 | .pseudo_dbg_var_i_u, | |
| 625 | .pseudo_dbg_var_i_64, | |
| 626 | .pseudo_dbg_var_ro, | |
| 627 | .pseudo_dbg_var_fa, | |
| 628 | .pseudo_dbg_var_m, | |
| 629 | .pseudo_dbg_var_val, | |
| 630 | => .local_var, | |
| 631 | }, | |
| 632 | local.name.toSlice(&emit.lower.mir), | |
| 633 | .fromInterned(local.type), | |
| 634 | loc, | |
| 635 | ); | |
| 636 | }, | |
| 637 | .none => local_index += 1, | |
| 638 | }, | |
| 639 | .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) { | |
| 640 | .dwarf => |dwarf| { | |
| 641 | const local = &emit.lower.mir.locals[local_index]; | |
| 642 | local_index += 1; | |
| 643 | try dwarf.genLocalConstDebugInfo( | |
| 644 | switch (mir_inst.ops) { | |
| 645 | else => unreachable, | |
| 646 | .pseudo_dbg_arg_val => .comptime_arg, | |
| 647 | .pseudo_dbg_var_val => .local_const, | |
| 648 | }, | |
| 649 | local.name.toSlice(&emit.lower.mir), | |
| 650 | .fromInterned(mir_inst.data.ip_index), | |
| 651 | ); | |
| 652 | }, | |
| 653 | .none => local_index += 1, | |
| 627 | .pseudo_dbg_var_i_64, | |
| 628 | .pseudo_dbg_var_ro, | |
| 629 | .pseudo_dbg_var_fa, | |
| 630 | .pseudo_dbg_var_m, | |
| 631 | .pseudo_dbg_var_val, | |
| 632 | => .local_var, | |
| 633 | }, | |
| 634 | local.name.toSlice(&emit.lower.mir), | |
| 635 | .fromInterned(local.type), | |
| 636 | loc, | |
| 637 | ); | |
| 654 | 638 | }, |
| 655 | .pseudo_dbg_var_args_none => switch (emit.debug_output) { | |
| 656 | .dwarf => |dwarf| try dwarf.genVarArgsDebugInfo(), | |
| 657 | .none => {}, | |
| 639 | .eh_frame, .none => local_index += 1, | |
| 640 | }, | |
| 641 | .pseudo_dbg_arg_val, .pseudo_dbg_var_val => switch (emit.debug_output) { | |
| 642 | inline .dwarf, .dwarf2 => |dwarf| { | |
| 643 | const local = &emit.lower.mir.locals[local_index]; | |
| 644 | local_index += 1; | |
| 645 | try dwarf.genLocalConstDebugInfo( | |
| 646 | switch (mir_inst.ops) { | |
| 647 | else => unreachable, | |
| 648 | .pseudo_dbg_arg_val => .comptime_arg, | |
| 649 | .pseudo_dbg_var_val => .local_const, | |
| 650 | }, | |
| 651 | local.name.toSlice(&emit.lower.mir), | |
| 652 | .fromInterned(mir_inst.data.ip_index), | |
| 653 | ); | |
| 658 | 654 | }, |
| 659 | .pseudo_dead_none => {}, | |
| 655 | .eh_frame, .none => local_index += 1, | |
| 656 | }, | |
| 657 | .pseudo_dbg_var_args_none => switch (emit.debug_output) { | |
| 658 | inline .dwarf, .dwarf2 => |dwarf| try dwarf.genVarArgsDebugInfo(), | |
| 659 | .eh_frame, .none => {}, | |
| 660 | 660 | }, |
| 661 | .pseudo_dead_none => {}, | |
| 661 | 662 | } |
| 662 | 663 | } |
| 663 | 664 | } |
| ... | ... | @@ -974,19 +975,19 @@ const Loc = struct { |
| 974 | 975 | is_stmt: bool, |
| 975 | 976 | }; |
| 976 | 977 | |
| 977 | fn dbgAdvancePCAndLine(emit: *Emit, loc: Loc) Error!void { | |
| 978 | fn dbgAdvancePcAndLine(emit: *Emit, loc: Loc) Error!void { | |
| 978 | 979 | const delta_line = @as(i33, loc.line) - @as(i33, emit.prev_di_loc.line); |
| 979 | 980 | const delta_pc: usize = emit.w.end - emit.prev_di_pc; |
| 980 | 981 | log.debug(" (advance pc={d} and line={d})", .{ delta_pc, delta_line }); |
| 981 | 982 | switch (emit.debug_output) { |
| 982 | .dwarf => |dwarf| { | |
| 983 | inline .dwarf, .dwarf2 => |dwarf| { | |
| 983 | 984 | if (loc.is_stmt != emit.prev_di_loc.is_stmt) try dwarf.negateStmt(); |
| 984 | 985 | if (loc.column != emit.prev_di_loc.column) try dwarf.setColumn(loc.column); |
| 985 | try dwarf.advancePCAndLine(delta_line, delta_pc); | |
| 986 | try dwarf.advancePcAndLine(delta_line, delta_pc); | |
| 986 | 987 | emit.prev_di_loc = loc; |
| 987 | 988 | emit.prev_di_pc = emit.w.end; |
| 988 | 989 | }, |
| 989 | .none => {}, | |
| 990 | .eh_frame, .none => {}, | |
| 990 | 991 | } |
| 991 | 992 | } |
| 992 | 993 |
src/codegen/x86_64/Mir.zig+14-11| ... | ... | @@ -1978,7 +1978,7 @@ pub fn emit( |
| 1978 | 1978 | atom_id: link.File.AtomId, |
| 1979 | 1979 | w: *std.Io.Writer, |
| 1980 | 1980 | debug_output: link.File.DebugInfoOutput, |
| 1981 | ) codegen.Error!void { | |
| 1981 | ) codegen.EmitError!void { | |
| 1982 | 1982 | const zcu = pt.zcu; |
| 1983 | 1983 | const comp = zcu.comp; |
| 1984 | 1984 | const gpa = comp.gpa; |
| ... | ... | @@ -1986,7 +1986,7 @@ pub fn emit( |
| 1986 | 1986 | const fn_info = zcu.typeToFunc(.fromInterned(func.ty)).?; |
| 1987 | 1987 | const nav = func.owner_nav; |
| 1988 | 1988 | const mod = zcu.navFileScope(nav).mod.?; |
| 1989 | var e: Emit = .{ | |
| 1989 | var em: Emit = .{ | |
| 1990 | 1990 | .lower = .{ |
| 1991 | 1991 | .target = &mod.resolved_target.result, |
| 1992 | 1992 | .allocator = gpa, |
| ... | ... | @@ -2006,7 +2006,8 @@ pub fn emit( |
| 2006 | 2006 | .column = func.lbrace_column, |
| 2007 | 2007 | .is_stmt = switch (debug_output) { |
| 2008 | 2008 | .dwarf => |dwarf| dwarf.dwarf.debug_line.header.default_is_stmt, |
| 2009 | .none => undefined, | |
| 2009 | .dwarf2 => |dwarf| dwarf.wip_nav.dwarf.debug_line.header.default_is_stmt, | |
| 2010 | .eh_frame, .none => undefined, | |
| 2010 | 2011 | }, |
| 2011 | 2012 | }, |
| 2012 | 2013 | .prev_di_pc = 0, |
| ... | ... | @@ -2015,11 +2016,12 @@ pub fn emit( |
| 2015 | 2016 | .relocs = .empty, |
| 2016 | 2017 | .table_relocs = .empty, |
| 2017 | 2018 | }; |
| 2018 | defer e.deinit(); | |
| 2019 | e.emitMir() catch |err| switch (err) { | |
| 2020 | error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, e.lower.err_msg.?), | |
| 2019 | defer em.deinit(); | |
| 2020 | em.emitMir() catch |err| switch (err) { | |
| 2021 | error.LowerFail, error.EmitFail => return zcu.codegenFailMsg(nav, em.lower.err_msg.?), | |
| 2021 | 2022 | error.InvalidInstruction, error.CannotEncode => return zcu.codegenFail(nav, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}), |
| 2022 | 2023 | else => return zcu.codegenFail(nav, "emit MIR failed: {s}", .{@errorName(err)}), |
| 2024 | error.AlreadyReported, error.Canceled, error.MappedFileIo, error.WriteFailed => |e| return e, | |
| 2023 | 2025 | }; |
| 2024 | 2026 | } |
| 2025 | 2027 | |
| ... | ... | @@ -2031,12 +2033,12 @@ pub fn emitLazy( |
| 2031 | 2033 | atom_id: link.File.AtomId, |
| 2032 | 2034 | w: *std.Io.Writer, |
| 2033 | 2035 | debug_output: link.File.DebugInfoOutput, |
| 2034 | ) codegen.Error!void { | |
| 2036 | ) codegen.EmitError!void { | |
| 2035 | 2037 | const zcu = pt.zcu; |
| 2036 | 2038 | const comp = zcu.comp; |
| 2037 | 2039 | const gpa = comp.gpa; |
| 2038 | 2040 | const mod = comp.root_mod; |
| 2039 | var e: Emit = .{ | |
| 2041 | var em: Emit = .{ | |
| 2040 | 2042 | .lower = .{ |
| 2041 | 2043 | .target = &mod.resolved_target.result, |
| 2042 | 2044 | .allocator = gpa, |
| ... | ... | @@ -2058,11 +2060,12 @@ pub fn emitLazy( |
| 2058 | 2060 | .relocs = .empty, |
| 2059 | 2061 | .table_relocs = .empty, |
| 2060 | 2062 | }; |
| 2061 | defer e.deinit(); | |
| 2062 | e.emitMir() catch |err| switch (err) { | |
| 2063 | error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, e.lower.err_msg.?), | |
| 2063 | defer em.deinit(); | |
| 2064 | em.emitMir() catch |err| switch (err) { | |
| 2065 | error.LowerFail, error.EmitFail => return zcu.codegenFailTypeMsg(lazy_sym.ty, em.lower.err_msg.?), | |
| 2064 | 2066 | error.InvalidInstruction, error.CannotEncode => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s} (Zig compiler bug)", .{@errorName(err)}), |
| 2065 | 2067 | else => return zcu.codegenFailType(lazy_sym.ty, "emit MIR failed: {s}", .{@errorName(err)}), |
| 2068 | error.AlreadyReported, error.Canceled, error.MappedFileIo, error.WriteFailed => |e| return e, | |
| 2066 | 2069 | }; |
| 2067 | 2070 | } |
| 2068 | 2071 |
src/link.zig+3| ... | ... | @@ -757,6 +757,8 @@ pub const File = struct { |
| 757 | 757 | |
| 758 | 758 | pub const DebugInfoOutput = union(enum) { |
| 759 | 759 | dwarf: *Dwarf.WipNav, |
| 760 | eh_frame: *Dwarf2.WipNav, | |
| 761 | dwarf2: *Dwarf2.WipNav.Debug, | |
| 760 | 762 | none, |
| 761 | 763 | }; |
| 762 | 764 | pub const UpdateDebugInfoError = Dwarf.UpdateError; |
| ... | ... | @@ -1391,6 +1393,7 @@ pub const File = struct { |
| 1391 | 1393 | pub const SpirV = @import("link/SpirV.zig"); |
| 1392 | 1394 | pub const Wasm = @import("link/Wasm.zig"); |
| 1393 | 1395 | pub const Dwarf = @import("link/Dwarf.zig"); |
| 1396 | pub const Dwarf2 = @import("link/Dwarf2.zig"); | |
| 1394 | 1397 | }; |
| 1395 | 1398 | |
| 1396 | 1399 | pub const PrelinkTask = union(enum) { |
src/link/Dwarf.zig+14-15| ... | ... | @@ -1626,12 +1626,12 @@ pub const WipNav = struct { |
| 1626 | 1626 | wip_nav.any_children = true; |
| 1627 | 1627 | } |
| 1628 | 1628 | |
| 1629 | pub fn advancePCAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void { | |
| 1630 | return wip_nav.advancePCAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) { | |
| 1629 | pub fn advancePcAndLine(wip_nav: *WipNav, delta_line: i33, delta_pc: u64) Allocator.Error!void { | |
| 1630 | return wip_nav.advancePcAndLineWriterError(delta_line, delta_pc) catch |err| switch (err) { | |
| 1631 | 1631 | error.WriteFailed => error.OutOfMemory, |
| 1632 | 1632 | }; |
| 1633 | 1633 | } |
| 1634 | fn advancePCAndLineWriterError( | |
| 1634 | fn advancePcAndLineWriterError( | |
| 1635 | 1635 | wip_nav: *WipNav, |
| 1636 | 1636 | delta_line: i33, |
| 1637 | 1637 | delta_pc: u64, |
| ... | ... | @@ -1990,7 +1990,7 @@ pub const WipNav = struct { |
| 1990 | 1990 | try ctx.wip_nav.infoSectionOffset(.debug_info, unit, entry, 0); |
| 1991 | 1991 | } |
| 1992 | 1992 | } = .{ .wip_nav = wip_nav }; |
| 1993 | try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end); | |
| 1993 | try adapter.writer().writeUleb128(counter.dw.fullCount()); | |
| 1994 | 1994 | try loc.write(adapter); |
| 1995 | 1995 | } |
| 1996 | 1996 | |
| ... | ... | @@ -2032,7 +2032,7 @@ pub const WipNav = struct { |
| 2032 | 2032 | try ctx.wip_nav.sectionOffset(.debug_frame, .debug_info, unit, entry, 0); |
| 2033 | 2033 | } |
| 2034 | 2034 | } = .{ .wip_nav = wip_nav }; |
| 2035 | try adapter.writer().writeUleb128(counter.dw.count + counter.dw.writer.end); | |
| 2035 | try adapter.writer().writeUleb128(counter.dw.fullCount()); | |
| 2036 | 2036 | try loc.write(adapter); |
| 2037 | 2037 | } |
| 2038 | 2038 | |
| ... | ... | @@ -2105,20 +2105,20 @@ pub const WipNav = struct { |
| 2105 | 2105 | const size = ty.abiSize(wip_nav.pt.zcu); |
| 2106 | 2106 | try diw.writeUleb128(size); |
| 2107 | 2107 | if (size == 0) return; |
| 2108 | const old_end = wip_nav.debug_info.writer.end; | |
| 2108 | const old_end = diw.end; | |
| 2109 | 2109 | try codegen.generateSymbol( |
| 2110 | 2110 | wip_nav.dwarf.bin_file, |
| 2111 | 2111 | wip_nav.pt, |
| 2112 | 2112 | val, |
| 2113 | &wip_nav.debug_info.writer, | |
| 2113 | diw, | |
| 2114 | 2114 | .{ .debug_output = .{ .dwarf = wip_nav } }, |
| 2115 | 2115 | ); |
| 2116 | if (old_end + size != wip_nav.debug_info.writer.end) { | |
| 2116 | if (old_end + size != diw.end) { | |
| 2117 | 2117 | std.debug.print("{f} [{}]: {} != {}\n", .{ |
| 2118 | 2118 | ty.fmt(wip_nav.pt), |
| 2119 | 2119 | ty.toIntern(), |
| 2120 | 2120 | size, |
| 2121 | wip_nav.debug_info.writer.end - old_end, | |
| 2121 | diw.end - old_end, | |
| 2122 | 2122 | }); |
| 2123 | 2123 | unreachable; |
| 2124 | 2124 | } |
| ... | ... | @@ -2278,10 +2278,9 @@ fn padToIdeal(actual_size: anytype) @TypeOf(actual_size) { |
| 2278 | 2278 | |
| 2279 | 2279 | pub fn init(lf: *link.File, format: DW.Format) Dwarf { |
| 2280 | 2280 | const comp = lf.comp; |
| 2281 | const gpa = comp.gpa; | |
| 2282 | 2281 | const target = &comp.root_mod.resolved_target.result; |
| 2283 | 2282 | return .{ |
| 2284 | .gpa = gpa, | |
| 2283 | .gpa = comp.gpa, | |
| 2285 | 2284 | .bin_file = lf, |
| 2286 | 2285 | .format = format, |
| 2287 | 2286 | .address_size = switch (target.ptrBitWidth()) { |
| ... | ... | @@ -2774,7 +2773,7 @@ fn initWipNavInner( |
| 2774 | 2773 | try dlw.writeByte(DW.LNS.set_column); |
| 2775 | 2774 | try dlw.writeUleb128(func.lbrace_column + 1); |
| 2776 | 2775 | |
| 2777 | try wip_nav.advancePCAndLine(func.lbrace_line, 0); | |
| 2776 | try wip_nav.advancePcAndLine(func.lbrace_line, 0); | |
| 2778 | 2777 | } else { |
| 2779 | 2778 | try dlw.writeUleb128(1 + @backingInt(dwarf.address_size)); |
| 2780 | 2779 | try dlw.writeByte(DW.LNE.set_address); |
| ... | ... | @@ -2791,7 +2790,7 @@ fn initWipNavInner( |
| 2791 | 2790 | try dlw.writeByte(DW.LNS.set_column); |
| 2792 | 2791 | try dlw.writeUleb128(func.lbrace_column + 1); |
| 2793 | 2792 | |
| 2794 | try wip_nav.advancePCAndLine(@intCast(decl.src_line + func.lbrace_line), 0); | |
| 2793 | try wip_nav.advancePcAndLine(@intCast(decl.src_line + func.lbrace_line), 0); | |
| 2795 | 2794 | } |
| 2796 | 2795 | }, |
| 2797 | 2796 | else => { |
| ... | ... | @@ -6362,14 +6361,14 @@ fn uleb128Bytes(value: anytype) u32 { |
| 6362 | 6361 | var buf: [64]u8 = undefined; |
| 6363 | 6362 | var dw: Writer.Discarding = .init(&buf); |
| 6364 | 6363 | dw.writer.writeUleb128(value) catch unreachable; |
| 6365 | return @intCast(dw.count + dw.writer.end); | |
| 6364 | return @intCast(dw.fullCount()); | |
| 6366 | 6365 | } |
| 6367 | 6366 | |
| 6368 | 6367 | fn sleb128Bytes(value: anytype) u32 { |
| 6369 | 6368 | var buf: [64]u8 = undefined; |
| 6370 | 6369 | var dw: Writer.Discarding = .init(&buf); |
| 6371 | 6370 | dw.writer.writeSleb128(value) catch unreachable; |
| 6372 | return @intCast(dw.count + dw.writer.end); | |
| 6371 | return @intCast(dw.fullCount()); | |
| 6373 | 6372 | } |
| 6374 | 6373 | |
| 6375 | 6374 | /// overrides `-fno-incremental` for testing incremental debug info until `-fincremental` is functional |
src/link/Dwarf2.zig created+2685| ... | ... | @@ -0,0 +1,2685 @@ |
| 1 | tag: link.File.Tag, | |
| 2 | format: DW.Format, | |
| 3 | endian: std.lang.Endian, | |
| 4 | address_size: AddressSize, | |
| 5 | const_pool: link.ConstPool, | |
| 6 | ||
| 7 | units: std.array_hash_map.Auto(*Module, Unit), | |
| 8 | /// Indices are `link.ConstPool.Index`. | |
| 9 | values: std.ArrayList(struct { | |
| 10 | debug_info_ni: MappedFile.Node.Index, | |
| 11 | }), | |
| 12 | globals: std.array_hash_map.Auto(InternPool.Nav.Index, Global), | |
| 13 | funcs: std.array_hash_map.Auto(InternPool.Nav.Index, Func), | |
| 14 | ||
| 15 | frame: Frame, | |
| 16 | debug_info: DebugInfo, | |
| 17 | debug_line: DebugLine, | |
| 18 | ||
| 19 | pub const UpdateError = link.Error || error{MappedFileIo}; | |
| 20 | ||
| 21 | pub const AddressSize = enum(u8) { @"32" = 4, @"64" = 8, _ }; | |
| 22 | ||
| 23 | pub const Unit = struct { | |
| 24 | frame_ni: MappedFile.Node.Index.Optional, | |
| 25 | cie_ni: MappedFile.Node.Index.Optional, | |
| 26 | ||
| 27 | pub const Index = enum(u32) { | |
| 28 | _, | |
| 29 | ||
| 30 | pub fn mod(ui: Unit.Index, dwarf: *Dwarf) *Module { | |
| 31 | return dwarf.units.keys()[@backingInt(ui)]; | |
| 32 | } | |
| 33 | ||
| 34 | pub fn get(ui: Unit.Index, dwarf: *Dwarf) *Unit { | |
| 35 | return &dwarf.units.values()[@backingInt(ui)]; | |
| 36 | } | |
| 37 | }; | |
| 38 | }; | |
| 39 | ||
| 40 | pub const Global = struct { | |
| 41 | debug_info_ni: MappedFile.Node.Index.Optional, | |
| 42 | ||
| 43 | pub const Index = enum(u32) { | |
| 44 | _, | |
| 45 | ||
| 46 | pub fn nav(gi: Global.Index, dwarf: *Dwarf) InternPool.Nav.Index { | |
| 47 | return dwarf.globals.keys()[@backingInt(gi)]; | |
| 48 | } | |
| 49 | ||
| 50 | pub fn get(gi: Global.Index, dwarf: *Dwarf) *Global { | |
| 51 | return &dwarf.globals.values()[@backingInt(gi)]; | |
| 52 | } | |
| 53 | }; | |
| 54 | }; | |
| 55 | ||
| 56 | pub const Func = struct { | |
| 57 | fde_ni: MappedFile.Node.Index.Optional, | |
| 58 | debug_info_ni: MappedFile.Node.Index.Optional, | |
| 59 | debug_line_ni: MappedFile.Node.Index.Optional, | |
| 60 | ||
| 61 | pub const Index = enum(u32) { | |
| 62 | _, | |
| 63 | ||
| 64 | pub fn nav(fi: Func.Index, dwarf: *Dwarf) InternPool.Nav.Index { | |
| 65 | return dwarf.funcs.keys()[@backingInt(fi)]; | |
| 66 | } | |
| 67 | ||
| 68 | pub fn get(fi: Func.Index, dwarf: *Dwarf) *Func { | |
| 69 | return &dwarf.funcs.values()[@backingInt(fi)]; | |
| 70 | } | |
| 71 | }; | |
| 72 | }; | |
| 73 | ||
| 74 | pub const Frame = struct { | |
| 75 | header: Header, | |
| 76 | section_index: SectionIndex, | |
| 77 | ||
| 78 | pub const Header = struct { | |
| 79 | code_alignment_factor: u32, | |
| 80 | data_alignment_factor: i32, | |
| 81 | return_address_register: u32, | |
| 82 | initial_instructions: []const Cfa, | |
| 83 | }; | |
| 84 | ||
| 85 | pub const Format = std.debug.Dwarf.Unwind.Section; | |
| 86 | }; | |
| 87 | ||
| 88 | pub const DebugInfo = struct { | |
| 89 | section_index: SectionIndex, | |
| 90 | }; | |
| 91 | ||
| 92 | pub const DebugLine = struct { | |
| 93 | header: Header, | |
| 94 | section_index: SectionIndex, | |
| 95 | ||
| 96 | pub const Header = struct { | |
| 97 | minimum_instruction_length: u8, | |
| 98 | maximum_operations_per_instruction: u8, | |
| 99 | default_is_stmt: bool, | |
| 100 | line_base: i8, | |
| 101 | line_range: u8, | |
| 102 | opcode_base: u8, | |
| 103 | }; | |
| 104 | }; | |
| 105 | ||
| 106 | pub const SectionIndex = enum(u32) { none = std.math.maxInt(u32), _ }; | |
| 107 | ||
| 108 | pub const Loc = union(enum) { | |
| 109 | empty, | |
| 110 | addr_reloc: link.File.SymbolId, | |
| 111 | deref: *const Loc, | |
| 112 | constu: u64, | |
| 113 | consts: i64, | |
| 114 | plus: Bin, | |
| 115 | reg: u32, | |
| 116 | breg: u32, | |
| 117 | push_object_address, | |
| 118 | call: struct { | |
| 119 | args: []const Loc = &.{}, | |
| 120 | node: MappedFile.Node.Index, | |
| 121 | }, | |
| 122 | form_tls_address: *const Loc, | |
| 123 | implicit_value: []const u8, | |
| 124 | stack_value: *const Loc, | |
| 125 | implicit_pointer: struct { | |
| 126 | node: MappedFile.Node.Index, | |
| 127 | offset: i65, | |
| 128 | }, | |
| 129 | wasm_ext: union(enum) { | |
| 130 | local: u32, | |
| 131 | global: u32, | |
| 132 | operand_stack: u32, | |
| 133 | }, | |
| 134 | ||
| 135 | pub const Bin = struct { *const Loc, *const Loc }; | |
| 136 | ||
| 137 | fn getConst(loc: Loc, comptime Int: type) ?Int { | |
| 138 | return switch (loc) { | |
| 139 | .constu => |constu| std.math.cast(Int, constu), | |
| 140 | .consts => |consts| std.math.cast(Int, consts), | |
| 141 | else => null, | |
| 142 | }; | |
| 143 | } | |
| 144 | ||
| 145 | fn getBaseReg(loc: Loc) ?u32 { | |
| 146 | return switch (loc) { | |
| 147 | .breg => |breg| breg, | |
| 148 | else => null, | |
| 149 | }; | |
| 150 | } | |
| 151 | ||
| 152 | fn writeReg(reg: u32, op0: u8, opx: u8, writer: *Writer) Writer.Error!void { | |
| 153 | if (std.math.cast(u5, reg)) |small_reg| { | |
| 154 | try writer.writeByte(op0 + small_reg); | |
| 155 | } else { | |
| 156 | try writer.writeByte(opx); | |
| 157 | try writer.writeUleb128(reg); | |
| 158 | } | |
| 159 | } | |
| 160 | ||
| 161 | fn write(loc: Loc, adapter: anytype) (UpdateError || Writer.Error)!void { | |
| 162 | const writer = adapter.writer(); | |
| 163 | switch (loc) { | |
| 164 | .empty => {}, | |
| 165 | .addr_reloc => |si| { | |
| 166 | try writer.writeByte(DW.OP.addr); | |
| 167 | try adapter.addrSym(si); | |
| 168 | }, | |
| 169 | .deref => |addr| { | |
| 170 | try addr.write(adapter); | |
| 171 | try writer.writeByte(DW.OP.deref); | |
| 172 | }, | |
| 173 | .constu => |constu| if (std.math.cast(u5, constu)) |lit| { | |
| 174 | try writer.writeByte(@as(u8, DW.OP.lit0) + lit); | |
| 175 | } else if (std.math.cast(u8, constu)) |const1u| { | |
| 176 | try writer.writeAll(&.{ DW.OP.const1u, const1u }); | |
| 177 | } else if (std.math.cast(u16, constu)) |const2u| { | |
| 178 | try writer.writeByte(DW.OP.const2u); | |
| 179 | try writer.writeInt(u16, const2u, adapter.endian()); | |
| 180 | } else if (std.math.cast(u21, constu)) |const3u| { | |
| 181 | try writer.writeByte(DW.OP.constu); | |
| 182 | try writer.writeUleb128(const3u); | |
| 183 | } else if (std.math.cast(u32, constu)) |const4u| { | |
| 184 | try writer.writeByte(DW.OP.const4u); | |
| 185 | try writer.writeInt(u32, const4u, adapter.endian()); | |
| 186 | } else if (std.math.cast(u49, constu)) |const7u| { | |
| 187 | try writer.writeByte(DW.OP.constu); | |
| 188 | try writer.writeUleb128(const7u); | |
| 189 | } else { | |
| 190 | try writer.writeByte(DW.OP.const8u); | |
| 191 | try writer.writeInt(u64, constu, adapter.endian()); | |
| 192 | }, | |
| 193 | .consts => |consts| if (std.math.cast(i8, consts)) |const1s| { | |
| 194 | try writer.writeAll(&.{ DW.OP.const1s, @bitCast(const1s) }); | |
| 195 | } else if (std.math.cast(i16, consts)) |const2s| { | |
| 196 | try writer.writeByte(DW.OP.const2s); | |
| 197 | try writer.writeInt(i16, const2s, adapter.endian()); | |
| 198 | } else if (std.math.cast(i21, consts)) |const3s| { | |
| 199 | try writer.writeByte(DW.OP.consts); | |
| 200 | try writer.writeSleb128(const3s); | |
| 201 | } else if (std.math.cast(i32, consts)) |const4s| { | |
| 202 | try writer.writeByte(DW.OP.const4s); | |
| 203 | try writer.writeInt(i32, const4s, adapter.endian()); | |
| 204 | } else if (std.math.cast(i49, consts)) |const7s| { | |
| 205 | try writer.writeByte(DW.OP.consts); | |
| 206 | try writer.writeSleb128(const7s); | |
| 207 | } else { | |
| 208 | try writer.writeByte(DW.OP.const8s); | |
| 209 | try writer.writeInt(i64, consts, adapter.endian()); | |
| 210 | }, | |
| 211 | .plus => |plus| done: { | |
| 212 | if (plus[0].getConst(u0)) |_| { | |
| 213 | try plus[1].write(adapter); | |
| 214 | break :done; | |
| 215 | } | |
| 216 | if (plus[1].getConst(u0)) |_| { | |
| 217 | try plus[0].write(adapter); | |
| 218 | break :done; | |
| 219 | } | |
| 220 | if (plus[0].getBaseReg()) |breg| { | |
| 221 | if (plus[1].getConst(i65)) |offset| { | |
| 222 | try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); | |
| 223 | try writer.writeSleb128(offset); | |
| 224 | break :done; | |
| 225 | } | |
| 226 | } | |
| 227 | if (plus[1].getBaseReg()) |breg| { | |
| 228 | if (plus[0].getConst(i65)) |offset| { | |
| 229 | try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); | |
| 230 | try writer.writeSleb128(offset); | |
| 231 | break :done; | |
| 232 | } | |
| 233 | } | |
| 234 | if (plus[0].getConst(u64)) |uconst| { | |
| 235 | try plus[1].write(adapter); | |
| 236 | try writer.writeByte(DW.OP.plus_uconst); | |
| 237 | try writer.writeUleb128(uconst); | |
| 238 | break :done; | |
| 239 | } | |
| 240 | if (plus[1].getConst(u64)) |uconst| { | |
| 241 | try plus[0].write(adapter); | |
| 242 | try writer.writeByte(DW.OP.plus_uconst); | |
| 243 | try writer.writeUleb128(uconst); | |
| 244 | break :done; | |
| 245 | } | |
| 246 | try plus[0].write(adapter); | |
| 247 | try plus[1].write(adapter); | |
| 248 | try writer.writeByte(DW.OP.plus); | |
| 249 | }, | |
| 250 | .reg => |reg| try writeReg(reg, DW.OP.reg0, DW.OP.regx, writer), | |
| 251 | .breg => |breg| { | |
| 252 | try writeReg(breg, DW.OP.breg0, DW.OP.bregx, writer); | |
| 253 | try writer.writeSleb128(0); | |
| 254 | }, | |
| 255 | .push_object_address => try writer.writeByte(DW.OP.push_object_address), | |
| 256 | .call => |call| { | |
| 257 | for (call.args) |arg| try arg.write(adapter); | |
| 258 | try writer.writeByte(DW.OP.call_ref); | |
| 259 | try adapter.infoEntry(call.node); | |
| 260 | }, | |
| 261 | .form_tls_address => |addr| { | |
| 262 | try addr.write(adapter); | |
| 263 | try writer.writeByte(DW.OP.form_tls_address); | |
| 264 | }, | |
| 265 | .implicit_value => |value| { | |
| 266 | try writer.writeByte(DW.OP.implicit_value); | |
| 267 | try writer.writeUleb128(value.len); | |
| 268 | try writer.writeAll(value); | |
| 269 | }, | |
| 270 | .stack_value => |value| { | |
| 271 | try value.write(adapter); | |
| 272 | try writer.writeByte(DW.OP.stack_value); | |
| 273 | }, | |
| 274 | .implicit_pointer => |implicit_pointer| { | |
| 275 | try writer.writeByte(DW.OP.implicit_pointer); | |
| 276 | try adapter.infoEntry(implicit_pointer.node); | |
| 277 | try writer.writeSleb128(implicit_pointer.offset); | |
| 278 | }, | |
| 279 | .wasm_ext => |wasm_ext| { | |
| 280 | try writer.writeByte(DW.OP.WASM_location); | |
| 281 | switch (wasm_ext) { | |
| 282 | .local => |local| { | |
| 283 | try writer.writeByte(DW.OP.WASM_local); | |
| 284 | try writer.writeUleb128(local); | |
| 285 | }, | |
| 286 | .global => |global| if (std.math.cast(u21, global)) |global_u21| { | |
| 287 | try writer.writeByte(DW.OP.WASM_global); | |
| 288 | try writer.writeUleb128(global_u21); | |
| 289 | } else { | |
| 290 | try writer.writeByte(DW.OP.WASM_global_u32); | |
| 291 | try writer.writeInt(u32, global, adapter.endian()); | |
| 292 | }, | |
| 293 | .operand_stack => |operand_stack| { | |
| 294 | try writer.writeByte(DW.OP.WASM_operand_stack); | |
| 295 | try writer.writeUleb128(operand_stack); | |
| 296 | }, | |
| 297 | } | |
| 298 | }, | |
| 299 | } | |
| 300 | } | |
| 301 | }; | |
| 302 | ||
| 303 | pub const Cfa = union(enum) { | |
| 304 | nop, | |
| 305 | advance_loc: u32, | |
| 306 | offset: RegOff, | |
| 307 | rel_offset: RegOff, | |
| 308 | restore: u32, | |
| 309 | undefined: u32, | |
| 310 | same_value: u32, | |
| 311 | register: [2]u32, | |
| 312 | remember_state, | |
| 313 | restore_state, | |
| 314 | def_cfa: RegOff, | |
| 315 | def_cfa_register: u32, | |
| 316 | def_cfa_offset: i64, | |
| 317 | adjust_cfa_offset: i64, | |
| 318 | def_cfa_expression: Loc, | |
| 319 | expression: RegExpr, | |
| 320 | val_offset: RegOff, | |
| 321 | val_expression: RegExpr, | |
| 322 | escape: []const u8, | |
| 323 | ||
| 324 | const RegOff = struct { reg: u32, off: i64 }; | |
| 325 | const RegExpr = struct { reg: u32, expr: Loc }; | |
| 326 | ||
| 327 | fn write(cfa: Cfa, wip_nav: *WipNav) (UpdateError || Writer.Error)!void { | |
| 328 | const dfw = &wip_nav.fde_writer.interface; | |
| 329 | switch (cfa) { | |
| 330 | .nop => try dfw.writeByte(DW.CFA.nop), | |
| 331 | .advance_loc => |loc| { | |
| 332 | const delta = | |
| 333 | @divExact(loc - wip_nav.cfi.loc, wip_nav.dwarf.frame.header.code_alignment_factor); | |
| 334 | if (delta == 0) {} else if (std.math.cast(u6, delta)) |small_delta| | |
| 335 | try dfw.writeByte(@as(u8, DW.CFA.advance_loc) + small_delta) | |
| 336 | else if (std.math.cast(u8, delta)) |ubyte_delta| | |
| 337 | try dfw.writeAll(&.{ DW.CFA.advance_loc1, ubyte_delta }) | |
| 338 | else if (std.math.cast(u16, delta)) |uhalf_delta| { | |
| 339 | try dfw.writeByte(DW.CFA.advance_loc2); | |
| 340 | try dfw.writeInt(u16, uhalf_delta, wip_nav.dwarf.endian); | |
| 341 | } else if (std.math.cast(u32, delta)) |uword_delta| { | |
| 342 | try dfw.writeByte(DW.CFA.advance_loc4); | |
| 343 | try dfw.writeInt(u32, uword_delta, wip_nav.dwarf.endian); | |
| 344 | } | |
| 345 | wip_nav.cfi.loc = loc; | |
| 346 | }, | |
| 347 | .offset, .rel_offset => |reg_off| { | |
| 348 | const factored_off = @divExact(reg_off.off - switch (cfa) { | |
| 349 | else => unreachable, | |
| 350 | .offset => 0, | |
| 351 | .rel_offset => wip_nav.cfi.cfa.off, | |
| 352 | }, wip_nav.dwarf.frame.header.data_alignment_factor); | |
| 353 | if (std.math.cast(u63, factored_off)) |unsigned_off| { | |
| 354 | if (std.math.cast(u6, reg_off.reg)) |small_reg| { | |
| 355 | try dfw.writeByte(@as(u8, DW.CFA.offset) + small_reg); | |
| 356 | } else { | |
| 357 | try dfw.writeByte(DW.CFA.offset_extended); | |
| 358 | try dfw.writeUleb128(reg_off.reg); | |
| 359 | } | |
| 360 | try dfw.writeUleb128(unsigned_off); | |
| 361 | } else { | |
| 362 | try dfw.writeByte(DW.CFA.offset_extended_sf); | |
| 363 | try dfw.writeUleb128(reg_off.reg); | |
| 364 | try dfw.writeSleb128(factored_off); | |
| 365 | } | |
| 366 | }, | |
| 367 | .restore => |reg| if (std.math.cast(u6, reg)) |small_reg| | |
| 368 | try dfw.writeByte(@as(u8, DW.CFA.restore) + small_reg) | |
| 369 | else { | |
| 370 | try dfw.writeByte(DW.CFA.restore_extended); | |
| 371 | try dfw.writeUleb128(reg); | |
| 372 | }, | |
| 373 | .undefined => |reg| { | |
| 374 | try dfw.writeByte(DW.CFA.undefined); | |
| 375 | try dfw.writeUleb128(reg); | |
| 376 | }, | |
| 377 | .same_value => |reg| { | |
| 378 | try dfw.writeByte(DW.CFA.same_value); | |
| 379 | try dfw.writeUleb128(reg); | |
| 380 | }, | |
| 381 | .register => |regs| if (regs[0] != regs[1]) { | |
| 382 | try dfw.writeByte(DW.CFA.register); | |
| 383 | for (regs) |reg| try dfw.writeUleb128(reg); | |
| 384 | } else { | |
| 385 | try dfw.writeByte(DW.CFA.same_value); | |
| 386 | try dfw.writeUleb128(regs[0]); | |
| 387 | }, | |
| 388 | .remember_state => try dfw.writeByte(DW.CFA.remember_state), | |
| 389 | .restore_state => try dfw.writeByte(DW.CFA.restore_state), | |
| 390 | .def_cfa, .def_cfa_register, .def_cfa_offset, .adjust_cfa_offset => { | |
| 391 | const reg_off: RegOff = switch (cfa) { | |
| 392 | else => unreachable, | |
| 393 | .def_cfa => |reg_off| reg_off, | |
| 394 | .def_cfa_register => |reg| .{ .reg = reg, .off = wip_nav.cfi.cfa.off }, | |
| 395 | .def_cfa_offset => |off| .{ .reg = wip_nav.cfi.cfa.reg, .off = off }, | |
| 396 | .adjust_cfa_offset => |off| .{ | |
| 397 | .reg = wip_nav.cfi.cfa.reg, | |
| 398 | .off = wip_nav.cfi.cfa.off + off, | |
| 399 | }, | |
| 400 | }; | |
| 401 | const changed_reg = reg_off.reg != wip_nav.cfi.cfa.reg; | |
| 402 | const unsigned_off = std.math.cast(u63, reg_off.off); | |
| 403 | if (reg_off.off == wip_nav.cfi.cfa.off) { | |
| 404 | if (changed_reg) { | |
| 405 | try dfw.writeByte(DW.CFA.def_cfa_register); | |
| 406 | try dfw.writeUleb128(reg_off.reg); | |
| 407 | } | |
| 408 | } else if (switch (wip_nav.dwarf.frame.header.data_alignment_factor) { | |
| 409 | 0 => unreachable, | |
| 410 | 1 => unsigned_off != null, | |
| 411 | else => |data_alignment_factor| @rem(reg_off.off, data_alignment_factor) != 0, | |
| 412 | }) { | |
| 413 | try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa else DW.CFA.def_cfa_offset); | |
| 414 | if (changed_reg) try dfw.writeUleb128(reg_off.reg); | |
| 415 | try dfw.writeUleb128(unsigned_off.?); | |
| 416 | } else { | |
| 417 | try dfw.writeByte(if (changed_reg) DW.CFA.def_cfa_sf else DW.CFA.def_cfa_offset_sf); | |
| 418 | if (changed_reg) try dfw.writeUleb128(reg_off.reg); | |
| 419 | try dfw.writeSleb128( | |
| 420 | @divExact(reg_off.off, wip_nav.dwarf.frame.header.data_alignment_factor), | |
| 421 | ); | |
| 422 | } | |
| 423 | wip_nav.cfi.cfa = reg_off; | |
| 424 | }, | |
| 425 | .def_cfa_expression => |expr| { | |
| 426 | try dfw.writeByte(DW.CFA.def_cfa_expression); | |
| 427 | try wip_nav.frameExprLoc(expr); | |
| 428 | }, | |
| 429 | .expression => |reg_expr| { | |
| 430 | try dfw.writeByte(DW.CFA.expression); | |
| 431 | try dfw.writeUleb128(reg_expr.reg); | |
| 432 | try wip_nav.frameExprLoc(reg_expr.expr); | |
| 433 | }, | |
| 434 | .val_offset => |reg_off| { | |
| 435 | const factored_off = | |
| 436 | @divExact(reg_off.off, wip_nav.dwarf.frame.header.data_alignment_factor); | |
| 437 | if (std.math.cast(u63, factored_off)) |unsigned_off| { | |
| 438 | try dfw.writeByte(DW.CFA.val_offset); | |
| 439 | try dfw.writeUleb128(reg_off.reg); | |
| 440 | try dfw.writeUleb128(unsigned_off); | |
| 441 | } else { | |
| 442 | try dfw.writeByte(DW.CFA.val_offset_sf); | |
| 443 | try dfw.writeUleb128(reg_off.reg); | |
| 444 | try dfw.writeSleb128(factored_off); | |
| 445 | } | |
| 446 | }, | |
| 447 | .val_expression => |reg_expr| { | |
| 448 | try dfw.writeByte(DW.CFA.val_expression); | |
| 449 | try dfw.writeUleb128(reg_expr.reg); | |
| 450 | try wip_nav.frameExprLoc(reg_expr.expr); | |
| 451 | }, | |
| 452 | .escape => |bytes| try dfw.writeAll(bytes), | |
| 453 | } | |
| 454 | } | |
| 455 | }; | |
| 456 | ||
| 457 | pub const WipNav = struct { | |
| 458 | dwarf: *Dwarf, | |
| 459 | unit: Unit.Index, | |
| 460 | func: ?Func.Index, | |
| 461 | func_si: link.File.SymbolId, | |
| 462 | cfi: struct { | |
| 463 | loc: u32, | |
| 464 | cfa: Cfa.RegOff, | |
| 465 | }, | |
| 466 | frame_format: Frame.Format, | |
| 467 | fde_writer: MappedFile.Node.Writer, | |
| 468 | frame_func_length_offset: usize, | |
| 469 | ||
| 470 | pub const Debug = struct { | |
| 471 | wip_nav: WipNav, | |
| 472 | pt: Zcu.PerThread, | |
| 473 | any_children: bool, | |
| 474 | blocks: std.ArrayList(struct { | |
| 475 | abbrev_code: u32, | |
| 476 | low_pc_off: u64, | |
| 477 | high_pc: u32, | |
| 478 | }), | |
| 479 | info_writer: MappedFile.Node.Writer, | |
| 480 | line_writer: MappedFile.Node.Writer, | |
| 481 | ||
| 482 | pub fn deinit(debug: *Debug, gpa: Allocator) void { | |
| 483 | debug.line_writer.deinit(); | |
| 484 | debug.info_writer.deinit(); | |
| 485 | debug.blocks.deinit(gpa); | |
| 486 | debug.wip_nav.deinit(gpa); | |
| 487 | debug.* = undefined; | |
| 488 | } | |
| 489 | ||
| 490 | pub fn genFuncHeaders(debug: *Debug) UpdateError!void { | |
| 491 | try debug.wip_nav.genFuncHeaders(); | |
| 492 | } | |
| 493 | ||
| 494 | pub fn genDebugFrame(debug: *Debug, loc: u32, cfa: Cfa) UpdateError!void { | |
| 495 | return debug.wip_nav.genDebugFrame(loc, cfa); | |
| 496 | } | |
| 497 | ||
| 498 | pub const LocalVarTag = enum { arg, local_var }; | |
| 499 | pub fn genLocalVarDebugInfo( | |
| 500 | debug: *Debug, | |
| 501 | tag: LocalVarTag, | |
| 502 | opt_name: ?[]const u8, | |
| 503 | ty: Type, | |
| 504 | loc: Loc, | |
| 505 | ) UpdateError!void { | |
| 506 | if (true) return; | |
| 507 | return debug.genLocalVarDebugInfoInner(tag, opt_name, ty, loc) catch |err| switch (err) { | |
| 508 | error.WriteFailed => debug.info_writer.err.?, | |
| 509 | else => |e| e, | |
| 510 | }; | |
| 511 | } | |
| 512 | fn genLocalVarDebugInfoInner( | |
| 513 | debug: *Debug, | |
| 514 | tag: LocalVarTag, | |
| 515 | opt_name: ?[]const u8, | |
| 516 | ty: Type, | |
| 517 | loc: Loc, | |
| 518 | ) (UpdateError || Writer.Error)!void { | |
| 519 | assert(debug.wip_nav.func != null); | |
| 520 | try debug.abbrevCode(switch (tag) { | |
| 521 | .arg => if (opt_name) |_| .arg else .unnamed_arg, | |
| 522 | .local_var => if (opt_name) |_| .local_var else unreachable, | |
| 523 | }); | |
| 524 | if (opt_name) |name| try debug.strp(name); | |
| 525 | try debug.refType(ty); | |
| 526 | try debug.infoExprLoc(loc); | |
| 527 | debug.any_children = true; | |
| 528 | } | |
| 529 | ||
| 530 | pub const LocalConstTag = enum { comptime_arg, local_const }; | |
| 531 | pub fn genLocalConstDebugInfo( | |
| 532 | debug: *Debug, | |
| 533 | tag: LocalConstTag, | |
| 534 | opt_name: ?[]const u8, | |
| 535 | val: Value, | |
| 536 | ) UpdateError!void { | |
| 537 | if (true) return; | |
| 538 | return debug.genLocalConstDebugInfoInner(tag, opt_name, val) catch |err| switch (err) { | |
| 539 | error.WriteFailed => debug.info_writer.err.?, | |
| 540 | else => |e| e, | |
| 541 | }; | |
| 542 | } | |
| 543 | fn genLocalConstDebugInfoInner( | |
| 544 | debug: *Debug, | |
| 545 | tag: LocalConstTag, | |
| 546 | opt_name: ?[]const u8, | |
| 547 | val: Value, | |
| 548 | ) (UpdateError || Writer.Error)!void { | |
| 549 | assert(debug.wip_nav.func != null); | |
| 550 | const zcu = debug.pt.zcu; | |
| 551 | const ty = val.typeOf(zcu); | |
| 552 | const has_runtime_bits = ty.hasRuntimeBits(zcu); | |
| 553 | const has_comptime_state = ty.comptimeOnly(zcu); | |
| 554 | try debug.abbrevCode(if (has_runtime_bits and has_comptime_state) switch (tag) { | |
| 555 | .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits_comptime_state else .unnamed_comptime_arg_runtime_bits_comptime_state, | |
| 556 | .local_const => if (opt_name) |_| .local_const_runtime_bits_comptime_state else unreachable, | |
| 557 | } else if (has_comptime_state) switch (tag) { | |
| 558 | .comptime_arg => if (opt_name) |_| .comptime_arg_comptime_state else .unnamed_comptime_arg_comptime_state, | |
| 559 | .local_const => if (opt_name) |_| .local_const_comptime_state else unreachable, | |
| 560 | } else if (has_runtime_bits) switch (tag) { | |
| 561 | .comptime_arg => if (opt_name) |_| .comptime_arg_runtime_bits else .unnamed_comptime_arg_runtime_bits, | |
| 562 | .local_const => if (opt_name) |_| .local_const_runtime_bits else unreachable, | |
| 563 | } else switch (tag) { | |
| 564 | .comptime_arg => if (opt_name) |_| .comptime_arg else .unnamed_comptime_arg, | |
| 565 | .local_const => if (opt_name) |_| .local_const else unreachable, | |
| 566 | }); | |
| 567 | if (opt_name) |name| try debug.strp(name); | |
| 568 | try debug.refType(ty); | |
| 569 | if (has_runtime_bits) try debug.blockValue(val); | |
| 570 | if (has_comptime_state) try debug.refValue(val); | |
| 571 | debug.any_children = true; | |
| 572 | } | |
| 573 | ||
| 574 | pub fn genVarArgsDebugInfo(debug: *Debug) UpdateError!void { | |
| 575 | if (true) return; | |
| 576 | return debug.genVarArgsDebugInfoInner() catch |err| switch (err) { | |
| 577 | error.WriteFailed => debug.info_writer.err.?, | |
| 578 | else => |e| e, | |
| 579 | }; | |
| 580 | } | |
| 581 | fn genVarArgsDebugInfoInner(debug: *Debug) (UpdateError || Writer.Error)!void { | |
| 582 | assert(debug.wip_nav.func != null); | |
| 583 | try debug.abbrevCode(.is_var_args); | |
| 584 | debug.any_children = true; | |
| 585 | } | |
| 586 | ||
| 587 | pub fn advancePcAndLine(debug: *Debug, delta_line: i33, delta_pc: u64) UpdateError!void { | |
| 588 | if (true) return; | |
| 589 | return debug.advancePcAndLineInner(delta_line, delta_pc) catch |err| switch (err) { | |
| 590 | error.WriteFailed => debug.line_writer.err.?, | |
| 591 | }; | |
| 592 | } | |
| 593 | fn advancePcAndLineInner(debug: *Debug, delta_line: i33, delta_pc: u64) Writer.Error!void { | |
| 594 | const dlw = &debug.line_writer.interface; | |
| 595 | ||
| 596 | const header = debug.wip_nav.dwarf.debug_line.header; | |
| 597 | assert(header.maximum_operations_per_instruction == 1); | |
| 598 | const delta_op: u64 = 0; | |
| 599 | ||
| 600 | const remaining_delta_line: i9 = @intCast(if (delta_line < header.line_base or | |
| 601 | delta_line - header.line_base >= header.line_range) | |
| 602 | remaining: { | |
| 603 | assert(delta_line != 0); | |
| 604 | try dlw.writeByte(DW.LNS.advance_line); | |
| 605 | try dlw.writeSleb128(delta_line); | |
| 606 | break :remaining 0; | |
| 607 | } else delta_line); | |
| 608 | ||
| 609 | const op_advance = @divExact(delta_pc, header.minimum_instruction_length) * | |
| 610 | header.maximum_operations_per_instruction + delta_op; | |
| 611 | const max_op_advance: u9 = (std.math.maxInt(u8) - header.opcode_base) / header.line_range; | |
| 612 | const remaining_op_advance: u8 = @intCast(if (op_advance >= 2 * max_op_advance) remaining: { | |
| 613 | try dlw.writeByte(DW.LNS.advance_pc); | |
| 614 | try dlw.writeUleb128(op_advance); | |
| 615 | break :remaining 0; | |
| 616 | } else if (op_advance >= max_op_advance) remaining: { | |
| 617 | try dlw.writeByte(DW.LNS.const_add_pc); | |
| 618 | break :remaining op_advance - max_op_advance; | |
| 619 | } else op_advance); | |
| 620 | ||
| 621 | if (remaining_delta_line == 0 and remaining_op_advance == 0) | |
| 622 | try dlw.writeByte(DW.LNS.copy) | |
| 623 | else | |
| 624 | try dlw.writeByte(@intCast((remaining_delta_line - header.line_base) + | |
| 625 | (header.line_range * remaining_op_advance) + header.opcode_base)); | |
| 626 | } | |
| 627 | ||
| 628 | pub fn setColumn(debug: *Debug, column: u32) UpdateError!void { | |
| 629 | if (true) return; | |
| 630 | return debug.setColumnInner(column) catch |err| switch (err) { | |
| 631 | error.WriteFailed => debug.line_writer.err.?, | |
| 632 | }; | |
| 633 | } | |
| 634 | fn setColumnInner(debug: *Debug, column: u32) Writer.Error!void { | |
| 635 | const dlw = &debug.line_writer.interface; | |
| 636 | try dlw.writeByte(DW.LNS.set_column); | |
| 637 | try dlw.writeUleb128(column + 1); | |
| 638 | } | |
| 639 | ||
| 640 | pub fn negateStmt(debug: *Debug) UpdateError!void { | |
| 641 | if (true) return; | |
| 642 | return debug.negateStmtInner() catch |err| switch (err) { | |
| 643 | error.WriteFailed => debug.line_writer.err.?, | |
| 644 | }; | |
| 645 | } | |
| 646 | fn negateStmtInner(debug: *Debug) Writer.Error!void { | |
| 647 | try debug.line_writer.interface.writeByte(DW.LNS.negate_stmt); | |
| 648 | } | |
| 649 | ||
| 650 | pub fn setPrologueEnd(debug: *Debug) UpdateError!void { | |
| 651 | if (true) return; | |
| 652 | return debug.setPrologueEndInner() catch |err| switch (err) { | |
| 653 | error.WriteFailed => debug.line_writer.err.?, | |
| 654 | }; | |
| 655 | } | |
| 656 | fn setPrologueEndInner(debug: *Debug) Writer.Error!void { | |
| 657 | try debug.line_writer.interface.writeByte(DW.LNS.set_prologue_end); | |
| 658 | } | |
| 659 | ||
| 660 | pub fn setEpilogueBegin(debug: *Debug) UpdateError!void { | |
| 661 | if (true) return; | |
| 662 | return debug.setEpilogueBeginInner() catch |err| switch (err) { | |
| 663 | error.WriteFailed => debug.line_writer.err.?, | |
| 664 | }; | |
| 665 | } | |
| 666 | fn setEpilogueBeginInner(debug: *Debug) Writer.Error!void { | |
| 667 | try debug.line_writer.interface.writeByte(DW.LNS.set_epilogue_begin); | |
| 668 | } | |
| 669 | ||
| 670 | pub fn enterBlock(debug: *Debug, code_off: u64) UpdateError!void { | |
| 671 | if (true) return; | |
| 672 | return debug.enterBlockInner(code_off) catch |err| switch (err) { | |
| 673 | error.WriteFailed => debug.info_writer.err.?, | |
| 674 | else => |e| e, | |
| 675 | }; | |
| 676 | } | |
| 677 | fn enterBlockInner(debug: *Debug, code_off: u64) (UpdateError || Writer.Error)!void { | |
| 678 | const dwarf = debug.wip_nav.dwarf; | |
| 679 | const diw = &debug.info_writer.interface; | |
| 680 | const block = try debug.blocks.addOne(dwarf.linkFile().comp.gpa); | |
| 681 | ||
| 682 | block.abbrev_code = @intCast(diw.end); | |
| 683 | try debug.abbrevCode(.block); | |
| 684 | block.low_pc_off = code_off; | |
| 685 | try debug.infoAddrSym(debug.wip_nav.func_si, code_off); | |
| 686 | block.high_pc = @intCast(diw.end); | |
| 687 | try diw.writeInt(u32, 0, dwarf.endian); | |
| 688 | debug.any_children = false; | |
| 689 | } | |
| 690 | ||
| 691 | pub fn leaveBlock(debug: *Debug, code_off: u64) UpdateError!void { | |
| 692 | if (true) return; | |
| 693 | return debug.leaveBlockInner(code_off) catch |err| switch (err) { | |
| 694 | error.WriteFailed => debug.info_writer.err.?, | |
| 695 | else => |e| e, | |
| 696 | }; | |
| 697 | } | |
| 698 | fn leaveBlockInner(debug: *Debug, code_off: u64) (UpdateError || Writer.Error)!void { | |
| 699 | const dwarf = debug.wip_nav.dwarf; | |
| 700 | const block_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.block)); | |
| 701 | const block = debug.blocks.pop().?; | |
| 702 | if (debug.any_children) | |
| 703 | try debug.info_writer.interface.writeUleb128(@backingInt(AbbrevCode.null)) | |
| 704 | else | |
| 705 | std.leb.writeUnsignedFixed( | |
| 706 | block_bytes, | |
| 707 | debug.info_writer.interface.buffered()[block.abbrev_code..][0..block_bytes], | |
| 708 | @intCast(try dwarf.refAbbrevCode(.empty_block)), | |
| 709 | ); | |
| 710 | std.mem.writeInt( | |
| 711 | u32, | |
| 712 | debug.info_writer.interface.buffered()[block.high_pc..][0..4], | |
| 713 | @intCast(code_off - block.low_pc_off), | |
| 714 | dwarf.endian, | |
| 715 | ); | |
| 716 | debug.any_children = true; | |
| 717 | } | |
| 718 | ||
| 719 | pub fn enterInlineFunc( | |
| 720 | debug: *Debug, | |
| 721 | func: InternPool.Index, | |
| 722 | code_off: u64, | |
| 723 | line: u32, | |
| 724 | column: u32, | |
| 725 | ) UpdateError!void { | |
| 726 | if (true) return; | |
| 727 | return debug.enterInlineFuncInner(func, code_off, line, column) catch |err| switch (err) { | |
| 728 | error.WriteFailed => debug.info_writer.err.?, | |
| 729 | else => |e| e, | |
| 730 | }; | |
| 731 | } | |
| 732 | fn enterInlineFuncInner( | |
| 733 | debug: *Debug, | |
| 734 | func: InternPool.Index, | |
| 735 | code_off: u64, | |
| 736 | line: u32, | |
| 737 | column: u32, | |
| 738 | ) (UpdateError || Writer.Error)!void { | |
| 739 | const dwarf = debug.wip_nav.dwarf; | |
| 740 | const zcu = debug.pt.zcu; | |
| 741 | const diw = &debug.info_writer.interface; | |
| 742 | const block = try debug.blocks.addOne(zcu.gpa); | |
| 743 | ||
| 744 | block.abbrev_code = @intCast(diw.end); | |
| 745 | try debug.abbrevCode(.inlined_func); | |
| 746 | try debug.refNav(zcu.funcInfo(func).owner_nav); | |
| 747 | try diw.writeUleb128(zcu.navSrcLine(debug.wip_nav.func.?.nav(dwarf)) + line + 1); | |
| 748 | try diw.writeUleb128(column + 1); | |
| 749 | block.low_pc_off = code_off; | |
| 750 | try debug.infoAddrSym(debug.wip_nav.func_si, code_off); | |
| 751 | block.high_pc = @intCast(diw.end); | |
| 752 | try diw.writeInt(u32, 0, dwarf.endian); | |
| 753 | try debug.setInlineFunc(func); | |
| 754 | debug.any_children = false; | |
| 755 | } | |
| 756 | ||
| 757 | pub fn leaveInlineFunc(debug: *Debug, func: InternPool.Index, code_off: u64) UpdateError!void { | |
| 758 | if (true) return; | |
| 759 | return debug.leaveInlineFuncInner(func, code_off) catch |err| switch (err) { | |
| 760 | error.WriteFailed => debug.info_writer.err.?, | |
| 761 | else => |e| e, | |
| 762 | }; | |
| 763 | } | |
| 764 | fn leaveInlineFuncInner( | |
| 765 | debug: *Debug, | |
| 766 | func: InternPool.Index, | |
| 767 | code_off: u64, | |
| 768 | ) (UpdateError || Writer.Error)!void { | |
| 769 | const dwarf = debug.wip_nav.dwarf; | |
| 770 | const inlined_func_bytes = comptime uleb128Bytes(@backingInt(AbbrevCode.inlined_func)); | |
| 771 | const block = debug.blocks.pop().?; | |
| 772 | if (debug.any_children) | |
| 773 | try debug.info_writer.interface.writeUleb128(@backingInt(AbbrevCode.null)) | |
| 774 | else | |
| 775 | std.leb.writeUnsignedFixed( | |
| 776 | inlined_func_bytes, | |
| 777 | debug.info_writer.interface.buffered()[block.abbrev_code..][0..inlined_func_bytes], | |
| 778 | @intCast(try dwarf.refAbbrevCode(.empty_inlined_func)), | |
| 779 | ); | |
| 780 | std.mem.writeInt( | |
| 781 | u32, | |
| 782 | debug.info_writer.interface.buffered()[block.high_pc..][0..4], | |
| 783 | @intCast(code_off - block.low_pc_off), | |
| 784 | dwarf.endian, | |
| 785 | ); | |
| 786 | try debug.setInlineFunc(func); | |
| 787 | debug.any_children = true; | |
| 788 | } | |
| 789 | ||
| 790 | pub fn setInlineFunc(debug: *Debug, func: InternPool.Index) UpdateError!void { | |
| 791 | return debug.setInlineFuncInner(func) catch |err| switch (err) { | |
| 792 | error.WriteFailed => debug.line_writer.err.?, | |
| 793 | else => |e| e, | |
| 794 | }; | |
| 795 | } | |
| 796 | fn setInlineFuncInner(debug: *Debug, func: InternPool.Index) (UpdateError || Writer.Error)!void { | |
| 797 | const wip_nav = &debug.wip_nav; | |
| 798 | const zcu = debug.pt.zcu; | |
| 799 | const dwarf = wip_nav.dwarf; | |
| 800 | ||
| 801 | const func_index = try dwarf.getFunc(zcu.funcInfo(func).owner_nav); | |
| 802 | if (wip_nav.func == func_index) return; | |
| 803 | ||
| 804 | if (true) @panic("TODO"); | |
| 805 | const new_func_info = zcu.funcInfo(func); | |
| 806 | const new_file = zcu.navFileScopeIndex(new_func_info.owner_nav); | |
| 807 | const new_unit = try dwarf.getUnit(zcu.fileByIndex(new_file).mod.?); | |
| 808 | ||
| 809 | const dlw = &debug.line_writer.interface; | |
| 810 | if (zcu.comp.config.incremental) { | |
| 811 | const new_func_gop = try dwarf.funcs.getOrPut(dwarf.gpa, new_func_info.owner_nav); | |
| 812 | errdefer _ = if (!new_func_gop.found_existing) dwarf.funcs.pop(); | |
| 813 | if (!new_func_gop.found_existing) new_func_gop.value_ptr.* = .{ | |
| 814 | .frame_node = .none, | |
| 815 | .debug_info_node = .none, | |
| 816 | .debug_line_node = .none, | |
| 817 | }; | |
| 818 | ||
| 819 | const section_offset_size: u4 = switch (dwarf.format) { | |
| 820 | .@"32" => 4, | |
| 821 | .@"64" => 8, | |
| 822 | }; | |
| 823 | ||
| 824 | try dlw.writeByte(DW.LNS.extended_op); | |
| 825 | try dlw.writeUleb128(1 + section_offset_size); | |
| 826 | try dlw.writeByte(DW.LNE.ZIG_set_decl); | |
| 827 | try dwarf.debug_line.section.getUnit(wip_nav.unit).getEntry(wip_nav.entry).cross_section_relocs.append(dwarf.gpa, .{ | |
| 828 | .source_off = @intCast(dlw.end), | |
| 829 | .target_sec = .debug_info, | |
| 830 | .target_unit = new_unit, | |
| 831 | .target_entry = new_func_gop.value_ptr.toOptional(), | |
| 832 | }); | |
| 833 | try dlw.splatByteAll(0, section_offset_size); | |
| 834 | return; | |
| 835 | } | |
| 836 | ||
| 837 | const old_func_info = zcu.funcInfo(wip_nav.func); | |
| 838 | const old_file = zcu.navFileScopeIndex(old_func_info.owner_nav); | |
| 839 | if (old_file != new_file) { | |
| 840 | const mod_info = dwarf.getModInfo(wip_nav.unit); | |
| 841 | try mod_info.dirs.put(dwarf.gpa, new_unit, {}); | |
| 842 | const file_gop = try mod_info.files.getOrPut(dwarf.gpa, new_file); | |
| 843 | ||
| 844 | try dlw.writeByte(DW.LNS.set_file); | |
| 845 | try dlw.writeUleb128(file_gop.index); | |
| 846 | } | |
| 847 | ||
| 848 | const old_src_line: i33 = zcu.navSrcLine(old_func_info.owner_nav); | |
| 849 | const new_src_line: i33 = zcu.navSrcLine(new_func_info.owner_nav); | |
| 850 | if (new_src_line != old_src_line) { | |
| 851 | try dlw.writeByte(DW.LNS.advance_line); | |
| 852 | try dlw.writeSleb128(new_src_line - old_src_line); | |
| 853 | } | |
| 854 | ||
| 855 | wip_nav.func = func; | |
| 856 | } | |
| 857 | ||
| 858 | fn abbrevCode(debug: *Debug, abbrev_code: AbbrevCode) (UpdateError || Writer.Error)!void { | |
| 859 | try debug.info_writer.interface.writeUleb128(try debug.wip_nav.dwarf.refAbbrevCode(abbrev_code)); | |
| 860 | } | |
| 861 | ||
| 862 | fn infoExternalReloc(debug: *Debug, reloc: struct { | |
| 863 | source_off: u32 = 0, | |
| 864 | target_si: link.File.SymbolId, | |
| 865 | target_off: u64 = 0, | |
| 866 | }) Allocator.Error!void { | |
| 867 | if (true) @panic("TODO"); | |
| 868 | try debug.wip_nav.externalReloc(&debug.wip_nav.dwarf.debug_frame.section, reloc); | |
| 869 | } | |
| 870 | ||
| 871 | fn infoSectionOffset( | |
| 872 | debug: *Debug, | |
| 873 | target: MappedFile.Node.Index, | |
| 874 | addend: i64, | |
| 875 | ) (UpdateError || Writer.Error)!void { | |
| 876 | const dwarf = debug.wip_nav.dwarf; | |
| 877 | const diw = &debug.info_writer.interface; | |
| 878 | const offset = diw.end; | |
| 879 | switch (dwarf.format) { | |
| 880 | .@"32" => try diw.writeInt(u32, 0, dwarf.endian), | |
| 881 | .@"64" => try diw.writeInt(u64, 0, dwarf.endian), | |
| 882 | } | |
| 883 | try dwarf.linkFile().cast(.elf2).?.addNodeReloc( | |
| 884 | debug.info_writer.ni, | |
| 885 | offset, | |
| 886 | target, | |
| 887 | addend, | |
| 888 | switch (dwarf.format) { | |
| 889 | .@"32" => .abs32, | |
| 890 | .@"64" => .abs64, | |
| 891 | }, | |
| 892 | ); | |
| 893 | } | |
| 894 | ||
| 895 | fn strp(debug: *Debug, str: []const u8) (UpdateError || Writer.Error)!void { | |
| 896 | if (true) @panic("TODO"); | |
| 897 | const dwarf = debug.wip_nav.dwarf; | |
| 898 | try debug.infoSectionOffset(.debug_str, try dwarf.debug_str.addString(dwarf, str), 0); | |
| 899 | } | |
| 900 | ||
| 901 | fn strpFmt( | |
| 902 | debug: *Debug, | |
| 903 | comptime fmt: []const u8, | |
| 904 | args: anytype, | |
| 905 | ) (UpdateError || Writer.Error)!void { | |
| 906 | const gpa = &debug.wip_nav.dwarf.gpa; | |
| 907 | const str = try std.fmt.allocPrint(gpa, fmt, args); | |
| 908 | defer gpa.free(str); | |
| 909 | return debug.strp(str); | |
| 910 | } | |
| 911 | ||
| 912 | fn infoExprLoc(debug: *Debug, loc: Loc) (UpdateError || Writer.Error)!void { | |
| 913 | var buf: [64]u8 = undefined; | |
| 914 | var counter: ExprLocCounter = .init(debug.wip_nav.dwarf, &buf); | |
| 915 | try loc.write(&counter); | |
| 916 | ||
| 917 | const adapter: struct { | |
| 918 | debug: *Debug, | |
| 919 | fn writer(ctx: @This()) *Writer { | |
| 920 | return &ctx.debug.info_writer.interface; | |
| 921 | } | |
| 922 | fn endian(ctx: @This()) std.lang.Endian { | |
| 923 | return ctx.debug.wip_nav.dwarf.endian; | |
| 924 | } | |
| 925 | fn addrSym(ctx: @This(), si: link.File.SymbolId) (UpdateError || Writer.Error)!void { | |
| 926 | try ctx.debug.infoAddrSym(si, 0); | |
| 927 | } | |
| 928 | fn infoEntry( | |
| 929 | ctx: @This(), | |
| 930 | node: MappedFile.Node.Index, | |
| 931 | ) (UpdateError || Writer.Error)!void { | |
| 932 | try ctx.debug.infoSectionOffset(node, 0); | |
| 933 | } | |
| 934 | } = .{ .debug = debug }; | |
| 935 | try adapter.writer().writeUleb128(counter.dw.fullCount()); | |
| 936 | try loc.write(adapter); | |
| 937 | } | |
| 938 | ||
| 939 | fn infoAddrSym( | |
| 940 | debug: *Debug, | |
| 941 | si: link.File.SymbolId, | |
| 942 | sym_off: u64, | |
| 943 | ) (UpdateError || Writer.Error)!void { | |
| 944 | const diw = &debug.info_writer.interface; | |
| 945 | try debug.infoExternalReloc(.{ | |
| 946 | .source_off = @intCast(diw.end), | |
| 947 | .target_si = si, | |
| 948 | .target_off = sym_off, | |
| 949 | }); | |
| 950 | try diw.splatByteAll(0, @backingInt(debug.wip_nav.dwarf.address_size)); | |
| 951 | } | |
| 952 | ||
| 953 | fn refNav(debug: *Debug, nav_index: InternPool.Nav.Index) (UpdateError || Writer.Error)!void { | |
| 954 | try debug.infoSectionOffset(try debug.wip_nav.dwarf.getNavNode(nav_index), 0); | |
| 955 | } | |
| 956 | ||
| 957 | fn refType(debug: *Debug, ty: Type) (UpdateError || Writer.Error)!void { | |
| 958 | return debug.refValue(ty.toValue()); | |
| 959 | } | |
| 960 | ||
| 961 | fn refValue(debug: *Debug, value: Value) (UpdateError || Writer.Error)!void { | |
| 962 | if (true) @panic("TODO"); | |
| 963 | try debug.infoSectionOffset(.debug_info, try debug.getValueNode(value), 0); | |
| 964 | } | |
| 965 | ||
| 966 | fn getValueNode(debug: *Debug, value: Value) UpdateError!MappedFile.Node.Index { | |
| 967 | if (value.typeOf(debug.zcu).toIntern() != .type_type) { | |
| 968 | assert(value.typeOf(debug.zcu).comptimeOnly(debug.zcu)); | |
| 969 | } | |
| 970 | const dwarf = debug.wip_nav.dwarf; | |
| 971 | const index = try dwarf.const_pool.get(debug.pt, .{ .dwarf = dwarf }, value.toIntern()); | |
| 972 | return dwarf.values.items[@backingInt(index)]; | |
| 973 | } | |
| 974 | ||
| 975 | fn blockValue(debug: *Debug, val: Value) (UpdateError || Writer.Error)!void { | |
| 976 | const ty = val.typeOf(debug.pt.zcu); | |
| 977 | const diw = &debug.info_writer.interface; | |
| 978 | const size = ty.abiSize(debug.pt.zcu); | |
| 979 | try diw.writeUleb128(size); | |
| 980 | if (size == 0) return; | |
| 981 | const old_end = diw.end; | |
| 982 | try codegen.generateSymbol( | |
| 983 | debug.wip_nav.dwarf.linkFile(), | |
| 984 | debug.pt, | |
| 985 | val, | |
| 986 | diw, | |
| 987 | .{ .debug_output = .{ .dwarf2 = debug } }, | |
| 988 | ); | |
| 989 | if (old_end + size != diw.end) { | |
| 990 | std.debug.print("{f} [{}]: {} != {}\n", .{ | |
| 991 | ty.fmt(debug.pt), | |
| 992 | ty.toIntern(), | |
| 993 | size, | |
| 994 | diw.end - old_end, | |
| 995 | }); | |
| 996 | unreachable; | |
| 997 | } | |
| 998 | } | |
| 999 | }; | |
| 1000 | ||
| 1001 | pub fn deinit(wip_nav: *WipNav, gpa: Allocator) void { | |
| 1002 | _ = gpa; | |
| 1003 | wip_nav.fde_writer.deinit(); | |
| 1004 | wip_nav.* = undefined; | |
| 1005 | } | |
| 1006 | ||
| 1007 | pub fn genFuncHeaders(wip_nav: *WipNav) UpdateError!void { | |
| 1008 | wip_nav.genDebugFrameHeader() catch |err| switch (err) { | |
| 1009 | error.WriteFailed => return wip_nav.fde_writer.err.?, | |
| 1010 | else => |e| return e, | |
| 1011 | }; | |
| 1012 | } | |
| 1013 | fn genDebugFrameHeader(wip_nav: *WipNav) (UpdateError || Writer.Error)!void { | |
| 1014 | assert(wip_nav.func != null); | |
| 1015 | const dwarf = wip_nav.dwarf; | |
| 1016 | const dfw = &wip_nav.fde_writer.interface; | |
| 1017 | switch (dwarf.format) { | |
| 1018 | .@"32" => try dfw.writeInt(u32, undefined, dwarf.endian), | |
| 1019 | .@"64" => { | |
| 1020 | try dfw.writeInt(u32, std.math.maxInt(u32), dwarf.endian); | |
| 1021 | try dfw.writeInt(u64, undefined, dwarf.endian); | |
| 1022 | }, | |
| 1023 | } | |
| 1024 | const unit = wip_nav.unit.get(dwarf); | |
| 1025 | switch (wip_nav.frame_format) { | |
| 1026 | .eh_frame => { | |
| 1027 | try dfw.writeInt(u32, undefined, dwarf.endian); | |
| 1028 | { | |
| 1029 | const offset = dfw.end; | |
| 1030 | try dfw.writeInt(u32, 0, dwarf.endian); | |
| 1031 | const elf = dwarf.linkFile().cast(.elf2).?; | |
| 1032 | try elf.addReloc( | |
| 1033 | @bitCast(wip_nav.fde_writer.ni), | |
| 1034 | offset, | |
| 1035 | wip_nav.func_si, | |
| 1036 | 0, | |
| 1037 | .rel32(elf), | |
| 1038 | ); | |
| 1039 | } | |
| 1040 | wip_nav.frame_func_length_offset = dfw.end; | |
| 1041 | try dfw.writeInt(u32, undefined, dwarf.endian); | |
| 1042 | try dfw.writeUleb128(0); | |
| 1043 | }, | |
| 1044 | .debug_frame => { | |
| 1045 | try wip_nav.frameSectionOffset(unit.cie_ni.unwrap().?, 0); | |
| 1046 | try wip_nav.frameAddrSym(wip_nav.func_si, 0); | |
| 1047 | wip_nav.frame_func_length_offset = dfw.end; | |
| 1048 | try dfw.splatByteAll(undefined, @backingInt(dwarf.address_size)); | |
| 1049 | }, | |
| 1050 | } | |
| 1051 | } | |
| 1052 | ||
| 1053 | pub fn genDebugFrame(wip_nav: *WipNav, loc: u32, cfa: Cfa) UpdateError!void { | |
| 1054 | return wip_nav.genDebugFrameInner(loc, cfa) catch |err| switch (err) { | |
| 1055 | error.WriteFailed => wip_nav.fde_writer.err.?, | |
| 1056 | else => |e| e, | |
| 1057 | }; | |
| 1058 | } | |
| 1059 | fn genDebugFrameInner(wip_nav: *WipNav, loc: u32, cfa: Cfa) (UpdateError || Writer.Error)!void { | |
| 1060 | assert(wip_nav.func != null); | |
| 1061 | const loc_cfa: Cfa = .{ .advance_loc = loc }; | |
| 1062 | try loc_cfa.write(wip_nav); | |
| 1063 | try cfa.write(wip_nav); | |
| 1064 | } | |
| 1065 | ||
| 1066 | pub fn finishDebugFrameFde(wip_nav: *WipNav, func_length: u64) void { | |
| 1067 | const dwarf = wip_nav.dwarf; | |
| 1068 | const fde = wip_nav.fde_writer.interface.buffer; | |
| 1069 | switch (wip_nav.frame_format) { | |
| 1070 | .eh_frame => std.mem.writeInt( | |
| 1071 | u32, | |
| 1072 | fde[wip_nav.frame_func_length_offset..][0..4], | |
| 1073 | @intCast(func_length), | |
| 1074 | dwarf.endian, | |
| 1075 | ), | |
| 1076 | .debug_frame => switch (dwarf.address_size) { | |
| 1077 | _ => unreachable, | |
| 1078 | .@"32" => std.mem.writeInt( | |
| 1079 | u32, | |
| 1080 | fde[wip_nav.frame_func_length_offset..][0..4], | |
| 1081 | @intCast(func_length), | |
| 1082 | dwarf.endian, | |
| 1083 | ), | |
| 1084 | .@"64" => std.mem.writeInt( | |
| 1085 | u64, | |
| 1086 | fde[wip_nav.frame_func_length_offset..][0..8], | |
| 1087 | func_length, | |
| 1088 | dwarf.endian, | |
| 1089 | ), | |
| 1090 | }, | |
| 1091 | } | |
| 1092 | } | |
| 1093 | ||
| 1094 | const ExprLocCounter = struct { | |
| 1095 | dw: Writer.Discarding, | |
| 1096 | section_offset_bytes: u32, | |
| 1097 | address_size: AddressSize, | |
| 1098 | fn init(dwarf: *Dwarf, buf: []u8) ExprLocCounter { | |
| 1099 | return .{ | |
| 1100 | .dw = .init(buf), | |
| 1101 | .section_offset_bytes = switch (dwarf.format) { | |
| 1102 | .@"32" => 4, | |
| 1103 | .@"64" => 8, | |
| 1104 | }, | |
| 1105 | .address_size = dwarf.address_size, | |
| 1106 | }; | |
| 1107 | } | |
| 1108 | fn writer(counter: *ExprLocCounter) *Writer { | |
| 1109 | return &counter.dw.writer; | |
| 1110 | } | |
| 1111 | fn endian(_: ExprLocCounter) std.lang.Endian { | |
| 1112 | return .native; | |
| 1113 | } | |
| 1114 | fn addrSym(counter: *ExprLocCounter, _: link.File.SymbolId) Writer.Error!void { | |
| 1115 | try counter.dw.writer.splatByteAll(undefined, @backingInt(counter.address_size)); | |
| 1116 | } | |
| 1117 | fn infoEntry(counter: *ExprLocCounter, _: MappedFile.Node.Index) Writer.Error!void { | |
| 1118 | try counter.dw.writer.splatByteAll(undefined, counter.section_offset_bytes); | |
| 1119 | } | |
| 1120 | }; | |
| 1121 | ||
| 1122 | fn frameSectionOffset( | |
| 1123 | wip_nav: *WipNav, | |
| 1124 | target: MappedFile.Node.Index, | |
| 1125 | addend: i64, | |
| 1126 | ) (UpdateError || Writer.Error)!void { | |
| 1127 | const dwarf = wip_nav.dwarf; | |
| 1128 | const dfw = &wip_nav.fde_writer.interface; | |
| 1129 | const offset = dfw.end; | |
| 1130 | switch (dwarf.format) { | |
| 1131 | .@"32" => try dfw.writeInt(u32, 0, dwarf.endian), | |
| 1132 | .@"64" => try dfw.writeInt(u64, 0, dwarf.endian), | |
| 1133 | } | |
| 1134 | try dwarf.linkFile().cast(.elf2).?.addNodeReloc( | |
| 1135 | wip_nav.fde_writer.ni, | |
| 1136 | offset, | |
| 1137 | target, | |
| 1138 | addend, | |
| 1139 | switch (dwarf.format) { | |
| 1140 | .@"32" => .abs32, | |
| 1141 | .@"64" => .abs64, | |
| 1142 | }, | |
| 1143 | ); | |
| 1144 | } | |
| 1145 | ||
| 1146 | fn frameExprLoc(wip_nav: *WipNav, loc: Loc) (UpdateError || Writer.Error)!void { | |
| 1147 | var buf: [64]u8 = undefined; | |
| 1148 | var counter: ExprLocCounter = .init(wip_nav.dwarf, &buf); | |
| 1149 | try loc.write(&counter); | |
| 1150 | ||
| 1151 | const adapter: struct { | |
| 1152 | wip_nav: *WipNav, | |
| 1153 | fn writer(ctx: @This()) *Writer { | |
| 1154 | return &ctx.wip_nav.fde_writer.interface; | |
| 1155 | } | |
| 1156 | fn endian(ctx: @This()) std.lang.Endian { | |
| 1157 | return ctx.wip_nav.dwarf.endian; | |
| 1158 | } | |
| 1159 | fn addrSym(ctx: @This(), si: link.File.SymbolId) (UpdateError || Writer.Error)!void { | |
| 1160 | try ctx.wip_nav.frameAddrSym(si, 0); | |
| 1161 | } | |
| 1162 | fn infoEntry(ctx: @This(), node: MappedFile.Node.Index) (UpdateError || Writer.Error)!void { | |
| 1163 | try ctx.wip_nav.frameSectionOffset(node, 0); | |
| 1164 | } | |
| 1165 | } = .{ .wip_nav = wip_nav }; | |
| 1166 | try adapter.writer().writeUleb128(counter.dw.fullCount()); | |
| 1167 | try loc.write(adapter); | |
| 1168 | } | |
| 1169 | ||
| 1170 | fn frameAddrSym( | |
| 1171 | wip_nav: *WipNav, | |
| 1172 | si: link.File.SymbolId, | |
| 1173 | sym_off: u64, | |
| 1174 | ) (UpdateError || Writer.Error)!void { | |
| 1175 | const dwarf = wip_nav.dwarf; | |
| 1176 | const dfw = &wip_nav.fde_writer.interface; | |
| 1177 | const offset = dfw.end; | |
| 1178 | try dfw.splatByteAll(0, @backingInt(dwarf.address_size)); | |
| 1179 | const elf = dwarf.linkFile().cast(.elf2).?; | |
| 1180 | try elf.addReloc( | |
| 1181 | @bitCast(wip_nav.fde_writer.ni), | |
| 1182 | offset, | |
| 1183 | si, | |
| 1184 | @bitCast(sym_off), | |
| 1185 | switch (dwarf.format) { | |
| 1186 | .@"32" => .abs32(elf), | |
| 1187 | .@"64" => .abs64(elf), | |
| 1188 | }, | |
| 1189 | ); | |
| 1190 | } | |
| 1191 | }; | |
| 1192 | ||
| 1193 | pub fn init(lf: *link.File, format: DW.Format) Dwarf { | |
| 1194 | const comp = lf.comp; | |
| 1195 | const target = &comp.root_mod.resolved_target.result; | |
| 1196 | return .{ | |
| 1197 | .tag = lf.tag, | |
| 1198 | .format = format, | |
| 1199 | .address_size = switch (target.ptrBitWidth()) { | |
| 1200 | 0...32 => .@"32", | |
| 1201 | 33...64 => .@"64", | |
| 1202 | else => unreachable, | |
| 1203 | }, | |
| 1204 | .endian = target.cpu.arch.endian(), | |
| 1205 | .const_pool = .empty, | |
| 1206 | .units = .empty, | |
| 1207 | .values = .empty, | |
| 1208 | .globals = .empty, | |
| 1209 | .funcs = .empty, | |
| 1210 | ||
| 1211 | .debug_info = .{ | |
| 1212 | .section_index = .none, | |
| 1213 | }, | |
| 1214 | .debug_line = .{ | |
| 1215 | .header = switch (target.cpu.arch) { | |
| 1216 | .x86_64, .aarch64 => .{ | |
| 1217 | .minimum_instruction_length = 1, | |
| 1218 | .maximum_operations_per_instruction = 1, | |
| 1219 | .default_is_stmt = true, | |
| 1220 | .line_base = -5, | |
| 1221 | .line_range = 14, | |
| 1222 | .opcode_base = DW.LNS.set_isa + 1, | |
| 1223 | }, | |
| 1224 | else => .{ | |
| 1225 | .minimum_instruction_length = 1, | |
| 1226 | .maximum_operations_per_instruction = 1, | |
| 1227 | .default_is_stmt = true, | |
| 1228 | .line_base = 0, | |
| 1229 | .line_range = 1, | |
| 1230 | .opcode_base = DW.LNS.set_isa + 1, | |
| 1231 | }, | |
| 1232 | }, | |
| 1233 | .section_index = .none, | |
| 1234 | }, | |
| 1235 | .frame = .{ | |
| 1236 | .header = if (target.cpu.arch == .x86_64 and target.ofmt == .elf) header: { | |
| 1237 | dev.check(.x86_64_backend); | |
| 1238 | const Register = @import("../codegen/x86_64/bits.zig").Register; | |
| 1239 | break :header comptime .{ | |
| 1240 | .code_alignment_factor = 1, | |
| 1241 | .data_alignment_factor = -8, | |
| 1242 | .return_address_register = Register.rip.dwarfNum(), | |
| 1243 | .initial_instructions = &.{ | |
| 1244 | .{ .def_cfa = .{ .reg = Register.rsp.dwarfNum(), .off = 8 } }, | |
| 1245 | .{ .offset = .{ .reg = Register.rip.dwarfNum(), .off = -8 } }, | |
| 1246 | }, | |
| 1247 | }; | |
| 1248 | } else .{ | |
| 1249 | .code_alignment_factor = undefined, | |
| 1250 | .data_alignment_factor = undefined, | |
| 1251 | .return_address_register = undefined, | |
| 1252 | .initial_instructions = &.{}, | |
| 1253 | }, | |
| 1254 | .section_index = .none, | |
| 1255 | }, | |
| 1256 | }; | |
| 1257 | } | |
| 1258 | ||
| 1259 | pub fn deinit(dwarf: *Dwarf, gpa: Allocator) void { | |
| 1260 | dwarf.const_pool.deinit(gpa); | |
| 1261 | dwarf.units.deinit(gpa); | |
| 1262 | dwarf.values.deinit(gpa); | |
| 1263 | dwarf.globals.deinit(gpa); | |
| 1264 | dwarf.funcs.deinit(gpa); | |
| 1265 | dwarf.* = undefined; | |
| 1266 | } | |
| 1267 | ||
| 1268 | fn linkFile(dwarf: *Dwarf) *link.File { | |
| 1269 | return switch (dwarf.tag) { | |
| 1270 | else => unreachable, | |
| 1271 | .elf2 => |tag| &@as(*tag.Type(), @alignCast(@fieldParentPtr("dwarf", dwarf))).base, | |
| 1272 | }; | |
| 1273 | } | |
| 1274 | ||
| 1275 | pub fn initUnits(dwarf: *Dwarf, zcu: *Zcu) Allocator.Error!void { | |
| 1276 | try dwarf.units.ensureTotalCapacity(zcu.gpa, zcu.module_roots.count()); | |
| 1277 | for (zcu.module_roots.keys(), zcu.module_roots.values()) |mod, root| switch (root) { | |
| 1278 | .none => {}, | |
| 1279 | else => dwarf.units.putAssumeCapacityNoClobber(mod, .{ | |
| 1280 | .frame_ni = .none, | |
| 1281 | .cie_ni = .none, | |
| 1282 | }), | |
| 1283 | }; | |
| 1284 | } | |
| 1285 | ||
| 1286 | fn getNavNode(dwarf: *Dwarf, nav_index: InternPool.Nav.Index) UpdateError!MappedFile.Node.Index { | |
| 1287 | if (true) @panic("TODO"); | |
| 1288 | const zcu = dwarf.linkFile().comp.zcu.?; | |
| 1289 | const ip = &zcu.intern_pool; | |
| 1290 | const nav = ip.getNav(nav_index); | |
| 1291 | const unit = try dwarf.getUnit(zcu.fileByIndex(nav.srcInst(ip).resolveFile(ip)).mod.?); | |
| 1292 | const gop = try dwarf.navs.getOrPut(dwarf.gpa, nav_index); | |
| 1293 | if (gop.found_existing) return .{ unit, gop.value_ptr.* }; | |
| 1294 | const entry = try dwarf.addCommonEntry(unit); | |
| 1295 | gop.value_ptr.* = entry; | |
| 1296 | return .{ unit, entry }; | |
| 1297 | } | |
| 1298 | ||
| 1299 | pub fn getUnit(dwarf: *Dwarf, mod: *Module) Unit.Index { | |
| 1300 | return @fromBackingInt(@intCast(dwarf.units.getIndex(mod).?)); | |
| 1301 | } | |
| 1302 | ||
| 1303 | pub fn getFunc(dwarf: *Dwarf, owner_nav: InternPool.Nav.Index) Allocator.Error!Func.Index { | |
| 1304 | const func_gop = try dwarf.funcs.getOrPut(dwarf.linkFile().comp.gpa, owner_nav); | |
| 1305 | if (!func_gop.found_existing) func_gop.value_ptr.* = .{ | |
| 1306 | .fde_ni = .none, | |
| 1307 | .debug_info_ni = .none, | |
| 1308 | .debug_line_ni = .none, | |
| 1309 | }; | |
| 1310 | return @fromBackingInt(@intCast(func_gop.index)); | |
| 1311 | } | |
| 1312 | ||
| 1313 | pub fn updateUnitLength(dwarf: *Dwarf, header: []u8, unit_length: u64) void { | |
| 1314 | switch (dwarf.format) { | |
| 1315 | .@"32" => std.mem.writeInt(u32, header[0..4], @intCast(unit_length - 4), dwarf.endian), | |
| 1316 | .@"64" => std.mem.writeInt(u64, header[4..12], unit_length - 12, dwarf.endian), | |
| 1317 | } | |
| 1318 | } | |
| 1319 | ||
| 1320 | pub const EhFrameHdr = extern struct { | |
| 1321 | version: u8, | |
| 1322 | eh_frame_ptr_enc: std.dwarf.EH.PE, | |
| 1323 | fde_count_enc: std.dwarf.EH.PE, | |
| 1324 | table_enc: std.dwarf.EH.PE, | |
| 1325 | eh_frame_ptr: u32, | |
| 1326 | }; | |
| 1327 | pub fn genEhFrameHdr( | |
| 1328 | dwarf: *Dwarf, | |
| 1329 | eh_frame_hdr_ai: link.File.AtomId, | |
| 1330 | eh_frame_hdr: *EhFrameHdr, | |
| 1331 | eh_frame_si: link.File.SymbolId, | |
| 1332 | ) UpdateError!void { | |
| 1333 | eh_frame_hdr.* = .{ | |
| 1334 | .version = 1, | |
| 1335 | .eh_frame_ptr_enc = .{ .type = .sdata4, .rel = .pcrel }, | |
| 1336 | .fde_count_enc = .omit, | |
| 1337 | .table_enc = .omit, | |
| 1338 | .eh_frame_ptr = undefined, | |
| 1339 | }; | |
| 1340 | const elf = dwarf.linkFile().cast(.elf2).?; | |
| 1341 | try elf.addReloc( | |
| 1342 | eh_frame_hdr_ai, | |
| 1343 | @offsetOf(EhFrameHdr, "eh_frame_ptr"), | |
| 1344 | eh_frame_si, | |
| 1345 | 0, | |
| 1346 | .rel32(elf), | |
| 1347 | ); | |
| 1348 | } | |
| 1349 | ||
| 1350 | pub fn genDebugFrameCie( | |
| 1351 | dwarf: *Dwarf, | |
| 1352 | w: *Writer, | |
| 1353 | /// `null` means to generate an architecture-agnostic padding cie | |
| 1354 | arch: ?std.Target.Cpu.Arch, | |
| 1355 | format: Frame.Format, | |
| 1356 | ) Writer.Error!void { | |
| 1357 | switch (dwarf.format) { | |
| 1358 | .@"32" => try w.writeInt(u32, undefined, dwarf.endian), | |
| 1359 | .@"64" => { | |
| 1360 | try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian); | |
| 1361 | try w.writeInt(u64, undefined, dwarf.endian); | |
| 1362 | }, | |
| 1363 | } | |
| 1364 | switch (format) { | |
| 1365 | .eh_frame => try w.writeInt(u32, 0, dwarf.endian), | |
| 1366 | .debug_frame => switch (dwarf.format) { | |
| 1367 | .@"32" => try w.writeInt(u32, std.math.maxInt(u32), dwarf.endian), | |
| 1368 | .@"64" => try w.writeInt(u64, std.math.maxInt(u64), dwarf.endian), | |
| 1369 | }, | |
| 1370 | } | |
| 1371 | try w.writeByte(if (arch) |_| switch (format) { | |
| 1372 | .eh_frame => 1, | |
| 1373 | .debug_frame => 4, | |
| 1374 | } else 0); | |
| 1375 | switch (arch orelse return) { | |
| 1376 | else => unreachable, | |
| 1377 | .x86_64 => { | |
| 1378 | dev.check(.x86_64_backend); | |
| 1379 | const Register = @import("../codegen/x86_64/bits.zig").Register; | |
| 1380 | switch (format) { | |
| 1381 | .eh_frame => try w.writeAll("zR\x00"), | |
| 1382 | .debug_frame => { | |
| 1383 | try w.writeAll("\x00"); | |
| 1384 | try w.writeByte(@backingInt(dwarf.address_size)); | |
| 1385 | try w.writeByte(0); | |
| 1386 | }, | |
| 1387 | } | |
| 1388 | try w.writeUleb128(dwarf.frame.header.code_alignment_factor); | |
| 1389 | try w.writeSleb128(dwarf.frame.header.data_alignment_factor); | |
| 1390 | switch (format) { | |
| 1391 | .eh_frame => try w.writeByte(@intCast(dwarf.frame.header.return_address_register)), | |
| 1392 | .debug_frame => try w.writeUleb128(dwarf.frame.header.return_address_register), | |
| 1393 | } | |
| 1394 | switch (format) { | |
| 1395 | .eh_frame => { | |
| 1396 | try w.writeUleb128(1); | |
| 1397 | try w.writeByte(@bitCast(@as(DW.EH.PE, .{ .type = .sdata4, .rel = .pcrel }))); | |
| 1398 | }, | |
| 1399 | .debug_frame => {}, | |
| 1400 | } | |
| 1401 | try w.writeByte(DW.CFA.def_cfa_sf); | |
| 1402 | try w.writeUleb128(Register.rsp.dwarfNum()); | |
| 1403 | try w.writeSleb128(-1); | |
| 1404 | try w.writeByte(@as(u8, DW.CFA.offset) + Register.rip.dwarfNum()); | |
| 1405 | try w.writeUleb128(1); | |
| 1406 | }, | |
| 1407 | } | |
| 1408 | } | |
| 1409 | ||
| 1410 | pub fn updateEhFrameFde(dwarf: *Dwarf, fde: []u8, fde_offset: u64) void { | |
| 1411 | const cie_pointer_offset: usize = switch (dwarf.format) { | |
| 1412 | .@"32" => 4, | |
| 1413 | .@"64" => 12, | |
| 1414 | }; | |
| 1415 | std.mem.writeInt( | |
| 1416 | u32, | |
| 1417 | fde[cie_pointer_offset..][0..4], | |
| 1418 | @intCast(fde_offset + cie_pointer_offset), | |
| 1419 | dwarf.endian, | |
| 1420 | ); | |
| 1421 | } | |
| 1422 | ||
| 1423 | fn refAbbrevCode( | |
| 1424 | dwarf: *Dwarf, | |
| 1425 | abbrev_code: AbbrevCode, | |
| 1426 | ) (UpdateError || Writer.Error)!@typeInfo(AbbrevCode).@"enum".tag_type { | |
| 1427 | if (true) @panic("TODO"); | |
| 1428 | const Entry = {}; | |
| 1429 | const DebugAbbrev = {}; | |
| 1430 | assert(abbrev_code != .null); | |
| 1431 | const entry: Entry.Index = @fromBackingInt(@intCast(@backingInt(abbrev_code))); | |
| 1432 | if (dwarf.debug_abbrev.section.getUnit(DebugAbbrev.unit).getEntry(entry).len > 0) return @backingInt(abbrev_code); | |
| 1433 | var debug_abbrev_aw: Writer.Allocating = .init(dwarf.gpa); | |
| 1434 | defer debug_abbrev_aw.deinit(); | |
| 1435 | const daw = &debug_abbrev_aw.writer; | |
| 1436 | const abbrev = AbbrevCode.abbrevs.get(abbrev_code); | |
| 1437 | try daw.writeUleb128(@backingInt(abbrev_code)); | |
| 1438 | try daw.writeUleb128(@backingInt(abbrev.tag)); | |
| 1439 | try daw.writeByte(if (abbrev.children) DW.CHILDREN.yes else DW.CHILDREN.no); | |
| 1440 | for (abbrev.attrs) |*attr| inline for (attr) |info| try daw.writeUleb128(@backingInt(info)); | |
| 1441 | for (0..2) |_| try daw.writeUleb128(0); | |
| 1442 | try dwarf.debug_abbrev.section.replaceEntry(DebugAbbrev.unit, entry, dwarf, debug_abbrev_aw.written()); | |
| 1443 | return @backingInt(abbrev_code); | |
| 1444 | } | |
| 1445 | ||
| 1446 | fn DeclValEnum(comptime T: type) type { | |
| 1447 | const decl_names = @typeInfo(T).@"struct".decl_names; | |
| 1448 | @setEvalBranchQuota(10 * decl_names.len); | |
| 1449 | var field_names: [decl_names.len][]const u8 = undefined; | |
| 1450 | var fields_len = 0; | |
| 1451 | var min_value: ?comptime_int = null; | |
| 1452 | var max_value: ?comptime_int = null; | |
| 1453 | for (decl_names) |decl_name| { | |
| 1454 | if (std.mem.startsWith(u8, decl_name, "HP_") or std.mem.endsWith(u8, decl_name, "_user")) continue; | |
| 1455 | const value = @field(T, decl_name); | |
| 1456 | field_names[fields_len] = decl_name; | |
| 1457 | fields_len += 1; | |
| 1458 | if (min_value == null or min_value.? > value) min_value = value; | |
| 1459 | if (max_value == null or max_value.? < value) max_value = value; | |
| 1460 | } | |
| 1461 | if (fields_len == 0) return enum {}; | |
| 1462 | const TagInt = std.math.IntFittingRange(min_value orelse 0, max_value orelse 0); | |
| 1463 | var field_vals: [fields_len]TagInt = undefined; | |
| 1464 | for (field_names[0..fields_len], &field_vals) |name, *val| val.* = @field(T, name); | |
| 1465 | return @Enum(TagInt, .exhaustive, field_names[0..fields_len], &field_vals); | |
| 1466 | } | |
| 1467 | ||
| 1468 | const AbbrevCode = enum { | |
| 1469 | null, | |
| 1470 | // padding codes must be one byte uleb128 values to function | |
| 1471 | pad_1, | |
| 1472 | pad_n, | |
| 1473 | // decl, generic decl, and instance codes are assumed to all have the same uleb128 length | |
| 1474 | decl_alias, | |
| 1475 | decl_empty_enum, | |
| 1476 | decl_enum, | |
| 1477 | decl_namespace_struct, | |
| 1478 | decl_struct, | |
| 1479 | decl_packed_struct, | |
| 1480 | decl_union, | |
| 1481 | decl_packed_union, | |
| 1482 | decl_var, | |
| 1483 | decl_const, | |
| 1484 | decl_const_runtime_bits, | |
| 1485 | decl_const_comptime_state, | |
| 1486 | decl_const_runtime_bits_comptime_state, | |
| 1487 | decl_nullary_func, | |
| 1488 | decl_func, | |
| 1489 | decl_nullary_func_generic, | |
| 1490 | decl_func_generic, | |
| 1491 | decl_extern_nullary_func, | |
| 1492 | decl_extern_func, | |
| 1493 | generic_decl_var, | |
| 1494 | generic_decl_const, | |
| 1495 | generic_decl_func, | |
| 1496 | decl_instance_alias, | |
| 1497 | decl_instance_empty_enum, | |
| 1498 | decl_instance_enum, | |
| 1499 | decl_instance_namespace_struct, | |
| 1500 | decl_instance_struct, | |
| 1501 | decl_instance_packed_struct, | |
| 1502 | decl_instance_union, | |
| 1503 | decl_instance_packed_union, | |
| 1504 | decl_instance_var, | |
| 1505 | decl_instance_const, | |
| 1506 | decl_instance_const_runtime_bits, | |
| 1507 | decl_instance_const_comptime_state, | |
| 1508 | decl_instance_const_runtime_bits_comptime_state, | |
| 1509 | decl_instance_nullary_func, | |
| 1510 | decl_instance_func, | |
| 1511 | decl_instance_nullary_func_generic, | |
| 1512 | decl_instance_func_generic, | |
| 1513 | decl_instance_extern_nullary_func, | |
| 1514 | decl_instance_extern_func, | |
| 1515 | // the rest are unrestricted other than empty variants must not be longer | |
| 1516 | // than the non-empty variant, and so should appear first | |
| 1517 | compile_unit, | |
| 1518 | module, | |
| 1519 | empty_file, | |
| 1520 | file, | |
| 1521 | access, | |
| 1522 | enum_field, | |
| 1523 | generated_field, | |
| 1524 | field, | |
| 1525 | field_default_runtime_bits, | |
| 1526 | field_default_comptime_state, | |
| 1527 | field_comptime, | |
| 1528 | field_comptime_runtime_bits, | |
| 1529 | field_comptime_comptime_state, | |
| 1530 | packed_field, | |
| 1531 | tagged_union, | |
| 1532 | tagged_union_field, | |
| 1533 | tagged_union_default_field, | |
| 1534 | void_type, | |
| 1535 | numeric_type, | |
| 1536 | inferred_error_set_type, | |
| 1537 | ptr_type, | |
| 1538 | ptr_sentinel_type, | |
| 1539 | ptr_aligned_type, | |
| 1540 | ptr_aligned_sentinel_type, | |
| 1541 | is_const, | |
| 1542 | is_volatile, | |
| 1543 | array_type, | |
| 1544 | array_sentinel_type, | |
| 1545 | vector_type, | |
| 1546 | array_index, | |
| 1547 | array_len, | |
| 1548 | nullary_func_type, | |
| 1549 | func_type, | |
| 1550 | func_type_param, | |
| 1551 | is_var_args, | |
| 1552 | generated_empty_enum_type, | |
| 1553 | generated_enum_type, | |
| 1554 | generated_empty_struct_type, | |
| 1555 | generated_struct_type, | |
| 1556 | generated_union_type, | |
| 1557 | empty_enum_type, | |
| 1558 | enum_type, | |
| 1559 | empty_struct_type, | |
| 1560 | struct_type, | |
| 1561 | empty_packed_struct_type, | |
| 1562 | packed_struct_type, | |
| 1563 | empty_union_type, | |
| 1564 | union_type, | |
| 1565 | empty_packed_union_type, | |
| 1566 | packed_union_type, | |
| 1567 | builtin_extern_nullary_func, | |
| 1568 | builtin_extern_func, | |
| 1569 | builtin_extern_var, | |
| 1570 | empty_block, | |
| 1571 | block, | |
| 1572 | empty_inlined_func, | |
| 1573 | inlined_func, | |
| 1574 | arg, | |
| 1575 | unnamed_arg, | |
| 1576 | comptime_arg, | |
| 1577 | unnamed_comptime_arg, | |
| 1578 | comptime_arg_runtime_bits, | |
| 1579 | unnamed_comptime_arg_runtime_bits, | |
| 1580 | comptime_arg_comptime_state, | |
| 1581 | unnamed_comptime_arg_comptime_state, | |
| 1582 | comptime_arg_runtime_bits_comptime_state, | |
| 1583 | unnamed_comptime_arg_runtime_bits_comptime_state, | |
| 1584 | extern_param, | |
| 1585 | local_var, | |
| 1586 | local_const, | |
| 1587 | local_const_runtime_bits, | |
| 1588 | local_const_comptime_state, | |
| 1589 | local_const_runtime_bits_comptime_state, | |
| 1590 | undefined_comptime_value, | |
| 1591 | comptime_value, | |
| 1592 | location_comptime_value, | |
| 1593 | aggregate_undefined_comptime_value, | |
| 1594 | aggregate_comptime_value, | |
| 1595 | aggregate_location_comptime_value, | |
| 1596 | comptime_value_field_runtime_bits, | |
| 1597 | comptime_value_field_comptime_state, | |
| 1598 | comptime_value_elem_runtime_bits, | |
| 1599 | comptime_value_elem_comptime_state, | |
| 1600 | ||
| 1601 | const decl_bytes = uleb128Bytes(@backingInt(AbbrevCode.decl_instance_extern_func)); | |
| 1602 | comptime { | |
| 1603 | assert(uleb128Bytes(@backingInt(AbbrevCode.pad_1)) == 1); | |
| 1604 | assert(uleb128Bytes(@backingInt(AbbrevCode.pad_n)) == 1); | |
| 1605 | assert(uleb128Bytes(@backingInt(AbbrevCode.decl_alias)) == decl_bytes); | |
| 1606 | } | |
| 1607 | ||
| 1608 | const Attr = struct { | |
| 1609 | DeclValEnum(DW.AT), | |
| 1610 | DeclValEnum(DW.FORM), | |
| 1611 | }; | |
| 1612 | const decl_abbrev_common_attrs = &[_]Attr{ | |
| 1613 | .{ .ZIG_parent, .ref_addr }, | |
| 1614 | .{ .decl_line, .data4 }, | |
| 1615 | .{ .decl_column, .udata }, | |
| 1616 | .{ .accessibility, .data1 }, | |
| 1617 | .{ .name, .strp }, | |
| 1618 | }; | |
| 1619 | const generic_decl_abbrev_common_attrs = decl_abbrev_common_attrs ++ &[_]Attr{ | |
| 1620 | .{ .declaration, .flag_present }, | |
| 1621 | }; | |
| 1622 | const decl_instance_abbrev_common_attrs = &[_]Attr{ | |
| 1623 | .{ .ZIG_parent, .ref_addr }, | |
| 1624 | .{ .abstract_origin, .ref_addr }, | |
| 1625 | }; | |
| 1626 | const abbrevs = std.EnumArray(AbbrevCode, struct { | |
| 1627 | tag: DeclValEnum(DW.TAG), | |
| 1628 | children: bool = false, | |
| 1629 | attrs: []const Attr = &.{}, | |
| 1630 | }).init(.{ | |
| 1631 | .pad_1 = .{ | |
| 1632 | .tag = .ZIG_padding, | |
| 1633 | }, | |
| 1634 | .pad_n = .{ | |
| 1635 | .tag = .ZIG_padding, | |
| 1636 | .attrs = &.{ | |
| 1637 | .{ .ZIG_padding, .block }, | |
| 1638 | }, | |
| 1639 | }, | |
| 1640 | .decl_alias = .{ | |
| 1641 | .tag = .imported_declaration, | |
| 1642 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1643 | .{ .import, .ref_addr }, | |
| 1644 | }, | |
| 1645 | }, | |
| 1646 | .decl_empty_enum = .{ | |
| 1647 | .tag = .enumeration_type, | |
| 1648 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1649 | .{ .type, .ref_addr }, | |
| 1650 | }, | |
| 1651 | }, | |
| 1652 | .decl_enum = .{ | |
| 1653 | .tag = .enumeration_type, | |
| 1654 | .children = true, | |
| 1655 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1656 | .{ .type, .ref_addr }, | |
| 1657 | }, | |
| 1658 | }, | |
| 1659 | .decl_namespace_struct = .{ | |
| 1660 | .tag = .structure_type, | |
| 1661 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1662 | .{ .declaration, .flag }, | |
| 1663 | }, | |
| 1664 | }, | |
| 1665 | .decl_struct = .{ | |
| 1666 | .tag = .structure_type, | |
| 1667 | .children = true, | |
| 1668 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1669 | .{ .byte_size, .udata }, | |
| 1670 | .{ .alignment, .udata }, | |
| 1671 | }, | |
| 1672 | }, | |
| 1673 | .decl_packed_struct = .{ | |
| 1674 | .tag = .structure_type, | |
| 1675 | .children = true, | |
| 1676 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1677 | .{ .type, .ref_addr }, | |
| 1678 | }, | |
| 1679 | }, | |
| 1680 | .decl_union = .{ | |
| 1681 | .tag = .union_type, | |
| 1682 | .children = true, | |
| 1683 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1684 | .{ .byte_size, .udata }, | |
| 1685 | .{ .alignment, .udata }, | |
| 1686 | }, | |
| 1687 | }, | |
| 1688 | .decl_packed_union = .{ | |
| 1689 | .tag = .union_type, | |
| 1690 | .children = true, | |
| 1691 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1692 | .{ .type, .ref_addr }, | |
| 1693 | }, | |
| 1694 | }, | |
| 1695 | .decl_var = .{ | |
| 1696 | .tag = .variable, | |
| 1697 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1698 | .{ .linkage_name, .strp }, | |
| 1699 | .{ .type, .ref_addr }, | |
| 1700 | .{ .location, .exprloc }, | |
| 1701 | .{ .alignment, .udata }, | |
| 1702 | .{ .external, .flag }, | |
| 1703 | }, | |
| 1704 | }, | |
| 1705 | .decl_const = .{ | |
| 1706 | .tag = .constant, | |
| 1707 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1708 | .{ .linkage_name, .strp }, | |
| 1709 | .{ .type, .ref_addr }, | |
| 1710 | .{ .alignment, .udata }, | |
| 1711 | .{ .external, .flag }, | |
| 1712 | }, | |
| 1713 | }, | |
| 1714 | .decl_const_runtime_bits = .{ | |
| 1715 | .tag = .constant, | |
| 1716 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1717 | .{ .linkage_name, .strp }, | |
| 1718 | .{ .type, .ref_addr }, | |
| 1719 | .{ .alignment, .udata }, | |
| 1720 | .{ .external, .flag }, | |
| 1721 | .{ .const_value, .block }, | |
| 1722 | }, | |
| 1723 | }, | |
| 1724 | .decl_const_comptime_state = .{ | |
| 1725 | .tag = .constant, | |
| 1726 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1727 | .{ .linkage_name, .strp }, | |
| 1728 | .{ .type, .ref_addr }, | |
| 1729 | .{ .alignment, .udata }, | |
| 1730 | .{ .external, .flag }, | |
| 1731 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 1732 | }, | |
| 1733 | }, | |
| 1734 | .decl_const_runtime_bits_comptime_state = .{ | |
| 1735 | .tag = .constant, | |
| 1736 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1737 | .{ .linkage_name, .strp }, | |
| 1738 | .{ .type, .ref_addr }, | |
| 1739 | .{ .alignment, .udata }, | |
| 1740 | .{ .external, .flag }, | |
| 1741 | .{ .const_value, .block }, | |
| 1742 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 1743 | }, | |
| 1744 | }, | |
| 1745 | .decl_nullary_func = .{ | |
| 1746 | .tag = .subprogram, | |
| 1747 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1748 | .{ .linkage_name, .strp }, | |
| 1749 | .{ .type, .ref_addr }, | |
| 1750 | .{ .low_pc, .addr }, | |
| 1751 | .{ .high_pc, .data4 }, | |
| 1752 | .{ .alignment, .udata }, | |
| 1753 | .{ .external, .flag }, | |
| 1754 | .{ .noreturn, .flag }, | |
| 1755 | }, | |
| 1756 | }, | |
| 1757 | .decl_func = .{ | |
| 1758 | .tag = .subprogram, | |
| 1759 | .children = true, | |
| 1760 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1761 | .{ .linkage_name, .strp }, | |
| 1762 | .{ .type, .ref_addr }, | |
| 1763 | .{ .low_pc, .addr }, | |
| 1764 | .{ .high_pc, .data4 }, | |
| 1765 | .{ .alignment, .udata }, | |
| 1766 | .{ .external, .flag }, | |
| 1767 | .{ .noreturn, .flag }, | |
| 1768 | }, | |
| 1769 | }, | |
| 1770 | .decl_nullary_func_generic = .{ | |
| 1771 | .tag = .subprogram, | |
| 1772 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1773 | .{ .type, .ref_addr }, | |
| 1774 | }, | |
| 1775 | }, | |
| 1776 | .decl_func_generic = .{ | |
| 1777 | .tag = .subprogram, | |
| 1778 | .children = true, | |
| 1779 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1780 | .{ .type, .ref_addr }, | |
| 1781 | }, | |
| 1782 | }, | |
| 1783 | .decl_extern_nullary_func = .{ | |
| 1784 | .tag = .subprogram, | |
| 1785 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1786 | .{ .linkage_name, .strp }, | |
| 1787 | .{ .type, .ref_addr }, | |
| 1788 | .{ .low_pc, .addr }, | |
| 1789 | .{ .external, .flag_present }, | |
| 1790 | .{ .noreturn, .flag }, | |
| 1791 | }, | |
| 1792 | }, | |
| 1793 | .decl_extern_func = .{ | |
| 1794 | .tag = .subprogram, | |
| 1795 | .children = true, | |
| 1796 | .attrs = decl_abbrev_common_attrs ++ .{ | |
| 1797 | .{ .linkage_name, .strp }, | |
| 1798 | .{ .type, .ref_addr }, | |
| 1799 | .{ .low_pc, .addr }, | |
| 1800 | .{ .external, .flag_present }, | |
| 1801 | .{ .noreturn, .flag }, | |
| 1802 | }, | |
| 1803 | }, | |
| 1804 | .generic_decl_var = .{ | |
| 1805 | .tag = .variable, | |
| 1806 | .attrs = generic_decl_abbrev_common_attrs, | |
| 1807 | }, | |
| 1808 | .generic_decl_const = .{ | |
| 1809 | .tag = .constant, | |
| 1810 | .attrs = generic_decl_abbrev_common_attrs, | |
| 1811 | }, | |
| 1812 | .generic_decl_func = .{ | |
| 1813 | .tag = .subprogram, | |
| 1814 | .attrs = generic_decl_abbrev_common_attrs, | |
| 1815 | }, | |
| 1816 | .decl_instance_alias = .{ | |
| 1817 | .tag = .imported_declaration, | |
| 1818 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1819 | .{ .import, .ref_addr }, | |
| 1820 | }, | |
| 1821 | }, | |
| 1822 | .decl_instance_empty_enum = .{ | |
| 1823 | .tag = .enumeration_type, | |
| 1824 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1825 | .{ .type, .ref_addr }, | |
| 1826 | }, | |
| 1827 | }, | |
| 1828 | .decl_instance_enum = .{ | |
| 1829 | .tag = .enumeration_type, | |
| 1830 | .children = true, | |
| 1831 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1832 | .{ .type, .ref_addr }, | |
| 1833 | }, | |
| 1834 | }, | |
| 1835 | .decl_instance_namespace_struct = .{ | |
| 1836 | .tag = .structure_type, | |
| 1837 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1838 | .{ .declaration, .flag }, | |
| 1839 | }, | |
| 1840 | }, | |
| 1841 | .decl_instance_struct = .{ | |
| 1842 | .tag = .structure_type, | |
| 1843 | .children = true, | |
| 1844 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1845 | .{ .byte_size, .udata }, | |
| 1846 | .{ .alignment, .udata }, | |
| 1847 | }, | |
| 1848 | }, | |
| 1849 | .decl_instance_packed_struct = .{ | |
| 1850 | .tag = .structure_type, | |
| 1851 | .children = true, | |
| 1852 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1853 | .{ .type, .ref_addr }, | |
| 1854 | }, | |
| 1855 | }, | |
| 1856 | .decl_instance_union = .{ | |
| 1857 | .tag = .union_type, | |
| 1858 | .children = true, | |
| 1859 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1860 | .{ .byte_size, .udata }, | |
| 1861 | .{ .alignment, .udata }, | |
| 1862 | }, | |
| 1863 | }, | |
| 1864 | .decl_instance_packed_union = .{ | |
| 1865 | .tag = .union_type, | |
| 1866 | .children = true, | |
| 1867 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1868 | .{ .type, .ref_addr }, | |
| 1869 | }, | |
| 1870 | }, | |
| 1871 | .decl_instance_var = .{ | |
| 1872 | .tag = .variable, | |
| 1873 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1874 | .{ .linkage_name, .strp }, | |
| 1875 | .{ .type, .ref_addr }, | |
| 1876 | .{ .location, .exprloc }, | |
| 1877 | .{ .alignment, .udata }, | |
| 1878 | .{ .external, .flag }, | |
| 1879 | }, | |
| 1880 | }, | |
| 1881 | .decl_instance_const = .{ | |
| 1882 | .tag = .constant, | |
| 1883 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1884 | .{ .linkage_name, .strp }, | |
| 1885 | .{ .type, .ref_addr }, | |
| 1886 | .{ .alignment, .udata }, | |
| 1887 | .{ .external, .flag }, | |
| 1888 | }, | |
| 1889 | }, | |
| 1890 | .decl_instance_const_runtime_bits = .{ | |
| 1891 | .tag = .constant, | |
| 1892 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1893 | .{ .linkage_name, .strp }, | |
| 1894 | .{ .type, .ref_addr }, | |
| 1895 | .{ .alignment, .udata }, | |
| 1896 | .{ .external, .flag }, | |
| 1897 | .{ .const_value, .block }, | |
| 1898 | }, | |
| 1899 | }, | |
| 1900 | .decl_instance_const_comptime_state = .{ | |
| 1901 | .tag = .constant, | |
| 1902 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1903 | .{ .linkage_name, .strp }, | |
| 1904 | .{ .type, .ref_addr }, | |
| 1905 | .{ .alignment, .udata }, | |
| 1906 | .{ .external, .flag }, | |
| 1907 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 1908 | }, | |
| 1909 | }, | |
| 1910 | .decl_instance_const_runtime_bits_comptime_state = .{ | |
| 1911 | .tag = .constant, | |
| 1912 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1913 | .{ .linkage_name, .strp }, | |
| 1914 | .{ .type, .ref_addr }, | |
| 1915 | .{ .alignment, .udata }, | |
| 1916 | .{ .external, .flag }, | |
| 1917 | .{ .const_value, .block }, | |
| 1918 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 1919 | }, | |
| 1920 | }, | |
| 1921 | .decl_instance_nullary_func = .{ | |
| 1922 | .tag = .subprogram, | |
| 1923 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1924 | .{ .linkage_name, .strp }, | |
| 1925 | .{ .type, .ref_addr }, | |
| 1926 | .{ .low_pc, .addr }, | |
| 1927 | .{ .high_pc, .data4 }, | |
| 1928 | .{ .alignment, .udata }, | |
| 1929 | .{ .external, .flag }, | |
| 1930 | .{ .noreturn, .flag }, | |
| 1931 | }, | |
| 1932 | }, | |
| 1933 | .decl_instance_func = .{ | |
| 1934 | .tag = .subprogram, | |
| 1935 | .children = true, | |
| 1936 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1937 | .{ .linkage_name, .strp }, | |
| 1938 | .{ .type, .ref_addr }, | |
| 1939 | .{ .low_pc, .addr }, | |
| 1940 | .{ .high_pc, .data4 }, | |
| 1941 | .{ .alignment, .udata }, | |
| 1942 | .{ .external, .flag }, | |
| 1943 | .{ .noreturn, .flag }, | |
| 1944 | }, | |
| 1945 | }, | |
| 1946 | .decl_instance_nullary_func_generic = .{ | |
| 1947 | .tag = .subprogram, | |
| 1948 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1949 | .{ .type, .ref_addr }, | |
| 1950 | }, | |
| 1951 | }, | |
| 1952 | .decl_instance_func_generic = .{ | |
| 1953 | .tag = .subprogram, | |
| 1954 | .children = true, | |
| 1955 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1956 | .{ .type, .ref_addr }, | |
| 1957 | }, | |
| 1958 | }, | |
| 1959 | .decl_instance_extern_nullary_func = .{ | |
| 1960 | .tag = .subprogram, | |
| 1961 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1962 | .{ .linkage_name, .strp }, | |
| 1963 | .{ .type, .ref_addr }, | |
| 1964 | .{ .low_pc, .addr }, | |
| 1965 | .{ .external, .flag_present }, | |
| 1966 | .{ .noreturn, .flag }, | |
| 1967 | }, | |
| 1968 | }, | |
| 1969 | .decl_instance_extern_func = .{ | |
| 1970 | .tag = .subprogram, | |
| 1971 | .children = true, | |
| 1972 | .attrs = decl_instance_abbrev_common_attrs ++ .{ | |
| 1973 | .{ .linkage_name, .strp }, | |
| 1974 | .{ .type, .ref_addr }, | |
| 1975 | .{ .low_pc, .addr }, | |
| 1976 | .{ .external, .flag_present }, | |
| 1977 | .{ .noreturn, .flag }, | |
| 1978 | }, | |
| 1979 | }, | |
| 1980 | .compile_unit = .{ | |
| 1981 | .tag = .compile_unit, | |
| 1982 | .children = true, | |
| 1983 | .attrs = &.{ | |
| 1984 | .{ .language, .data1 }, | |
| 1985 | .{ .producer, .line_strp }, | |
| 1986 | .{ .comp_dir, .line_strp }, | |
| 1987 | .{ .name, .line_strp }, | |
| 1988 | .{ .base_types, .ref_addr }, | |
| 1989 | .{ .stmt_list, .sec_offset }, | |
| 1990 | .{ .rnglists_base, .sec_offset }, | |
| 1991 | .{ .ranges, .rnglistx }, | |
| 1992 | }, | |
| 1993 | }, | |
| 1994 | .module = .{ | |
| 1995 | .tag = .module, | |
| 1996 | .children = true, | |
| 1997 | .attrs = &.{ | |
| 1998 | .{ .name, .strp }, | |
| 1999 | .{ .ranges, .rnglistx }, | |
| 2000 | }, | |
| 2001 | }, | |
| 2002 | .empty_file = .{ | |
| 2003 | .tag = .structure_type, | |
| 2004 | .attrs = &.{ | |
| 2005 | .{ .decl_file, .udata }, | |
| 2006 | .{ .name, .strp }, | |
| 2007 | }, | |
| 2008 | }, | |
| 2009 | .file = .{ | |
| 2010 | .tag = .structure_type, | |
| 2011 | .children = true, | |
| 2012 | .attrs = &.{ | |
| 2013 | .{ .decl_file, .udata }, | |
| 2014 | .{ .name, .strp }, | |
| 2015 | .{ .byte_size, .udata }, | |
| 2016 | .{ .alignment, .udata }, | |
| 2017 | }, | |
| 2018 | }, | |
| 2019 | .access = .{ | |
| 2020 | .tag = .member, | |
| 2021 | .attrs = &.{ | |
| 2022 | .{ .name, .strp }, | |
| 2023 | }, | |
| 2024 | }, | |
| 2025 | .enum_field = .{ | |
| 2026 | .tag = .enumerator, | |
| 2027 | .attrs = &.{ | |
| 2028 | .{ .const_value, .indirect }, | |
| 2029 | .{ .name, .strp }, | |
| 2030 | }, | |
| 2031 | }, | |
| 2032 | .generated_field = .{ | |
| 2033 | .tag = .member, | |
| 2034 | .attrs = &.{ | |
| 2035 | .{ .name, .strp }, | |
| 2036 | .{ .type, .ref_addr }, | |
| 2037 | .{ .data_member_location, .udata }, | |
| 2038 | .{ .artificial, .flag_present }, | |
| 2039 | }, | |
| 2040 | }, | |
| 2041 | .field = .{ | |
| 2042 | .tag = .member, | |
| 2043 | .attrs = &.{ | |
| 2044 | .{ .name, .strp }, | |
| 2045 | .{ .type, .ref_addr }, | |
| 2046 | .{ .data_member_location, .udata }, | |
| 2047 | .{ .alignment, .udata }, | |
| 2048 | }, | |
| 2049 | }, | |
| 2050 | .field_default_runtime_bits = .{ | |
| 2051 | .tag = .member, | |
| 2052 | .attrs = &.{ | |
| 2053 | .{ .name, .strp }, | |
| 2054 | .{ .type, .ref_addr }, | |
| 2055 | .{ .data_member_location, .udata }, | |
| 2056 | .{ .alignment, .udata }, | |
| 2057 | .{ .default_value, .block }, | |
| 2058 | }, | |
| 2059 | }, | |
| 2060 | .field_default_comptime_state = .{ | |
| 2061 | .tag = .member, | |
| 2062 | .attrs = &.{ | |
| 2063 | .{ .name, .strp }, | |
| 2064 | .{ .type, .ref_addr }, | |
| 2065 | .{ .data_member_location, .udata }, | |
| 2066 | .{ .alignment, .udata }, | |
| 2067 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2068 | }, | |
| 2069 | }, | |
| 2070 | .field_comptime = .{ | |
| 2071 | .tag = .member, | |
| 2072 | .attrs = &.{ | |
| 2073 | .{ .const_expr, .flag_present }, | |
| 2074 | .{ .name, .strp }, | |
| 2075 | .{ .type, .ref_addr }, | |
| 2076 | }, | |
| 2077 | }, | |
| 2078 | .field_comptime_runtime_bits = .{ | |
| 2079 | .tag = .member, | |
| 2080 | .attrs = &.{ | |
| 2081 | .{ .const_expr, .flag_present }, | |
| 2082 | .{ .name, .strp }, | |
| 2083 | .{ .type, .ref_addr }, | |
| 2084 | .{ .const_value, .block }, | |
| 2085 | }, | |
| 2086 | }, | |
| 2087 | .field_comptime_comptime_state = .{ | |
| 2088 | .tag = .member, | |
| 2089 | .attrs = &.{ | |
| 2090 | .{ .const_expr, .flag_present }, | |
| 2091 | .{ .name, .strp }, | |
| 2092 | .{ .type, .ref_addr }, | |
| 2093 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2094 | }, | |
| 2095 | }, | |
| 2096 | .packed_field = .{ | |
| 2097 | .tag = .member, | |
| 2098 | .attrs = &.{ | |
| 2099 | .{ .name, .strp }, | |
| 2100 | .{ .type, .ref_addr }, | |
| 2101 | .{ .data_bit_offset, .udata }, | |
| 2102 | }, | |
| 2103 | }, | |
| 2104 | .tagged_union = .{ | |
| 2105 | .tag = .variant_part, | |
| 2106 | .children = true, | |
| 2107 | .attrs = &.{ | |
| 2108 | .{ .discr, .ref_addr }, | |
| 2109 | }, | |
| 2110 | }, | |
| 2111 | .tagged_union_field = .{ | |
| 2112 | .tag = .variant, | |
| 2113 | .children = true, | |
| 2114 | .attrs = &.{ | |
| 2115 | .{ .discr_value, .indirect }, | |
| 2116 | }, | |
| 2117 | }, | |
| 2118 | .tagged_union_default_field = .{ | |
| 2119 | .tag = .variant, | |
| 2120 | .children = true, | |
| 2121 | }, | |
| 2122 | .void_type = .{ | |
| 2123 | .tag = .unspecified_type, | |
| 2124 | .attrs = &.{ | |
| 2125 | .{ .name, .strp }, | |
| 2126 | }, | |
| 2127 | }, | |
| 2128 | .numeric_type = .{ | |
| 2129 | .tag = .base_type, | |
| 2130 | .attrs = &.{ | |
| 2131 | .{ .name, .strp }, | |
| 2132 | .{ .encoding, .data1 }, | |
| 2133 | .{ .bit_size, .udata }, | |
| 2134 | .{ .byte_size, .udata }, | |
| 2135 | .{ .alignment, .udata }, | |
| 2136 | }, | |
| 2137 | }, | |
| 2138 | .inferred_error_set_type = .{ | |
| 2139 | .tag = .typedef, | |
| 2140 | .attrs = &.{ | |
| 2141 | .{ .name, .strp }, | |
| 2142 | .{ .type, .ref_addr }, | |
| 2143 | }, | |
| 2144 | }, | |
| 2145 | .ptr_type = .{ | |
| 2146 | .tag = .pointer_type, | |
| 2147 | .attrs = &.{ | |
| 2148 | .{ .name, .strp }, | |
| 2149 | .{ .address_class, .data1 }, | |
| 2150 | .{ .type, .ref_addr }, | |
| 2151 | }, | |
| 2152 | }, | |
| 2153 | .ptr_sentinel_type = .{ | |
| 2154 | .tag = .pointer_type, | |
| 2155 | .attrs = &.{ | |
| 2156 | .{ .name, .strp }, | |
| 2157 | .{ .ZIG_sentinel, .block }, | |
| 2158 | .{ .address_class, .data1 }, | |
| 2159 | .{ .type, .ref_addr }, | |
| 2160 | }, | |
| 2161 | }, | |
| 2162 | .ptr_aligned_type = .{ | |
| 2163 | .tag = .pointer_type, | |
| 2164 | .attrs = &.{ | |
| 2165 | .{ .name, .strp }, | |
| 2166 | .{ .alignment, .udata }, | |
| 2167 | .{ .address_class, .data1 }, | |
| 2168 | .{ .type, .ref_addr }, | |
| 2169 | }, | |
| 2170 | }, | |
| 2171 | .ptr_aligned_sentinel_type = .{ | |
| 2172 | .tag = .pointer_type, | |
| 2173 | .attrs = &.{ | |
| 2174 | .{ .name, .strp }, | |
| 2175 | .{ .ZIG_sentinel, .block }, | |
| 2176 | .{ .alignment, .udata }, | |
| 2177 | .{ .address_class, .data1 }, | |
| 2178 | .{ .type, .ref_addr }, | |
| 2179 | }, | |
| 2180 | }, | |
| 2181 | .is_const = .{ | |
| 2182 | .tag = .const_type, | |
| 2183 | .attrs = &.{ | |
| 2184 | .{ .type, .ref_addr }, | |
| 2185 | }, | |
| 2186 | }, | |
| 2187 | .is_volatile = .{ | |
| 2188 | .tag = .volatile_type, | |
| 2189 | .attrs = &.{ | |
| 2190 | .{ .type, .ref_addr }, | |
| 2191 | }, | |
| 2192 | }, | |
| 2193 | .array_type = .{ | |
| 2194 | .tag = .array_type, | |
| 2195 | .children = true, | |
| 2196 | .attrs = &.{ | |
| 2197 | .{ .name, .strp }, | |
| 2198 | .{ .type, .ref_addr }, | |
| 2199 | }, | |
| 2200 | }, | |
| 2201 | .array_sentinel_type = .{ | |
| 2202 | .tag = .array_type, | |
| 2203 | .children = true, | |
| 2204 | .attrs = &.{ | |
| 2205 | .{ .name, .strp }, | |
| 2206 | .{ .ZIG_sentinel, .block }, | |
| 2207 | .{ .type, .ref_addr }, | |
| 2208 | }, | |
| 2209 | }, | |
| 2210 | .vector_type = .{ | |
| 2211 | .tag = .array_type, | |
| 2212 | .children = true, | |
| 2213 | .attrs = &.{ | |
| 2214 | .{ .name, .strp }, | |
| 2215 | .{ .type, .ref_addr }, | |
| 2216 | .{ .GNU_vector, .flag_present }, | |
| 2217 | }, | |
| 2218 | }, | |
| 2219 | .array_index = .{ | |
| 2220 | .tag = .subrange_type, | |
| 2221 | .attrs = &.{ | |
| 2222 | .{ .lower_bound, .udata }, | |
| 2223 | }, | |
| 2224 | }, | |
| 2225 | .array_len = .{ | |
| 2226 | .tag = .subrange_type, | |
| 2227 | .attrs = &.{ | |
| 2228 | .{ .type, .ref_addr }, | |
| 2229 | .{ .count, .udata }, | |
| 2230 | }, | |
| 2231 | }, | |
| 2232 | .nullary_func_type = .{ | |
| 2233 | .tag = .subroutine_type, | |
| 2234 | .attrs = &.{ | |
| 2235 | .{ .name, .strp }, | |
| 2236 | .{ .calling_convention, .data1 }, | |
| 2237 | .{ .type, .ref_addr }, | |
| 2238 | }, | |
| 2239 | }, | |
| 2240 | .func_type = .{ | |
| 2241 | .tag = .subroutine_type, | |
| 2242 | .children = true, | |
| 2243 | .attrs = &.{ | |
| 2244 | .{ .name, .strp }, | |
| 2245 | .{ .calling_convention, .data1 }, | |
| 2246 | .{ .type, .ref_addr }, | |
| 2247 | }, | |
| 2248 | }, | |
| 2249 | .func_type_param = .{ | |
| 2250 | .tag = .formal_parameter, | |
| 2251 | .attrs = &.{ | |
| 2252 | .{ .type, .ref_addr }, | |
| 2253 | }, | |
| 2254 | }, | |
| 2255 | .is_var_args = .{ | |
| 2256 | .tag = .unspecified_parameters, | |
| 2257 | }, | |
| 2258 | .generated_empty_enum_type = .{ | |
| 2259 | .tag = .enumeration_type, | |
| 2260 | .attrs = &.{ | |
| 2261 | .{ .name, .strp }, | |
| 2262 | .{ .type, .ref_addr }, | |
| 2263 | }, | |
| 2264 | }, | |
| 2265 | .generated_enum_type = .{ | |
| 2266 | .tag = .enumeration_type, | |
| 2267 | .children = true, | |
| 2268 | .attrs = &.{ | |
| 2269 | .{ .name, .strp }, | |
| 2270 | .{ .type, .ref_addr }, | |
| 2271 | }, | |
| 2272 | }, | |
| 2273 | .generated_empty_struct_type = .{ | |
| 2274 | .tag = .structure_type, | |
| 2275 | .attrs = &.{ | |
| 2276 | .{ .name, .strp }, | |
| 2277 | .{ .declaration, .flag }, | |
| 2278 | }, | |
| 2279 | }, | |
| 2280 | .generated_struct_type = .{ | |
| 2281 | .tag = .structure_type, | |
| 2282 | .children = true, | |
| 2283 | .attrs = &.{ | |
| 2284 | .{ .name, .strp }, | |
| 2285 | .{ .byte_size, .udata }, | |
| 2286 | .{ .alignment, .udata }, | |
| 2287 | }, | |
| 2288 | }, | |
| 2289 | .generated_union_type = .{ | |
| 2290 | .tag = .union_type, | |
| 2291 | .children = true, | |
| 2292 | .attrs = &.{ | |
| 2293 | .{ .name, .strp }, | |
| 2294 | .{ .byte_size, .udata }, | |
| 2295 | .{ .alignment, .udata }, | |
| 2296 | }, | |
| 2297 | }, | |
| 2298 | .empty_enum_type = .{ | |
| 2299 | .tag = .enumeration_type, | |
| 2300 | .attrs = &.{ | |
| 2301 | .{ .decl_file, .udata }, | |
| 2302 | .{ .name, .strp }, | |
| 2303 | .{ .type, .ref_addr }, | |
| 2304 | }, | |
| 2305 | }, | |
| 2306 | .enum_type = .{ | |
| 2307 | .tag = .enumeration_type, | |
| 2308 | .children = true, | |
| 2309 | .attrs = &.{ | |
| 2310 | .{ .decl_file, .udata }, | |
| 2311 | .{ .name, .strp }, | |
| 2312 | .{ .type, .ref_addr }, | |
| 2313 | }, | |
| 2314 | }, | |
| 2315 | .empty_struct_type = .{ | |
| 2316 | .tag = .structure_type, | |
| 2317 | .attrs = &.{ | |
| 2318 | .{ .decl_file, .udata }, | |
| 2319 | .{ .name, .strp }, | |
| 2320 | .{ .declaration, .flag }, | |
| 2321 | }, | |
| 2322 | }, | |
| 2323 | .struct_type = .{ | |
| 2324 | .tag = .structure_type, | |
| 2325 | .children = true, | |
| 2326 | .attrs = &.{ | |
| 2327 | .{ .decl_file, .udata }, | |
| 2328 | .{ .name, .strp }, | |
| 2329 | .{ .byte_size, .udata }, | |
| 2330 | .{ .alignment, .udata }, | |
| 2331 | }, | |
| 2332 | }, | |
| 2333 | .empty_packed_struct_type = .{ | |
| 2334 | .tag = .structure_type, | |
| 2335 | .attrs = &.{ | |
| 2336 | .{ .decl_file, .udata }, | |
| 2337 | .{ .name, .strp }, | |
| 2338 | .{ .type, .ref_addr }, | |
| 2339 | }, | |
| 2340 | }, | |
| 2341 | .packed_struct_type = .{ | |
| 2342 | .tag = .structure_type, | |
| 2343 | .children = true, | |
| 2344 | .attrs = &.{ | |
| 2345 | .{ .decl_file, .udata }, | |
| 2346 | .{ .name, .strp }, | |
| 2347 | .{ .type, .ref_addr }, | |
| 2348 | }, | |
| 2349 | }, | |
| 2350 | .empty_union_type = .{ | |
| 2351 | .tag = .union_type, | |
| 2352 | .attrs = &.{ | |
| 2353 | .{ .decl_file, .udata }, | |
| 2354 | .{ .name, .strp }, | |
| 2355 | .{ .byte_size, .udata }, | |
| 2356 | .{ .alignment, .udata }, | |
| 2357 | }, | |
| 2358 | }, | |
| 2359 | .union_type = .{ | |
| 2360 | .tag = .union_type, | |
| 2361 | .children = true, | |
| 2362 | .attrs = &.{ | |
| 2363 | .{ .decl_file, .udata }, | |
| 2364 | .{ .name, .strp }, | |
| 2365 | .{ .byte_size, .udata }, | |
| 2366 | .{ .alignment, .udata }, | |
| 2367 | }, | |
| 2368 | }, | |
| 2369 | .empty_packed_union_type = .{ | |
| 2370 | .tag = .union_type, | |
| 2371 | .attrs = &.{ | |
| 2372 | .{ .decl_file, .udata }, | |
| 2373 | .{ .name, .strp }, | |
| 2374 | .{ .type, .ref_addr }, | |
| 2375 | }, | |
| 2376 | }, | |
| 2377 | .packed_union_type = .{ | |
| 2378 | .tag = .union_type, | |
| 2379 | .children = true, | |
| 2380 | .attrs = &.{ | |
| 2381 | .{ .decl_file, .udata }, | |
| 2382 | .{ .name, .strp }, | |
| 2383 | .{ .type, .ref_addr }, | |
| 2384 | }, | |
| 2385 | }, | |
| 2386 | .builtin_extern_nullary_func = .{ | |
| 2387 | .tag = .subprogram, | |
| 2388 | .attrs = &.{ | |
| 2389 | .{ .ZIG_parent, .ref_addr }, | |
| 2390 | .{ .linkage_name, .strp }, | |
| 2391 | .{ .type, .ref_addr }, | |
| 2392 | .{ .low_pc, .addr }, | |
| 2393 | .{ .external, .flag_present }, | |
| 2394 | .{ .noreturn, .flag }, | |
| 2395 | }, | |
| 2396 | }, | |
| 2397 | .builtin_extern_func = .{ | |
| 2398 | .tag = .subprogram, | |
| 2399 | .children = true, | |
| 2400 | .attrs = &.{ | |
| 2401 | .{ .ZIG_parent, .ref_addr }, | |
| 2402 | .{ .linkage_name, .strp }, | |
| 2403 | .{ .type, .ref_addr }, | |
| 2404 | .{ .low_pc, .addr }, | |
| 2405 | .{ .external, .flag_present }, | |
| 2406 | .{ .noreturn, .flag }, | |
| 2407 | }, | |
| 2408 | }, | |
| 2409 | .builtin_extern_var = .{ | |
| 2410 | .tag = .variable, | |
| 2411 | .attrs = &.{ | |
| 2412 | .{ .ZIG_parent, .ref_addr }, | |
| 2413 | .{ .linkage_name, .strp }, | |
| 2414 | .{ .type, .ref_addr }, | |
| 2415 | .{ .location, .exprloc }, | |
| 2416 | .{ .external, .flag_present }, | |
| 2417 | }, | |
| 2418 | }, | |
| 2419 | .empty_block = .{ | |
| 2420 | .tag = .lexical_block, | |
| 2421 | .attrs = &.{ | |
| 2422 | .{ .low_pc, .addr }, | |
| 2423 | .{ .high_pc, .data4 }, | |
| 2424 | }, | |
| 2425 | }, | |
| 2426 | .block = .{ | |
| 2427 | .tag = .lexical_block, | |
| 2428 | .children = true, | |
| 2429 | .attrs = &.{ | |
| 2430 | .{ .low_pc, .addr }, | |
| 2431 | .{ .high_pc, .data4 }, | |
| 2432 | }, | |
| 2433 | }, | |
| 2434 | .empty_inlined_func = .{ | |
| 2435 | .tag = .inlined_subroutine, | |
| 2436 | .attrs = &.{ | |
| 2437 | .{ .abstract_origin, .ref_addr }, | |
| 2438 | .{ .call_line, .udata }, | |
| 2439 | .{ .call_column, .udata }, | |
| 2440 | .{ .low_pc, .addr }, | |
| 2441 | .{ .high_pc, .data4 }, | |
| 2442 | }, | |
| 2443 | }, | |
| 2444 | .inlined_func = .{ | |
| 2445 | .tag = .inlined_subroutine, | |
| 2446 | .children = true, | |
| 2447 | .attrs = &.{ | |
| 2448 | .{ .abstract_origin, .ref_addr }, | |
| 2449 | .{ .call_line, .udata }, | |
| 2450 | .{ .call_column, .udata }, | |
| 2451 | .{ .low_pc, .addr }, | |
| 2452 | .{ .high_pc, .data4 }, | |
| 2453 | }, | |
| 2454 | }, | |
| 2455 | .arg = .{ | |
| 2456 | .tag = .formal_parameter, | |
| 2457 | .attrs = &.{ | |
| 2458 | .{ .name, .strp }, | |
| 2459 | .{ .type, .ref_addr }, | |
| 2460 | .{ .location, .exprloc }, | |
| 2461 | }, | |
| 2462 | }, | |
| 2463 | .unnamed_arg = .{ | |
| 2464 | .tag = .formal_parameter, | |
| 2465 | .attrs = &.{ | |
| 2466 | .{ .type, .ref_addr }, | |
| 2467 | .{ .location, .exprloc }, | |
| 2468 | }, | |
| 2469 | }, | |
| 2470 | .comptime_arg = .{ | |
| 2471 | .tag = .formal_parameter, | |
| 2472 | .attrs = &.{ | |
| 2473 | .{ .const_expr, .flag_present }, | |
| 2474 | .{ .name, .strp }, | |
| 2475 | .{ .type, .ref_addr }, | |
| 2476 | }, | |
| 2477 | }, | |
| 2478 | .unnamed_comptime_arg = .{ | |
| 2479 | .tag = .formal_parameter, | |
| 2480 | .attrs = &.{ | |
| 2481 | .{ .const_expr, .flag_present }, | |
| 2482 | .{ .type, .ref_addr }, | |
| 2483 | }, | |
| 2484 | }, | |
| 2485 | .comptime_arg_runtime_bits = .{ | |
| 2486 | .tag = .formal_parameter, | |
| 2487 | .attrs = &.{ | |
| 2488 | .{ .const_expr, .flag_present }, | |
| 2489 | .{ .name, .strp }, | |
| 2490 | .{ .type, .ref_addr }, | |
| 2491 | .{ .const_value, .block }, | |
| 2492 | }, | |
| 2493 | }, | |
| 2494 | .unnamed_comptime_arg_runtime_bits = .{ | |
| 2495 | .tag = .formal_parameter, | |
| 2496 | .attrs = &.{ | |
| 2497 | .{ .const_expr, .flag_present }, | |
| 2498 | .{ .type, .ref_addr }, | |
| 2499 | .{ .const_value, .block }, | |
| 2500 | }, | |
| 2501 | }, | |
| 2502 | .comptime_arg_comptime_state = .{ | |
| 2503 | .tag = .formal_parameter, | |
| 2504 | .attrs = &.{ | |
| 2505 | .{ .const_expr, .flag_present }, | |
| 2506 | .{ .name, .strp }, | |
| 2507 | .{ .type, .ref_addr }, | |
| 2508 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2509 | }, | |
| 2510 | }, | |
| 2511 | .unnamed_comptime_arg_comptime_state = .{ | |
| 2512 | .tag = .formal_parameter, | |
| 2513 | .attrs = &.{ | |
| 2514 | .{ .const_expr, .flag_present }, | |
| 2515 | .{ .type, .ref_addr }, | |
| 2516 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2517 | }, | |
| 2518 | }, | |
| 2519 | .comptime_arg_runtime_bits_comptime_state = .{ | |
| 2520 | .tag = .formal_parameter, | |
| 2521 | .attrs = &.{ | |
| 2522 | .{ .const_expr, .flag_present }, | |
| 2523 | .{ .name, .strp }, | |
| 2524 | .{ .type, .ref_addr }, | |
| 2525 | .{ .const_value, .block }, | |
| 2526 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2527 | }, | |
| 2528 | }, | |
| 2529 | .unnamed_comptime_arg_runtime_bits_comptime_state = .{ | |
| 2530 | .tag = .formal_parameter, | |
| 2531 | .attrs = &.{ | |
| 2532 | .{ .const_expr, .flag_present }, | |
| 2533 | .{ .type, .ref_addr }, | |
| 2534 | .{ .const_value, .block }, | |
| 2535 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2536 | }, | |
| 2537 | }, | |
| 2538 | .extern_param = .{ | |
| 2539 | .tag = .formal_parameter, | |
| 2540 | .attrs = &.{ | |
| 2541 | .{ .type, .ref_addr }, | |
| 2542 | }, | |
| 2543 | }, | |
| 2544 | .local_var = .{ | |
| 2545 | .tag = .variable, | |
| 2546 | .attrs = &.{ | |
| 2547 | .{ .name, .strp }, | |
| 2548 | .{ .type, .ref_addr }, | |
| 2549 | .{ .location, .exprloc }, | |
| 2550 | }, | |
| 2551 | }, | |
| 2552 | .local_const = .{ | |
| 2553 | .tag = .constant, | |
| 2554 | .attrs = &.{ | |
| 2555 | .{ .name, .strp }, | |
| 2556 | .{ .type, .ref_addr }, | |
| 2557 | }, | |
| 2558 | }, | |
| 2559 | .local_const_runtime_bits = .{ | |
| 2560 | .tag = .constant, | |
| 2561 | .attrs = &.{ | |
| 2562 | .{ .name, .strp }, | |
| 2563 | .{ .type, .ref_addr }, | |
| 2564 | .{ .const_value, .block }, | |
| 2565 | }, | |
| 2566 | }, | |
| 2567 | .local_const_comptime_state = .{ | |
| 2568 | .tag = .constant, | |
| 2569 | .attrs = &.{ | |
| 2570 | .{ .name, .strp }, | |
| 2571 | .{ .type, .ref_addr }, | |
| 2572 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2573 | }, | |
| 2574 | }, | |
| 2575 | .local_const_runtime_bits_comptime_state = .{ | |
| 2576 | .tag = .constant, | |
| 2577 | .attrs = &.{ | |
| 2578 | .{ .name, .strp }, | |
| 2579 | .{ .type, .ref_addr }, | |
| 2580 | .{ .const_value, .block }, | |
| 2581 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2582 | }, | |
| 2583 | }, | |
| 2584 | .undefined_comptime_value = .{ | |
| 2585 | .tag = .ZIG_comptime_value, | |
| 2586 | .attrs = &.{ | |
| 2587 | .{ .type, .ref_addr }, | |
| 2588 | }, | |
| 2589 | }, | |
| 2590 | .aggregate_undefined_comptime_value = .{ | |
| 2591 | .tag = .ZIG_comptime_value, | |
| 2592 | .children = true, | |
| 2593 | .attrs = &.{ | |
| 2594 | .{ .type, .ref_addr }, | |
| 2595 | }, | |
| 2596 | }, | |
| 2597 | .comptime_value = .{ | |
| 2598 | .tag = .ZIG_comptime_value, | |
| 2599 | .attrs = &.{ | |
| 2600 | .{ .type, .ref_addr }, | |
| 2601 | .{ .const_value, .indirect }, | |
| 2602 | }, | |
| 2603 | }, | |
| 2604 | .aggregate_comptime_value = .{ | |
| 2605 | .tag = .ZIG_comptime_value, | |
| 2606 | .children = true, | |
| 2607 | .attrs = &.{ | |
| 2608 | .{ .type, .ref_addr }, | |
| 2609 | .{ .const_value, .indirect }, | |
| 2610 | }, | |
| 2611 | }, | |
| 2612 | .location_comptime_value = .{ | |
| 2613 | .tag = .ZIG_comptime_value, | |
| 2614 | .attrs = &.{ | |
| 2615 | .{ .type, .ref_addr }, | |
| 2616 | .{ .location, .exprloc }, | |
| 2617 | }, | |
| 2618 | }, | |
| 2619 | .aggregate_location_comptime_value = .{ | |
| 2620 | .tag = .ZIG_comptime_value, | |
| 2621 | .children = true, | |
| 2622 | .attrs = &.{ | |
| 2623 | .{ .type, .ref_addr }, | |
| 2624 | .{ .location, .exprloc }, | |
| 2625 | }, | |
| 2626 | }, | |
| 2627 | .comptime_value_field_runtime_bits = .{ | |
| 2628 | .tag = .member, | |
| 2629 | .attrs = &.{ | |
| 2630 | .{ .name, .strp }, | |
| 2631 | .{ .const_value, .block }, | |
| 2632 | }, | |
| 2633 | }, | |
| 2634 | .comptime_value_field_comptime_state = .{ | |
| 2635 | .tag = .member, | |
| 2636 | .attrs = &.{ | |
| 2637 | .{ .name, .strp }, | |
| 2638 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2639 | }, | |
| 2640 | }, | |
| 2641 | .comptime_value_elem_runtime_bits = .{ | |
| 2642 | .tag = .member, | |
| 2643 | .attrs = &.{ | |
| 2644 | .{ .const_value, .block }, | |
| 2645 | }, | |
| 2646 | }, | |
| 2647 | .comptime_value_elem_comptime_state = .{ | |
| 2648 | .tag = .member, | |
| 2649 | .attrs = &.{ | |
| 2650 | .{ .ZIG_comptime_value, .ref_addr }, | |
| 2651 | }, | |
| 2652 | }, | |
| 2653 | .null = undefined, | |
| 2654 | }); | |
| 2655 | }; | |
| 2656 | ||
| 2657 | fn uleb128Bytes(value: anytype) u32 { | |
| 2658 | var buf: [64]u8 = undefined; | |
| 2659 | var dw: Writer.Discarding = .init(&buf); | |
| 2660 | dw.writer.writeUleb128(value) catch unreachable; | |
| 2661 | return @intCast(dw.fullCount()); | |
| 2662 | } | |
| 2663 | ||
| 2664 | fn sleb128Bytes(value: anytype) u32 { | |
| 2665 | var buf: [64]u8 = undefined; | |
| 2666 | var dw: Writer.Discarding = .init(&buf); | |
| 2667 | dw.writer.writeSleb128(value) catch unreachable; | |
| 2668 | return @intCast(dw.fullCount()); | |
| 2669 | } | |
| 2670 | ||
| 2671 | const Allocator = std.mem.Allocator; | |
| 2672 | const assert = std.debug.assert; | |
| 2673 | const codegen = @import("../codegen.zig"); | |
| 2674 | const dev = @import("../dev.zig"); | |
| 2675 | const DW = std.dwarf; | |
| 2676 | const Dwarf = @This(); | |
| 2677 | const InternPool = @import("../InternPool.zig"); | |
| 2678 | const link = @import("../link.zig"); | |
| 2679 | const MappedFile = @import("MappedFile.zig"); | |
| 2680 | const Module = @import("../Module.zig"); | |
| 2681 | const std = @import("std"); | |
| 2682 | const Type = @import("../Type.zig"); | |
| 2683 | const Value = @import("../Value.zig"); | |
| 2684 | const Writer = std.Io.Writer; | |
| 2685 | const Zcu = @import("../Zcu.zig"); |
src/link/Elf/ZigObject.zig+11-16| ... | ... | @@ -946,14 +946,11 @@ pub fn getNavVAddr( |
| 946 | 946 | .r_addend = reloc_info.addend, |
| 947 | 947 | }, self); |
| 948 | 948 | }, |
| 949 | .debug_output => |debug_output| switch (debug_output) { | |
| 950 | .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ | |
| 951 | .source_off = @intCast(reloc_info.offset), | |
| 952 | .target_sym = @fromBackingInt(@intCast(this_sym_index)), | |
| 953 | .target_off = reloc_info.addend, | |
| 954 | }), | |
| 955 | .none => unreachable, | |
| 956 | }, | |
| 949 | .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{ | |
| 950 | .source_off = @intCast(reloc_info.offset), | |
| 951 | .target_sym = @fromBackingInt(@intCast(this_sym_index)), | |
| 952 | .target_off = reloc_info.addend, | |
| 953 | }), | |
| 957 | 954 | } |
| 958 | 955 | return @intCast(vaddr); |
| 959 | 956 | } |
| ... | ... | @@ -978,14 +975,11 @@ pub fn getUavVAddr( |
| 978 | 975 | .r_addend = reloc_info.addend, |
| 979 | 976 | }, self); |
| 980 | 977 | }, |
| 981 | .debug_output => |debug_output| switch (debug_output) { | |
| 982 | .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ | |
| 983 | .source_off = @intCast(reloc_info.offset), | |
| 984 | .target_sym = @fromBackingInt(@intCast(sym_index)), | |
| 985 | .target_off = reloc_info.addend, | |
| 986 | }), | |
| 987 | .none => unreachable, | |
| 988 | }, | |
| 978 | .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{ | |
| 979 | .source_off = @intCast(reloc_info.offset), | |
| 980 | .target_sym = @fromBackingInt(@intCast(sym_index)), | |
| 981 | .target_off = reloc_info.addend, | |
| 982 | }), | |
| 989 | 983 | } |
| 990 | 984 | return @intCast(vaddr); |
| 991 | 985 | } |
| ... | ... | @@ -1555,6 +1549,7 @@ pub fn updateFunc( |
| 1555 | 1549 | if (debug_wip_nav) |*dn| .{ .dwarf = dn } else .none, |
| 1556 | 1550 | ) catch |err| switch (err) { |
| 1557 | 1551 | error.WriteFailed => return error.OutOfMemory, |
| 1552 | error.MappedFileIo => unreachable, // MappedFile is not being used | |
| 1558 | 1553 | else => |e| return e, |
| 1559 | 1554 | }; |
| 1560 | 1555 | const code = aw.written(); |
src/link/Elf2.zig+1426-570| ... | ... | @@ -1,8 +1,5 @@ |
| 1 | 1 | const Elf = @This(); |
| 2 | 2 | |
| 3 | const builtin = @import("builtin"); | |
| 4 | const native_endian = builtin.cpu.arch.endian(); | |
| 5 | ||
| 6 | 3 | const std = @import("std"); |
| 7 | 4 | const Io = std.Io; |
| 8 | 5 | const assert = std.debug.assert; |
| ... | ... | @@ -10,6 +7,8 @@ const log = std.log.scoped(.link); |
| 10 | 7 | |
| 11 | 8 | const codegen = @import("../codegen.zig"); |
| 12 | 9 | const Compilation = @import("../Compilation.zig"); |
| 10 | const dev = @import("../dev.zig"); | |
| 11 | const Dwarf = @import("Dwarf2.zig"); | |
| 13 | 12 | const InternPool = @import("../InternPool.zig"); |
| 14 | 13 | const link = @import("../link.zig"); |
| 15 | 14 | const MappedFile = @import("MappedFile.zig"); |
| ... | ... | @@ -43,6 +42,11 @@ shndx: struct { |
| 43 | 42 | tdata: Section.Index, |
| 44 | 43 | rela_dyn: Section.Index, |
| 45 | 44 | rela_plt: Section.Index, |
| 45 | eh_frame_hdr: Section.Index, | |
| 46 | eh_frame: Section.Index, | |
| 47 | debug_frame: Section.Index, | |
| 48 | debug_info: Section.Index, | |
| 49 | debug_line: Section.Index, | |
| 46 | 50 | // These sections are created only as needed, and are initially `.UNDEF`. |
| 47 | 51 | init_array: Section.Index, |
| 48 | 52 | fini_array: Section.Index, |
| ... | ... | @@ -123,6 +127,8 @@ got: std.array_hash_map.Auto(GotKey, Section.RelaIndex.Optional), |
| 123 | 127 | plt: std.array_hash_map.Auto(String(.strtab), void), |
| 124 | 128 | /// The `.plt` section contains zero or more symbol relocations starting at this index. |
| 125 | 129 | plt_first_symbol_reloc: SymbolReloc.Index, |
| 130 | /// The `.eh_frame_hdr` section contains zero or more symbol relocations starting at this index. | |
| 131 | eh_frame_hdr_first_symbol_reloc: SymbolReloc.Index, | |
| 126 | 132 | |
| 127 | 133 | needed: std.array_hash_map.Auto(String(.dynstr), void), |
| 128 | 134 | inputs: std.ArrayList(struct { |
| ... | ... | @@ -175,9 +181,10 @@ lazy: std.EnumArray(link.File.LazySymbol.Kind, struct { |
| 175 | 181 | }), |
| 176 | 182 | pending_uavs: std.ArrayList(Node.UavMapIndex), |
| 177 | 183 | symbol_relocs: std.ArrayList(SymbolReloc), |
| 178 | got_relocs: std.ArrayList(GotReloc), | |
| 179 | 184 | /// Set of relocations which must be re-applied if the size of the TLS segment changes. |
| 180 | 185 | tls_size_symbol_relocs: std.array_hash_map.Auto(SymbolReloc.Index, void), |
| 186 | node_relocs: std.ArrayList(NodeReloc), | |
| 187 | got_relocs: std.ArrayList(GotReloc), | |
| 181 | 188 | /// Index matches the index into `shdrs`. Like `shdrs`, this map excludes `SHN_UNDEF`. |
| 182 | 189 | section_by_name: std.array_hash_map.Auto(String(.shstrtab), void), |
| 183 | 190 | /// Key is the name of a global symbol which has been moved to a new symtab index. Any relocation |
| ... | ... | @@ -191,6 +198,17 @@ changed_symtab_index: std.array_hash_map.Auto(String(.strtab), void), |
| 191 | 198 | /// section in `flush` only when it is actually necessary. See also `nodeWantsDsoRelocation`. |
| 192 | 199 | textrel_count: u32, |
| 193 | 200 | |
| 201 | dwarf: Dwarf, | |
| 202 | dwarf_units: std.ArrayList(struct { | |
| 203 | unit_frame_cie_first_target_reloc: NodeReloc.Index, | |
| 204 | }), | |
| 205 | dwarf_values: std.ArrayList(struct {}), | |
| 206 | dwarf_globals: std.ArrayList(struct {}), | |
| 207 | dwarf_funcs: std.ArrayList(struct { | |
| 208 | func_frame_fde_first_symbol_reloc: SymbolReloc.Index, | |
| 209 | func_frame_fde_first_node_reloc: NodeReloc.Index, | |
| 210 | }), | |
| 211 | ||
| 194 | 212 | overflowed_reloc_count: u32, |
| 195 | 213 | misaligned_reloc_count: u32, |
| 196 | 214 | |
| ... | ... | @@ -232,8 +250,9 @@ const Node = union(enum) { |
| 232 | 250 | ehdr, |
| 233 | 251 | shdr, |
| 234 | 252 | segment: u32, |
| 235 | /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`. | |
| 236 | 253 | section: Section.Index, |
| 254 | /// The section '.plt' may contain relocations via `elf.plt_first_symbol_reloc`. | |
| 255 | section_manual_size: Section.Index, | |
| 237 | 256 | /// May contain relocations. |
| 238 | 257 | input_section: InputSection.Index, |
| 239 | 258 | /// Value is the name of a global which has an entry in `elf.copied_globals`, so, a global for |
| ... | ... | @@ -253,6 +272,15 @@ const Node = union(enum) { |
| 253 | 272 | /// May contain relocations. |
| 254 | 273 | lazy_const_data: LazyMapRef.Index(.const_data), |
| 255 | 274 | |
| 275 | value_debug_info: link.ConstPool.Index, | |
| 276 | global_debug_info: Dwarf.Global.Index, | |
| 277 | frame_padding, | |
| 278 | unit_frame: Dwarf.Unit.Index, | |
| 279 | unit_frame_cie: Dwarf.Unit.Index, | |
| 280 | func_frame_fde: Dwarf.Func.Index, | |
| 281 | func_debug_info: Dwarf.Func.Index, | |
| 282 | func_debug_line: Dwarf.Func.Index, | |
| 283 | ||
| 256 | 284 | pub const InputIndex = enum(u32) { |
| 257 | 285 | _, |
| 258 | 286 | |
| ... | ... | @@ -373,6 +401,7 @@ const Node = union(enum) { |
| 373 | 401 | data: MappedFile.Node.Index, |
| 374 | 402 | data_rel_ro: MappedFile.Node.Index, |
| 375 | 403 | tls: MappedFile.Node.Index.Optional, |
| 404 | gnu_eh_frame: MappedFile.Node.Index.Optional, | |
| 376 | 405 | }; |
| 377 | 406 | |
| 378 | 407 | comptime { |
| ... | ... | @@ -649,7 +678,7 @@ const Section = struct { |
| 649 | 678 | }, |
| 650 | 679 | .addend = @intCast(old_free_len + 1), // list length |
| 651 | 680 | }; |
| 652 | if (elf.targetEndian() != native_endian) { | |
| 681 | if (elf.targetEndian() != std.lang.Endian.native) { | |
| 653 | 682 | std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(index)]); |
| 654 | 683 | } |
| 655 | 684 | }, |
| ... | ... | @@ -708,7 +737,7 @@ const Section = struct { |
| 708 | 737 | }, |
| 709 | 738 | .addend = @intCast(opts.addend), |
| 710 | 739 | }; |
| 711 | if (elf.targetEndian() != native_endian) { | |
| 740 | if (elf.targetEndian() != std.lang.Endian.native) { | |
| 712 | 741 | std.mem.byteSwapAllFields(class.ElfN().Rela, &relas[@backingInt(new_index)]); |
| 713 | 742 | } |
| 714 | 743 | return new_index; |
| ... | ... | @@ -807,244 +836,13 @@ const Section = struct { |
| 807 | 836 | }, |
| 808 | 837 | } |
| 809 | 838 | } |
| 810 | }; | |
| 811 | }; | |
| 812 | ||
| 813 | /// Identifies a single entry in the GOT. | |
| 814 | const GotKey = union(enum) { | |
| 815 | /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these | |
| 816 | /// as the target machine ABI requires. | |
| 817 | /// | |
| 818 | /// This `u32` value exists to allow reserving multiple words with distinct keys. | |
| 819 | reserved: u32, | |
| 820 | ||
| 821 | /// Value is the address of the given symbol. | |
| 822 | symbol: Symbol.Id, | |
| 823 | ||
| 824 | /// Value is the signed offset of the given symbol from the TLS pointer. | |
| 825 | tpoff: Symbol.Id, | |
| 826 | ||
| 827 | /// Value is the TLS module ID of the DSO we are creating. | |
| 828 | /// | |
| 829 | /// Used for the first of the two GOT entries generated by a TLSLD relocation. | |
| 830 | tlsld0, | |
| 831 | /// Value is always 0. | |
| 832 | /// | |
| 833 | /// Used for the second of the two GOT entries generated by a TLSLD relocation. | |
| 834 | tlsld1, | |
| 835 | ||
| 836 | /// Value is the TLS module ID for the given STT_TLS symbol. | |
| 837 | /// | |
| 838 | /// Used for the first of the two GOT entries generated by a TLSGD relocation. | |
| 839 | tlsgd0: Symbol.Id, | |
| 840 | /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area. | |
| 841 | /// | |
| 842 | /// Used for the second of the two GOT entries generated by a TLSGD relocation. | |
| 843 | tlsgd1: Symbol.Id, | |
| 844 | }; | |
| 845 | ||
| 846 | /// A relocation targeting a particular GOT entry. | |
| 847 | const GotReloc = struct { | |
| 848 | /// The node containing this relocation. Possible values are: | |
| 849 | /// * An input section | |
| 850 | /// * A section | |
| 851 | /// * A NAV, UAV, or lazy code/data | |
| 852 | /// * `.none`, if this relocation was deleted (in which case it should be ignored) | |
| 853 | node: MappedFile.Node.Index.Optional, | |
| 854 | /// The offset of the relocation inside of `node`. | |
| 855 | offset: u64, | |
| 856 | target: GotKey, | |
| 857 | addend: i64, | |
| 858 | type: GotReloc.Type, | |
| 859 | result: enum(u8) { ok, overflowed, misaligned }, | |
| 860 | ||
| 861 | /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target` | |
| 862 | /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview. | |
| 863 | const Type = packed struct(u16) { | |
| 864 | fn simple(target: Target, action: Simple) GotReloc.Type { | |
| 865 | assert(target != .special); | |
| 866 | return .{ .target = target, .action = .{ .simple = action } }; | |
| 867 | } | |
| 868 | ||
| 869 | fn special(s: Special) GotReloc.Type { | |
| 870 | return .{ .target = .special, .action = .{ .special = s } }; | |
| 871 | } | |
| 872 | ||
| 873 | target: Target, | |
| 874 | action: packed union { | |
| 875 | simple: Simple, | |
| 876 | special: Special, | |
| 877 | }, | |
| 878 | ||
| 879 | /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there | |
| 880 | /// are fewer different kinds of GOT relocation. | |
| 881 | const Target = enum(u3) { | |
| 882 | /// This is a "special" relocation whose specific type is in the `action.special` field. | |
| 883 | special, | |
| 884 | ||
| 885 | /// Absolute address of the GOT entry. | |
| 886 | abs, | |
| 887 | /// Offset from the relocation itself to the GOT entry ("PC-relative"). | |
| 888 | rel, | |
| 889 | /// Offset from the base of the GOT to the GOT entry. | |
| 890 | offset, | |
| 891 | }; | |
| 892 | ||
| 893 | const Simple = SymbolReloc.Type.Simple; | |
| 894 | ||
| 895 | /// Like `SymbolReloc.Special`, but for GOT relocations. | |
| 896 | const Special = enum(u13) { | |
| 897 | larch_pcala_hi20, | |
| 898 | larch_pcala64_lo20, | |
| 899 | larch_pcala64_hi12, | |
| 900 | ||
| 901 | sparc_op_lox10, | |
| 902 | sparc_op_hix22, | |
| 903 | ||
| 904 | fn applyInner( | |
| 905 | s: Special, | |
| 906 | elf: *Elf, | |
| 907 | got_vaddr: u64, | |
| 908 | got_offset: u64, | |
| 909 | addend: u64, | |
| 910 | dest_vaddr: u64, | |
| 911 | dest_slice: []u8, | |
| 912 | ) error{ RelocationMisaligned, RelocationOverflow }!void { | |
| 913 | switch (s) { | |
| 914 | .larch_pcala_hi20 => { | |
| 915 | const val = got_vaddr +% got_offset +% addend; | |
| 916 | const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]); | |
| 917 | elf.targetStore(inst, .{ | |
| 918 | .b0_4 = elf.targetLoad(inst).b0_4, | |
| 919 | .j20 = link.loongarch.pcalaHi20(val, dest_vaddr), | |
| 920 | .b25_31 = elf.targetLoad(inst).b25_31, | |
| 921 | }); | |
| 922 | }, | |
| 923 | .larch_pcala64_lo20 => { | |
| 924 | const val = got_vaddr +% got_offset +% addend; | |
| 925 | const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]); | |
| 926 | elf.targetStore(inst, .{ | |
| 927 | .b0_4 = elf.targetLoad(inst).b0_4, | |
| 928 | .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr), | |
| 929 | .b25_31 = elf.targetLoad(inst).b25_31, | |
| 930 | }); | |
| 931 | }, | |
| 932 | .larch_pcala64_hi12 => { | |
| 933 | const val = got_vaddr +% got_offset +% addend; | |
| 934 | const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]); | |
| 935 | elf.targetStore(inst, .{ | |
| 936 | .b0_9 = elf.targetLoad(inst).b0_9, | |
| 937 | .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr), | |
| 938 | .b22_31 = elf.targetLoad(inst).b22_31, | |
| 939 | }); | |
| 940 | }, | |
| 941 | .sparc_op_lox10 => { | |
| 942 | const dest_ptr: *align(1) packed struct(u32) { | |
| 943 | imm13: u13, | |
| 944 | b13_31: u19, | |
| 945 | } = @ptrCast(dest_slice); | |
| 946 | elf.targetStore(dest_ptr, .{ | |
| 947 | .imm13 = @as(u10, @truncate(got_offset)), | |
| 948 | .b13_31 = elf.targetLoad(dest_ptr).b13_31, | |
| 949 | }); | |
| 950 | }, | |
| 951 | .sparc_op_hix22 => { | |
| 952 | const dest_ptr: *align(1) packed struct(u32) { | |
| 953 | imm22: u22, | |
| 954 | b22_31: u10, | |
| 955 | } = @ptrCast(dest_slice); | |
| 956 | elf.targetStore(dest_ptr, .{ | |
| 957 | .imm22 = @truncate(got_offset >> 10), | |
| 958 | .b22_31 = elf.targetLoad(dest_ptr).b22_31, | |
| 959 | }); | |
| 960 | }, | |
| 961 | } | |
| 962 | } | |
| 963 | }; | |
| 964 | }; | |
| 965 | ||
| 966 | const Index = enum(u32) { | |
| 967 | none = std.math.maxInt(u32), | |
| 968 | _, | |
| 969 | 839 | |
| 970 | fn get(index: GotReloc.Index, elf: *Elf) *GotReloc { | |
| 971 | return &elf.got_relocs.items[@backingInt(index)]; | |
| 840 | fn debugFrameFormat(shndx: Index, elf: *Elf) ?Dwarf.Frame.Format { | |
| 841 | if (shndx == elf.shndx.eh_frame) return .eh_frame; | |
| 842 | if (shndx == elf.shndx.debug_frame) return .debug_frame; | |
| 843 | return null; | |
| 972 | 844 | } |
| 973 | 845 | }; |
| 974 | ||
| 975 | fn apply(reloc: *GotReloc, elf: *Elf) void { | |
| 976 | assert(elf.ehdrType() != .REL); | |
| 977 | const node = reloc.node.unwrap() orelse { | |
| 978 | return; // deleted | |
| 979 | }; | |
| 980 | if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) { | |
| 981 | // There's no point applying the relocation now, because it will be re-applied by | |
| 982 | // `flushMoved` at some point anyway. | |
| 983 | return; | |
| 984 | } | |
| 985 | switch (reloc.result) { | |
| 986 | .ok => {}, | |
| 987 | .overflowed => elf.overflowed_reloc_count -= 1, | |
| 988 | .misaligned => elf.misaligned_reloc_count -= 1, | |
| 989 | } | |
| 990 | if (reloc.applyInner(elf)) { | |
| 991 | @branchHint(.likely); | |
| 992 | reloc.result = .ok; | |
| 993 | } else |err| switch (err) { | |
| 994 | error.RelocationOverflow => { | |
| 995 | reloc.result = .overflowed; | |
| 996 | elf.overflowed_reloc_count += 1; | |
| 997 | }, | |
| 998 | error.RelocationMisaligned => { | |
| 999 | reloc.result = .misaligned; | |
| 1000 | elf.misaligned_reloc_count += 1; | |
| 1001 | }, | |
| 1002 | } | |
| 1003 | } | |
| 1004 | fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { | |
| 1005 | const node = reloc.node.unwrap().?; | |
| 1006 | const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset; | |
| 1007 | const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..]; | |
| 1008 | ||
| 1009 | const got_vaddr = elf.shndx.got.vaddr(elf); | |
| 1010 | const got_index: u64 = elf.got.getIndex(reloc.target).?; | |
| 1011 | const got_offset: u64 = switch (elf.identClass()) { | |
| 1012 | .NONE, _ => unreachable, | |
| 1013 | inline else => |class| @sizeOf(class.ElfN().Addr) * got_index, | |
| 1014 | }; | |
| 1015 | const addend: u64 = @bitCast(reloc.addend); | |
| 1016 | ||
| 1017 | const target_val: u64 = switch (reloc.type.target) { | |
| 1018 | .abs => got_vaddr +% got_offset +% addend, | |
| 1019 | .rel => got_vaddr +% got_offset +% addend -% dest_vaddr, | |
| 1020 | .offset => got_offset +% addend, | |
| 1021 | .special => return reloc.type.action.special.applyInner( | |
| 1022 | elf, | |
| 1023 | got_vaddr, | |
| 1024 | got_offset, | |
| 1025 | addend, | |
| 1026 | dest_vaddr, | |
| 1027 | dest_slice, | |
| 1028 | ), | |
| 1029 | }; | |
| 1030 | try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian()); | |
| 1031 | } | |
| 1032 | ||
| 1033 | fn delete(reloc: *GotReloc, elf: *Elf) void { | |
| 1034 | switch (reloc.result) { | |
| 1035 | .ok => {}, | |
| 1036 | .overflowed => elf.overflowed_reloc_count -= 1, | |
| 1037 | .misaligned => elf.misaligned_reloc_count -= 1, | |
| 1038 | } | |
| 1039 | reloc.* = .{ | |
| 1040 | .node = .none, | |
| 1041 | .offset = undefined, | |
| 1042 | .target = undefined, | |
| 1043 | .addend = undefined, | |
| 1044 | .type = undefined, | |
| 1045 | .result = undefined, | |
| 1046 | }; | |
| 1047 | } | |
| 1048 | 846 | }; |
| 1049 | 847 | |
| 1050 | 848 | pub const MachineRelocType = union { |
| ... | ... | @@ -1118,51 +916,144 @@ pub const MachineRelocType = union { |
| 1118 | 916 | pub fn globDat(elf: *const Elf) MachineRelocType { |
| 1119 | 917 | return switch (elf.ehdrMachine()) { |
| 1120 | 918 | .AARCH64 => .{ .AARCH64 = .GLOB_DAT }, |
| 1121 | .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | |
| 919 | .LOONGARCH => .{ .LARCH = switch (elf.identClass()) { | |
| 920 | .NONE, _ => unreachable, | |
| 921 | .@"32" => .@"32", | |
| 922 | .@"64" => .@"64", | |
| 923 | } }, | |
| 1122 | 924 | .PPC64 => .{ .PPC64 = .GLOB_DAT }, |
| 1123 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | |
| 925 | .RISCV => .{ .RISCV = switch (elf.identClass()) { | |
| 926 | .NONE, _ => unreachable, | |
| 927 | .@"32" => .@"32", | |
| 928 | .@"64" => .@"64", | |
| 929 | } }, | |
| 1124 | 930 | .SPARCV9 => .{ .SPARC = .GLOB_DAT }, |
| 1125 | 931 | .X86_64 => .{ .X86_64 = .GLOB_DAT }, |
| 1126 | 932 | }; |
| 1127 | 933 | } |
| 1128 | 934 | pub fn dtpMod(elf: *const Elf) MachineRelocType { |
| 1129 | 935 | return switch (elf.ehdrMachine()) { |
| 1130 | .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_DTPMOD else .P32_TLS_DTPMOD }, | |
| 1131 | .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 }, | |
| 936 | .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) { | |
| 937 | .NONE, _ => unreachable, | |
| 938 | .@"32" => .P32_TLS_DTPMOD, | |
| 939 | .@"64" => .TLS_DTPMOD, | |
| 940 | } }, | |
| 941 | .LOONGARCH => .{ .LARCH = switch (elf.identClass()) { | |
| 942 | .NONE, _ => unreachable, | |
| 943 | .@"32" => .TLS_DTPMOD32, | |
| 944 | .@"64" => .TLS_DTPMOD64, | |
| 945 | } }, | |
| 1132 | 946 | .PPC64 => .{ .PPC64 = .DTPMOD64 }, |
| 1133 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 }, | |
| 1134 | .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPMOD64 else .TLS_DTPMOD32 }, | |
| 947 | .RISCV => .{ .RISCV = switch (elf.identClass()) { | |
| 948 | .NONE, _ => unreachable, | |
| 949 | .@"32" => .TLS_DTPMOD32, | |
| 950 | .@"64" => .TLS_DTPMOD64, | |
| 951 | } }, | |
| 952 | .SPARCV9 => .{ .SPARC = switch (elf.identClass()) { | |
| 953 | .NONE, _ => unreachable, | |
| 954 | .@"32" => .TLS_DTPMOD32, | |
| 955 | .@"64" => .TLS_DTPMOD64, | |
| 956 | } }, | |
| 1135 | 957 | .X86_64 => .{ .X86_64 = .DTPMOD64 }, |
| 1136 | 958 | }; |
| 1137 | 959 | } |
| 1138 | 960 | pub fn dtpOff(elf: *const Elf) MachineRelocType { |
| 1139 | 961 | return switch (elf.ehdrMachine()) { |
| 1140 | .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_DTPREL else .P32_TLS_DTPREL }, | |
| 1141 | .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 }, | |
| 962 | .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) { | |
| 963 | .NONE, _ => unreachable, | |
| 964 | .@"32" => .P32_TLS_DTPREL, | |
| 965 | .@"64" => .TLS_DTPREL, | |
| 966 | } }, | |
| 967 | .LOONGARCH => .{ .LARCH = switch (elf.identClass()) { | |
| 968 | .NONE, _ => unreachable, | |
| 969 | .@"32" => .TLS_DTPREL32, | |
| 970 | .@"64" => .TLS_DTPREL64, | |
| 971 | } }, | |
| 1142 | 972 | .PPC64 => .{ .PPC64 = .DTPREL64 }, |
| 1143 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_DTPREL64 else .TLS_DTPREL32 }, | |
| 1144 | .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_DTPOFF64 else .TLS_DTPOFF32 }, | |
| 973 | .RISCV => .{ .RISCV = switch (elf.identClass()) { | |
| 974 | .NONE, _ => unreachable, | |
| 975 | .@"32" => .TLS_DTPREL32, | |
| 976 | .@"64" => .TLS_DTPREL64, | |
| 977 | } }, | |
| 978 | .SPARCV9 => .{ .SPARC = switch (elf.identClass()) { | |
| 979 | .NONE, _ => unreachable, | |
| 980 | .@"32" => .TLS_DTPOFF32, | |
| 981 | .@"64" => .TLS_DTPOFF64, | |
| 982 | } }, | |
| 1145 | 983 | .X86_64 => .{ .X86_64 = .DTPOFF64 }, |
| 1146 | 984 | }; |
| 1147 | 985 | } |
| 1148 | 986 | pub fn tpOff(elf: *const Elf) MachineRelocType { |
| 1149 | 987 | return switch (elf.ehdrMachine()) { |
| 1150 | .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .TLS_TPREL else .P32_TLS_TPREL }, | |
| 1151 | .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 }, | |
| 988 | .AARCH64 => .{ .AARCH64 = switch (elf.identClass()) { | |
| 989 | .NONE, _ => unreachable, | |
| 990 | .@"32" => .P32_TLS_TPREL, | |
| 991 | .@"64" => .TLS_TPREL, | |
| 992 | } }, | |
| 993 | .LOONGARCH => .{ .LARCH = switch (elf.identClass()) { | |
| 994 | .NONE, _ => unreachable, | |
| 995 | .@"32" => .TLS_TPREL32, | |
| 996 | .@"64" => .TLS_TPREL64, | |
| 997 | } }, | |
| 1152 | 998 | .PPC64 => .{ .PPC64 = .TPREL64 }, |
| 1153 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .TLS_TPREL64 else .TLS_TPREL32 }, | |
| 1154 | .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .TLS_TPOFF64 else .TLS_TPOFF32 }, | |
| 999 | .RISCV => .{ .RISCV = switch (elf.identClass()) { | |
| 1000 | .NONE, _ => unreachable, | |
| 1001 | .@"32" => .TLS_TPREL32, | |
| 1002 | .@"64" => .TLS_TPREL64, | |
| 1003 | } }, | |
| 1004 | .SPARCV9 => .{ .SPARC = switch (elf.identClass()) { | |
| 1005 | .NONE, _ => unreachable, | |
| 1006 | .@"32" => .TLS_TPOFF32, | |
| 1007 | .@"64" => .TLS_TPOFF64, | |
| 1008 | } }, | |
| 1155 | 1009 | .X86_64 => .{ .X86_64 = .TPOFF64 }, |
| 1156 | 1010 | }; |
| 1157 | 1011 | } |
| 1158 | 1012 | pub fn absAddr(elf: *const Elf) MachineRelocType { |
| 1013 | return switch (elf.identClass()) { | |
| 1014 | .NONE, _ => unreachable, | |
| 1015 | .@"32" => .abs32(elf), | |
| 1016 | .@"64" => .abs64(elf), | |
| 1017 | }; | |
| 1018 | } | |
| 1019 | pub fn abs32(elf: *const Elf) MachineRelocType { | |
| 1159 | 1020 | return switch (elf.ehdrMachine()) { |
| 1160 | .AARCH64 => .{ .AARCH64 = if (elf.identClass() == .@"64") .ABS64 else .P32_ABS32 }, | |
| 1161 | .LOONGARCH => .{ .LARCH = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | |
| 1021 | .AARCH64 => .{ .AARCH64 = .P32_ABS32 }, | |
| 1022 | .LOONGARCH => .{ .LARCH = .@"32" }, | |
| 1023 | .PPC64 => .{ .PPC64 = .ADDR32 }, | |
| 1024 | .RISCV => .{ .RISCV = .@"32" }, | |
| 1025 | .SPARCV9 => .{ .SPARC = .@"32" }, | |
| 1026 | .X86_64 => .{ .X86_64 = .@"32" }, | |
| 1027 | }; | |
| 1028 | } | |
| 1029 | pub fn abs64(elf: *const Elf) MachineRelocType { | |
| 1030 | return switch (elf.ehdrMachine()) { | |
| 1031 | .AARCH64 => .{ .AARCH64 = .ABS64 }, | |
| 1032 | .LOONGARCH => .{ .LARCH = .@"64" }, | |
| 1162 | 1033 | .PPC64 => .{ .PPC64 = .ADDR64 }, |
| 1163 | .RISCV => .{ .RISCV = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | |
| 1164 | .SPARCV9 => .{ .SPARC = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | |
| 1165 | .X86_64 => .{ .X86_64 = if (elf.identClass() == .@"64") .@"64" else .@"32" }, | |
| 1034 | .RISCV => .{ .RISCV = .@"64" }, | |
| 1035 | .SPARCV9 => .{ .SPARC = .@"64" }, | |
| 1036 | .X86_64 => .{ .X86_64 = .@"64" }, | |
| 1037 | }; | |
| 1038 | } | |
| 1039 | pub fn rel32(elf: *const Elf) MachineRelocType { | |
| 1040 | return switch (elf.ehdrMachine()) { | |
| 1041 | .AARCH64 => .{ .AARCH64 = .PREL32 }, | |
| 1042 | .LOONGARCH => .{ .LARCH = .@"32_PCREL" }, | |
| 1043 | .PPC64 => .{ .PPC64 = .REL32 }, | |
| 1044 | .RISCV => .{ .RISCV = .@"32_PCREL" }, | |
| 1045 | .SPARCV9 => .{ .SPARC = .DISP32 }, | |
| 1046 | .X86_64 => .{ .X86_64 = .PC32 }, | |
| 1047 | }; | |
| 1048 | } | |
| 1049 | pub fn rel64(elf: *const Elf) MachineRelocType { | |
| 1050 | return switch (elf.ehdrMachine()) { | |
| 1051 | .AARCH64 => .{ .AARCH64 = .PREL64 }, | |
| 1052 | .LOONGARCH => unreachable, | |
| 1053 | .PPC64 => .{ .PPC64 = .REL64 }, | |
| 1054 | .RISCV => unreachable, | |
| 1055 | .SPARCV9 => .{ .SPARC = .DISP64 }, | |
| 1056 | .X86_64 => .{ .X86_64 = .PC64 }, | |
| 1166 | 1057 | }; |
| 1167 | 1058 | } |
| 1168 | 1059 | pub fn size32(elf: *const Elf) ?MachineRelocType { |
| ... | ... | @@ -1265,15 +1156,6 @@ const SymbolReloc = struct { |
| 1265 | 1156 | return shndx; |
| 1266 | 1157 | } |
| 1267 | 1158 | |
| 1268 | const Index = enum(u32) { | |
| 1269 | none = std.math.maxInt(u32), | |
| 1270 | _, | |
| 1271 | ||
| 1272 | fn get(index: SymbolReloc.Index, elf: *Elf) *SymbolReloc { | |
| 1273 | return &elf.symbol_relocs.items[@backingInt(index)]; | |
| 1274 | } | |
| 1275 | }; | |
| 1276 | ||
| 1277 | 1159 | /// Instead of using the ELF relocation enums, we have our own internal representation for |
| 1278 | 1160 | /// relocation types. This representation is more compact (requiring only 16 bits), and allows |
| 1279 | 1161 | /// sharing a lot of relocation handling between multiple relocs and target architectures. |
| ... | ... | @@ -1679,9 +1561,417 @@ const SymbolReloc = struct { |
| 1679 | 1561 | } |
| 1680 | 1562 | }; |
| 1681 | 1563 | |
| 1564 | const Index = enum(u32) { | |
| 1565 | none = std.math.maxInt(u32), | |
| 1566 | _, | |
| 1567 | ||
| 1568 | fn get(index: SymbolReloc.Index, elf: *Elf) *SymbolReloc { | |
| 1569 | return &elf.symbol_relocs.items[@backingInt(index)]; | |
| 1570 | } | |
| 1571 | }; | |
| 1572 | ||
| 1682 | 1573 | fn apply(reloc: *SymbolReloc, elf: *Elf) void { |
| 1683 | 1574 | assert(elf.ehdrType() != .REL); |
| 1684 | if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) { | |
| 1575 | if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(elf)) { | |
| 1576 | // There's no point applying the relocation now, because it will be re-applied by | |
| 1577 | // `flushMoved` at some point anyway. | |
| 1578 | return; | |
| 1579 | } | |
| 1580 | switch (reloc.result) { | |
| 1581 | .ok => {}, | |
| 1582 | .overflowed => elf.overflowed_reloc_count -= 1, | |
| 1583 | .misaligned => elf.misaligned_reloc_count -= 1, | |
| 1584 | } | |
| 1585 | if (reloc.applyInner(elf)) { | |
| 1586 | @branchHint(.likely); | |
| 1587 | reloc.result = .ok; | |
| 1588 | } else |err| switch (err) { | |
| 1589 | error.RelocationOverflow => { | |
| 1590 | reloc.result = .overflowed; | |
| 1591 | elf.overflowed_reloc_count += 1; | |
| 1592 | }, | |
| 1593 | error.RelocationMisaligned => { | |
| 1594 | reloc.result = .misaligned; | |
| 1595 | elf.misaligned_reloc_count += 1; | |
| 1596 | }, | |
| 1597 | } | |
| 1598 | } | |
| 1599 | fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { | |
| 1600 | const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset; | |
| 1601 | const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; | |
| 1602 | ||
| 1603 | const addend: u64 = @bitCast(reloc.addend); | |
| 1604 | const target_val: u64 = type: switch (reloc.type.target) { | |
| 1605 | .abs => reloc.target.value(elf) +% addend, | |
| 1606 | .rel => reloc.target.value(elf) +% addend -% dest_vaddr, | |
| 1607 | .pltabs => { | |
| 1608 | const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs; | |
| 1609 | break :type plt_entry_addr +% addend; | |
| 1610 | }, | |
| 1611 | .pltrel => { | |
| 1612 | const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .rel; | |
| 1613 | break :type plt_entry_addr +% addend -% dest_vaddr; | |
| 1614 | }, | |
| 1615 | .dtpoff => reloc.target.value(elf) +% addend, | |
| 1616 | .tpoff => switch (elf.targetTlsVariant()) { | |
| 1617 | .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend, | |
| 1618 | .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend, | |
| 1619 | .II => { | |
| 1620 | const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment; | |
| 1621 | const tls_size: u64 = switch (elf.phdrSlice()) { | |
| 1622 | inline else => |phdr| tls_size: { | |
| 1623 | assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS); | |
| 1624 | break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz); | |
| 1625 | }, | |
| 1626 | }; | |
| 1627 | break :type reloc.target.value(elf) +% addend -% tls_size; | |
| 1628 | }, | |
| 1629 | }, | |
| 1630 | .size => switch (elf.symPtr(reloc.target.index(elf))) { | |
| 1631 | inline else => |sym| elf.targetLoad(&sym.size), | |
| 1632 | }, | |
| 1633 | .special => return reloc.type.action.special.applyInner( | |
| 1634 | elf, | |
| 1635 | reloc.target, | |
| 1636 | addend, | |
| 1637 | dest_vaddr, | |
| 1638 | dest_slice, | |
| 1639 | ), | |
| 1640 | }; | |
| 1641 | ||
| 1642 | // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast | |
| 1643 | // is required, meaning we can handle it now and return early. | |
| 1644 | if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) { | |
| 1645 | .static => unreachable, | |
| 1646 | .dynamic => return, // the relocation happens at runtime | |
| 1647 | .static_relative => { | |
| 1648 | // We have emitted an R_*_RELATIVE relocation to help lower an absolute-address | |
| 1649 | // relocation. The value computed above is valid, but instead of writing it to the | |
| 1650 | // destination slice, we actually want to write it to the runtime relocation entry. | |
| 1651 | switch (elf.identClass()) { | |
| 1652 | .NONE, _ => unreachable, | |
| 1653 | .@"32" => assert(reloc.type.action.simple.dest == .@"32"), | |
| 1654 | .@"64" => assert(reloc.type.action.simple.dest == .@"64"), | |
| 1655 | } | |
| 1656 | assert(reloc.type.action.simple.cast == .unsigned); | |
| 1657 | assert(reloc.type.action.simple.shift == .@"0"); | |
| 1658 | elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, target_val); | |
| 1659 | return; | |
| 1660 | }, | |
| 1661 | }; | |
| 1662 | ||
| 1663 | try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian()); | |
| 1664 | } | |
| 1665 | ||
| 1666 | fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void { | |
| 1667 | assert(index.get(elf) == reloc); | |
| 1668 | ||
| 1669 | reloc.deleteOutputRel(elf); | |
| 1670 | if (reloc.type.dependsOnTlsSize(elf)) { | |
| 1671 | assert(elf.tls_size_symbol_relocs.swapRemove(index)); | |
| 1672 | } | |
| 1673 | ||
| 1674 | switch (reloc.prev) { | |
| 1675 | .none => { | |
| 1676 | const first_target_reloc = &reloc.target.index(elf).ptr(elf).first_target_reloc; | |
| 1677 | assert(first_target_reloc.* == index); | |
| 1678 | first_target_reloc.* = reloc.next; | |
| 1679 | }, | |
| 1680 | else => |prev| prev.get(elf).next = reloc.next, | |
| 1681 | } | |
| 1682 | switch (reloc.next) { | |
| 1683 | .none => {}, | |
| 1684 | else => |next| next.get(elf).prev = reloc.prev, | |
| 1685 | } | |
| 1686 | switch (reloc.result) { | |
| 1687 | .ok => {}, | |
| 1688 | .overflowed => elf.overflowed_reloc_count -= 1, | |
| 1689 | .misaligned => elf.misaligned_reloc_count -= 1, | |
| 1690 | } | |
| 1691 | ||
| 1692 | reloc.* = undefined; | |
| 1693 | } | |
| 1694 | ||
| 1695 | /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating | |
| 1696 | /// `elf.textrel_count` if necessary. | |
| 1697 | fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void { | |
| 1698 | const rela_index = reloc.rela_index.unwrap() orelse return; | |
| 1699 | reloc.relaSection(elf).relaDeleteOne(elf, rela_index); | |
| 1700 | switch (elf.ehdrType()) { | |
| 1701 | .REL => {}, | |
| 1702 | .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node)) { | |
| 1703 | .no => unreachable, // there *was* a dynamic relocation! | |
| 1704 | .yes => {}, | |
| 1705 | .yes_textrel => elf.textrel_count -= 1, | |
| 1706 | }, | |
| 1707 | } | |
| 1708 | reloc.rela_index = .none; | |
| 1709 | } | |
| 1710 | }; | |
| 1711 | ||
| 1712 | /// A relocation targeting an arbitrary node (within a section) with a fixed addend. | |
| 1713 | /// This represents a symbol reloc against the section symbol containing the node | |
| 1714 | /// with a variable addend that changes when the target node moves. | |
| 1715 | const NodeReloc = struct { | |
| 1716 | node: MappedFile.Node.Index, | |
| 1717 | offset: u64, | |
| 1718 | target: MappedFile.Node.Index, | |
| 1719 | addend: i64, | |
| 1720 | type: NodeReloc.Type, | |
| 1721 | next: NodeReloc.Index, | |
| 1722 | prev: NodeReloc.Index, | |
| 1723 | rela_index: Section.RelaIndex.Optional, | |
| 1724 | result: enum(u8) { ok, overflowed, misaligned }, | |
| 1725 | ||
| 1726 | const Type = enum { abs32, abs64 }; | |
| 1727 | ||
| 1728 | const Index = enum(u32) { | |
| 1729 | none = std.math.maxInt(u32), | |
| 1730 | _, | |
| 1731 | ||
| 1732 | fn get(index: NodeReloc.Index, elf: *Elf) *NodeReloc { | |
| 1733 | return &elf.node_relocs.items[@backingInt(index)]; | |
| 1734 | } | |
| 1735 | }; | |
| 1736 | ||
| 1737 | fn apply(reloc: *NodeReloc, elf: *Elf) void { | |
| 1738 | assert(elf.ehdrType() != .REL); | |
| 1739 | if (reloc.node.hasMoved(&elf.mf) or reloc.target.hasMoved(&elf.mf)) { | |
| 1740 | // There's no point applying the relocation now, because it will be re-applied by | |
| 1741 | // `flushMoved` at some point anyway. | |
| 1742 | return; | |
| 1743 | } | |
| 1744 | switch (reloc.result) { | |
| 1745 | .ok => {}, | |
| 1746 | .overflowed => elf.overflowed_reloc_count -= 1, | |
| 1747 | .misaligned => elf.misaligned_reloc_count -= 1, | |
| 1748 | } | |
| 1749 | if (reloc.applyInner(elf)) { | |
| 1750 | @branchHint(.likely); | |
| 1751 | reloc.result = .ok; | |
| 1752 | } else |err| switch (err) { | |
| 1753 | error.RelocationOverflow => { | |
| 1754 | reloc.result = .overflowed; | |
| 1755 | elf.overflowed_reloc_count += 1; | |
| 1756 | }, | |
| 1757 | error.RelocationMisaligned => { | |
| 1758 | reloc.result = .misaligned; | |
| 1759 | elf.misaligned_reloc_count += 1; | |
| 1760 | }, | |
| 1761 | } | |
| 1762 | } | |
| 1763 | fn applyInner(reloc: *const NodeReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { | |
| 1764 | const simple: SymbolReloc.Type.Simple = .{ .dest = switch (reloc.type) { | |
| 1765 | .abs32 => .@"32", | |
| 1766 | .abs64 => .@"64", | |
| 1767 | }, .cast = .unsigned, .shift = .@"0" }; | |
| 1768 | const addend: u64 = @bitCast(reloc.addend); | |
| 1769 | const target_val = elf.getNodeVAddr(reloc.target) +% addend; | |
| 1770 | const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; | |
| 1771 | try simple.write(target_val, dest_slice, elf.targetEndian()); | |
| 1772 | } | |
| 1773 | ||
| 1774 | fn delete(reloc: *NodeReloc, elf: *Elf) void { | |
| 1775 | reloc.deleteOutputRel(elf); | |
| 1776 | ||
| 1777 | switch (reloc.prev) { | |
| 1778 | .none => { | |
| 1779 | const first_target_reloc = switch (elf.getNode(reloc.target)) { | |
| 1780 | else => unreachable, | |
| 1781 | .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].unit_frame_cie_first_target_reloc, | |
| 1782 | }; | |
| 1783 | first_target_reloc.* = reloc.next; | |
| 1784 | }, | |
| 1785 | else => |prev| prev.get(elf).next = reloc.next, | |
| 1786 | } | |
| 1787 | switch (reloc.next) { | |
| 1788 | .none => {}, | |
| 1789 | else => |next| next.get(elf).prev = reloc.prev, | |
| 1790 | } | |
| 1791 | switch (reloc.result) { | |
| 1792 | .ok => {}, | |
| 1793 | .overflowed => elf.overflowed_reloc_count -= 1, | |
| 1794 | .misaligned => elf.misaligned_reloc_count -= 1, | |
| 1795 | } | |
| 1796 | ||
| 1797 | reloc.* = undefined; | |
| 1798 | } | |
| 1799 | ||
| 1800 | /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation. | |
| 1801 | fn deleteOutputRel(reloc: *NodeReloc, elf: *Elf) void { | |
| 1802 | const rela_index = reloc.rela_index.unwrap() orelse return; | |
| 1803 | assert(elf.ehdrType() == .REL); | |
| 1804 | elf.getNodeShndx(reloc.node).get(elf).rela.shndx.relaDeleteOne(elf, rela_index); | |
| 1805 | reloc.rela_index = .none; | |
| 1806 | } | |
| 1807 | }; | |
| 1808 | ||
| 1809 | /// Identifies a single entry in the GOT. | |
| 1810 | const GotKey = union(enum) { | |
| 1811 | /// The entry is a reserved word, initialized to zero. `initHeaders` will add as many of these | |
| 1812 | /// as the target machine ABI requires. | |
| 1813 | /// | |
| 1814 | /// This `u32` value exists to allow reserving multiple words with distinct keys. | |
| 1815 | reserved: u32, | |
| 1816 | ||
| 1817 | /// Value is the address of the given symbol. | |
| 1818 | symbol: Symbol.Id, | |
| 1819 | ||
| 1820 | /// Value is the signed offset of the given symbol from the TLS pointer. | |
| 1821 | tpoff: Symbol.Id, | |
| 1822 | ||
| 1823 | /// Value is the TLS module ID of the DSO we are creating. | |
| 1824 | /// | |
| 1825 | /// Used for the first of the two GOT entries generated by a TLSLD relocation. | |
| 1826 | tlsld0, | |
| 1827 | /// Value is always 0. | |
| 1828 | /// | |
| 1829 | /// Used for the second of the two GOT entries generated by a TLSLD relocation. | |
| 1830 | tlsld1, | |
| 1831 | ||
| 1832 | /// Value is the TLS module ID for the given STT_TLS symbol. | |
| 1833 | /// | |
| 1834 | /// Used for the first of the two GOT entries generated by a TLSGD relocation. | |
| 1835 | tlsgd0: Symbol.Id, | |
| 1836 | /// Value is the offset of the given STT_TLS symbol from the base of the per-module TLS area. | |
| 1837 | /// | |
| 1838 | /// Used for the second of the two GOT entries generated by a TLSGD relocation. | |
| 1839 | tlsgd1: Symbol.Id, | |
| 1840 | }; | |
| 1841 | ||
| 1842 | /// A relocation targeting a particular GOT entry. | |
| 1843 | const GotReloc = struct { | |
| 1844 | /// The node containing this relocation. Possible values are: | |
| 1845 | /// * An input section | |
| 1846 | /// * A section | |
| 1847 | /// * A NAV, UAV, or lazy code/data | |
| 1848 | /// * `.none`, if this relocation was deleted (in which case it should be ignored) | |
| 1849 | node: MappedFile.Node.Index.Optional, | |
| 1850 | /// The offset of the relocation inside of `node`. | |
| 1851 | offset: u64, | |
| 1852 | target: GotKey, | |
| 1853 | addend: i64, | |
| 1854 | type: GotReloc.Type, | |
| 1855 | result: enum(u8) { ok, overflowed, misaligned }, | |
| 1856 | ||
| 1857 | /// `GotReloc.Type` has the same structure as `SymbolReloc.Type`, just with different `Target` | |
| 1858 | /// and `Special` enums---consult doc comments on `SymbolReloc.Type` for an overview. | |
| 1859 | const Type = packed struct(u16) { | |
| 1860 | fn simple(target: Target, action: Simple) GotReloc.Type { | |
| 1861 | assert(target != .special); | |
| 1862 | return .{ .target = target, .action = .{ .simple = action } }; | |
| 1863 | } | |
| 1864 | ||
| 1865 | fn special(s: Special) GotReloc.Type { | |
| 1866 | return .{ .target = .special, .action = .{ .special = s } }; | |
| 1867 | } | |
| 1868 | ||
| 1869 | target: Target, | |
| 1870 | action: packed union { | |
| 1871 | simple: Simple, | |
| 1872 | special: Special, | |
| 1873 | }, | |
| 1874 | ||
| 1875 | /// Like `SymbolReloc.Target`, but for GOT relocations. There are fewer tags because there | |
| 1876 | /// are fewer different kinds of GOT relocation. | |
| 1877 | const Target = enum(u3) { | |
| 1878 | /// This is a "special" relocation whose specific type is in the `action.special` field. | |
| 1879 | special, | |
| 1880 | ||
| 1881 | /// Absolute address of the GOT entry. | |
| 1882 | abs, | |
| 1883 | /// Offset from the relocation itself to the GOT entry ("PC-relative"). | |
| 1884 | rel, | |
| 1885 | /// Offset from the base of the GOT to the GOT entry. | |
| 1886 | offset, | |
| 1887 | }; | |
| 1888 | ||
| 1889 | const Simple = SymbolReloc.Type.Simple; | |
| 1890 | ||
| 1891 | /// Like `SymbolReloc.Special`, but for GOT relocations. | |
| 1892 | const Special = enum(u13) { | |
| 1893 | larch_pcala_hi20, | |
| 1894 | larch_pcala64_lo20, | |
| 1895 | larch_pcala64_hi12, | |
| 1896 | ||
| 1897 | sparc_op_lox10, | |
| 1898 | sparc_op_hix22, | |
| 1899 | ||
| 1900 | fn applyInner( | |
| 1901 | s: Special, | |
| 1902 | elf: *Elf, | |
| 1903 | got_vaddr: u64, | |
| 1904 | got_offset: u64, | |
| 1905 | addend: u64, | |
| 1906 | dest_vaddr: u64, | |
| 1907 | dest_slice: []u8, | |
| 1908 | ) error{ RelocationMisaligned, RelocationOverflow }!void { | |
| 1909 | switch (s) { | |
| 1910 | .larch_pcala_hi20 => { | |
| 1911 | const val = got_vaddr +% got_offset +% addend; | |
| 1912 | const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]); | |
| 1913 | elf.targetStore(inst, .{ | |
| 1914 | .b0_4 = elf.targetLoad(inst).b0_4, | |
| 1915 | .j20 = link.loongarch.pcalaHi20(val, dest_vaddr), | |
| 1916 | .b25_31 = elf.targetLoad(inst).b25_31, | |
| 1917 | }); | |
| 1918 | }, | |
| 1919 | .larch_pcala64_lo20 => { | |
| 1920 | const val = got_vaddr +% got_offset +% addend; | |
| 1921 | const inst: *align(1) link.loongarch.J20 = @ptrCast(dest_slice[0..4]); | |
| 1922 | elf.targetStore(inst, .{ | |
| 1923 | .b0_4 = elf.targetLoad(inst).b0_4, | |
| 1924 | .j20 = link.loongarch.pcala64Lo20(val, dest_vaddr), | |
| 1925 | .b25_31 = elf.targetLoad(inst).b25_31, | |
| 1926 | }); | |
| 1927 | }, | |
| 1928 | .larch_pcala64_hi12 => { | |
| 1929 | const val = got_vaddr +% got_offset +% addend; | |
| 1930 | const inst: *align(1) link.loongarch.K12 = @ptrCast(dest_slice[0..4]); | |
| 1931 | elf.targetStore(inst, .{ | |
| 1932 | .b0_9 = elf.targetLoad(inst).b0_9, | |
| 1933 | .k12 = link.loongarch.pcala64Hi12(val, dest_vaddr), | |
| 1934 | .b22_31 = elf.targetLoad(inst).b22_31, | |
| 1935 | }); | |
| 1936 | }, | |
| 1937 | .sparc_op_lox10 => { | |
| 1938 | const dest_ptr: *align(1) packed struct(u32) { | |
| 1939 | imm13: u13, | |
| 1940 | b13_31: u19, | |
| 1941 | } = @ptrCast(dest_slice); | |
| 1942 | elf.targetStore(dest_ptr, .{ | |
| 1943 | .imm13 = @as(u10, @truncate(got_offset)), | |
| 1944 | .b13_31 = elf.targetLoad(dest_ptr).b13_31, | |
| 1945 | }); | |
| 1946 | }, | |
| 1947 | .sparc_op_hix22 => { | |
| 1948 | const dest_ptr: *align(1) packed struct(u32) { | |
| 1949 | imm22: u22, | |
| 1950 | b22_31: u10, | |
| 1951 | } = @ptrCast(dest_slice); | |
| 1952 | elf.targetStore(dest_ptr, .{ | |
| 1953 | .imm22 = @truncate(got_offset >> 10), | |
| 1954 | .b22_31 = elf.targetLoad(dest_ptr).b22_31, | |
| 1955 | }); | |
| 1956 | }, | |
| 1957 | } | |
| 1958 | } | |
| 1959 | }; | |
| 1960 | }; | |
| 1961 | ||
| 1962 | const Index = enum(u32) { | |
| 1963 | none = std.math.maxInt(u32), | |
| 1964 | _, | |
| 1965 | ||
| 1966 | fn get(index: GotReloc.Index, elf: *Elf) *GotReloc { | |
| 1967 | return &elf.got_relocs.items[@backingInt(index)]; | |
| 1968 | } | |
| 1969 | }; | |
| 1970 | ||
| 1971 | fn apply(reloc: *GotReloc, elf: *Elf) void { | |
| 1972 | assert(elf.ehdrType() != .REL); | |
| 1973 | const node = reloc.node.unwrap() orelse return; // deleted | |
| 1974 | if (node.hasMoved(&elf.mf) or elf.shndx.got.get(elf).ni.hasMoved(&elf.mf)) { | |
| 1685 | 1975 | // There's no point applying the relocation now, because it will be re-applied by |
| 1686 | 1976 | // `flushMoved` at some point anyway. |
| 1687 | 1977 | return; |
| ... | ... | @@ -1705,118 +1995,99 @@ const SymbolReloc = struct { |
| 1705 | 1995 | }, |
| 1706 | 1996 | } |
| 1707 | 1997 | } |
| 1708 | fn applyInner(reloc: *const SymbolReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { | |
| 1709 | const dest_vaddr = elf.getNodeVAddr(reloc.node) + reloc.offset; | |
| 1710 | const dest_slice = reloc.node.slice(&elf.mf)[@intCast(reloc.offset)..]; | |
| 1998 | fn applyInner(reloc: *const GotReloc, elf: *Elf) error{ RelocationOverflow, RelocationMisaligned }!void { | |
| 1999 | const node = reloc.node.unwrap().?; | |
| 2000 | const dest_vaddr = elf.getNodeVAddr(node) + reloc.offset; | |
| 2001 | const dest_slice = node.slice(&elf.mf)[@intCast(reloc.offset)..]; | |
| 1711 | 2002 | |
| 2003 | const got_vaddr = elf.shndx.got.vaddr(elf); | |
| 2004 | const got_index: u64 = elf.got.getIndex(reloc.target).?; | |
| 2005 | const got_offset: u64 = switch (elf.identClass()) { | |
| 2006 | .NONE, _ => unreachable, | |
| 2007 | inline else => |class| @sizeOf(class.ElfN().Addr) * got_index, | |
| 2008 | }; | |
| 1712 | 2009 | const addend: u64 = @bitCast(reloc.addend); |
| 1713 | const target_val: u64 = type: switch (reloc.type.target) { | |
| 1714 | .abs => reloc.target.value(elf) +% addend, | |
| 1715 | .rel => reloc.target.value(elf) +% addend -% dest_vaddr, | |
| 1716 | .pltabs => { | |
| 1717 | const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .abs; | |
| 1718 | break :type plt_entry_addr +% addend; | |
| 1719 | }, | |
| 1720 | .pltrel => { | |
| 1721 | const plt_entry_addr = elf.pltEntryTargetAddr(reloc.target) orelse continue :type .rel; | |
| 1722 | break :type plt_entry_addr +% addend -% dest_vaddr; | |
| 1723 | }, | |
| 1724 | .dtpoff => reloc.target.value(elf) +% addend, | |
| 1725 | .tpoff => switch (elf.targetTlsVariant()) { | |
| 1726 | .I_original => |tls| tls.tcb_size +% reloc.target.value(elf) +% addend, | |
| 1727 | .I_modified => |tls| 0 -% tls.tp_off +% reloc.target.value(elf) +% addend, | |
| 1728 | .II => { | |
| 1729 | const tls_phndx = elf.getNode(elf.ni.tls.unwrap().?).segment; | |
| 1730 | const tls_size: u64 = switch (elf.phdrSlice()) { | |
| 1731 | inline else => |phdr| tls_size: { | |
| 1732 | assert(elf.targetLoad(&phdr[tls_phndx].type) == .TLS); | |
| 1733 | break :tls_size elf.targetLoad(&phdr[tls_phndx].memsz); | |
| 1734 | }, | |
| 1735 | }; | |
| 1736 | break :type reloc.target.value(elf) +% addend -% tls_size; | |
| 1737 | }, | |
| 1738 | }, | |
| 1739 | .size => switch (elf.symPtr(reloc.target.index(elf))) { | |
| 1740 | inline else => |sym| elf.targetLoad(&sym.size), | |
| 1741 | }, | |
| 2010 | ||
| 2011 | const target_val: u64 = switch (reloc.type.target) { | |
| 2012 | .abs => got_vaddr +% got_offset +% addend, | |
| 2013 | .rel => got_vaddr +% got_offset +% addend -% dest_vaddr, | |
| 2014 | .offset => got_offset +% addend, | |
| 1742 | 2015 | .special => return reloc.type.action.special.applyInner( |
| 1743 | 2016 | elf, |
| 1744 | reloc.target, | |
| 2017 | got_vaddr, | |
| 2018 | got_offset, | |
| 1745 | 2019 | addend, |
| 1746 | 2020 | dest_vaddr, |
| 1747 | 2021 | dest_slice, |
| 1748 | 2022 | ), |
| 1749 | 2023 | }; |
| 1750 | ||
| 1751 | // Check for the `R_*_RELATIVE` case now, because it is possible only when no shift or cast | |
| 1752 | // is required, meaning we can handle it now and return early. | |
| 1753 | if (reloc.rela_index.unwrap()) |rela_index| switch (elf.classifySymbolValue(reloc.target)) { | |
| 1754 | .static => unreachable, | |
| 1755 | .dynamic => return, // the relocation happens at runtime | |
| 1756 | .static_relative => { | |
| 1757 | // We have emitted an R_*_RELATIVE relocation to help lower an absolute-address | |
| 1758 | // relocation. The value computed above is valid, but instead of writing it to the | |
| 1759 | // destination slice, we actually want to write it to the runtime relocation entry. | |
| 1760 | switch (elf.identClass()) { | |
| 1761 | .NONE, _ => unreachable, | |
| 1762 | .@"32" => assert(reloc.type.action.simple.dest == .@"32"), | |
| 1763 | .@"64" => assert(reloc.type.action.simple.dest == .@"64"), | |
| 1764 | } | |
| 1765 | assert(reloc.type.action.simple.cast == .unsigned); | |
| 1766 | assert(reloc.type.action.simple.shift == .@"0"); | |
| 1767 | elf.shndx.rela_dyn.relaSetRelativeOffset(elf, rela_index, target_val); | |
| 1768 | return; | |
| 1769 | }, | |
| 1770 | }; | |
| 1771 | ||
| 1772 | 2024 | try reloc.type.action.simple.write(target_val, dest_slice, elf.targetEndian()); |
| 1773 | 2025 | } |
| 1774 | 2026 | |
| 1775 | fn delete(reloc: *SymbolReloc, elf: *Elf, index: SymbolReloc.Index) void { | |
| 1776 | assert(index.get(elf) == reloc); | |
| 1777 | ||
| 1778 | reloc.deleteOutputRel(elf); | |
| 1779 | if (reloc.type.dependsOnTlsSize(elf)) { | |
| 1780 | assert(elf.tls_size_symbol_relocs.swapRemove(index)); | |
| 1781 | } | |
| 1782 | ||
| 1783 | switch (reloc.prev) { | |
| 1784 | .none => { | |
| 1785 | const target_ptr = reloc.target.index(elf).ptr(elf); | |
| 1786 | assert(target_ptr.first_target_reloc == index); | |
| 1787 | target_ptr.first_target_reloc = reloc.next; | |
| 1788 | }, | |
| 1789 | else => |prev| prev.get(elf).next = reloc.next, | |
| 1790 | } | |
| 1791 | switch (reloc.next) { | |
| 1792 | .none => {}, | |
| 1793 | else => |next| next.get(elf).prev = reloc.prev, | |
| 1794 | } | |
| 2027 | fn delete(reloc: *GotReloc, elf: *Elf) void { | |
| 1795 | 2028 | switch (reloc.result) { |
| 1796 | 2029 | .ok => {}, |
| 1797 | 2030 | .overflowed => elf.overflowed_reloc_count -= 1, |
| 1798 | 2031 | .misaligned => elf.misaligned_reloc_count -= 1, |
| 1799 | 2032 | } |
| 2033 | reloc.* = .{ | |
| 2034 | .node = .none, | |
| 2035 | .offset = undefined, | |
| 2036 | .target = undefined, | |
| 2037 | .addend = undefined, | |
| 2038 | .type = undefined, | |
| 2039 | .result = undefined, | |
| 2040 | }; | |
| 2041 | } | |
| 2042 | }; | |
| 1800 | 2043 | |
| 1801 | reloc.* = undefined; | |
| 2044 | fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void { | |
| 2045 | const gpa = elf.base.comp.gpa; | |
| 2046 | ||
| 2047 | try elf.symtab.ensureUnusedCapacity(gpa, len); | |
| 2048 | ||
| 2049 | // If adding locals, we may need to move one global out of the way for each local. If adding | |
| 2050 | // globals, they could all get demoted to STB_LOCAL, meaning we have to move N other globals | |
| 2051 | // around to keep `.dynsym` compact. Either way, the maximum is N. | |
| 2052 | try elf.changed_symtab_index.ensureUnusedCapacity(gpa, len); | |
| 2053 | ||
| 2054 | { | |
| 2055 | // Ensure the symtab section's node is big enough | |
| 2056 | const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) { | |
| 2057 | inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym), | |
| 2058 | }; | |
| 2059 | try Section.Index.symtab.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_node_size); | |
| 1802 | 2060 | } |
| 1803 | 2061 | |
| 1804 | /// If `reloc.rela_index` is populated, reset it to `.none` and delete the relocation, updating | |
| 1805 | /// `elf.textrel_count` if necessary. | |
| 1806 | fn deleteOutputRel(reloc: *SymbolReloc, elf: *Elf) void { | |
| 1807 | const rela_index = reloc.rela_index.unwrap() orelse return; | |
| 1808 | reloc.relaSection(elf).relaDeleteOne(elf, rela_index); | |
| 1809 | switch (elf.ehdrType()) { | |
| 1810 | .REL => {}, | |
| 1811 | .EXEC, .DYN => switch (elf.nodeWantsDsoRelocation(reloc.node)) { | |
| 1812 | .no => unreachable, // there *was* a dynamic relocation! | |
| 1813 | .yes => {}, | |
| 1814 | .yes_textrel => elf.textrel_count -= 1, | |
| 1815 | }, | |
| 1816 | } | |
| 1817 | reloc.rela_index = .none; | |
| 2062 | switch (kind) { | |
| 2063 | .all_local => {}, | |
| 2064 | .maybe_global => { | |
| 2065 | try elf.globals.strong_def.ensureUnusedCapacity(gpa, len); | |
| 2066 | try elf.globals.weak_def.ensureUnusedCapacity(gpa, len); | |
| 2067 | try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len); | |
| 2068 | try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len); | |
| 2069 | ||
| 2070 | try elf.node_global_symbols.ensureUnusedCapacity(gpa, len); | |
| 2071 | ||
| 2072 | if (elf.shndx.dynsym != .UNDEF) { | |
| 2073 | const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) { | |
| 2074 | inline else => |shdr, class| .{ | |
| 2075 | elf.targetLoad(&shdr.size), | |
| 2076 | @sizeOf(class.ElfN().Sym), | |
| 2077 | }, | |
| 2078 | }; | |
| 2079 | const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size)); | |
| 2080 | ||
| 2081 | const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size; | |
| 2082 | try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, dynsym_need_size); | |
| 2083 | ||
| 2084 | try elf.ensureDynsymHashCapacity(dynsym_cur_len + len); | |
| 2085 | ||
| 2086 | try elf.ensureUnusedPltCapacity(len); | |
| 2087 | } | |
| 2088 | }, | |
| 1818 | 2089 | } |
| 1819 | }; | |
| 2090 | } | |
| 1820 | 2091 | |
| 1821 | 2092 | fn ensureDynsymHashCapacity(elf: *Elf, max_dynsym_count: u32) Error!void { |
| 1822 | 2093 | const gpa = elf.base.comp.gpa; |
| ... | ... | @@ -1984,53 +2255,6 @@ fn clearDynsymHashEntry(elf: *Elf, dynsym_index: u32) void { |
| 1984 | 2255 | } |
| 1985 | 2256 | } |
| 1986 | 2257 | |
| 1987 | fn ensureUnusedSymbolCapacity(elf: *Elf, len: u32, kind: enum { all_local, maybe_global }) Error!void { | |
| 1988 | const gpa = elf.base.comp.gpa; | |
| 1989 | ||
| 1990 | try elf.symtab.ensureUnusedCapacity(gpa, len); | |
| 1991 | ||
| 1992 | // If adding locals, we may need to move one global out of the way for each local. If adding | |
| 1993 | // globals, they could all get demoted to STB_LOCAL, meaning we have to move N other globals | |
| 1994 | // around to keep `.dynsym` compact. Either way, the maximum is N. | |
| 1995 | try elf.changed_symtab_index.ensureUnusedCapacity(gpa, len); | |
| 1996 | ||
| 1997 | { | |
| 1998 | // Ensure the symtab section's node is big enough | |
| 1999 | const need_node_size: u64 = switch (elf.shdrPtr(.symtab)) { | |
| 2000 | inline else => |shdr, class| elf.targetLoad(&shdr.size) + len * @sizeOf(class.ElfN().Sym), | |
| 2001 | }; | |
| 2002 | try Section.Index.symtab.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, need_node_size); | |
| 2003 | } | |
| 2004 | ||
| 2005 | switch (kind) { | |
| 2006 | .all_local => {}, | |
| 2007 | .maybe_global => { | |
| 2008 | try elf.globals.strong_def.ensureUnusedCapacity(gpa, len); | |
| 2009 | try elf.globals.weak_def.ensureUnusedCapacity(gpa, len); | |
| 2010 | try elf.globals.strong_undef.ensureUnusedCapacity(gpa, len); | |
| 2011 | try elf.globals.weak_undef.ensureUnusedCapacity(gpa, len); | |
| 2012 | ||
| 2013 | try elf.node_global_symbols.ensureUnusedCapacity(gpa, len); | |
| 2014 | ||
| 2015 | if (elf.shndx.dynsym != .UNDEF) { | |
| 2016 | const dynsym_cur_size: u64, const dynsym_ent_size: u32 = switch (elf.shdrPtr(elf.shndx.dynsym)) { | |
| 2017 | inline else => |shdr, class| .{ | |
| 2018 | elf.targetLoad(&shdr.size), | |
| 2019 | @sizeOf(class.ElfN().Sym), | |
| 2020 | }, | |
| 2021 | }; | |
| 2022 | const dynsym_cur_len: u32 = @intCast(@divExact(dynsym_cur_size, dynsym_ent_size)); | |
| 2023 | ||
| 2024 | const dynsym_need_size: u64 = (dynsym_cur_len + len) * dynsym_ent_size; | |
| 2025 | try elf.shndx.dynsym.get(elf).ni.ensureMinimumSize(&elf.mf, gpa, dynsym_need_size); | |
| 2026 | ||
| 2027 | try elf.ensureDynsymHashCapacity(dynsym_cur_len + len); | |
| 2028 | ||
| 2029 | try elf.ensureUnusedPltCapacity(len); | |
| 2030 | } | |
| 2031 | }, | |
| 2032 | } | |
| 2033 | } | |
| 2034 | 2258 | fn ensureUnusedPltCapacity(elf: *Elf, len: u32) Error!void { |
| 2035 | 2259 | const gpa = elf.base.comp.gpa; |
| 2036 | 2260 | |
| ... | ... | @@ -2138,7 +2362,7 @@ fn addLocalSymbolAssumeCapacity(elf: *Elf, opts: AddLocalSymbolOptions) Symbol.L |
| 2138 | 2362 | .other = .{ .visibility = .DEFAULT }, |
| 2139 | 2363 | .shndx = opts.shndx.toSection().?, |
| 2140 | 2364 | }; |
| 2141 | if (elf.targetEndian() != native_endian) { | |
| 2365 | if (elf.targetEndian() != std.lang.Endian.native) { | |
| 2142 | 2366 | std.mem.byteSwapAllFields(class.ElfN().Sym, target_sym); |
| 2143 | 2367 | } |
| 2144 | 2368 | |
| ... | ... | @@ -2323,7 +2547,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{ |
| 2323 | 2547 | .other = .{ .visibility = opts.visibility }, |
| 2324 | 2548 | .shndx = opts.shndx.toSection().?, |
| 2325 | 2549 | }; |
| 2326 | if (elf.targetEndian() != native_endian) { | |
| 2550 | if (elf.targetEndian() != std.lang.Endian.native) { | |
| 2327 | 2551 | std.mem.byteSwapAllFields(Sym, sym); |
| 2328 | 2552 | } |
| 2329 | 2553 | }, |
| ... | ... | @@ -2359,7 +2583,7 @@ fn addGlobalSymbolAssumeCapacity(elf: *Elf, opts: AddGlobalSymbolOptions) error{ |
| 2359 | 2583 | .other = .{ .visibility = opts.visibility }, |
| 2360 | 2584 | .shndx = opts.shndx.toSection().?, |
| 2361 | 2585 | }; |
| 2362 | if (elf.targetEndian() != native_endian) { | |
| 2586 | if (elf.targetEndian() != std.lang.Endian.native) { | |
| 2363 | 2587 | std.mem.byteSwapAllFields(Sym, sym); |
| 2364 | 2588 | } |
| 2365 | 2589 | elf.appendDynsymHashEntry(dynsym_index); |
| ... | ... | @@ -2991,10 +3215,18 @@ pub fn symbolForAtom(elf: *Elf, atom: link.File.AtomId) link.File.SymbolId { |
| 2991 | 3215 | .shdr, |
| 2992 | 3216 | .segment, |
| 2993 | 3217 | .section, |
| 3218 | .section_manual_size, | |
| 2994 | 3219 | .input_section, |
| 2995 | 3220 | .copied_global, |
| 3221 | .value_debug_info, | |
| 3222 | .global_debug_info, | |
| 3223 | .frame_padding, | |
| 3224 | .unit_frame, | |
| 3225 | .unit_frame_cie, | |
| 3226 | .func_frame_fde, | |
| 3227 | .func_debug_info, | |
| 3228 | .func_debug_line, | |
| 2996 | 3229 | => unreachable, |
| 2997 | ||
| 2998 | 3230 | inline .nav, |
| 2999 | 3231 | .uav, |
| 3000 | 3232 | .lazy_code, |
| ... | ... | @@ -3025,7 +3257,7 @@ fn lazySymbolInner(elf: *Elf, lazy: link.File.LazySymbol) Error!link.File.Symbol |
| 3025 | 3257 | .const_data => .{ .rodata, .OBJECT }, |
| 3026 | 3258 | }; |
| 3027 | 3259 | const node = try shndx.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{}); |
| 3028 | var name_buf: [64]u8 = undefined; | |
| 3260 | var name_buf: [std.fmt.count("__lazy_const_data_{d}", .{std.math.maxInt(u32)})]u8 = undefined; | |
| 3029 | 3261 | const name = std.mem.print( |
| 3030 | 3262 | &name_buf, |
| 3031 | 3263 | "__lazy_{t}_{d}", |
| ... | ... | @@ -3114,6 +3346,24 @@ pub fn addReloc( |
| 3114 | 3346 | else => |e| return e, |
| 3115 | 3347 | }; |
| 3116 | 3348 | } |
| 3349 | pub fn addNodeReloc( | |
| 3350 | elf: *Elf, | |
| 3351 | node: MappedFile.Node.Index, | |
| 3352 | offset: u64, | |
| 3353 | target: MappedFile.Node.Index, | |
| 3354 | addend: i64, | |
| 3355 | @"type": NodeReloc.Type, | |
| 3356 | ) link.Error!void { | |
| 3357 | const diags = &elf.base.comp.link_diags; | |
| 3358 | elf.ensureUnusedRelocCapacity(node, 1) catch |err| switch (err) { | |
| 3359 | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), | |
| 3360 | else => |e| return e, | |
| 3361 | }; | |
| 3362 | elf.addNodeRelocAssumeCapacity(node, offset, target, addend, @"type") catch |err| switch (err) { | |
| 3363 | error.MappedFileIo => return diags.fail("failed to write output file: {t}", .{elf.mf.io_err.?}), | |
| 3364 | else => |e| return e, | |
| 3365 | }; | |
| 3366 | } | |
| 3117 | 3367 | pub fn navSymbol(elf: *Elf, nav_index: InternPool.Nav.Index) link.Error!link.File.SymbolId { |
| 3118 | 3368 | const diags = &elf.base.comp.link_diags; |
| 3119 | 3369 | const zcu = elf.base.comp.zcu.?; |
| ... | ... | @@ -3393,6 +3643,7 @@ fn create( |
| 3393 | 3643 | .data = undefined, |
| 3394 | 3644 | .data_rel_ro = undefined, |
| 3395 | 3645 | .tls = .none, |
| 3646 | .gnu_eh_frame = .none, | |
| 3396 | 3647 | }, |
| 3397 | 3648 | .archive = null, |
| 3398 | 3649 | .nodes = .empty, |
| ... | ... | @@ -3410,6 +3661,11 @@ fn create( |
| 3410 | 3661 | .tdata = .UNDEF, |
| 3411 | 3662 | .rela_dyn = .UNDEF, |
| 3412 | 3663 | .rela_plt = .UNDEF, |
| 3664 | .eh_frame_hdr = .UNDEF, | |
| 3665 | .eh_frame = .UNDEF, | |
| 3666 | .debug_frame = .UNDEF, | |
| 3667 | .debug_info = .UNDEF, | |
| 3668 | .debug_line = .UNDEF, | |
| 3413 | 3669 | .init_array = .UNDEF, |
| 3414 | 3670 | .fini_array = .UNDEF, |
| 3415 | 3671 | .preinit_array = .UNDEF, |
| ... | ... | @@ -3437,6 +3693,7 @@ fn create( |
| 3437 | 3693 | .got = .empty, |
| 3438 | 3694 | .plt = .empty, |
| 3439 | 3695 | .plt_first_symbol_reloc = .none, |
| 3696 | .eh_frame_hdr_first_symbol_reloc = .none, | |
| 3440 | 3697 | .needed = .empty, |
| 3441 | 3698 | .inputs = .empty, |
| 3442 | 3699 | .input_pending_index = 0, |
| ... | ... | @@ -3451,13 +3708,26 @@ fn create( |
| 3451 | 3708 | }), |
| 3452 | 3709 | .pending_uavs = .empty, |
| 3453 | 3710 | .symbol_relocs = .empty, |
| 3454 | .got_relocs = .empty, | |
| 3455 | 3711 | .tls_size_symbol_relocs = .empty, |
| 3712 | .node_relocs = .empty, | |
| 3713 | .got_relocs = .empty, | |
| 3456 | 3714 | .section_by_name = .empty, |
| 3457 | 3715 | .changed_symtab_index = .empty, |
| 3458 | 3716 | .textrel_count = 0, |
| 3717 | ||
| 3718 | .dwarf = .init(&elf.base, switch (comp.config.debug_format) { | |
| 3719 | .strip => .@"32", | |
| 3720 | .dwarf => |v| v, | |
| 3721 | .code_view => unreachable, | |
| 3722 | }), | |
| 3723 | .dwarf_units = .empty, | |
| 3724 | .dwarf_values = .empty, | |
| 3725 | .dwarf_globals = .empty, | |
| 3726 | .dwarf_funcs = .empty, | |
| 3727 | ||
| 3459 | 3728 | .overflowed_reloc_count = 0, |
| 3460 | 3729 | .misaligned_reloc_count = 0, |
| 3730 | ||
| 3461 | 3731 | .const_prog_node = .none, |
| 3462 | 3732 | .synth_prog_node = .none, |
| 3463 | 3733 | .input_prog_node = .none, |
| ... | ... | @@ -3498,10 +3768,18 @@ pub fn deinit(elf: *Elf) void { |
| 3498 | 3768 | for (&elf.lazy.values) |*lazy| lazy.map.deinit(gpa); |
| 3499 | 3769 | elf.pending_uavs.deinit(gpa); |
| 3500 | 3770 | elf.symbol_relocs.deinit(gpa); |
| 3501 | elf.got_relocs.deinit(gpa); | |
| 3502 | 3771 | elf.tls_size_symbol_relocs.deinit(gpa); |
| 3772 | elf.node_relocs.deinit(gpa); | |
| 3773 | elf.got_relocs.deinit(gpa); | |
| 3503 | 3774 | elf.section_by_name.deinit(gpa); |
| 3504 | 3775 | elf.changed_symtab_index.deinit(gpa); |
| 3776 | ||
| 3777 | elf.dwarf.deinit(gpa); | |
| 3778 | elf.dwarf_units.deinit(gpa); | |
| 3779 | elf.dwarf_values.deinit(gpa); | |
| 3780 | elf.dwarf_globals.deinit(gpa); | |
| 3781 | elf.dwarf_funcs.deinit(gpa); | |
| 3782 | ||
| 3505 | 3783 | elf.* = undefined; |
| 3506 | 3784 | } |
| 3507 | 3785 | |
| ... | ... | @@ -3518,11 +3796,17 @@ fn initHeaders( |
| 3518 | 3796 | const gpa = comp.gpa; |
| 3519 | 3797 | |
| 3520 | 3798 | const is_archive = comp.config.output_mode == .Lib and comp.config.link_mode == .static; |
| 3521 | const have_dynamic_section = switch (@"type") { | |
| 3799 | const have_dynamic = switch (@"type") { | |
| 3522 | 3800 | .REL => false, |
| 3523 | 3801 | .EXEC => comp.config.link_mode == .dynamic, |
| 3524 | 3802 | .DYN => true, |
| 3525 | 3803 | }; |
| 3804 | const have_eh_frame = machine == .X86_64 and comp.config.any_unwind_tables; | |
| 3805 | const have_debug_frame = machine == .X86_64 and switch (comp.config.debug_format) { | |
| 3806 | .strip => false, | |
| 3807 | .dwarf => !comp.config.any_unwind_tables, | |
| 3808 | .code_view => unreachable, | |
| 3809 | }; | |
| 3526 | 3810 | const addr_align: Alignment = switch (class) { |
| 3527 | 3811 | .NONE, _ => unreachable, |
| 3528 | 3812 | .@"32" => .@"4", |
| ... | ... | @@ -3537,7 +3821,7 @@ fn initHeaders( |
| 3537 | 3821 | // |
| 3538 | 3822 | // It can be handy to temporarily set this to `.@"1"` when working on the linker, because it |
| 3539 | 3823 | // prevents alignment bugs from being hidden by your filesystem's block alignment. |
| 3540 | const node_block_align: Alignment = elf.mf.flags.block_size; | |
| 3824 | const node_block_align = elf.mf.flags.block_size; | |
| 3541 | 3825 | |
| 3542 | 3826 | const plt: PltInfo = .fromMachine(machine); |
| 3543 | 3827 | |
| ... | ... | @@ -3552,7 +3836,7 @@ fn initHeaders( |
| 3552 | 3836 | shnum += 1; // .data |
| 3553 | 3837 | shnum += @intFromBool(comp.config.any_non_single_threaded); // .tdata |
| 3554 | 3838 | shnum += 1; // .data.rel.ro |
| 3555 | if (have_dynamic_section) { | |
| 3839 | if (have_dynamic) { | |
| 3556 | 3840 | shnum += 1; // .dynamic |
| 3557 | 3841 | shnum += 1; // .dynstr |
| 3558 | 3842 | shnum += 1; // .dynsym |
| ... | ... | @@ -3560,6 +3844,19 @@ fn initHeaders( |
| 3560 | 3844 | shnum += 1; // .rela.dyn |
| 3561 | 3845 | shnum += 1; // .rela.plt |
| 3562 | 3846 | } |
| 3847 | if (have_eh_frame) { | |
| 3848 | shnum += @intFromBool(@"type" != .REL); // .eh_frame_hdr | |
| 3849 | shnum += 1; // .eh_frame | |
| 3850 | } | |
| 3851 | switch (comp.config.debug_format) { | |
| 3852 | .strip => {}, | |
| 3853 | .dwarf => { | |
| 3854 | shnum += @intFromBool(have_debug_frame); // .debug_frame | |
| 3855 | shnum += 1; // .debug_info | |
| 3856 | shnum += 1; // .debug_line | |
| 3857 | }, | |
| 3858 | .code_view => unreachable, | |
| 3859 | } | |
| 3563 | 3860 | if (@"type" != .REL) { |
| 3564 | 3861 | shnum += 1; // .got |
| 3565 | 3862 | shnum += @intFromBool(plt.got_plt != null); // .got.plt |
| ... | ... | @@ -3574,14 +3871,15 @@ fn initHeaders( |
| 3574 | 3871 | interp: u32, |
| 3575 | 3872 | rodata: u32, |
| 3576 | 3873 | text: u32, |
| 3577 | data: u32, | |
| 3578 | 3874 | /// On most targets this is `undefined`, but on machines where JUMP_SLOT relocations write |
| 3579 | 3875 | /// directly to the PLT, we place the PLT in its own segment in order to avoid making the |
| 3580 | 3876 | /// general data segment RWX. |
| 3581 | 3877 | plt: u32, |
| 3878 | data: u32, | |
| 3582 | 3879 | tls: u32, |
| 3583 | 3880 | dynamic: u32, |
| 3584 | 3881 | relro: u32, |
| 3882 | gnu_eh_frame: u32, | |
| 3585 | 3883 | gnu_stack: u32, |
| 3586 | 3884 | }, const phnum: u32 = ph: { |
| 3587 | 3885 | switch (@"type") { |
| ... | ... | @@ -3622,7 +3920,7 @@ fn initHeaders( |
| 3622 | 3920 | defer phnum += 1; |
| 3623 | 3921 | break :phndx phnum; |
| 3624 | 3922 | } else undefined, |
| 3625 | .dynamic = if (have_dynamic_section) phndx: { | |
| 3923 | .dynamic = if (have_dynamic) phndx: { | |
| 3626 | 3924 | defer phnum += 1; |
| 3627 | 3925 | break :phndx phnum; |
| 3628 | 3926 | } else undefined, |
| ... | ... | @@ -3630,6 +3928,10 @@ fn initHeaders( |
| 3630 | 3928 | defer phnum += 1; |
| 3631 | 3929 | break :phndx phnum; |
| 3632 | 3930 | }, |
| 3931 | .gnu_eh_frame = if (have_eh_frame) phndx: { | |
| 3932 | defer phnum += 1; | |
| 3933 | break :phndx phnum; | |
| 3934 | } else undefined, | |
| 3633 | 3935 | .gnu_stack = phndx: { |
| 3634 | 3936 | defer phnum += 1; |
| 3635 | 3937 | break :phndx phnum; |
| ... | ... | @@ -3872,7 +4174,7 @@ fn initHeaders( |
| 3872 | 4174 | ehdr.shentsize = @sizeOf(ElfN.Shdr); |
| 3873 | 4175 | ehdr.shnum = 1; // Only the SHN_UNDEF shdr initially---will be incremented by `addSection` |
| 3874 | 4176 | ehdr.shstrndx = std.elf.SHN_UNDEF; |
| 3875 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | |
| 4177 | if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Ehdr, ehdr); | |
| 3876 | 4178 | }, |
| 3877 | 4179 | } |
| 3878 | 4180 | |
| ... | ... | @@ -3925,8 +4227,7 @@ fn initHeaders( |
| 3925 | 4227 | elf.ni.phdr.slice(&elf.mf)[0 .. phnum * @sizeOf(ElfN.Phdr)], |
| 3926 | 4228 | )); |
| 3927 | 4229 | |
| 3928 | const ph_phdr = &phdr[phndx.phdr]; | |
| 3929 | ph_phdr.* = .{ | |
| 4230 | phdr[phndx.phdr] = .{ | |
| 3930 | 4231 | .type = .PHDR, |
| 3931 | 4232 | .offset = 0, |
| 3932 | 4233 | .vaddr = 0, |
| ... | ... | @@ -3938,8 +4239,7 @@ fn initHeaders( |
| 3938 | 4239 | }; |
| 3939 | 4240 | |
| 3940 | 4241 | if (maybe_interp) |_| { |
| 3941 | const ph_interp = &phdr[phndx.interp]; | |
| 3942 | ph_interp.* = .{ | |
| 4242 | phdr[phndx.interp] = .{ | |
| 3943 | 4243 | .type = .INTERP, |
| 3944 | 4244 | .offset = 0, |
| 3945 | 4245 | .vaddr = 0, |
| ... | ... | @@ -3951,8 +4251,7 @@ fn initHeaders( |
| 3951 | 4251 | }; |
| 3952 | 4252 | } |
| 3953 | 4253 | |
| 3954 | const ph_rodata = &phdr[phndx.rodata]; | |
| 3955 | ph_rodata.* = .{ | |
| 4254 | phdr[phndx.rodata] = .{ | |
| 3956 | 4255 | .type = .NULL, |
| 3957 | 4256 | .offset = 0, |
| 3958 | 4257 | .vaddr = @intCast(base_vaddr), |
| ... | ... | @@ -3963,74 +4262,62 @@ fn initHeaders( |
| 3963 | 4262 | .@"align" = @intCast(page_align.toByteUnits()), |
| 3964 | 4263 | }; |
| 3965 | 4264 | |
| 3966 | const ph_text = &phdr[phndx.text]; | |
| 3967 | ph_text.* = .{ | |
| 4265 | phdr[phndx.text] = .{ | |
| 4266 | .type = .NULL, | |
| 4267 | .offset = 0, | |
| 4268 | .vaddr = @intCast(base_vaddr), | |
| 4269 | .paddr = @intCast(base_vaddr), | |
| 4270 | .filesz = 0, | |
| 4271 | .memsz = 0, | |
| 4272 | .flags = .{ .R = true, .X = true }, | |
| 4273 | .@"align" = @intCast(page_align.toByteUnits()), | |
| 4274 | }; | |
| 4275 | ||
| 4276 | phdr[phndx.data] = .{ | |
| 3968 | 4277 | .type = .NULL, |
| 3969 | 4278 | .offset = 0, |
| 3970 | 4279 | .vaddr = @intCast(base_vaddr), |
| 3971 | 4280 | .paddr = @intCast(base_vaddr), |
| 3972 | 4281 | .filesz = 0, |
| 3973 | 4282 | .memsz = 0, |
| 3974 | .flags = .{ .R = true, .X = true }, | |
| 4283 | .flags = .{ .R = true, .W = true }, | |
| 3975 | 4284 | .@"align" = @intCast(page_align.toByteUnits()), |
| 3976 | 4285 | }; |
| 3977 | 4286 | |
| 3978 | const ph_data = &phdr[phndx.data]; | |
| 3979 | ph_data.* = .{ | |
| 4287 | if (plt.got_plt == null) phdr[phndx.plt] = .{ | |
| 3980 | 4288 | .type = .NULL, |
| 3981 | 4289 | .offset = 0, |
| 3982 | 4290 | .vaddr = @intCast(base_vaddr), |
| 3983 | 4291 | .paddr = @intCast(base_vaddr), |
| 3984 | 4292 | .filesz = 0, |
| 3985 | 4293 | .memsz = 0, |
| 3986 | .flags = .{ .R = true, .W = true }, | |
| 4294 | .flags = .{ .R = true, .W = true, .X = true }, | |
| 3987 | 4295 | .@"align" = @intCast(page_align.toByteUnits()), |
| 3988 | 4296 | }; |
| 3989 | 4297 | |
| 3990 | if (plt.got_plt == null) { | |
| 3991 | const ph_plt = &phdr[phndx.plt]; | |
| 3992 | ph_plt.* = .{ | |
| 3993 | .type = .NULL, | |
| 3994 | .offset = 0, | |
| 3995 | .vaddr = @intCast(base_vaddr), | |
| 3996 | .paddr = @intCast(base_vaddr), | |
| 3997 | .filesz = 0, | |
| 3998 | .memsz = 0, | |
| 3999 | .flags = .{ .R = true, .W = true, .X = true }, | |
| 4000 | .@"align" = @intCast(page_align.toByteUnits()), | |
| 4001 | }; | |
| 4002 | } | |
| 4003 | ||
| 4004 | if (elf.ni.tls.unwrap()) |tls_segment_ni| { | |
| 4005 | const ph_tls = &phdr[phndx.tls]; | |
| 4006 | ph_tls.* = .{ | |
| 4007 | .type = .TLS, | |
| 4008 | .offset = 0, | |
| 4009 | .vaddr = 0, | |
| 4010 | .paddr = 0, | |
| 4011 | .filesz = 0, | |
| 4012 | .memsz = 0, | |
| 4013 | .flags = .{ .R = true }, | |
| 4014 | .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()), | |
| 4015 | }; | |
| 4016 | } | |
| 4298 | if (elf.ni.tls.unwrap()) |tls_segment_ni| phdr[phndx.tls] = .{ | |
| 4299 | .type = .TLS, | |
| 4300 | .offset = 0, | |
| 4301 | .vaddr = 0, | |
| 4302 | .paddr = 0, | |
| 4303 | .filesz = 0, | |
| 4304 | .memsz = 0, | |
| 4305 | .flags = .{ .R = true }, | |
| 4306 | .@"align" = @intCast(tls_segment_ni.alignment(&elf.mf).toByteUnits()), | |
| 4307 | }; | |
| 4017 | 4308 | |
| 4018 | if (have_dynamic_section) { | |
| 4019 | const ph_dynamic = &phdr[phndx.dynamic]; | |
| 4020 | ph_dynamic.* = .{ | |
| 4021 | .type = .DYNAMIC, | |
| 4022 | .offset = 0, | |
| 4023 | .vaddr = 0, | |
| 4024 | .paddr = 0, | |
| 4025 | .filesz = 0, | |
| 4026 | .memsz = 0, | |
| 4027 | .flags = .{ .R = true, .W = true }, | |
| 4028 | .@"align" = @intCast(addr_align.toByteUnits()), | |
| 4029 | }; | |
| 4030 | } | |
| 4309 | if (have_dynamic) phdr[phndx.dynamic] = .{ | |
| 4310 | .type = .DYNAMIC, | |
| 4311 | .offset = 0, | |
| 4312 | .vaddr = 0, | |
| 4313 | .paddr = 0, | |
| 4314 | .filesz = 0, | |
| 4315 | .memsz = 0, | |
| 4316 | .flags = .{ .R = true, .W = true }, | |
| 4317 | .@"align" = @intCast(addr_align.toByteUnits()), | |
| 4318 | }; | |
| 4031 | 4319 | |
| 4032 | const ph_relro = &phdr[phndx.relro]; | |
| 4033 | ph_relro.* = .{ | |
| 4320 | phdr[phndx.relro] = .{ | |
| 4034 | 4321 | .type = .GNU_RELRO, |
| 4035 | 4322 | .offset = 0, |
| 4036 | 4323 | .vaddr = 0, |
| ... | ... | @@ -4041,8 +4328,18 @@ fn initHeaders( |
| 4041 | 4328 | .@"align" = @intCast(elf.ni.data_rel_ro.alignment(&elf.mf).toByteUnits()), |
| 4042 | 4329 | }; |
| 4043 | 4330 | |
| 4044 | const ph_gnu_stack = &phdr[phndx.gnu_stack]; | |
| 4045 | ph_gnu_stack.* = .{ | |
| 4331 | if (have_eh_frame) phdr[phndx.gnu_eh_frame] = .{ | |
| 4332 | .type = .GNU_EH_FRAME, | |
| 4333 | .offset = 0, | |
| 4334 | .vaddr = 0, | |
| 4335 | .paddr = 0, | |
| 4336 | .filesz = @sizeOf(Dwarf.EhFrameHdr), | |
| 4337 | .memsz = @sizeOf(Dwarf.EhFrameHdr), | |
| 4338 | .flags = .{ .R = true }, | |
| 4339 | .@"align" = 4, | |
| 4340 | }; | |
| 4341 | ||
| 4342 | phdr[phndx.gnu_stack] = .{ | |
| 4046 | 4343 | .type = .GNU_STACK, |
| 4047 | 4344 | .offset = 0, |
| 4048 | 4345 | .vaddr = 0, |
| ... | ... | @@ -4071,7 +4368,7 @@ fn initHeaders( |
| 4071 | 4368 | .addralign = 0, |
| 4072 | 4369 | .entsize = 0, |
| 4073 | 4370 | }; |
| 4074 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef); | |
| 4371 | if (target_endian != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Shdr, sh_undef); | |
| 4075 | 4372 | |
| 4076 | 4373 | elf.symtab.addOneAssumeCapacity().* = .{ |
| 4077 | 4374 | .node = .none, |
| ... | ... | @@ -4084,6 +4381,7 @@ fn initHeaders( |
| 4084 | 4381 | .entsize = @sizeOf(ElfN.Sym), |
| 4085 | 4382 | .node_align = node_block_align, |
| 4086 | 4383 | .info = 1, // index of first non-local symbol |
| 4384 | .manual_size = true, | |
| 4087 | 4385 | })); |
| 4088 | 4386 | const symtab_null = @field(elf.symPtr(.null), @tagName(ct_class)); |
| 4089 | 4387 | symtab_null.* = .{ |
| ... | ... | @@ -4094,7 +4392,7 @@ fn initHeaders( |
| 4094 | 4392 | .other = .{ .visibility = .DEFAULT }, |
| 4095 | 4393 | .shndx = std.elf.SHN_UNDEF, |
| 4096 | 4394 | }; |
| 4097 | if (target_endian != native_endian) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null); | |
| 4395 | if (target_endian != std.lang.Endian.native) std.mem.byteSwapAllFields(ElfN.Sym, symtab_null); | |
| 4098 | 4396 | |
| 4099 | 4397 | const ehdr = @field(elf.ehdrPtr(), @tagName(ct_class)); |
| 4100 | 4398 | ehdr.shstrndx = ehdr.shnum; |
| ... | ... | @@ -4105,6 +4403,7 @@ fn initHeaders( |
| 4105 | 4403 | .size = 1, |
| 4106 | 4404 | .entsize = 1, |
| 4107 | 4405 | .node_align = node_block_align, |
| 4406 | .manual_size = true, | |
| 4108 | 4407 | })); |
| 4109 | 4408 | Section.Index.get(.shstrtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 4110 | 4409 | |
| ... | ... | @@ -4117,6 +4416,7 @@ fn initHeaders( |
| 4117 | 4416 | .size = 1, |
| 4118 | 4417 | .entsize = 1, |
| 4119 | 4418 | .node_align = node_block_align, |
| 4419 | .manual_size = true, | |
| 4120 | 4420 | })); |
| 4121 | 4421 | Section.Index.get(.strtab, elf).ni.slice(&elf.mf)[0] = 0; |
| 4122 | 4422 | switch (elf.shdrPtr(.symtab)) { |
| ... | ... | @@ -4156,6 +4456,7 @@ fn initHeaders( |
| 4156 | 4456 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 4157 | 4457 | .addralign = addr_align, |
| 4158 | 4458 | .entsize = @intCast(addr_align.toByteUnits()), |
| 4459 | .manual_size = true, | |
| 4159 | 4460 | }); |
| 4160 | 4461 | { |
| 4161 | 4462 | const init_plt_size = plt.entry_size * plt.header_entries; |
| ... | ... | @@ -4168,6 +4469,7 @@ fn initHeaders( |
| 4168 | 4469 | .size = got_plt.header_entries * elf.targetPtrSize(), |
| 4169 | 4470 | .addralign = addr_align, |
| 4170 | 4471 | .entsize = @intCast(addr_align.toByteUnits()), |
| 4472 | .manual_size = true, | |
| 4171 | 4473 | }); |
| 4172 | 4474 | elf.shndx.plt = try elf.addSection(elf.ni.text, .{ |
| 4173 | 4475 | .name = ".plt", |
| ... | ... | @@ -4176,6 +4478,7 @@ fn initHeaders( |
| 4176 | 4478 | .size = plt.@"align".forward(init_plt_size), |
| 4177 | 4479 | .addralign = plt.@"align", |
| 4178 | 4480 | .node_align = node_block_align, |
| 4481 | .manual_size = true, | |
| 4179 | 4482 | }); |
| 4180 | 4483 | } else { |
| 4181 | 4484 | elf.shndx.plt = try elf.addSection(elf.phdrs.items[phndx.plt].unwrap().?, .{ |
| ... | ... | @@ -4185,6 +4488,7 @@ fn initHeaders( |
| 4185 | 4488 | .size = plt.@"align".forward(init_plt_size), |
| 4186 | 4489 | .addralign = plt.@"align", |
| 4187 | 4490 | .node_align = node_block_align, |
| 4491 | .manual_size = true, | |
| 4188 | 4492 | }); |
| 4189 | 4493 | } |
| 4190 | 4494 | // And the award for most annoying PLT requirement goes to SPARC, which decided that the |
| ... | ... | @@ -4222,7 +4526,7 @@ fn initHeaders( |
| 4222 | 4526 | @memcpy(sec_interp[0..interp.len], interp); |
| 4223 | 4527 | sec_interp[interp.len] = 0; |
| 4224 | 4528 | } |
| 4225 | if (have_dynamic_section) { | |
| 4529 | if (have_dynamic) { | |
| 4226 | 4530 | assert(elf.ni.data_rel_ro.alignment(&elf.mf).compare(.gte, addr_align)); |
| 4227 | 4531 | const dynamic_ni = try elf.ni.data_rel_ro.addFloatingChild(&elf.mf, gpa, .{ |
| 4228 | 4532 | .alignment = addr_align, |
| ... | ... | @@ -4239,6 +4543,7 @@ fn initHeaders( |
| 4239 | 4543 | .size = 1, |
| 4240 | 4544 | .entsize = 1, |
| 4241 | 4545 | .node_align = node_block_align, |
| 4546 | .manual_size = true, | |
| 4242 | 4547 | }); |
| 4243 | 4548 | dynstr_shndx.get(elf).ni.slice(&elf.mf)[0] = 0; |
| 4244 | 4549 | elf.shndx.dynstr = dynstr_shndx; |
| ... | ... | @@ -4257,6 +4562,7 @@ fn initHeaders( |
| 4257 | 4562 | .addralign = addr_align, |
| 4258 | 4563 | .entsize = @sizeOf(Sym), |
| 4259 | 4564 | .node_align = node_block_align, |
| 4565 | .manual_size = true, | |
| 4260 | 4566 | }); |
| 4261 | 4567 | const dynsym_null = @field(elf.dynsymPtr(0), @tagName(ct_class)); |
| 4262 | 4568 | dynsym_null.* = .{ |
| ... | ... | @@ -4267,7 +4573,7 @@ fn initHeaders( |
| 4267 | 4573 | .other = .{ .visibility = .DEFAULT }, |
| 4268 | 4574 | .shndx = std.elf.SHN_UNDEF, |
| 4269 | 4575 | }; |
| 4270 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields( | |
| 4576 | if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields( | |
| 4271 | 4577 | Sym, |
| 4272 | 4578 | dynsym_null, |
| 4273 | 4579 | ); |
| ... | ... | @@ -4285,6 +4591,7 @@ fn initHeaders( |
| 4285 | 4591 | .addralign = addr_align, |
| 4286 | 4592 | .entsize = rela_size, |
| 4287 | 4593 | .node_align = node_block_align, |
| 4594 | .manual_size = true, | |
| 4288 | 4595 | }); |
| 4289 | 4596 | elf.shndx.rela_plt = try elf.addSection(elf.ni.rodata, .{ |
| 4290 | 4597 | .name = ".rela.plt", |
| ... | ... | @@ -4295,6 +4602,7 @@ fn initHeaders( |
| 4295 | 4602 | .addralign = addr_align, |
| 4296 | 4603 | .entsize = rela_size, |
| 4297 | 4604 | .node_align = node_block_align, |
| 4605 | .manual_size = true, | |
| 4298 | 4606 | }); |
| 4299 | 4607 | elf.shndx.dynamic = try elf.addSection(dynamic_ni, .{ |
| 4300 | 4608 | .name = ".dynamic", |
| ... | ... | @@ -4303,6 +4611,7 @@ fn initHeaders( |
| 4303 | 4611 | .link = dynstr_shndx.toSection().?, |
| 4304 | 4612 | .entsize = @intCast(addr_align.toByteUnits() * 2), |
| 4305 | 4613 | .addralign = addr_align, |
| 4614 | .manual_size = true, | |
| 4306 | 4615 | }); |
| 4307 | 4616 | switch (elf.targetDynsymHashInfo()) { |
| 4308 | 4617 | inline else => |info| { |
| ... | ... | @@ -4318,6 +4627,7 @@ fn initHeaders( |
| 4318 | 4627 | .addralign = .fromByteUnits(@sizeOf(info.Int())), |
| 4319 | 4628 | // initially: nbucket = 8 + nchain = 1 |
| 4320 | 4629 | .size = @sizeOf(info.Header()) + @sizeOf(info.Int()) * (8 + 1), |
| 4630 | .manual_size = true, | |
| 4321 | 4631 | }); |
| 4322 | 4632 | const hash_slice: []align(@sizeOf(info.Int())) u8 = @alignCast(elf.shndx.hash.get(elf).ni.slice(&elf.mf)); |
| 4323 | 4633 | const header: *info.Header() = @ptrCast(hash_slice[0..@sizeOf(info.Header())]); |
| ... | ... | @@ -4407,13 +4717,45 @@ fn initHeaders( |
| 4407 | 4717 | .SPARCV9 => {}, |
| 4408 | 4718 | } |
| 4409 | 4719 | } |
| 4720 | if (have_eh_frame) { | |
| 4721 | elf.ni.gnu_eh_frame = .wrap(try elf.ni.rodata.addFloatingChild(&elf.mf, gpa, .{ | |
| 4722 | .size = @sizeOf(Dwarf.EhFrameHdr), | |
| 4723 | .alignment = .@"4", | |
| 4724 | .moved = true, | |
| 4725 | .bubbles_moved = false, | |
| 4726 | })); | |
| 4727 | elf.nodes.appendAssumeCapacity(.{ .segment = phndx.gnu_eh_frame }); | |
| 4728 | elf.phdrs.items[phndx.gnu_eh_frame] = elf.ni.gnu_eh_frame; | |
| 4729 | ||
| 4730 | elf.shndx.eh_frame_hdr = try elf.addSection(elf.ni.gnu_eh_frame.unwrap().?, .{ | |
| 4731 | .name = ".eh_frame_hdr", | |
| 4732 | .type = .PROGBITS, | |
| 4733 | .flags = .{ .ALLOC = true }, | |
| 4734 | .size = @sizeOf(Dwarf.EhFrameHdr), | |
| 4735 | .addralign = .@"4", | |
| 4736 | }); | |
| 4737 | elf.shndx.eh_frame = try elf.addSection(elf.ni.rodata, .{ | |
| 4738 | .name = ".eh_frame", | |
| 4739 | .flags = .{ .ALLOC = true }, | |
| 4740 | .addralign = addr_align, | |
| 4741 | .node_align = elf.mf.flags.block_size, | |
| 4742 | }); | |
| 4743 | const eh_frame_hdr_ni = elf.shndx.eh_frame_hdr.get(elf).ni; | |
| 4744 | elf.eh_frame_hdr_first_symbol_reloc = | |
| 4745 | @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); | |
| 4746 | try elf.dwarf.genEhFrameHdr( | |
| 4747 | Node.toAtom(eh_frame_hdr_ni), | |
| 4748 | @ptrCast(@alignCast(eh_frame_hdr_ni.slice(&elf.mf))), | |
| 4749 | Symbol.Id.local(elf.shndx.eh_frame.get(elf).lsi).toTypeErased(), | |
| 4750 | ); | |
| 4751 | } | |
| 4410 | 4752 | |
| 4411 | 4753 | // Populate reserved GOT words. |
| 4412 | 4754 | switch (machine) { |
| 4413 | 4755 | .AARCH64, .PPC64, .RISCV => @panic(@tagName(machine)), |
| 4414 | 4756 | .X86_64 => { |
| 4415 | 4757 | try elf.got.ensureUnusedCapacity(gpa, 3); |
| 4416 | elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) { | |
| 4758 | elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) { | |
| 4417 | 4759 | true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) }, |
| 4418 | 4760 | false => .{ .reserved = 0 }, |
| 4419 | 4761 | }, .none); |
| ... | ... | @@ -4422,7 +4764,7 @@ fn initHeaders( |
| 4422 | 4764 | }, |
| 4423 | 4765 | .LOONGARCH, .SPARCV9 => { |
| 4424 | 4766 | try elf.got.ensureUnusedCapacity(gpa, 1); |
| 4425 | elf.got.putAssumeCapacityNoClobber(switch (have_dynamic_section) { | |
| 4767 | elf.got.putAssumeCapacityNoClobber(switch (have_dynamic) { | |
| 4426 | 4768 | true => .{ .symbol = .local(elf.shndx.dynamic.get(elf).lsi) }, |
| 4427 | 4769 | false => .{ .reserved = 0 }, |
| 4428 | 4770 | }, .none); |
| ... | ... | @@ -4567,7 +4909,7 @@ fn initHeaders( |
| 4567 | 4909 | }) catch |err| switch (err) { |
| 4568 | 4910 | error.MultipleDefinitions => unreachable, // no inputs are processed yet |
| 4569 | 4911 | }; |
| 4570 | if (have_dynamic_section) { | |
| 4912 | if (have_dynamic) { | |
| 4571 | 4913 | _ = elf.addGlobalSymbolAssumeCapacity(.{ |
| 4572 | 4914 | .node = .wrap(elf.shndx.dynamic.get(elf).ni), |
| 4573 | 4915 | .name = try .string(elf, "_DYNAMIC"), |
| ... | ... | @@ -4583,13 +4925,39 @@ fn initHeaders( |
| 4583 | 4925 | } |
| 4584 | 4926 | } else { |
| 4585 | 4927 | assert(maybe_interp == null); |
| 4586 | assert(!have_dynamic_section); | |
| 4928 | assert(!have_dynamic); | |
| 4929 | if (have_eh_frame) elf.shndx.eh_frame = try elf.addSection(elf.ni.rodata, .{ | |
| 4930 | .name = ".eh_frame", | |
| 4931 | .type = if (machine == .X86_64) .X86_64_UNWIND else .NULL, | |
| 4932 | .flags = .{ .ALLOC = true }, | |
| 4933 | .addralign = addr_align, | |
| 4934 | .node_align = elf.mf.flags.block_size, | |
| 4935 | }); | |
| 4587 | 4936 | } |
| 4588 | 4937 | if (elf.ni.tls.unwrap()) |tls_segment_ni| elf.shndx.tdata = try elf.addSection(tls_segment_ni, .{ |
| 4589 | 4938 | .name = ".tdata", |
| 4590 | 4939 | .flags = .{ .WRITE = true, .ALLOC = true, .TLS = true }, |
| 4591 | 4940 | .node_align = node_block_align, |
| 4592 | 4941 | }); |
| 4942 | switch (comp.config.debug_format) { | |
| 4943 | .strip => {}, | |
| 4944 | .dwarf => { | |
| 4945 | if (have_debug_frame) elf.shndx.debug_frame = try elf.addSection(elf.ni.elf, .{ | |
| 4946 | .name = ".debug_frame", | |
| 4947 | .addralign = addr_align, | |
| 4948 | .node_align = elf.mf.flags.block_size, | |
| 4949 | }); | |
| 4950 | elf.shndx.debug_info = try elf.addSection(elf.ni.elf, .{ | |
| 4951 | .name = ".debug_info", | |
| 4952 | .node_align = elf.mf.flags.block_size, | |
| 4953 | }); | |
| 4954 | elf.shndx.debug_line = try elf.addSection(elf.ni.elf, .{ | |
| 4955 | .name = ".debug_line", | |
| 4956 | .node_align = elf.mf.flags.block_size, | |
| 4957 | }); | |
| 4958 | }, | |
| 4959 | .code_view => unreachable, | |
| 4960 | } | |
| 4593 | 4961 | |
| 4594 | 4962 | assert(elf.nodes.len == expected_nodes_len); |
| 4595 | 4963 | assert(elf.shdrs.items.len == shnum - 1); // -1 to exclude SHN_UNDEF |
| ... | ... | @@ -4599,7 +4967,7 @@ fn initHeaders( |
| 4599 | 4967 | elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {}); |
| 4600 | 4968 | } |
| 4601 | 4969 | |
| 4602 | if (have_dynamic_section) elf.dynamic = .{ | |
| 4970 | if (have_dynamic) elf.dynamic = .{ | |
| 4603 | 4971 | .flags = if (elf.options.z_now) std.elf.DF_BIND_NOW else 0, |
| 4604 | 4972 | .flags_1 = f: { |
| 4605 | 4973 | var f: u32 = 0; |
| ... | ... | @@ -4677,15 +5045,26 @@ fn getNodeShndx(elf: *const Elf, ni: MappedFile.Node.Index) Section.Index { |
| 4677 | 5045 | .ehdr, |
| 4678 | 5046 | .shdr, |
| 4679 | 5047 | .segment, |
| 5048 | .value_debug_info, | |
| 5049 | .global_debug_info, | |
| 5050 | .frame_padding, | |
| 5051 | .func_debug_info, | |
| 5052 | .func_debug_line, | |
| 4680 | 5053 | => unreachable, |
| 4681 | .section => |shndx| shndx, | |
| 5054 | .section, .section_manual_size => |shndx| shndx, | |
| 4682 | 5055 | .input_section, |
| 4683 | 5056 | .copied_global, |
| 4684 | 5057 | .nav, |
| 4685 | 5058 | .uav, |
| 4686 | 5059 | .lazy_code, |
| 4687 | 5060 | .lazy_const_data, |
| 5061 | .unit_frame, | |
| 4688 | 5062 | => elf.getNode(ni.parent(&elf.mf).unwrap().?).section, |
| 5063 | .unit_frame_cie, .func_frame_fde => { | |
| 5064 | const unit_frame_ni = ni.parent(&elf.mf).unwrap().?; | |
| 5065 | assert(elf.getNode(unit_frame_ni) == .unit_frame); | |
| 5066 | return elf.getNode(unit_frame_ni.parent(&elf.mf).unwrap().?).section; | |
| 5067 | }, | |
| 4689 | 5068 | }; |
| 4690 | 5069 | } |
| 4691 | 5070 | fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| ... | ... | @@ -4699,31 +5078,52 @@ fn getNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4699 | 5078 | .shdr, |
| 4700 | 5079 | .segment, |
| 4701 | 5080 | .copied_global, |
| 5081 | .value_debug_info, | |
| 5082 | .global_debug_info, | |
| 5083 | .frame_padding, | |
| 5084 | .func_debug_info, | |
| 5085 | .func_debug_line, | |
| 4702 | 5086 | => unreachable, |
| 4703 | .section => |shndx| shndx.vaddr(elf), | |
| 5087 | .section, .section_manual_size => |shndx| shndx.vaddr(elf), | |
| 4704 | 5088 | .input_section => |isi| isi.ptrConst(elf).vaddr, |
| 4705 | 5089 | inline .nav, |
| 4706 | 5090 | .uav, |
| 4707 | 5091 | .lazy_code, |
| 4708 | 5092 | .lazy_const_data, |
| 4709 | 5093 | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), |
| 5094 | .unit_frame, .unit_frame_cie, .func_frame_fde => elf.computeNodeVAddr(ni), | |
| 4710 | 5095 | }; |
| 4711 | 5096 | } |
| 4712 | 5097 | fn computeNodeVAddr(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4713 | const parent_vaddr = switch (elf.getNode(ni.parent(&elf.mf).unwrap().?)) { | |
| 4714 | .archive, | |
| 4715 | .archive_header, | |
| 4716 | .archive_input_member, | |
| 4717 | .archive_elf_member_header, | |
| 4718 | => unreachable, | |
| 5098 | const parent_ni = ni.parent(&elf.mf).unwrap().?; | |
| 5099 | const parent_vaddr = parent_vaddr: switch (elf.getNode(parent_ni)) { | |
| 5100 | .archive, .archive_header, .archive_input_member, .archive_elf_member_header => unreachable, | |
| 4719 | 5101 | .elf => return 0, |
| 4720 | 5102 | .ehdr, .shdr => unreachable, |
| 4721 | 5103 | .segment => |phndx| switch (elf.phdrSlice()) { |
| 4722 | 5104 | inline else => |phdr| elf.targetLoad(&phdr[phndx].vaddr), |
| 4723 | 5105 | }, |
| 4724 | .section => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), | |
| 5106 | .section, .section_manual_size => |shndx| if (shndx == elf.shndx.tdata) 0 else shndx.vaddr(elf), | |
| 4725 | 5107 | .input_section, .copied_global => unreachable, |
| 4726 | inline .nav, .uav, .lazy_code, .lazy_const_data => |i| Symbol.Id.local(i.symbol(elf)).value(elf), | |
| 5108 | inline .nav, | |
| 5109 | .uav, | |
| 5110 | .lazy_code, | |
| 5111 | .lazy_const_data, | |
| 5112 | => |i| Symbol.Id.local(i.symbol(elf)).value(elf), | |
| 5113 | .value_debug_info, | |
| 5114 | .global_debug_info, | |
| 5115 | .frame_padding, | |
| 5116 | => unreachable, | |
| 5117 | .unit_frame => { | |
| 5118 | const section_ni = parent_ni.parent(&elf.mf).unwrap().?; | |
| 5119 | const section_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); | |
| 5120 | break :parent_vaddr elf.getNode(section_ni).section.vaddr(elf) + section_offset; | |
| 5121 | }, | |
| 5122 | .unit_frame_cie, | |
| 5123 | .func_frame_fde, | |
| 5124 | .func_debug_info, | |
| 5125 | .func_debug_line, | |
| 5126 | => unreachable, | |
| 4727 | 5127 | }; |
| 4728 | 5128 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); |
| 4729 | 5129 | return parent_vaddr + offset; |
| ... | ... | @@ -4736,9 +5136,9 @@ fn getNodeElfOffset(elf: *Elf, ni: MappedFile.Node.Index) u64 { |
| 4736 | 5136 | /// sequence of relocations, so that the caller may append the node's updated relocations. |
| 4737 | 5137 | /// |
| 4738 | 5138 | /// Asserts that `ni` must be a node which supports relocations (see `Elf.Node`). Does not support |
| 4739 | /// the special-case sections '.plt' and '.dynamic'. | |
| 5139 | /// the special-case sections '.plt', '.dynamic', and '.eh_frame_hdr'. | |
| 4740 | 5140 | fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 4741 | const symbol_relocs: *SymbolReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { | |
| 5141 | const symbol_relocs: *SymbolReloc.Index, const node_relocs: ?*NodeReloc.Index, const got_relocs: ?*GotReloc.Index = switch (elf.getNode(ni)) { | |
| 4742 | 5142 | .archive, |
| 4743 | 5143 | .archive_header, |
| 4744 | 5144 | .archive_input_member, |
| ... | ... | @@ -4748,24 +5148,42 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 4748 | 5148 | .shdr, |
| 4749 | 5149 | .segment, |
| 4750 | 5150 | .copied_global, |
| 5151 | .value_debug_info, | |
| 5152 | .global_debug_info, | |
| 5153 | .frame_padding, | |
| 5154 | .unit_frame, | |
| 5155 | .unit_frame_cie, | |
| 5156 | .func_debug_info, | |
| 5157 | .func_debug_line, | |
| 4751 | 5158 | => unreachable, // cannot contain relocs |
| 4752 | .section => unreachable, // cannot contain relocs (.plt and .dynamic unsupported) | |
| 5159 | .section, | |
| 5160 | .section_manual_size, | |
| 5161 | => unreachable, // cannot contain relocs (.plt, .dynamic, and .eh_frame_hdr unsupported) | |
| 4753 | 5162 | .input_section => |isi| .{ |
| 4754 | 5163 | &elf.input_sections.items[@backingInt(isi)].first_symbol_reloc, |
| 5164 | null, | |
| 4755 | 5165 | &elf.input_sections.items[@backingInt(isi)].first_got_reloc, |
| 4756 | 5166 | }, |
| 4757 | 5167 | .nav => |nmi| .{ |
| 4758 | 5168 | &elf.navs.values()[@backingInt(nmi)].first_symbol_reloc, |
| 5169 | null, | |
| 4759 | 5170 | &elf.navs.values()[@backingInt(nmi)].first_got_reloc, |
| 4760 | 5171 | }, |
| 4761 | 5172 | .uav => |umi| .{ |
| 4762 | 5173 | &elf.uavs.values()[@backingInt(umi)].first_symbol_reloc, |
| 4763 | 5174 | null, |
| 5175 | null, | |
| 4764 | 5176 | }, |
| 4765 | 5177 | inline .lazy_code, .lazy_const_data => |lmi| .{ |
| 4766 | 5178 | &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_symbol_reloc, |
| 5179 | null, | |
| 4767 | 5180 | &elf.lazy.getPtr(lmi.ref().kind).map.values()[lmi.ref().index].first_got_reloc, |
| 4768 | 5181 | }, |
| 5182 | .func_frame_fde => |fi| .{ | |
| 5183 | &elf.dwarf_funcs.items[@backingInt(fi)].func_frame_fde_first_symbol_reloc, | |
| 5184 | &elf.dwarf_funcs.items[@backingInt(fi)].func_frame_fde_first_node_reloc, | |
| 5185 | null, | |
| 5186 | }, | |
| 4769 | 5187 | }; |
| 4770 | 5188 | |
| 4771 | 5189 | if (symbol_relocs.* != .none) { |
| ... | ... | @@ -4779,6 +5197,16 @@ fn resetNodeRelocs(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 4779 | 5197 | } |
| 4780 | 5198 | symbol_relocs.* = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); |
| 4781 | 5199 | |
| 5200 | if (node_relocs) |ptr| { | |
| 5201 | if (ptr.* != .none) { | |
| 5202 | for (elf.node_relocs.items[@backingInt(ptr.*)..]) |*reloc| { | |
| 5203 | if (reloc.node != ni) break; | |
| 5204 | reloc.delete(elf); | |
| 5205 | } | |
| 5206 | } | |
| 5207 | ptr.* = @fromBackingInt(@intCast(elf.node_relocs.items.len)); | |
| 5208 | } | |
| 5209 | ||
| 4782 | 5210 | if (got_relocs) |ptr| { |
| 4783 | 5211 | if (ptr.* != .none) { |
| 4784 | 5212 | for (elf.got_relocs.items[@backingInt(ptr.*)..]) |*reloc| { |
| ... | ... | @@ -4797,6 +5225,7 @@ fn flushMovedNodeRelocs( |
| 4797 | 5225 | node: MappedFile.Node.Index, |
| 4798 | 5226 | node_vaddr: u64, |
| 4799 | 5227 | first_symbol_reloc: SymbolReloc.Index, |
| 5228 | first_node_reloc: NodeReloc.Index, | |
| 4800 | 5229 | first_got_reloc: GotReloc.Index, |
| 4801 | 5230 | ) void { |
| 4802 | 5231 | if (first_symbol_reloc != .none) { |
| ... | ... | @@ -4816,6 +5245,21 @@ fn flushMovedNodeRelocs( |
| 4816 | 5245 | } |
| 4817 | 5246 | } |
| 4818 | 5247 | |
| 5248 | if (first_node_reloc != .none) { | |
| 5249 | for (elf.node_relocs.items[@backingInt(first_node_reloc)..]) |*reloc| { | |
| 5250 | if (reloc.node != node) break; | |
| 5251 | if (reloc.rela_index.unwrap()) |rela_index| { | |
| 5252 | assert(elf.ehdrType() == .REL); | |
| 5253 | // The node has moved, so the offset of the relocation within the section might have | |
| 5254 | // changed, so update the `offset` field of the `ElfN.Rela` entry. | |
| 5255 | elf.getNodeShndx(reloc.node).get(elf).rela.shndx.relaSetOffset(elf, rela_index, node_vaddr + reloc.offset); | |
| 5256 | } else { | |
| 5257 | assert(elf.ehdrType() != .REL); | |
| 5258 | reloc.apply(elf); | |
| 5259 | } | |
| 5260 | } | |
| 5261 | } | |
| 5262 | ||
| 4819 | 5263 | if (first_got_reloc != .none) { |
| 4820 | 5264 | for (elf.got_relocs.items[@backingInt(first_got_reloc)..]) |*reloc| { |
| 4821 | 5265 | if (reloc.node != node.toOptional()) break; |
| ... | ... | @@ -5226,7 +5670,7 @@ fn mapInputSection(elf: *Elf, opts: struct { |
| 5226 | 5670 | } |
| 5227 | 5671 | |
| 5228 | 5672 | switch (elf.targetLoad(&shdr.type)) { |
| 5229 | .NULL, .PROGBITS => {}, | |
| 5673 | .NULL, .PROGBITS, .X86_64_UNWIND => {}, | |
| 5230 | 5674 | else => return error.SectionTypeConflict, |
| 5231 | 5675 | } |
| 5232 | 5676 | |
| ... | ... | @@ -5360,7 +5804,7 @@ fn uavMapIndex( |
| 5360 | 5804 | .moved = true, // see assert at end of `genUav` |
| 5361 | 5805 | .alignment = resolved_align, |
| 5362 | 5806 | }); |
| 5363 | var name_buf: [32]u8 = undefined; | |
| 5807 | var name_buf: [std.fmt.count("__anon_{d}", .{std.math.maxInt(u32)})]u8 = undefined; | |
| 5364 | 5808 | const name = std.mem.print( |
| 5365 | 5809 | &name_buf, |
| 5366 | 5810 | "__anon_{d}", |
| ... | ... | @@ -5520,7 +5964,7 @@ fn loadArchive(elf: *Elf, path: std.Build.Cache.Path, fr: *Io.File.Reader) (Load |
| 5520 | 5964 | } |
| 5521 | 5965 | var strtab: std.Io.Writer.Allocating = .init(gpa); |
| 5522 | 5966 | defer strtab.deinit(); |
| 5523 | while (r.takeStruct(std.elf.ar_hdr, native_endian)) |header| { | |
| 5967 | while (r.takeStruct(std.elf.ar_hdr, .native)) |header| { | |
| 5524 | 5968 | if (!std.mem.eql(u8, &header.ar_fmag, std.elf.ARFMAG)) |
| 5525 | 5969 | return diags.failParse(path, "bad file magic", .{}); |
| 5526 | 5970 | const offset = fr.logicalPos(); |
| ... | ... | @@ -5717,13 +6161,13 @@ fn loadObject( |
| 5717 | 6161 | for (sections[1..]) |*section| { |
| 5718 | 6162 | if (section.shdr.name >= shstrtab.len) continue; |
| 5719 | 6163 | const name = std.mem.sliceTo(shstrtab[section.shdr.name..], 0); |
| 6164 | if (!comp.config.any_unwind_tables and std.mem.eql(u8, name, ".eh_frame")) continue; | |
| 5720 | 6165 | const opts: struct { |
| 5721 | 6166 | shndx: Section.Index, |
| 5722 | has_file_bits: bool, | |
| 5723 | 6167 | node_fixed: bool, |
| 5724 | 6168 | } = switch (section.shdr.type) { |
| 5725 | 6169 | else => continue, |
| 5726 | .PROGBITS, .NOBITS => opts: { | |
| 6170 | .PROGBITS, .NOBITS, .X86_64_UNWIND => opts: { | |
| 5727 | 6171 | const shndx = elf.mapInputSection(.{ |
| 5728 | 6172 | .name = name, |
| 5729 | 6173 | .flags = section.shdr.flags.shf, |
| ... | ... | @@ -5776,7 +6220,6 @@ fn loadObject( |
| 5776 | 6220 | } |
| 5777 | 6221 | break :opts .{ |
| 5778 | 6222 | .shndx = shndx, |
| 5779 | .has_file_bits = section.shdr.type == .PROGBITS, | |
| 5780 | 6223 | // For well-known sections, we know that it's fine to have e.g. random |
| 5781 | 6224 | // padding, so there's no need to make the sections fixed. For custom |
| 5782 | 6225 | // sections, however, we do want fixed nodes to avoid padding. |
| ... | ... | @@ -5819,7 +6262,6 @@ fn loadObject( |
| 5819 | 6262 | } |
| 5820 | 6263 | break :shndx shndx.*; |
| 5821 | 6264 | }, |
| 5822 | .has_file_bits = true, | |
| 5823 | 6265 | // This node must be fixed to prevent padding from being added between different |
| 5824 | 6266 | // INIT_ARRAY/FINI_ARRAY/PREINIT_ARRAY input sections. |
| 5825 | 6267 | .node_fixed = true, |
| ... | ... | @@ -5855,7 +6297,7 @@ fn loadObject( |
| 5855 | 6297 | .input = input_index, |
| 5856 | 6298 | .file_location = .{ |
| 5857 | 6299 | .offset = fl.offset + section.shdr.offset, |
| 5858 | .size = if (opts.has_file_bits) section.shdr.size else 0, | |
| 6300 | .size = if (section.shdr.type == .NOBITS) 0 else section.shdr.size, | |
| 5859 | 6301 | }, |
| 5860 | 6302 | // The section vaddr is initially 0, because the symbol addresses are |
| 5861 | 6303 | // zero-based. This will eventually be updated by `flushMoved`. |
| ... | ... | @@ -6407,6 +6849,7 @@ fn createInitFiniArraySection( |
| 6407 | 6849 | .type = @"type", |
| 6408 | 6850 | .flags = .{ .WRITE = true, .ALLOC = true }, |
| 6409 | 6851 | .node_align = addr_align, |
| 6852 | .manual_size = true, | |
| 6410 | 6853 | }); |
| 6411 | 6854 | elf.section_by_name.putAssumeCapacityNoClobber(shndx.name(elf), {}); |
| 6412 | 6855 | try elf.ensureUnusedSymbolCapacity(2, .maybe_global); |
| ... | ... | @@ -6455,7 +6898,9 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 6455 | 6898 | const comp = elf.base.comp; |
| 6456 | 6899 | const gpa = comp.gpa; |
| 6457 | 6900 | |
| 6458 | if (comp.zcu != null and !comp.config.use_llvm and elf.ni.elf == .root) { | |
| 6901 | if (comp.zcu) |zcu| self_hosted_codegen: { | |
| 6902 | if (comp.config.use_llvm) break :self_hosted_codegen; | |
| 6903 | ||
| 6459 | 6904 | // We're using self-hosted codegen---add an input representing the Zig "object". |
| 6460 | 6905 | try elf.ensureUnusedSymbolCapacity(1, .all_local); |
| 6461 | 6906 | try elf.inputs.ensureUnusedCapacity(gpa, 1); |
| ... | ... | @@ -6475,6 +6920,37 @@ fn prelinkInner(elf: *Elf) Error!void { |
| 6475 | 6920 | .extra = .{ .file_symbol = zcu_file_symbol }, |
| 6476 | 6921 | }; |
| 6477 | 6922 | elf.input_pending_index += 1; |
| 6923 | ||
| 6924 | try elf.dwarf.initUnits(zcu); | |
| 6925 | try elf.dwarf_units.appendNTimes(gpa, .{ | |
| 6926 | .unit_frame_cie_first_target_reloc = .none, | |
| 6927 | }, elf.dwarf.units.count()); | |
| 6928 | ||
| 6929 | try elf.nodes.ensureUnusedCapacity(gpa, 2); | |
| 6930 | for ( | |
| 6931 | [2]Dwarf.Frame.Format{ .eh_frame, .debug_frame }, | |
| 6932 | [2]Section.Index{ elf.shndx.eh_frame, elf.shndx.debug_frame }, | |
| 6933 | ) |format, frame_shndx| { | |
| 6934 | if (frame_shndx == .UNDEF) continue; | |
| 6935 | const frame_ni = frame_shndx.get(elf).ni; | |
| 6936 | _ = frame_ni.last(&elf.mf).unwrap() orelse continue; | |
| 6937 | const frame_padding_ni = try frame_ni.addFloatingChild(&elf.mf, gpa, .{ | |
| 6938 | .alignment = switch (elf.identClass()) { | |
| 6939 | .NONE, _ => unreachable, | |
| 6940 | .@"32" => .@"4", | |
| 6941 | .@"64" => .@"8", | |
| 6942 | }, | |
| 6943 | .next_moved = true, | |
| 6944 | .enable_next_moved = true, | |
| 6945 | }); | |
| 6946 | elf.nodes.appendAssumeCapacity(.frame_padding); | |
| 6947 | var cie_writer: MappedFile.Node.Writer = undefined; | |
| 6948 | frame_padding_ni.writer(&elf.mf, gpa, &cie_writer); | |
| 6949 | defer cie_writer.deinit(); | |
| 6950 | elf.dwarf.genDebugFrameCie(&cie_writer.interface, null, format) catch |err| switch (err) { | |
| 6951 | error.WriteFailed => return cie_writer.err.?, | |
| 6952 | }; | |
| 6953 | } | |
| 6478 | 6954 | } |
| 6479 | 6955 | } |
| 6480 | 6956 | |
| ... | ... | @@ -6610,7 +7086,7 @@ fn flushDynamic(elf: *Elf) void { |
| 6610 | 7086 | dynamic_index += 9; |
| 6611 | 7087 | |
| 6612 | 7088 | assert(dynamic_index == dynamic_entries.len); |
| 6613 | if (elf.targetEndian() != native_endian) for (dynamic_entries) |*dynamic_entry| | |
| 7089 | if (elf.targetEndian() != std.lang.Endian.native) for (dynamic_entries) |*dynamic_entry| | |
| 6614 | 7090 | std.mem.byteSwapAllFields(@TypeOf(dynamic_entry.*), dynamic_entry); |
| 6615 | 7091 | }, |
| 6616 | 7092 | } |
| ... | ... | @@ -6626,6 +7102,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6626 | 7102 | addralign: Alignment = .@"1", |
| 6627 | 7103 | entsize: std.elf.Word = 0, |
| 6628 | 7104 | node_align: Alignment = .@"1", |
| 7105 | manual_size: bool = false, | |
| 6629 | 7106 | }) Error!Section.Index { |
| 6630 | 7107 | switch (opts.type) { |
| 6631 | 7108 | .NULL => assert(opts.size == 0), |
| ... | ... | @@ -6679,6 +7156,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6679 | 7156 | .size = opts.node_align.forward(opts.size), |
| 6680 | 7157 | .alignment = opts.addralign.max(opts.node_align), |
| 6681 | 7158 | .resized = opts.size > 0, |
| 7159 | .bubbles_moved = opts.flags.ALLOC, | |
| 6682 | 7160 | }); |
| 6683 | 7161 | const addr = elf.computeNodeVAddr(ni); |
| 6684 | 7162 | const lsi: Symbol.LocalIndex = if (opts.flags.ALLOC) elf.addLocalSymbolAssumeCapacity(.{ |
| ... | ... | @@ -6694,7 +7172,10 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6694 | 7172 | .RELA => .{ .free_head = .none }, |
| 6695 | 7173 | else => .{ .shndx = .UNDEF }, |
| 6696 | 7174 | } }); |
| 6697 | elf.nodes.appendAssumeCapacity(.{ .section = shndx }); | |
| 7175 | elf.nodes.appendAssumeCapacity(switch (opts.manual_size) { | |
| 7176 | false => .{ .section = shndx }, | |
| 7177 | true => .{ .section_manual_size = shndx }, | |
| 7178 | }); | |
| 6698 | 7179 | switch (elf.shdrPtr(shndx)) { |
| 6699 | 7180 | inline else => |shdr, class| { |
| 6700 | 7181 | shdr.* = .{ |
| ... | ... | @@ -6709,7 +7190,7 @@ fn addSection(elf: *Elf, segment_ni: MappedFile.Node.Index, opts: struct { |
| 6709 | 7190 | .addralign = @intCast(opts.addralign.toByteUnits()), |
| 6710 | 7191 | .entsize = opts.entsize, |
| 6711 | 7192 | }; |
| 6712 | if (elf.targetEndian() != native_endian) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr); | |
| 7193 | if (elf.targetEndian() != std.lang.Endian.native) std.mem.byteSwapAllFields(class.ElfN().Shdr, shdr); | |
| 6713 | 7194 | }, |
| 6714 | 7195 | } |
| 6715 | 7196 | return shndx; |
| ... | ... | @@ -6719,6 +7200,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 6719 | 7200 | if (len == 0) return; |
| 6720 | 7201 | const gpa = elf.base.comp.gpa; |
| 6721 | 7202 | try elf.symbol_relocs.ensureUnusedCapacity(gpa, len); |
| 7203 | try elf.node_relocs.ensureUnusedCapacity(gpa, len); | |
| 6722 | 7204 | try elf.got_relocs.ensureUnusedCapacity(gpa, len); |
| 6723 | 7205 | const class = elf.identClass(); |
| 6724 | 7206 | switch (elf.ehdrType()) { |
| ... | ... | @@ -6749,6 +7231,7 @@ fn ensureUnusedRelocCapacity(elf: *Elf, node: MappedFile.Node.Index, len: usize) |
| 6749 | 7231 | inline else => |ct_class| @sizeOf(ct_class.ElfN().Rela), |
| 6750 | 7232 | }, |
| 6751 | 7233 | .node_align = elf.mf.flags.block_size, |
| 7234 | .manual_size = true, | |
| 6752 | 7235 | }); |
| 6753 | 7236 | elf.section_by_name.putAssumeCapacityNoClobber(rela_shndx.name(elf), {}); |
| 6754 | 7237 | shndx.get(elf).rela.shndx = rela_shndx; |
| ... | ... | @@ -6795,15 +7278,10 @@ fn addRelocAssumeCapacity( |
| 6795 | 7278 | .addend = addend, |
| 6796 | 7279 | }); |
| 6797 | 7280 | const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); |
| 6798 | const next: SymbolReloc.Index = next: { | |
| 6799 | const target_ptr = target.index(elf).ptr(elf); | |
| 6800 | const next = target_ptr.first_target_reloc; | |
| 6801 | target_ptr.first_target_reloc = ri; | |
| 6802 | break :next next; | |
| 6803 | }; | |
| 6804 | if (next != .none) { | |
| 6805 | next.get(elf).prev = ri; | |
| 6806 | } | |
| 7281 | const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc; | |
| 7282 | const next = first_target_reloc.*; | |
| 7283 | first_target_reloc.* = ri; | |
| 7284 | if (next != .none) next.get(elf).prev = ri; | |
| 6807 | 7285 | elf.symbol_relocs.appendAssumeCapacity(.{ |
| 6808 | 7286 | .node = node, |
| 6809 | 7287 | .offset = offset, |
| ... | ... | @@ -6816,7 +7294,6 @@ fn addRelocAssumeCapacity( |
| 6816 | 7294 | .result = .ok, |
| 6817 | 7295 | }); |
| 6818 | 7296 | }, |
| 6819 | ||
| 6820 | 7297 | .DYN, .EXEC => switch (elf.ehdrMachine()) { |
| 6821 | 7298 | .AARCH64 => switch (@"type".AARCH64) { |
| 6822 | 7299 | .NONE => {}, |
| ... | ... | @@ -7239,12 +7716,10 @@ fn addSymbolRelocAssumeCapacity( |
| 7239 | 7716 | }; |
| 7240 | 7717 | |
| 7241 | 7718 | const ri: SymbolReloc.Index = @fromBackingInt(@intCast(elf.symbol_relocs.items.len)); |
| 7242 | const target_ptr = target.index(elf).ptr(elf); | |
| 7243 | const next = target_ptr.first_target_reloc; | |
| 7244 | target_ptr.first_target_reloc = ri; | |
| 7245 | if (next != .none) { | |
| 7246 | next.get(elf).prev = ri; | |
| 7247 | } | |
| 7719 | const first_target_reloc = &target.index(elf).ptr(elf).first_target_reloc; | |
| 7720 | const next = first_target_reloc.*; | |
| 7721 | first_target_reloc.* = ri; | |
| 7722 | if (next != .none) next.get(elf).prev = ri; | |
| 7248 | 7723 | elf.symbol_relocs.appendAssumeCapacity(.{ |
| 7249 | 7724 | .node = node, |
| 7250 | 7725 | .offset = offset, |
| ... | ... | @@ -7263,6 +7738,92 @@ fn addSymbolRelocAssumeCapacity( |
| 7263 | 7738 | // Actually apply the new relocation! |
| 7264 | 7739 | ri.get(elf).apply(elf); |
| 7265 | 7740 | } |
| 7741 | fn addNodeRelocAssumeCapacity( | |
| 7742 | elf: *Elf, | |
| 7743 | node: MappedFile.Node.Index, | |
| 7744 | offset: u64, | |
| 7745 | target: MappedFile.Node.Index, | |
| 7746 | addend: i64, | |
| 7747 | @"type": NodeReloc.Type, | |
| 7748 | ) Error!void { | |
| 7749 | const shndx = elf.getNodeShndx(target); | |
| 7750 | assert(!shndx.flags(elf).ALLOC); // not yet needed so not implemented | |
| 7751 | const first_target_reloc = switch (elf.getNode(target)) { | |
| 7752 | else => unreachable, | |
| 7753 | .unit_frame_cie => |ui| &elf.dwarf_units.items[@backingInt(ui)].unit_frame_cie_first_target_reloc, | |
| 7754 | }; | |
| 7755 | const next = first_target_reloc.*; | |
| 7756 | const ri: NodeReloc.Index = @fromBackingInt(@intCast(elf.node_relocs.items.len)); | |
| 7757 | first_target_reloc.* = ri; | |
| 7758 | if (next != .none) next.get(elf).prev = ri; | |
| 7759 | switch (elf.ehdrType()) { | |
| 7760 | .REL => { | |
| 7761 | const rela_shndx = elf.getNodeShndx(node).get(elf).rela.shndx; | |
| 7762 | const rela_index = rela_shndx.relaAddOneAssumeCapacity(elf, .{ | |
| 7763 | .type = switch (elf.ehdrMachine()) { | |
| 7764 | .AARCH64 => .{ .AARCH64 = switch (@"type") { | |
| 7765 | .abs32 => .ABS32, | |
| 7766 | .abs64 => .ABS64, | |
| 7767 | } }, | |
| 7768 | .LOONGARCH => .{ .LARCH = switch (@"type") { | |
| 7769 | .abs32 => .@"32", | |
| 7770 | .abs64 => .@"64", | |
| 7771 | } }, | |
| 7772 | .PPC64 => .{ .PPC64 = switch (@"type") { | |
| 7773 | .abs32 => .ADDR32, | |
| 7774 | .abs64 => .ADDR64, | |
| 7775 | } }, | |
| 7776 | .RISCV => .{ .RISCV = switch (@"type") { | |
| 7777 | .abs32 => .@"32", | |
| 7778 | .abs64 => .@"64", | |
| 7779 | } }, | |
| 7780 | .SPARCV9 => .{ .SPARC = switch (@"type") { | |
| 7781 | .abs32 => .UA32, | |
| 7782 | .abs64 => .UA64, | |
| 7783 | } }, | |
| 7784 | .X86_64 => .{ .SPARC = switch (@"type") { | |
| 7785 | .abs32 => .@"32", | |
| 7786 | .abs64 => .@"64", | |
| 7787 | } }, | |
| 7788 | }, | |
| 7789 | // This field needs to equal the offset into the section, which is *not* necessarily | |
| 7790 | // the same thing as our `offset`, which is the offset into `node`. We could compute | |
| 7791 | // the section offset now, but there's no point, because `flushMovedNodeRelocs` will | |
| 7792 | // eventually do it for us anyway, so just init to 0. | |
| 7793 | .offset = 0, | |
| 7794 | .raw_sym_index = @backingInt(shndx.get(elf).lsi.index()), | |
| 7795 | .addend = addend, | |
| 7796 | }); | |
| 7797 | elf.node_relocs.appendAssumeCapacity(.{ | |
| 7798 | .node = node, | |
| 7799 | .offset = offset, | |
| 7800 | .type = undefined, | |
| 7801 | .target = target, | |
| 7802 | .addend = addend, | |
| 7803 | .next = next, | |
| 7804 | .prev = .none, | |
| 7805 | .rela_index = rela_index.toOptional(), | |
| 7806 | .result = .ok, | |
| 7807 | }); | |
| 7808 | }, | |
| 7809 | .DYN, .EXEC => { | |
| 7810 | elf.node_relocs.appendAssumeCapacity(.{ | |
| 7811 | .node = node, | |
| 7812 | .offset = offset, | |
| 7813 | .target = target, | |
| 7814 | .addend = addend, | |
| 7815 | .type = @"type", | |
| 7816 | .next = next, | |
| 7817 | .prev = .none, | |
| 7818 | .rela_index = .none, | |
| 7819 | .result = .ok, | |
| 7820 | }); | |
| 7821 | ||
| 7822 | // Actually apply the new relocation! | |
| 7823 | ri.get(elf).apply(elf); | |
| 7824 | }, | |
| 7825 | } | |
| 7826 | } | |
| 7266 | 7827 | fn addGotRelocAssumeCapacity( |
| 7267 | 7828 | elf: *Elf, |
| 7268 | 7829 | node: MappedFile.Node.Index, |
| ... | ... | @@ -7282,8 +7843,17 @@ fn addGotRelocAssumeCapacity( |
| 7282 | 7843 | .shdr, |
| 7283 | 7844 | .segment, |
| 7284 | 7845 | .copied_global, |
| 7846 | .value_debug_info, | |
| 7847 | .global_debug_info, | |
| 7848 | .frame_padding, | |
| 7849 | .unit_frame, | |
| 7850 | .unit_frame_cie, | |
| 7851 | .func_frame_fde, | |
| 7852 | .func_debug_info, | |
| 7853 | .func_debug_line, | |
| 7285 | 7854 | => unreachable, // cannot contain relocs, |
| 7286 | 7855 | .section, |
| 7856 | .section_manual_size, | |
| 7287 | 7857 | .uav, |
| 7288 | 7858 | => unreachable, // cannot contain GOT relocs |
| 7289 | 7859 | .input_section, |
| ... | ... | @@ -7572,7 +8142,6 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 7572 | 8142 | |
| 7573 | 8143 | const nmi = try elf.navMapIndex(zcu, nav_index); |
| 7574 | 8144 | const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?; |
| 7575 | elf.resetNodeRelocs(ni); | |
| 7576 | 8145 | |
| 7577 | 8146 | // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be |
| 7578 | 8147 | // called to apply the NAV's new relocations. |
| ... | ... | @@ -7582,6 +8151,7 @@ fn updateNavInner(elf: *Elf, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) |
| 7582 | 8151 | var nw: MappedFile.Node.Writer = undefined; |
| 7583 | 8152 | ni.writer(&elf.mf, gpa, &nw); |
| 7584 | 8153 | defer nw.deinit(); |
| 8154 | elf.resetNodeRelocs(ni); | |
| 7585 | 8155 | codegen.generateSymbol( |
| 7586 | 8156 | &elf.base, |
| 7587 | 8157 | pt, |
| ... | ... | @@ -7628,7 +8198,6 @@ fn updateFuncInner( |
| 7628 | 8198 | const nmi = try elf.navMapIndex(zcu, func.owner_nav); |
| 7629 | 8199 | log.debug("updateFunc({f}) = {d}", .{ nav.fqn.fmt(ip), nmi.symbol(elf) }); |
| 7630 | 8200 | const ni = nmi.symbol(elf).index().ptr(elf).node.unwrap().?; |
| 7631 | elf.resetNodeRelocs(ni); | |
| 7632 | 8201 | |
| 7633 | 8202 | // Ensure the NAV is marked as moved so that once we're done, `flushMoved` will eventually be |
| 7634 | 8203 | // called to apply the NAV's new relocations. |
| ... | ... | @@ -7638,6 +8207,132 @@ fn updateFuncInner( |
| 7638 | 8207 | var nw: MappedFile.Node.Writer = undefined; |
| 7639 | 8208 | ni.writer(&elf.mf, gpa, &nw); |
| 7640 | 8209 | defer nw.deinit(); |
| 8210 | var debug: Dwarf.WipNav.Debug = undefined; | |
| 8211 | const debug_output: link.File.DebugInfoOutput = debug_output: { | |
| 8212 | if (elf.ehdrMachine() != .X86_64) break :debug_output .none; | |
| 8213 | const dwarf = &elf.dwarf; | |
| 8214 | const mod = zcu.navFileScope(func.owner_nav).mod.?; | |
| 8215 | if (mod.strip and mod.unwind_tables == .none) break :debug_output .none; | |
| 8216 | ||
| 8217 | try elf.nodes.ensureUnusedCapacity(gpa, 5); | |
| 8218 | const dwarf_func_index = try dwarf.getFunc(func.owner_nav); | |
| 8219 | try elf.dwarf_funcs.appendNTimes(gpa, .{ | |
| 8220 | .func_frame_fde_first_symbol_reloc = .none, | |
| 8221 | .func_frame_fde_first_node_reloc = .none, | |
| 8222 | }, @backingInt(dwarf_func_index) + 1 -| elf.dwarf_funcs.items.len); | |
| 8223 | ||
| 8224 | debug.wip_nav = .{ | |
| 8225 | .dwarf = dwarf, | |
| 8226 | .unit = dwarf.getUnit(mod), | |
| 8227 | .func = dwarf_func_index, | |
| 8228 | .func_si = Symbol.Id.local(nmi.symbol(elf)).toTypeErased(), | |
| 8229 | .cfi = .{ | |
| 8230 | .loc = 0, | |
| 8231 | .cfa = dwarf.frame.header.initial_instructions[0].def_cfa, | |
| 8232 | }, | |
| 8233 | .frame_format = switch (mod.unwind_tables) { | |
| 8234 | .none => .debug_frame, | |
| 8235 | .sync, .async => .eh_frame, | |
| 8236 | }, | |
| 8237 | .fde_writer = undefined, | |
| 8238 | .frame_func_length_offset = std.math.maxInt(usize), | |
| 8239 | }; | |
| 8240 | const unit = debug.wip_nav.unit.get(dwarf); | |
| 8241 | const frame_align: Alignment = switch (elf.identClass()) { | |
| 8242 | .NONE, _ => unreachable, | |
| 8243 | .@"32" => .@"4", | |
| 8244 | .@"64" => .@"8", | |
| 8245 | }; | |
| 8246 | const frame_ni = unit.frame_ni.unwrap() orelse frame_ni: { | |
| 8247 | const frame_ni = try switch (debug.wip_nav.frame_format) { | |
| 8248 | .debug_frame => elf.shndx.debug_frame, | |
| 8249 | .eh_frame => elf.shndx.eh_frame, | |
| 8250 | }.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ | |
| 8251 | .alignment = frame_align.max(elf.mf.flags.block_size), | |
| 8252 | .next_moved = true, | |
| 8253 | .enable_next_moved = true, | |
| 8254 | }); | |
| 8255 | unit.frame_ni = .wrap(frame_ni); | |
| 8256 | elf.nodes.appendAssumeCapacity(.{ .unit_frame = debug.wip_nav.unit }); | |
| 8257 | break :frame_ni frame_ni; | |
| 8258 | }; | |
| 8259 | _ = unit.cie_ni.unwrap() orelse { | |
| 8260 | const cie_ni = try frame_ni.addOnlyHeaderChild(&elf.mf, gpa, .{ | |
| 8261 | .alignment = frame_align, | |
| 8262 | .next_moved = true, | |
| 8263 | .enable_next_moved = true, | |
| 8264 | }); | |
| 8265 | unit.cie_ni = .wrap(cie_ni); | |
| 8266 | elf.nodes.appendAssumeCapacity(.{ .unit_frame_cie = debug.wip_nav.unit }); | |
| 8267 | var cie_writer: MappedFile.Node.Writer = undefined; | |
| 8268 | cie_ni.writer(&elf.mf, gpa, &cie_writer); | |
| 8269 | defer cie_writer.deinit(); | |
| 8270 | dwarf.genDebugFrameCie(&cie_writer.interface, switch (elf.ehdrMachine()) { | |
| 8271 | else => unreachable, | |
| 8272 | .X86_64 => .x86_64, | |
| 8273 | }, debug.wip_nav.frame_format) catch |err| switch (err) { | |
| 8274 | error.WriteFailed => return cie_writer.err.?, | |
| 8275 | }; | |
| 8276 | @memset(cie_writer.interface.unusedCapacitySlice(), std.dwarf.CFA.nop); | |
| 8277 | }; | |
| 8278 | const dwarf_func = dwarf_func_index.get(dwarf); | |
| 8279 | const fde_ni = if (dwarf_func.fde_ni.unwrap()) |fde_ni| fde_ni: { | |
| 8280 | try fde_ni.moved(gpa, &elf.mf); | |
| 8281 | try fde_ni.nextMoved(gpa, &elf.mf); | |
| 8282 | break :fde_ni fde_ni; | |
| 8283 | } else fde_ni: { | |
| 8284 | const fde_ni = try frame_ni.addFloatingChild(&elf.mf, gpa, .{ | |
| 8285 | .alignment = frame_align, | |
| 8286 | .moved = true, | |
| 8287 | .next_moved = true, | |
| 8288 | .enable_next_moved = true, | |
| 8289 | }); | |
| 8290 | dwarf_func.fde_ni = .wrap(fde_ni); | |
| 8291 | break :fde_ni fde_ni; | |
| 8292 | }; | |
| 8293 | fde_ni.writer(&elf.mf, gpa, &debug.wip_nav.fde_writer); | |
| 8294 | if (mod.strip) break :debug_output .{ .eh_frame = &debug.wip_nav }; | |
| 8295 | ||
| 8296 | debug.pt = pt; | |
| 8297 | debug.any_children = false; | |
| 8298 | debug.blocks = .empty; | |
| 8299 | const debug_info_ni = dwarf_func.debug_info_ni.unwrap() orelse debug_info_ni: { | |
| 8300 | const debug_info_ni = | |
| 8301 | try elf.shndx.debug_info.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ | |
| 8302 | .next_moved = true, | |
| 8303 | .enable_next_moved = true, | |
| 8304 | }); | |
| 8305 | dwarf_func.debug_info_ni = .wrap(debug_info_ni); | |
| 8306 | elf.nodes.appendAssumeCapacity(.{ .func_debug_info = dwarf_func_index }); | |
| 8307 | break :debug_info_ni debug_info_ni; | |
| 8308 | }; | |
| 8309 | debug_info_ni.writer(&elf.mf, gpa, &debug.info_writer); | |
| 8310 | const debug_line_ni = dwarf_func.debug_line_ni.unwrap() orelse debug_line_ni: { | |
| 8311 | const debug_line_ni = | |
| 8312 | try elf.shndx.debug_line.get(elf).ni.addFloatingChild(&elf.mf, gpa, .{ | |
| 8313 | .next_moved = true, | |
| 8314 | .enable_next_moved = true, | |
| 8315 | }); | |
| 8316 | elf.nodes.appendAssumeCapacity(.{ .func_debug_line = dwarf_func_index }); | |
| 8317 | break :debug_line_ni debug_line_ni; | |
| 8318 | }; | |
| 8319 | debug_line_ni.writer(&elf.mf, gpa, &debug.line_writer); | |
| 8320 | break :debug_output .{ .dwarf2 = &debug }; | |
| 8321 | }; | |
| 8322 | defer switch (debug_output) { | |
| 8323 | .dwarf => unreachable, | |
| 8324 | inline .eh_frame, .dwarf2 => |dwarf| dwarf.deinit(gpa), | |
| 8325 | .none => {}, | |
| 8326 | }; | |
| 8327 | switch (debug_output) { | |
| 8328 | .dwarf => unreachable, | |
| 8329 | inline .eh_frame, .dwarf2 => |dwarf| { | |
| 8330 | elf.resetNodeRelocs(debug.wip_nav.func.?.get(&elf.dwarf).fde_ni.unwrap().?); | |
| 8331 | try dwarf.genFuncHeaders(); | |
| 8332 | }, | |
| 8333 | .none => {}, | |
| 8334 | } | |
| 8335 | elf.resetNodeRelocs(ni); | |
| 7641 | 8336 | codegen.emitFunction( |
| 7642 | 8337 | &elf.base, |
| 7643 | 8338 | pt, |
| ... | ... | @@ -7645,13 +8340,35 @@ fn updateFuncInner( |
| 7645 | 8340 | Node.toAtom(ni), |
| 7646 | 8341 | mir, |
| 7647 | 8342 | &nw.interface, |
| 7648 | .none, | |
| 8343 | debug_output, | |
| 7649 | 8344 | ) catch |err| switch (err) { |
| 7650 | 8345 | error.WriteFailed => return nw.err.?, |
| 7651 | 8346 | else => |e| return e, |
| 7652 | 8347 | }; |
| 8348 | const func_length = nw.interface.end; | |
| 8349 | switch (debug_output) { | |
| 8350 | .dwarf => unreachable, | |
| 8351 | .eh_frame, .dwarf2 => { | |
| 8352 | debug.wip_nav.finishDebugFrameFde(func_length); | |
| 8353 | const frame_ni = switch (debug.wip_nav.frame_format) { | |
| 8354 | .debug_frame => elf.shndx.debug_frame, | |
| 8355 | .eh_frame => elf.shndx.eh_frame, | |
| 8356 | }.get(elf).ni; | |
| 8357 | try frame_ni.trimStart(&elf.mf, elf.base.comp.gpa); | |
| 8358 | switch (debug.wip_nav.frame_format) { | |
| 8359 | .debug_frame => {}, | |
| 8360 | .eh_frame => { | |
| 8361 | const last_offset, const last_size = | |
| 8362 | frame_ni.last(&elf.mf).unwrap().?.location(&elf.mf).resolve(&elf.mf); | |
| 8363 | const last_end = last_offset + last_size; | |
| 8364 | try frame_ni.ensureMinimumSize(&elf.mf, elf.base.comp.gpa, last_end + 4); | |
| 8365 | }, | |
| 8366 | } | |
| 8367 | }, | |
| 8368 | .none => {}, | |
| 8369 | } | |
| 7653 | 8370 | switch (elf.symPtr(nmi.symbol(elf).index())) { |
| 7654 | inline else => |sym| elf.targetStore(&sym.size, @intCast(nw.interface.end)), | |
| 8371 | inline else => |sym| elf.targetStore(&sym.size, @intCast(func_length)), | |
| 7655 | 8372 | } |
| 7656 | 8373 | } |
| 7657 | 8374 | |
| ... | ... | @@ -7915,11 +8632,11 @@ fn idleProgNode( |
| 7915 | 8632 | var name: [std.Progress.Node.max_name_len]u8 = undefined; |
| 7916 | 8633 | return prog_node.start(name: switch (node) { |
| 7917 | 8634 | else => |tag| @tagName(tag), |
| 7918 | .section => |shndx| shndx.name(elf).slice(elf), | |
| 7919 | 8635 | .archive_input_member => |ii| std.mem.print(&name, "{f}{f}", .{ |
| 7920 | 8636 | ii.path(elf).fmtEscapeString(), |
| 7921 | 8637 | fmtMemberString(ii.member(elf)), |
| 7922 | 8638 | }) catch &name, |
| 8639 | .section, .section_manual_size => |shndx| shndx.name(elf).slice(elf), | |
| 7923 | 8640 | .input_section => |isi| { |
| 7924 | 8641 | const ii = isi.input(elf); |
| 7925 | 8642 | break :name std.mem.print(&name, "{f}{f} {s}", .{ |
| ... | ... | @@ -7935,6 +8652,31 @@ fn idleProgNode( |
| 7935 | 8652 | .uav => |umi| std.mem.print(&name, "{f}", .{ |
| 7936 | 8653 | Value.fromInterned(umi.uavValue(elf)).fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), |
| 7937 | 8654 | }) catch &name, |
| 8655 | .value_debug_info => |cpi| std.mem.print(&name, "debug info for {f}", .{ | |
| 8656 | Value.fromInterned(cpi.val(&elf.dwarf.const_pool)) | |
| 8657 | .fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), | |
| 8658 | }) catch &name, | |
| 8659 | .global_debug_info => |gi| { | |
| 8660 | const ip = &elf.base.comp.zcu.?.intern_pool; | |
| 8661 | break :name std.mem.print(&name, "debug info for {f}", .{ | |
| 8662 | ip.getNav(gi.nav(&elf.dwarf)).fqn.fmt(ip), | |
| 8663 | }) catch &name; | |
| 8664 | }, | |
| 8665 | .unit_frame, .unit_frame_cie => |ui| std.mem.print(&name, "unwind info for {s}", .{ | |
| 8666 | ui.mod(&elf.dwarf).fully_qualified_name, | |
| 8667 | }) catch &name, | |
| 8668 | .func_frame_fde, .func_debug_info, .func_debug_line => |fi, tag| { | |
| 8669 | const ip = &elf.base.comp.zcu.?.intern_pool; | |
| 8670 | break :name std.mem.print(&name, "{s} info for {f}", .{ | |
| 8671 | switch (tag) { | |
| 8672 | else => unreachable, | |
| 8673 | .func_frame_fde => "unwind", | |
| 8674 | .func_debug_info => "debug", | |
| 8675 | .func_debug_line => "line", | |
| 8676 | }, | |
| 8677 | ip.getNav(fi.nav(&elf.dwarf)).fqn.fmt(ip), | |
| 8678 | }) catch &name; | |
| 8679 | }, | |
| 7938 | 8680 | }, 0); |
| 7939 | 8681 | } |
| 7940 | 8682 | |
| ... | ... | @@ -7984,11 +8726,11 @@ fn genUav( |
| 7984 | 8726 | |
| 7985 | 8727 | const uav_val = umi.uavValue(elf); |
| 7986 | 8728 | const ni = umi.symbol(elf).index().ptr(elf).node.unwrap().?; |
| 7987 | elf.resetNodeRelocs(ni); | |
| 7988 | 8729 | |
| 7989 | 8730 | var nw: MappedFile.Node.Writer = undefined; |
| 7990 | 8731 | ni.writer(&elf.mf, gpa, &nw); |
| 7991 | 8732 | defer nw.deinit(); |
| 8733 | elf.resetNodeRelocs(ni); | |
| 7992 | 8734 | codegen.generateSymbol( |
| 7993 | 8735 | &elf.base, |
| 7994 | 8736 | pt, |
| ... | ... | @@ -8013,7 +8755,6 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { |
| 8013 | 8755 | |
| 8014 | 8756 | const lazy = lmr.lazySymbol(elf); |
| 8015 | 8757 | const ni = lmr.symbol(elf).index().ptr(elf).node.unwrap().?; |
| 8016 | elf.resetNodeRelocs(ni); | |
| 8017 | 8758 | |
| 8018 | 8759 | // Ensure the lazy node is marked as moved so that once we're done, `flushMoved` will eventually |
| 8019 | 8760 | // be called to apply the lazy node's new relocations. |
| ... | ... | @@ -8023,6 +8764,7 @@ fn genLazy(elf: *Elf, pt: Zcu.PerThread, lmr: Node.LazyMapRef) Error!void { |
| 8023 | 8764 | var nw: MappedFile.Node.Writer = undefined; |
| 8024 | 8765 | ni.writer(&elf.mf, gpa, &nw); |
| 8025 | 8766 | defer nw.deinit(); |
| 8767 | elf.resetNodeRelocs(ni); | |
| 8026 | 8768 | codegen.generateLazySymbol( |
| 8027 | 8769 | &elf.base, |
| 8028 | 8770 | pt, |
| ... | ... | @@ -8155,7 +8897,7 @@ fn flushElfOffset(elf: *Elf, ni: MappedFile.Node.Index) void { |
| 8155 | 8897 | elf.flushElfOffset(child_ni); |
| 8156 | 8898 | } |
| 8157 | 8899 | }, |
| 8158 | .section => |shndx| switch (elf.shdrPtr(shndx)) { | |
| 8900 | .section, .section_manual_size => |shndx| switch (elf.shdrPtr(shndx)) { | |
| 8159 | 8901 | inline else => |shdr| elf.targetStore(&shdr.offset, @intCast(elf_offset)), |
| 8160 | 8902 | }, |
| 8161 | 8903 | } |
| ... | ... | @@ -8194,6 +8936,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 8194 | 8936 | .INTERP, |
| 8195 | 8937 | .PHDR, |
| 8196 | 8938 | .TLS, |
| 8939 | .GNU_EH_FRAME, | |
| 8197 | 8940 | .GNU_RELRO, |
| 8198 | 8941 | => { |
| 8199 | 8942 | const new_vaddr = elf.computeNodeVAddr(ni); |
| ... | ... | @@ -8204,14 +8947,11 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 8204 | 8947 | }, |
| 8205 | 8948 | } |
| 8206 | 8949 | }, |
| 8207 | .section => |shndx| { | |
| 8950 | .section, .section_manual_size => |shndx| { | |
| 8208 | 8951 | elf.flushElfOffset(ni); |
| 8209 | 8952 | const addr = elf.computeNodeVAddr(ni); |
| 8210 | 8953 | const old_addr: u64, const flags: std.elf.SHF = switch (elf.shdrPtr(shndx)) { |
| 8211 | inline else => |shdr| .{ | |
| 8212 | elf.targetLoad(&shdr.addr), | |
| 8213 | elf.targetLoad(&shdr.flags).shf, | |
| 8214 | }, | |
| 8954 | inline else => |shdr| .{ elf.targetLoad(&shdr.addr), elf.targetLoad(&shdr.flags).shf }, | |
| 8215 | 8955 | }; |
| 8216 | 8956 | |
| 8217 | 8957 | if (flags.ALLOC) { |
| ... | ... | @@ -8225,10 +8965,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 8225 | 8965 | var name = first_name; |
| 8226 | 8966 | while (name != .empty) { |
| 8227 | 8967 | const old_sym_addr = Symbol.Id.global(name).value(elf); |
| 8228 | Symbol.Id.global(name).flushMoved( | |
| 8229 | elf, | |
| 8230 | old_sym_addr - old_addr + addr, | |
| 8231 | ); | |
| 8968 | Symbol.Id.global(name).flushMoved(elf, old_sym_addr - old_addr + addr); | |
| 8232 | 8969 | name = elf.globalByName(name).?.next_in_node; |
| 8233 | 8970 | } |
| 8234 | 8971 | } |
| ... | ... | @@ -8246,12 +8983,14 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 8246 | 8983 | reloc.apply(elf); |
| 8247 | 8984 | } |
| 8248 | 8985 | } else if (shndx == elf.shndx.plt) { |
| 8249 | elf.flushMovedNodeRelocs(ni, addr, elf.plt_first_symbol_reloc, .none); | |
| 8986 | elf.flushMovedNodeRelocs(ni, addr, elf.plt_first_symbol_reloc, .none, .none); | |
| 8250 | 8987 | elf.flushMovedPltSection(.plt, old_addr, addr); |
| 8251 | 8988 | } else if (shndx == elf.shndx.got_plt) { |
| 8252 | 8989 | elf.flushMovedPltSection(.got_plt, old_addr, addr); |
| 8253 | 8990 | } else if (shndx == elf.shndx.plt_sec) { |
| 8254 | 8991 | elf.flushMovedPltSection(.plt_sec, old_addr, addr); |
| 8992 | } else if (shndx == elf.shndx.eh_frame_hdr) { | |
| 8993 | elf.flushMovedNodeRelocs(ni, addr, elf.eh_frame_hdr_first_symbol_reloc, .none, .none); | |
| 8255 | 8994 | } |
| 8256 | 8995 | }, |
| 8257 | 8996 | .input_section => |isi| { |
| ... | ... | @@ -8302,6 +9041,7 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 8302 | 9041 | ni, |
| 8303 | 9042 | new_section_addr, |
| 8304 | 9043 | isi.ptrConst(elf).first_symbol_reloc, |
| 9044 | .none, | |
| 8305 | 9045 | isi.ptrConst(elf).first_got_reloc, |
| 8306 | 9046 | ); |
| 8307 | 9047 | }, |
| ... | ... | @@ -8329,13 +9069,45 @@ fn flushMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!void |
| 8329 | 9069 | name = elf.globalByName(name).?.next_in_node; |
| 8330 | 9070 | } |
| 8331 | 9071 | } |
| 9072 | elf.flushMovedNodeRelocs(ni, new_addr, mi.firstSymbolReloc(elf), .none, mi.firstGotReloc(elf)); | |
| 9073 | }, | |
| 9074 | .value_debug_info, | |
| 9075 | .global_debug_info, | |
| 9076 | .frame_padding, | |
| 9077 | .unit_frame, | |
| 9078 | => {}, | |
| 9079 | .unit_frame_cie => |ui| { | |
| 9080 | const dwarf_unit = &elf.dwarf_units.items[@backingInt(ui)]; | |
| 9081 | var target_ri = dwarf_unit.unit_frame_cie_first_target_reloc; | |
| 9082 | while (target_ri != .none) { | |
| 9083 | const target_reloc = target_ri.get(elf); | |
| 9084 | assert(target_reloc.target == ni); | |
| 9085 | target_reloc.apply(elf); | |
| 9086 | target_ri = target_reloc.next; | |
| 9087 | } | |
| 9088 | }, | |
| 9089 | .func_frame_fde => |fi| { | |
| 9090 | const new_addr = elf.computeNodeVAddr(ni); | |
| 9091 | const dwarf_func = &elf.dwarf_funcs.items[@backingInt(fi)]; | |
| 9092 | const mod = elf.base.comp.zcu.?.navFileScope(fi.nav(&elf.dwarf)).mod.?; | |
| 9093 | switch (mod.unwind_tables) { | |
| 9094 | .none => {}, | |
| 9095 | .sync, .async => { | |
| 9096 | const offset, _ = ni.location(&elf.mf).resolve(&elf.mf); | |
| 9097 | elf.dwarf.updateEhFrameFde(ni.slice(&elf.mf), offset); | |
| 9098 | }, | |
| 9099 | } | |
| 8332 | 9100 | elf.flushMovedNodeRelocs( |
| 8333 | 9101 | ni, |
| 8334 | 9102 | new_addr, |
| 8335 | mi.firstSymbolReloc(elf), | |
| 8336 | mi.firstGotReloc(elf), | |
| 9103 | dwarf_func.func_frame_fde_first_symbol_reloc, | |
| 9104 | dwarf_func.func_frame_fde_first_node_reloc, | |
| 9105 | .none, | |
| 8337 | 9106 | ); |
| 8338 | 9107 | }, |
| 9108 | .func_debug_info, | |
| 9109 | .func_debug_line, | |
| 9110 | => {}, | |
| 8339 | 9111 | } |
| 8340 | 9112 | try ni.childrenMoved(elf.base.comp.gpa, &elf.mf); |
| 8341 | 9113 | } |
| ... | ... | @@ -8523,7 +9295,7 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 8523 | 9295 | elf.targetStore(&ph.type, if (size > 0) .LOAD else .NULL); |
| 8524 | 9296 | try elf.allocateSegmentLoadAddress(phndx); |
| 8525 | 9297 | }, |
| 8526 | .DYNAMIC, .INTERP, .PHDR, std.elf.PT.GNU_RELRO => { | |
| 9298 | .DYNAMIC, .INTERP, .PHDR, .GNU_EH_FRAME, .GNU_RELRO => { | |
| 8527 | 9299 | elf.targetStore(&ph.memsz, @intCast(size)); |
| 8528 | 9300 | }, |
| 8529 | 9301 | .TLS => { |
| ... | ... | @@ -8558,31 +9330,29 @@ fn flushResized(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error!vo |
| 8558 | 9330 | inline else => |shdr| { |
| 8559 | 9331 | switch (elf.targetLoad(&shdr.type)) { |
| 8560 | 9332 | else => unreachable, |
| 8561 | ||
| 8562 | 9333 | .NULL => if (size > 0) elf.targetStore(&shdr.type, .PROGBITS), |
| 8563 | 9334 | .PROGBITS => if (size == 0) elf.targetStore(&shdr.type, .NULL), |
| 8564 | ||
| 8565 | .INIT_ARRAY, | |
| 8566 | .FINI_ARRAY, | |
| 8567 | .PREINIT_ARRAY, | |
| 8568 | .STRTAB, | |
| 8569 | .SYMTAB, | |
| 8570 | .DYNAMIC, | |
| 8571 | .REL, | |
| 8572 | .RELA, | |
| 8573 | .DYNSYM, | |
| 8574 | .HASH, | |
| 8575 | => return, | |
| 8576 | } | |
| 8577 | if (shndx != elf.shndx.plt and | |
| 8578 | shndx != elf.shndx.got and | |
| 8579 | shndx != elf.shndx.got_plt) | |
| 8580 | { | |
| 8581 | elf.targetStore(&shdr.size, @intCast(size)); | |
| 9335 | .X86_64_UNWIND => {}, | |
| 8582 | 9336 | } |
| 9337 | elf.targetStore(&shdr.size, @intCast(size)); | |
| 8583 | 9338 | }, |
| 8584 | 9339 | }, |
| 8585 | .input_section, .copied_global, .nav, .uav, .lazy_code, .lazy_const_data => {}, | |
| 9340 | .section_manual_size, | |
| 9341 | .input_section, | |
| 9342 | .copied_global, | |
| 9343 | .nav, | |
| 9344 | .uav, | |
| 9345 | .lazy_code, | |
| 9346 | .lazy_const_data, | |
| 9347 | .value_debug_info, | |
| 9348 | .global_debug_info, | |
| 9349 | .frame_padding, | |
| 9350 | .unit_frame, | |
| 9351 | .unit_frame_cie, | |
| 9352 | .func_frame_fde, | |
| 9353 | .func_debug_info, | |
| 9354 | .func_debug_line, | |
| 9355 | => {}, | |
| 8586 | 9356 | } |
| 8587 | 9357 | } |
| 8588 | 9358 | |
| ... | ... | @@ -8599,6 +9369,7 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! |
| 8599 | 9369 | .shdr, |
| 8600 | 9370 | .segment, |
| 8601 | 9371 | .section, |
| 9372 | .section_manual_size, | |
| 8602 | 9373 | .input_section, |
| 8603 | 9374 | .copied_global, |
| 8604 | 9375 | .nav, |
| ... | ... | @@ -8633,6 +9404,66 @@ fn flushNextMoved(elf: *Elf, ni: MappedFile.Node.Index) std.mem.Allocator.Error! |
| 8633 | 9404 | error.NoSpaceLeft => archive.strtab_member_too_big = true, |
| 8634 | 9405 | } |
| 8635 | 9406 | }, |
| 9407 | .value_debug_info, | |
| 9408 | .global_debug_info, | |
| 9409 | => {}, | |
| 9410 | .frame_padding, .unit_frame_cie, .func_frame_fde => |_, tag| { | |
| 9411 | const offset, const size = ni.location(&elf.mf).resolve(&elf.mf); | |
| 9412 | const slice = slice: { | |
| 9413 | const parent_ni = ni.parent(&elf.mf).unwrap().?; | |
| 9414 | if (ni.next(&elf.mf).unwrap()) |next_ni| { | |
| 9415 | const parent_slice = parent_ni.slicePadding(&elf.mf); | |
| 9416 | const next_offset, _ = next_ni.location(&elf.mf).resolve(&elf.mf); | |
| 9417 | break :slice parent_slice[@intCast(offset)..@intCast(next_offset)]; | |
| 9418 | } else switch (tag) { | |
| 9419 | else => unreachable, | |
| 9420 | .frame_padding => { | |
| 9421 | const frame_slice = parent_ni.slicePadding(&elf.mf); | |
| 9422 | switch (elf.getNode(parent_ni).section.debugFrameFormat(elf).?) { | |
| 9423 | .eh_frame => { | |
| 9424 | const end = frame_slice.len - 4; | |
| 9425 | std.mem.writeInt(u32, frame_slice[end..][0..4], 0, elf.dwarf.endian); | |
| 9426 | break :slice frame_slice[@intCast(offset)..end]; | |
| 9427 | }, | |
| 9428 | .debug_frame => break :slice frame_slice[@intCast(offset)..], | |
| 9429 | } | |
| 9430 | }, | |
| 9431 | .unit_frame_cie, .func_frame_fde => { | |
| 9432 | const parent_offset, _ = parent_ni.location(&elf.mf).resolve(&elf.mf); | |
| 9433 | const frame_ni = parent_ni.parent(&elf.mf).unwrap().?; | |
| 9434 | const frame_slice = frame_ni.slicePadding(&elf.mf); | |
| 9435 | const format = elf.getNode(frame_ni).section.debugFrameFormat(elf).?; | |
| 9436 | const slice = frame_slice[@intCast(parent_offset + offset)..if (parent_ni.next(&elf.mf).unwrap()) |parent_next_ni| frame_end: { | |
| 9437 | const parent_next_offset, _ = parent_next_ni.location(&elf.mf).resolve(&elf.mf); | |
| 9438 | break :frame_end @intCast(parent_next_offset); | |
| 9439 | } else frame_end: switch (format) { | |
| 9440 | .eh_frame => { | |
| 9441 | const frame_end = frame_slice.len - 4; | |
| 9442 | std.mem.writeInt(u32, frame_slice[frame_end..][0..4], 0, elf.dwarf.endian); | |
| 9443 | break :frame_end frame_end; | |
| 9444 | }, | |
| 9445 | .debug_frame => frame_slice.len, | |
| 9446 | }]; | |
| 9447 | var fw: std.Io.Writer = .fixed(slice[@intCast(size)..]); | |
| 9448 | elf.dwarf.genDebugFrameCie(&fw, null, format) catch |err| switch (err) { | |
| 9449 | error.WriteFailed => break :slice slice, | |
| 9450 | }; | |
| 9451 | elf.dwarf.updateUnitLength(fw.buffer, fw.buffer.len); | |
| 9452 | break :slice slice[0..@intCast(size)]; | |
| 9453 | }, | |
| 9454 | } | |
| 9455 | }; | |
| 9456 | elf.dwarf.updateUnitLength(slice, slice.len); | |
| 9457 | switch (tag) { | |
| 9458 | else => unreachable, | |
| 9459 | .frame_padding => {}, | |
| 9460 | .unit_frame_cie, .func_frame_fde => @memset(slice[@intCast(size)..], std.dwarf.CFA.nop), | |
| 9461 | } | |
| 9462 | }, | |
| 9463 | .unit_frame, | |
| 9464 | .func_debug_info, | |
| 9465 | .func_debug_line, | |
| 9466 | => {}, | |
| 8636 | 9467 | } |
| 8637 | 9468 | } |
| 8638 | 9469 | |
| ... | ... | @@ -9118,7 +9949,7 @@ pub fn printNode( |
| 9118 | 9949 | try w.writeByte(')'); |
| 9119 | 9950 | }, |
| 9120 | 9951 | }, |
| 9121 | .section => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}), | |
| 9952 | .section, .section_manual_size => |shndx| try w.print("({s})", .{shndx.name(elf).slice(elf)}), | |
| 9122 | 9953 | .input_section => |isi| { |
| 9123 | 9954 | const ii = isi.input(elf); |
| 9124 | 9955 | try w.print("({f}{f}, {s})", .{ |
| ... | ... | @@ -9151,6 +9982,31 @@ pub fn printNode( |
| 9151 | 9982 | .tid = tid, |
| 9152 | 9983 | }), |
| 9153 | 9984 | }), |
| 9985 | .value_debug_info => |cpi| try w.print("({f})", .{ | |
| 9986 | Value.fromInterned(cpi.val(&elf.dwarf.const_pool)) | |
| 9987 | .fmtValue(.{ .zcu = elf.base.comp.zcu.?, .tid = tid }), | |
| 9988 | }), | |
| 9989 | .global_debug_info => |gi| { | |
| 9990 | const zcu = elf.base.comp.zcu.?; | |
| 9991 | const ip = &zcu.intern_pool; | |
| 9992 | const nav = ip.getNav(gi.nav(&elf.dwarf)); | |
| 9993 | try w.print("({f}, {f})", .{ | |
| 9994 | Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }), | |
| 9995 | nav.fqn.fmt(ip), | |
| 9996 | }); | |
| 9997 | }, | |
| 9998 | .unit_frame, .unit_frame_cie => |ui| try w.print("({s})", .{ | |
| 9999 | ui.mod(&elf.dwarf).fully_qualified_name, | |
| 10000 | }), | |
| 10001 | .func_frame_fde, .func_debug_info, .func_debug_line => |fi| { | |
| 10002 | const zcu = elf.base.comp.zcu.?; | |
| 10003 | const ip = &zcu.intern_pool; | |
| 10004 | const nav = ip.getNav(fi.nav(&elf.dwarf)); | |
| 10005 | try w.print("({f}, {f})", .{ | |
| 10006 | Type.fromInterned(ip.typeOf(nav.resolved.?.value)).fmt(.{ .zcu = zcu, .tid = tid }), | |
| 10007 | nav.fqn.fmt(ip), | |
| 10008 | }); | |
| 10009 | }, | |
| 9154 | 10010 | } |
| 9155 | 10011 | { |
| 9156 | 10012 | const mf_node = &elf.mf.nodes.items[@backingInt(ni)]; |
src/link/MachO/ZigObject.zig+11-16| ... | ... | @@ -647,14 +647,11 @@ pub fn getNavVAddr( |
| 647 | 647 | }, |
| 648 | 648 | }); |
| 649 | 649 | }, |
| 650 | .debug_output => |debug_output| switch (debug_output) { | |
| 651 | .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ | |
| 652 | .source_off = @intCast(reloc_info.offset), | |
| 653 | .target_sym = @fromBackingInt(@intCast(sym_index)), | |
| 654 | .target_off = reloc_info.addend, | |
| 655 | }), | |
| 656 | .none => unreachable, | |
| 657 | }, | |
| 650 | .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{ | |
| 651 | .source_off = @intCast(reloc_info.offset), | |
| 652 | .target_sym = @fromBackingInt(@intCast(sym_index)), | |
| 653 | .target_off = reloc_info.addend, | |
| 654 | }), | |
| 658 | 655 | } |
| 659 | 656 | return vaddr; |
| 660 | 657 | } |
| ... | ... | @@ -686,14 +683,11 @@ pub fn getUavVAddr( |
| 686 | 683 | }, |
| 687 | 684 | }); |
| 688 | 685 | }, |
| 689 | .debug_output => |debug_output| switch (debug_output) { | |
| 690 | .dwarf => |wip_nav| try wip_nav.infoExternalReloc(.{ | |
| 691 | .source_off = @intCast(reloc_info.offset), | |
| 692 | .target_sym = @fromBackingInt(@intCast(sym_index)), | |
| 693 | .target_off = reloc_info.addend, | |
| 694 | }), | |
| 695 | .none => unreachable, | |
| 696 | }, | |
| 686 | .debug_output => |debug_output| try debug_output.dwarf.infoExternalReloc(.{ | |
| 687 | .source_off = @intCast(reloc_info.offset), | |
| 688 | .target_sym = @fromBackingInt(@intCast(sym_index)), | |
| 689 | .target_off = reloc_info.addend, | |
| 690 | }), | |
| 697 | 691 | } |
| 698 | 692 | return vaddr; |
| 699 | 693 | } |
| ... | ... | @@ -796,6 +790,7 @@ pub fn updateFunc( |
| 796 | 790 | if (debug_wip_nav) |*wip_nav| .{ .dwarf = wip_nav } else .none, |
| 797 | 791 | ) catch |err| switch (err) { |
| 798 | 792 | error.WriteFailed => return error.OutOfMemory, |
| 793 | error.MappedFileIo => unreachable, // MappedFile is not being used | |
| 799 | 794 | else => |e| return e, |
| 800 | 795 | }; |
| 801 | 796 | const code = aw.written(); |
src/link/MappedFile.zig+22| ... | ... | @@ -636,11 +636,33 @@ pub const Node = extern struct { |
| 636 | 636 | return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; |
| 637 | 637 | } |
| 638 | 638 | |
| 639 | pub fn slicePadding(ni: Node.Index, mf: *const MappedFile) []u8 { | |
| 640 | const file_loc = ni.fileLocation(mf, false); | |
| 641 | return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; | |
| 642 | } | |
| 643 | ||
| 639 | 644 | pub fn sliceConst(ni: Node.Index, mf: *const MappedFile) []const u8 { |
| 640 | 645 | const file_loc = ni.fileLocation(mf, false); |
| 641 | 646 | return mf.memory_map.memory[@intCast(file_loc.offset)..][0..@intCast(file_loc.size)]; |
| 642 | 647 | } |
| 643 | 648 | |
| 649 | pub fn trimStart(ni: Node.Index, mf: *MappedFile, gpa: Allocator) Allocator.Error!void { | |
| 650 | mf.nodes_lock.assertUnlocked(); | |
| 651 | const node = ni.get(mf); | |
| 652 | const first_ni = node.first.unwrap() orelse return; | |
| 653 | const shift, _ = first_ni.location(mf).resolve(mf); | |
| 654 | if (shift == 0) return; | |
| 655 | const offset, const size = node.location().resolve(mf); | |
| 656 | try ni.setLocation(mf, gpa, offset + shift, size - shift); | |
| 657 | var child_oni = node.first; | |
| 658 | while (child_oni.unwrap()) |child_ni| { | |
| 659 | const child_node = child_ni.get(mf); | |
| 660 | const child_offset, const child_size = child_node.location().resolve(mf); | |
| 661 | try child_ni.setLocation(mf, gpa, child_offset - shift, child_size); | |
| 662 | child_oni = child_node.next; | |
| 663 | } | |
| 664 | } | |
| 665 | ||
| 644 | 666 | /// Ensures that the size of `ni` is at least `min_size`. Valid for any node. |
| 645 | 667 | /// |
| 646 | 668 | /// Applies `growth_factor` if necessary (so the caller should *not* apply `growth_factor`). |
tools/incr-check.zig+7| ... | ... | @@ -17,6 +17,7 @@ const usage = |
| 17 | 17 | \\Debug Options: |
| 18 | 18 | \\ --preserve-tmp |
| 19 | 19 | \\ --debug-log foo |
| 20 | \\ --debug-link-snapshot | |
| 20 | 21 | ; |
| 21 | 22 | |
| 22 | 23 | pub const std_options: std.Options = .{ |
| ... | ... | @@ -60,6 +61,7 @@ pub fn main(init: std.process.Init) !void { |
| 60 | 61 | var quiet: bool = false; |
| 61 | 62 | |
| 62 | 63 | var debug_log_args: std.ArrayList([]const u8) = .empty; |
| 64 | var debug_link_snapshot = false; | |
| 63 | 65 | |
| 64 | 66 | var arg_it = try init.minimal.args.iterateAllocator(arena); |
| 65 | 67 | _ = arg_it.skip(); |
| ... | ... | @@ -77,6 +79,8 @@ pub fn main(init: std.process.Init) !void { |
| 77 | 79 | arena, |
| 78 | 80 | arg_it.next() orelse badUsage("expected arg after --debug-log", .{}), |
| 79 | 81 | ); |
| 82 | } else if (std.mem.eql(u8, arg, "--debug-link-snapshot")) { | |
| 83 | debug_link_snapshot = true; | |
| 80 | 84 | } else if (std.mem.eql(u8, arg, "--preserve-tmp")) { |
| 81 | 85 | preserve_tmp = true; |
| 82 | 86 | } else if (std.mem.eql(u8, arg, "-fqemu")) { |
| ... | ... | @@ -173,6 +177,9 @@ pub fn main(init: std.process.Init) !void { |
| 173 | 177 | for (debug_log_args.items) |arg| { |
| 174 | 178 | try child_args.appendSlice(arena, &.{ "--debug-log", arg }); |
| 175 | 179 | } |
| 180 | if (debug_link_snapshot) { | |
| 181 | try child_args.append(arena, "--debug-link-snapshot"); | |
| 182 | } | |
| 176 | 183 | for (case.modules) |mod| { |
| 177 | 184 | try child_args.appendSlice(arena, &.{ "--dep", mod.name }); |
| 178 | 185 | } |