diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index a0f9c12c34..d7443faaf9 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -3187,7 +3187,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) error{OutOfMemory}!void { .macho => unreachable, else => unreachable, }; - try dw.addTypeReloc(atom, ty, @intCast(u32, index), null); + try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); }, .plan9 => {}, .none => {}, diff --git a/src/arch/riscv64/CodeGen.zig b/src/arch/riscv64/CodeGen.zig index c94b4de378..b1e86240ae 100644 --- a/src/arch/riscv64/CodeGen.zig +++ b/src/arch/riscv64/CodeGen.zig @@ -754,7 +754,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { .macho => unreachable, else => unreachable, }; - try dw.addTypeReloc(atom, ty, @intCast(u32, index), null); + try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); }, .plan9 => {}, .none => {}, diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index eb9d9a4ad9..ca9c2f125f 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -1550,7 +1550,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom, else => unreachable, }; - try dw.addTypeReloc(atom, ty, @intCast(u32, index), null); + try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); }, else => {}, } diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 944ef16294..00907a03c0 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -1050,7 +1050,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { const index = dbg_info.items.len; try dbg_info.resize(index + 4); const atom = &self.decl.link.wasm.dbg_info_atom; - try dwarf.addTypeReloc(atom, ty, @intCast(u32, index), null); + try dwarf.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); }, .plan9 => unreachable, .none => {}, diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index 33734eda30..4ac9103c7c 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -4371,7 +4371,7 @@ fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void { .macho => &fn_owner_decl.link.macho.dbg_info_atom, else => unreachable, }; - try dw.addTypeReloc(atom, ty, @intCast(u32, index), null); + try dw.addTypeRelocGlobal(atom, ty, @intCast(u32, index)); }, .plan9 => {}, .none => {}, diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 61bec1f880..f291dd4255 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -110,13 +110,22 @@ pub const DeclState = struct { }); } - pub fn addTypeReloc( - self: *DeclState, - atom: *const Atom, - ty: Type, - offset: u32, - addend: ?u32, - ) !void { + /// Adds local type relocation of the form: @offset => @this + addend + /// @this signifies the offset within the .debug_abbrev section of the containing atom. + pub fn addTypeRelocLocal(self: *DeclState, atom: *const Atom, offset: u32, addend: u32) !void { + log.debug("{x}: @this + {x}", .{ offset, addend }); + try self.abbrev_relocs.append(self.gpa, .{ + .target = null, + .atom = atom, + .offset = offset, + .addend = addend, + }); + } + + /// Adds global type relocation of the form: @offset => @symbol + 0 + /// @symbol signifies a type abbreviation posititioned somewhere in the .debug_abbrev section + /// which we use as our target of the relocation. + pub fn addTypeRelocGlobal(self: *DeclState, atom: *const Atom, ty: Type, offset: u32) !void { const resolv = self.abbrev_resolver.getContext(ty, .{ .mod = self.mod, }) orelse blk: { @@ -134,14 +143,12 @@ pub const DeclState = struct { .mod = self.mod, }).?; }; - const add: u32 = addend orelse 0; - - log.debug("{x}: @{d} + {x}", .{ offset, resolv, add }); + log.debug("{x}: @{d} + 0", .{ offset, resolv }); try self.abbrev_relocs.append(self.gpa, .{ .target = resolv, .atom = atom, .offset = offset, - .addend = add, + .addend = 0, }); } @@ -213,7 +220,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, Type.bool, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, Type.bool, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.ensureUnusedCapacity(6); dbg_info_buffer.appendAssumeCapacity(0); @@ -225,7 +232,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata const offset = abi_size - payload_ty.abiSize(target); try leb128.writeULEB128(dbg_info_buffer.writer(), offset); @@ -254,7 +261,7 @@ pub const DeclState = struct { try dbg_info_buffer.resize(index + 4); var buf = try arena.create(Type.SlicePtrFieldTypeBuffer); const ptr_ty = ty.slicePtrFieldType(buf); - try self.addTypeReloc(atom, ptr_ty, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, ptr_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.ensureUnusedCapacity(6); dbg_info_buffer.appendAssumeCapacity(0); @@ -266,7 +273,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.ensureUnusedCapacity(2); dbg_info_buffer.appendAssumeCapacity(@sizeOf(usize)); @@ -278,7 +285,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index)); } }, .Array => { @@ -289,13 +296,13 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, ty.childType(), @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, ty.childType(), @intCast(u32, index)); // DW.AT.subrange_type try dbg_info_buffer.append(@enumToInt(AbbrevKind.array_dim)); // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, Type.usize, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, Type.usize, @intCast(u32, index)); // DW.AT.count, DW.FORM.udata const len = ty.arrayLenIncludingSentinel(); try leb128.writeULEB128(dbg_info_buffer.writer(), len); @@ -323,7 +330,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, field, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, field, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata const field_off = ty.structFieldOffset(field_index, target); try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); @@ -354,7 +361,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata const field_off = ty.structFieldOffset(field_index, target); try leb128.writeULEB128(dbg_info_buffer.writer(), field_off); @@ -434,7 +441,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const inner_union_index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(inner_union_index + 4); - try self.addTypeReloc(atom, ty, @intCast(u32, inner_union_index), 5); + try self.addTypeRelocLocal(atom, @intCast(u32, inner_union_index), 5); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), payload_offset); } @@ -461,7 +468,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, field.ty, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, field.ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try dbg_info_buffer.append(0); } @@ -478,7 +485,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, union_obj.tag_ty, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, union_obj.tag_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), tag_offset); @@ -521,7 +528,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 var index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, payload_ty, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, payload_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), payload_off); @@ -534,7 +541,7 @@ pub const DeclState = struct { // DW.AT.type, DW.FORM.ref4 index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); - try self.addTypeReloc(atom, error_ty, @intCast(u32, index), null); + try self.addTypeRelocGlobal(atom, error_ty, @intCast(u32, index)); // DW.AT.data_member_location, DW.FORM.sdata try leb128.writeULEB128(dbg_info_buffer.writer(), error_off); @@ -556,7 +563,9 @@ pub const AbbrevEntry = struct { }; pub const AbbrevRelocation = struct { - target: u32, + /// If target is null, we deal with a local relocation that is based on simple offset + addend + /// only. + target: ?u32, atom: *const Atom, offset: u32, addend: u32, @@ -740,12 +749,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl: *Module.Decl) !DeclState .wasm => &decl.link.wasm.dbg_info_atom, else => unreachable, }; - try decl_state.addTypeReloc( - atom, - fn_ret_type, - @intCast(u32, dbg_info_buffer.items.len), - null, - ); + try decl_state.addTypeRelocGlobal(atom, fn_ret_type, @intCast(u32, dbg_info_buffer.items.len)); dbg_info_buffer.items.len += 4; // DW.AT.type, DW.FORM.ref4 } @@ -1036,30 +1040,39 @@ pub fn commitDeclState( try self.updateDeclDebugInfoAllocation(file, atom, @intCast(u32, dbg_info_buffer.items.len)); while (decl_state.abbrev_relocs.popOrNull()) |reloc| { - const symbol = decl_state.abbrev_table.items[reloc.target]; - const ty = symbol.@"type"; - const deferred: bool = blk: { - if (ty.isAnyError()) break :blk true; - switch (ty.tag()) { - .error_set_inferred => { - if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; - }, - else => {}, + if (reloc.target) |target| { + const symbol = decl_state.abbrev_table.items[target]; + const ty = symbol.@"type"; + const deferred: bool = blk: { + if (ty.isAnyError()) break :blk true; + switch (ty.tag()) { + .error_set_inferred => { + if (!ty.castTag(.error_set_inferred).?.data.is_resolved) break :blk true; + }, + else => {}, + } + break :blk false; + }; + if (deferred) { + try self.global_abbrev_relocs.append(gpa, .{ + .target = null, + .offset = reloc.offset, + .atom = reloc.atom, + .addend = reloc.addend, + }); + } else { + mem.writeInt( + u32, + dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], + symbol.atom.off + symbol.offset + reloc.addend, + target_endian, + ); } - break :blk false; - }; - if (deferred) { - try self.global_abbrev_relocs.append(gpa, .{ - .target = undefined, - .offset = reloc.offset, - .atom = reloc.atom, - .addend = reloc.addend, - }); } else { mem.writeInt( u32, dbg_info_buffer.items[reloc.offset..][0..@sizeOf(u32)], - symbol.atom.off + symbol.offset + reloc.addend, + reloc.atom.off + reloc.offset + reloc.addend, target_endian, ); } diff --git a/src/link/Elf.zig b/src/link/Elf.zig index 442ad73ea7..f9b6d7861a 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -497,7 +497,7 @@ fn makeString(self: *Elf, bytes: []const u8) !u32 { return @intCast(u32, result); } -fn getString(self: *Elf, str_off: u32) []const u8 { +fn getString(self: Elf, str_off: u32) []const u8 { assert(str_off < self.shstrtab.items.len); return mem.sliceTo(@ptrCast([*:0]const u8, self.shstrtab.items.ptr + str_off), 0); } @@ -1015,6 +1015,10 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node // mixing local and global symbols within a symbol table. try self.writeAllGlobalSymbols(); + if (build_options.enable_logging) { + self.logSymtab(); + } + if (self.dwarf) |*dw| { if (self.debug_abbrev_section_dirty) { try dw.writeDbgAbbrev(&self.base); @@ -1167,7 +1171,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node for (buf) |*shdr, i| { shdr.* = sectHeaderTo32(self.sections.items[i]); - log.debug("writing section {}", .{shdr.*}); + log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* }); if (foreign_endian) { mem.byteSwapAllFields(elf.Elf32_Shdr, shdr); } @@ -1180,7 +1184,7 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node for (buf) |*shdr, i| { shdr.* = self.sections.items[i]; - log.debug("writing section {}", .{shdr.*}); + log.debug("writing section {s}: {}", .{ self.getString(shdr.sh_name), shdr.* }); if (foreign_endian) { mem.byteSwapAllFields(elf.Elf64_Shdr, shdr); } @@ -2794,8 +2798,14 @@ fn writeSymbol(self: *Elf, index: usize) !void { if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { // Move all the symbols to a new file location. const new_offset = self.findFreeSpace(needed_size, sym_align); + log.debug("moving '.symtab' from 0x{x} to 0x{x}", .{ syms_sect.sh_offset, new_offset }); const existing_size = @as(u64, syms_sect.sh_info) * sym_size; - const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size); + const amt = try self.base.file.?.copyRangeAll( + syms_sect.sh_offset, + self.base.file.?, + new_offset, + existing_size, + ); if (amt != existing_size) return error.InputOutput; syms_sect.sh_offset = new_offset; } @@ -2804,30 +2814,35 @@ fn writeSymbol(self: *Elf, index: usize) !void { self.shdr_table_dirty = true; // TODO look into only writing one section } const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); + const off = switch (self.ptr_width) { + .p32 => syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index, + .p64 => syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index, + }; + const local = self.local_symbols.items[index]; + log.debug("writing symbol {d}, '{s}' at 0x{x}", .{ index, self.getString(local.st_name), off }); + log.debug(" ({})", .{local}); switch (self.ptr_width) { .p32 => { var sym = [1]elf.Elf32_Sym{ .{ - .st_name = self.local_symbols.items[index].st_name, - .st_value = @intCast(u32, self.local_symbols.items[index].st_value), - .st_size = @intCast(u32, self.local_symbols.items[index].st_size), - .st_info = self.local_symbols.items[index].st_info, - .st_other = self.local_symbols.items[index].st_other, - .st_shndx = self.local_symbols.items[index].st_shndx, + .st_name = local.st_name, + .st_value = @intCast(u32, local.st_value), + .st_size = @intCast(u32, local.st_size), + .st_info = local.st_info, + .st_other = local.st_other, + .st_shndx = local.st_shndx, }, }; if (foreign_endian) { mem.byteSwapAllFields(elf.Elf32_Sym, &sym[0]); } - const off = syms_sect.sh_offset + @sizeOf(elf.Elf32_Sym) * index; try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); }, .p64 => { - var sym = [1]elf.Elf64_Sym{self.local_symbols.items[index]}; + var sym = [1]elf.Elf64_Sym{local}; if (foreign_endian) { mem.byteSwapAllFields(elf.Elf64_Sym, &sym[0]); } - const off = syms_sect.sh_offset + @sizeOf(elf.Elf64_Sym) * index; try self.base.file.?.pwriteAll(mem.sliceAsBytes(sym[0..1]), off); }, } @@ -2847,8 +2862,14 @@ fn writeAllGlobalSymbols(self: *Elf) !void { if (needed_size > self.allocatedSize(syms_sect.sh_offset)) { // Move all the symbols to a new file location. const new_offset = self.findFreeSpace(needed_size, sym_align); + log.debug("moving '.symtab' from 0x{x} to 0x{x}", .{ syms_sect.sh_offset, new_offset }); const existing_size = @as(u64, syms_sect.sh_info) * sym_size; - const amt = try self.base.file.?.copyRangeAll(syms_sect.sh_offset, self.base.file.?, new_offset, existing_size); + const amt = try self.base.file.?.copyRangeAll( + syms_sect.sh_offset, + self.base.file.?, + new_offset, + existing_size, + ); if (amt != existing_size) return error.InputOutput; syms_sect.sh_offset = new_offset; } @@ -2857,19 +2878,21 @@ fn writeAllGlobalSymbols(self: *Elf) !void { const foreign_endian = self.base.options.target.cpu.arch.endian() != builtin.cpu.arch.endian(); const global_syms_off = syms_sect.sh_offset + self.local_symbols.items.len * sym_size; + log.debug("writing {d} global symbols at 0x{x}", .{ self.global_symbols.items.len, global_syms_off }); switch (self.ptr_width) { .p32 => { const buf = try self.base.allocator.alloc(elf.Elf32_Sym, self.global_symbols.items.len); defer self.base.allocator.free(buf); for (buf) |*sym, i| { + const global = self.global_symbols.items[i]; sym.* = .{ - .st_name = self.global_symbols.items[i].st_name, - .st_value = @intCast(u32, self.global_symbols.items[i].st_value), - .st_size = @intCast(u32, self.global_symbols.items[i].st_size), - .st_info = self.global_symbols.items[i].st_info, - .st_other = self.global_symbols.items[i].st_other, - .st_shndx = self.global_symbols.items[i].st_shndx, + .st_name = global.st_name, + .st_value = @intCast(u32, global.st_value), + .st_size = @intCast(u32, global.st_size), + .st_info = global.st_info, + .st_other = global.st_other, + .st_shndx = global.st_shndx, }; if (foreign_endian) { mem.byteSwapAllFields(elf.Elf32_Sym, sym); @@ -2882,13 +2905,14 @@ fn writeAllGlobalSymbols(self: *Elf) !void { defer self.base.allocator.free(buf); for (buf) |*sym, i| { + const global = self.global_symbols.items[i]; sym.* = .{ - .st_name = self.global_symbols.items[i].st_name, - .st_value = self.global_symbols.items[i].st_value, - .st_size = self.global_symbols.items[i].st_size, - .st_info = self.global_symbols.items[i].st_info, - .st_other = self.global_symbols.items[i].st_other, - .st_shndx = self.global_symbols.items[i].st_shndx, + .st_name = global.st_name, + .st_value = global.st_value, + .st_size = global.st_size, + .st_info = global.st_info, + .st_other = global.st_other, + .st_shndx = global.st_shndx, }; if (foreign_endian) { mem.byteSwapAllFields(elf.Elf64_Sym, sym); @@ -3194,3 +3218,14 @@ const CsuObjects = struct { self.crtn = crtn; } }; + +fn logSymtab(self: Elf) void { + log.debug("locals:", .{}); + for (self.local_symbols.items) |sym, id| { + log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx }); + } + log.debug("globals:", .{}); + for (self.global_symbols.items) |sym, id| { + log.debug(" {d}: {s}: @{x} in {d}", .{ id, self.getString(sym.st_name), sym.st_value, sym.st_shndx }); + } +}