authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-14 02:01:16-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-14 02:01:16-04:00
log59fa548be8944962d5882e2ac38f6013ac00e84a
tree767aa3d1d895975f7d162c07423ccf30b8bc39c1
parent9c509f1526b4560b4e97367a18755a9d1ae6fcf7
parentedb428fae42ea82c49347fce6d48d80f1fed6ef1
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11429 from ziglang/stage2-alive-decls

stage2: fix (recursively) marking decls as alive, and improve DWARF for local vars

5 files changed, 218 insertions(+), 46 deletions(-)

src/arch/x86_64/CodeGen.zig+81-43
...@@ -3903,17 +3903,17 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -3903,17 +3903,17 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
3903 const pl_op = self.air.instructions.items(.data)[inst].pl_op;3903 const pl_op = self.air.instructions.items(.data)[inst].pl_op;
3904 const operand = pl_op.operand;3904 const operand = pl_op.operand;
3905 const ty = self.air.typeOf(operand);3905 const ty = self.air.typeOf(operand);
3906 const mcv = try self.resolveInst(operand);
39063907
3907 if (!self.liveness.operandDies(inst, 0)) {3908 log.debug("airDbgVar: %{d}: {}, {}", .{ inst, ty.fmtDebug(), mcv });
3908 const mcv = try self.resolveInst(operand);
3909 const name = self.air.nullTerminatedString(pl_op.payload);
39103909
3911 const tag = self.air.instructions.items(.tag)[inst];3910 const name = self.air.nullTerminatedString(pl_op.payload);
3912 switch (tag) {3911
3913 .dbg_var_ptr => try self.genVarDbgInfo(ty.childType(), mcv, name),3912 const tag = self.air.instructions.items(.tag)[inst];
3914 .dbg_var_val => try self.genVarDbgInfo(ty, mcv, name),3913 switch (tag) {
3915 else => unreachable,3914 .dbg_var_ptr => try self.genVarDbgInfo(tag, ty.childType(), mcv, name),
3916 }3915 .dbg_var_val => try self.genVarDbgInfo(tag, ty, mcv, name),
3916 else => unreachable,
3917 }3917 }
39183918
3919 return self.finishAir(inst, .dead, .{ operand, .none, .none });3919 return self.finishAir(inst, .dead, .{ operand, .none, .none });
...@@ -3921,36 +3921,27 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {...@@ -3921,36 +3921,27 @@ fn airDbgVar(self: *Self, inst: Air.Inst.Index) !void {
39213921
3922fn genVarDbgInfo(3922fn genVarDbgInfo(
3923 self: *Self,3923 self: *Self,
3924 tag: Air.Inst.Tag,
3924 ty: Type,3925 ty: Type,
3925 mcv: MCValue,3926 mcv: MCValue,
3926 name: [:0]const u8,3927 name: [:0]const u8,
3927) !void {3928) !void {
3928 const name_with_null = name.ptr[0 .. name.len + 1];3929 const name_with_null = name.ptr[0 .. name.len + 1];
3929 switch (mcv) {3930 switch (self.debug_output) {
3930 .register => |reg| {3931 .dwarf => |dw| {
3931 switch (self.debug_output) {3932 const dbg_info = &dw.dbg_info;
3932 .dwarf => |dw| {3933 try dbg_info.append(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
3933 const dbg_info = &dw.dbg_info;3934
3934 try dbg_info.ensureUnusedCapacity(3);3935 switch (mcv) {
3935 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.variable));3936 .register => |reg| {
3937 try dbg_info.ensureUnusedCapacity(2);
3936 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc3938 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
3937 1, // ULEB128 dwarf expression length3939 1, // ULEB128 dwarf expression length
3938 reg.dwarfLocOp(),3940 reg.dwarfLocOp(),
3939 });3941 });
3940 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3941 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3942 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3943 },3942 },
3944 .plan9 => {},3943 .ptr_stack_offset, .stack_offset => |off| {
3945 .none => {},3944 try dbg_info.ensureUnusedCapacity(7);
3946 }
3947 },
3948 .ptr_stack_offset, .stack_offset => |off| {
3949 switch (self.debug_output) {
3950 .dwarf => |dw| {
3951 const dbg_info = &dw.dbg_info;
3952 try dbg_info.ensureUnusedCapacity(8);
3953 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.variable));
3954 const fixup = dbg_info.items.len;3945 const fixup = dbg_info.items.len;
3955 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc3946 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
3956 1, // we will backpatch it after we encode the displacement in LEB1283947 1, // we will backpatch it after we encode the displacement in LEB128
...@@ -3958,18 +3949,54 @@ fn genVarDbgInfo(...@@ -3958,18 +3949,54 @@ fn genVarDbgInfo(
3958 });3949 });
3959 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;3950 leb128.writeILEB128(dbg_info.writer(), -off) catch unreachable;
3960 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);3951 dbg_info.items[fixup] += @intCast(u8, dbg_info.items.len - fixup - 2);
3961 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3962 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3963 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3964
3965 },3952 },
3966 .plan9 => {},3953 .memory, .got_load, .direct_load => {
3967 .none => {},3954 const endian = self.target.cpu.arch.endian();
3955 const ptr_width = @intCast(u8, @divExact(self.target.cpu.arch.ptrBitWidth(), 8));
3956 const is_ptr = switch (tag) {
3957 .dbg_var_ptr => true,
3958 .dbg_var_val => false,
3959 else => unreachable,
3960 };
3961 try dbg_info.ensureUnusedCapacity(2 + ptr_width);
3962 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
3963 1 + ptr_width + @boolToInt(is_ptr),
3964 DW.OP.addr, // literal address
3965 });
3966 const offset = @intCast(u32, dbg_info.items.len);
3967 const addr = switch (mcv) {
3968 .memory => |addr| addr,
3969 else => 0,
3970 };
3971 switch (ptr_width) {
3972 0...4 => {
3973 try dbg_info.writer().writeInt(u32, @intCast(u32, addr), endian);
3974 },
3975 5...8 => {
3976 try dbg_info.writer().writeInt(u64, addr, endian);
3977 },
3978 else => unreachable,
3979 }
3980 if (is_ptr) {
3981 // We need deref the address as we point to the value via GOT entry.
3982 try dbg_info.append(DW.OP.deref);
3983 }
3984 switch (mcv) {
3985 .got_load, .direct_load => |index| try dw.addExprlocReloc(index, offset, is_ptr),
3986 else => {},
3987 }
3988 },
3989 else => {
3990 log.debug("TODO generate debug info for {}", .{mcv});
3991 },
3968 }3992 }
3993
3994 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
3995 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
3996 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
3969 },3997 },
3970 else => {3998 .plan9 => {},
3971 log.debug("TODO generate debug info for {}", .{mcv});3999 .none => {},
3972 },
3973 }4000 }
3974}4001}
39754002
...@@ -6089,6 +6116,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV...@@ -6089,6 +6116,7 @@ fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCV
6089}6116}
60906117
6091fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {6118fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
6119 log.debug("lowerDeclRef: ty = {}, val = {}", .{ tv.ty.fmtDebug(), tv.val.fmtDebug() });
6092 const ptr_bits = self.target.cpu.arch.ptrBitWidth();6120 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
6093 const ptr_bytes: u64 = @divExact(ptr_bits, 8);6121 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
60946122
...@@ -6100,7 +6128,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa...@@ -6100,7 +6128,8 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
6100 }6128 }
6101 }6129 }
61026130
6103 decl.alive = true;6131 decl.markAlive();
6132
6104 if (self.bin_file.cast(link.File.Elf)) |elf_file| {6133 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
6105 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];6134 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
6106 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;6135 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
...@@ -6120,8 +6149,6 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa...@@ -6120,8 +6149,6 @@ fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCVa
6120 } else {6149 } else {
6121 return self.fail("TODO codegen non-ELF const Decl pointer", .{});6150 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
6122 }6151 }
6123
6124 _ = tv;
6125}6152}
61266153
6127fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {6154fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
...@@ -6144,6 +6171,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {...@@ -6144,6 +6171,7 @@ fn lowerUnnamedConst(self: *Self, tv: TypedValue) InnerError!MCValue {
6144}6171}
61456172
6146fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {6173fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6174 log.debug("genTypedValue: ty = {}, val = {}", .{ typed_value.ty.fmtDebug(), typed_value.val.fmtDebug() });
6147 if (typed_value.val.isUndef())6175 if (typed_value.val.isUndef())
6148 return MCValue{ .undef = {} };6176 return MCValue{ .undef = {} };
6149 const ptr_bits = self.target.cpu.arch.ptrBitWidth();6177 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
...@@ -6181,8 +6209,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -6181,8 +6209,6 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6181 .Bool => {6209 .Bool => {
6182 return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) };6210 return MCValue{ .immediate = @boolToInt(typed_value.val.toBool()) };
6183 },6211 },
6184 .ComptimeInt => unreachable, // semantic analysis prevents this
6185 .ComptimeFloat => unreachable, // semantic analysis prevents this
6186 .Optional => {6212 .Optional => {
6187 if (typed_value.ty.isPtrLikeOptional()) {6213 if (typed_value.ty.isPtrLikeOptional()) {
6188 if (typed_value.val.isNull())6214 if (typed_value.val.isNull())
...@@ -6243,6 +6269,18 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {...@@ -6243,6 +6269,18 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
6243 }6269 }
6244 }6270 }
6245 },6271 },
6272
6273 .ComptimeInt => unreachable,
6274 .ComptimeFloat => unreachable,
6275 .Type => unreachable,
6276 .EnumLiteral => unreachable,
6277 .Void => unreachable,
6278 .NoReturn => unreachable,
6279 .Undefined => unreachable,
6280 .Null => unreachable,
6281 .BoundFn => unreachable,
6282 .Opaque => unreachable,
6283
6246 else => {},6284 else => {},
6247 }6285 }
62486286
src/codegen.zig-2
...@@ -203,7 +203,6 @@ pub fn generateSymbol(...@@ -203,7 +203,6 @@ pub fn generateSymbol(
203 },203 },
204 .Array => switch (typed_value.val.tag()) {204 .Array => switch (typed_value.val.tag()) {
205 .bytes => {205 .bytes => {
206 // TODO populate .debug_info for the array
207 const payload = typed_value.val.castTag(.bytes).?;206 const payload = typed_value.val.castTag(.bytes).?;
208 const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel());207 const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel());
209 // The bytes payload already includes the sentinel, if any208 // The bytes payload already includes the sentinel, if any
...@@ -212,7 +211,6 @@ pub fn generateSymbol(...@@ -212,7 +211,6 @@ pub fn generateSymbol(
212 return Result{ .appended = {} };211 return Result{ .appended = {} };
213 },212 },
214 .aggregate => {213 .aggregate => {
215 // TODO populate .debug_info for the array
216 const elem_vals = typed_value.val.castTag(.aggregate).?.data;214 const elem_vals = typed_value.val.castTag(.aggregate).?.data;
217 const elem_ty = typed_value.ty.elemType();215 const elem_ty = typed_value.ty.elemType();
218 const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel());216 const len = @intCast(usize, typed_value.ty.arrayLenIncludingSentinel());
src/link/Dwarf.zig+78
...@@ -79,6 +79,7 @@ pub const DeclState = struct {...@@ -79,6 +79,7 @@ pub const DeclState = struct {
79 std.hash_map.default_max_load_percentage,79 std.hash_map.default_max_load_percentage,
80 ) = .{},80 ) = .{},
81 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},81 abbrev_relocs: std.ArrayListUnmanaged(AbbrevRelocation) = .{},
82 exprloc_relocs: std.ArrayListUnmanaged(ExprlocRelocation) = .{},
8283
83 fn init(gpa: Allocator, target: std.Target) DeclState {84 fn init(gpa: Allocator, target: std.Target) DeclState {
84 return .{85 return .{
...@@ -97,6 +98,16 @@ pub const DeclState = struct {...@@ -97,6 +98,16 @@ pub const DeclState = struct {
97 self.abbrev_table.deinit(self.gpa);98 self.abbrev_table.deinit(self.gpa);
98 self.abbrev_resolver.deinit(self.gpa);99 self.abbrev_resolver.deinit(self.gpa);
99 self.abbrev_relocs.deinit(self.gpa);100 self.abbrev_relocs.deinit(self.gpa);
101 self.exprloc_relocs.deinit(self.gpa);
102 }
103
104 pub fn addExprlocReloc(self: *DeclState, target: u32, offset: u32, is_ptr: bool) !void {
105 log.debug("{x}: target sym @{d}, via GOT {}", .{ offset, target, is_ptr });
106 try self.exprloc_relocs.append(self.gpa, .{
107 .@"type" = if (is_ptr) .got_load else .direct_load,
108 .target = target,
109 .offset = offset,
110 });
100 }111 }
101112
102 pub fn addTypeReloc(113 pub fn addTypeReloc(
...@@ -270,6 +281,27 @@ pub const DeclState = struct {...@@ -270,6 +281,27 @@ pub const DeclState = struct {
270 try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);281 try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
271 }282 }
272 },283 },
284 .Array => {
285 // DW.AT.array_type
286 try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_type));
287 // DW.AT.name, DW.FORM.string
288 try dbg_info_buffer.writer().print("{}\x00", .{ty.fmt(target)});
289 // DW.AT.type, DW.FORM.ref4
290 var index = dbg_info_buffer.items.len;
291 try dbg_info_buffer.resize(index + 4);
292 try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null);
293 // DW.AT.subrange_type
294 try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim));
295 // DW.AT.type, DW.FORM.ref4
296 index = dbg_info_buffer.items.len;
297 try dbg_info_buffer.resize(index + 4);
298 try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null);
299 // DW.AT.count, DW.FORM.udata
300 const len = ty.arrayLenIncludingSentinel();
301 try leb128.writeULEB128(dbg_info_buffer.writer(), len);
302 // DW.AT.array_type delimit children
303 try dbg_info_buffer.append(0);
304 },
273 .Struct => blk: {305 .Struct => blk: {
274 // DW.AT.structure_type306 // DW.AT.structure_type
275 try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));307 try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_type));
...@@ -528,6 +560,18 @@ pub const AbbrevRelocation = struct {...@@ -528,6 +560,18 @@ pub const AbbrevRelocation = struct {
528 addend: u32,560 addend: u32,
529};561};
530562
563pub const ExprlocRelocation = struct {
564 /// Type of the relocation: direct load ref, or GOT load ref (via GOT table)
565 @"type": enum {
566 direct_load,
567 got_load,
568 },
569 /// Index of the target in the linker's locals symbol table.
570 target: u32,
571 /// Offset within the debug info buffer where to patch up the address value.
572 offset: u32,
573};
574
531pub const SrcFn = struct {575pub const SrcFn = struct {
532 /// Offset from the beginning of the Debug Line Program header that contains this function.576 /// Offset from the beginning of the Debug Line Program header that contains this function.
533 off: u32,577 off: u32,
...@@ -564,6 +608,8 @@ pub const AbbrevKind = enum(u8) {...@@ -564,6 +608,8 @@ pub const AbbrevKind = enum(u8) {
564 pad1,608 pad1,
565 parameter,609 parameter,
566 variable,610 variable,
611 array_type,
612 array_dim,
567};613};
568614
569/// The reloc offset for the virtual address of a function in its Line Number Program.615/// The reloc offset for the virtual address of a function in its Line Number Program.
...@@ -986,6 +1032,26 @@ pub fn commitDeclState(...@@ -986,6 +1032,26 @@ pub fn commitDeclState(
986 }1032 }
987 }1033 }
9881034
1035 while (decl_state.exprloc_relocs.popOrNull()) |reloc| {
1036 switch (self.tag) {
1037 .macho => {
1038 const macho_file = file.cast(File.MachO).?;
1039 const d_sym = &macho_file.d_sym.?;
1040 try d_sym.relocs.append(d_sym.base.base.allocator, .{
1041 .@"type" = switch (reloc.@"type") {
1042 .direct_load => .direct_load,
1043 .got_load => .got_load,
1044 },
1045 .target = reloc.target,
1046 .offset = reloc.offset + atom.off,
1047 .addend = 0,
1048 .prev_vaddr = 0,
1049 });
1050 },
1051 else => unreachable,
1052 }
1053 }
1054
989 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);1055 try self.writeDeclDebugInfo(file, atom, dbg_info_buffer.items);
990}1056}
9911057
...@@ -1357,6 +1423,18 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {...@@ -1357,6 +1423,18 @@ pub fn writeDbgAbbrev(self: *Dwarf, file: *File) !void {
1357 DW.AT.name, DW.FORM.string,1423 DW.AT.name, DW.FORM.string,
1358 0,1424 0,
1359 0, // table sentinel1425 0, // table sentinel
1426 @enumToInt(AbbrevKind.array_type),
1427 DW.TAG.array_type, DW.CHILDREN.yes, // header
1428 DW.AT.name, DW.FORM.string,
1429 DW.AT.type, DW.FORM.ref4,
1430 0,
1431 0, // table sentinel
1432 @enumToInt(AbbrevKind.array_dim),
1433 DW.TAG.subrange_type, DW.CHILDREN.no, // header
1434 DW.AT.type, DW.FORM.ref4,
1435 DW.AT.count, DW.FORM.udata,
1436 0,
1437 0, // table sentinel
1360 0,1438 0,
1361 0,1439 0,
1362 0, // section sentinel1440 0, // section sentinel
src/link/MachO.zig+8
...@@ -3472,6 +3472,9 @@ pub fn closeFiles(self: MachO) void {...@@ -3472,6 +3472,9 @@ pub fn closeFiles(self: MachO) void {
3472 for (self.dylibs.items) |dylib| {3472 for (self.dylibs.items) |dylib| {
3473 dylib.file.close();3473 dylib.file.close();
3474 }3474 }
3475 if (self.d_sym) |ds| {
3476 ds.file.close();
3477 }
3475}3478}
34763479
3477fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool) void {3480fn freeAtom(self: *MachO, atom: *Atom, match: MatchingSection, owns_atom: bool) void {
...@@ -4274,6 +4277,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {...@@ -4274,6 +4277,11 @@ pub fn freeDecl(self: *MachO, decl: *Module.Decl) void {
4274 self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {};4277 self.got_entries_free_list.append(self.base.allocator, @intCast(u32, got_index)) catch {};
4275 self.got_entries.items[got_index] = .{ .target = .{ .local = 0 }, .atom = undefined };4278 self.got_entries.items[got_index] = .{ .target = .{ .local = 0 }, .atom = undefined };
4276 _ = self.got_entries_table.swapRemove(.{ .local = decl.link.macho.local_sym_index });4279 _ = self.got_entries_table.swapRemove(.{ .local = decl.link.macho.local_sym_index });
4280
4281 if (self.d_sym) |*d_sym| {
4282 d_sym.swapRemoveRelocs(decl.link.macho.local_sym_index);
4283 }
4284
4277 log.debug(" adding GOT index {d} to free list (target local@{d})", .{4285 log.debug(" adding GOT index {d} to free list (target local@{d})", .{
4278 got_index,4286 got_index,
4279 decl.link.macho.local_sym_index,4287 decl.link.macho.local_sym_index,
src/link/MachO/DebugSymbols.zig+51-1
...@@ -59,6 +59,19 @@ debug_aranges_section_dirty: bool = false,...@@ -59,6 +59,19 @@ debug_aranges_section_dirty: bool = false,
59debug_info_header_dirty: bool = false,59debug_info_header_dirty: bool = false,
60debug_line_header_dirty: bool = false,60debug_line_header_dirty: bool = false,
6161
62relocs: std.ArrayListUnmanaged(Reloc) = .{},
63
64pub const Reloc = struct {
65 @"type": enum {
66 direct_load,
67 got_load,
68 },
69 target: u32,
70 offset: u64,
71 addend: u32,
72 prev_vaddr: u64,
73};
74
62/// You must call this function *after* `MachO.populateMissingMetadata()`75/// You must call this function *after* `MachO.populateMissingMetadata()`
63/// has been called to get a viable debug symbols output.76/// has been called to get a viable debug symbols output.
64pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {77pub fn populateMissingMetadata(self: *DebugSymbols, allocator: Allocator) !void {
...@@ -254,6 +267,30 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti...@@ -254,6 +267,30 @@ pub fn flushModule(self: *DebugSymbols, allocator: Allocator, options: link.Opti
254 // Zig source code.267 // Zig source code.
255 const module = options.module orelse return error.LinkingWithoutZigSourceUnimplemented;268 const module = options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
256269
270 for (self.relocs.items) |*reloc| {
271 const sym = switch (reloc.@"type") {
272 .direct_load => self.base.locals.items[reloc.target],
273 .got_load => blk: {
274 const got_index = self.base.got_entries_table.get(.{ .local = reloc.target }).?;
275 const got_entry = self.base.got_entries.items[got_index];
276 break :blk self.base.locals.items[got_entry.atom.local_sym_index];
277 },
278 };
279 if (sym.n_value == reloc.prev_vaddr) continue;
280
281 const seg = &self.load_commands.items[self.dwarf_segment_cmd_index.?].segment;
282 const sect = &seg.sections.items[self.debug_info_section_index.?];
283 const file_offset = sect.offset + reloc.offset;
284 log.debug("resolving relocation: {d}@{x} ('{s}') at offset {x}", .{
285 reloc.target,
286 sym.n_value,
287 self.base.getString(sym.n_strx),
288 file_offset,
289 });
290 try self.file.pwriteAll(mem.asBytes(&sym.n_value), file_offset);
291 reloc.prev_vaddr = sym.n_value;
292 }
293
257 if (self.debug_abbrev_section_dirty) {294 if (self.debug_abbrev_section_dirty) {
258 try self.dwarf.writeDbgAbbrev(&self.base.base);295 try self.dwarf.writeDbgAbbrev(&self.base.base);
259 self.load_commands_dirty = true;296 self.load_commands_dirty = true;
...@@ -330,7 +367,20 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {...@@ -330,7 +367,20 @@ pub fn deinit(self: *DebugSymbols, allocator: Allocator) void {
330 }367 }
331 self.load_commands.deinit(allocator);368 self.load_commands.deinit(allocator);
332 self.dwarf.deinit();369 self.dwarf.deinit();
333 self.file.close();370 self.relocs.deinit(allocator);
371}
372
373pub fn swapRemoveRelocs(self: *DebugSymbols, target: u32) void {
374 // TODO re-implement using a hashmap with free lists
375 var last_index: usize = 0;
376 while (last_index < self.relocs.items.len) {
377 const reloc = self.relocs.items[last_index];
378 if (reloc.target == target) {
379 _ = self.relocs.swapRemove(last_index);
380 } else {
381 last_index += 1;
382 }
383 }
334}384}
335385
336fn copySegmentCommand(386fn copySegmentCommand(