authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-24 10:33:42+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-01-25 23:51:19+01:00
log53c668d3a9dad430749cbc642d7bf8cf45eefba1
tree38b4ab6279aa9cd396b2a6622451c78116f35dea
parent05c5bb9edd51e73c0d4a2619817fbff73b82f230

stage2: add naive impl of pointer type in ELF

Augment relocation tracking mechanism to de-duplicate potential creation of base as well as composite types while unrolling composite types in the linker - there is still potential for further space optimisation by moving all type information into a separate section `.debug_types` and providing references to entries within that section whenever required (e.g., `ref4` form). Currently, we duplicate type definitions on a per-decl basis. Anyhow, with this patch, an example function signature of the following type: ```zig fn byPtrPtr(ptr_ptr_x: **u32, ptr_x: *u32) void { ptr_ptr_x.* = ptr_x; } ``` will generate the following `.debug_info` for formal parameters: ``` <1><1aa>: Abbrev Number: 3 (DW_TAG_subprogram) <1ab> DW_AT_low_pc : 0x8000197 <1b3> DW_AT_high_pc : 0x2c <1b7> DW_AT_name : byPtrPtr <2><1c0>: Abbrev Number: 7 (DW_TAG_formal_parameter) <1c1> DW_AT_location : 1 byte block: 55 (DW_OP_reg5 (rdi)) <1c3> DW_AT_type : <0x1df> <1c7> DW_AT_name : ptr_ptr_x <2><1d1>: Abbrev Number: 7 (DW_TAG_formal_parameter) <1d2> DW_AT_location : 1 byte block: 54 (DW_OP_reg4 (rsi)) <1d4> DW_AT_type : <0x1e4> <1d8> DW_AT_name : ptr_x <2><1de>: Abbrev Number: 0 <1><1df>: Abbrev Number: 5 (DW_TAG_pointer_type) <1e0> DW_AT_type : <0x1e4> <1><1e4>: Abbrev Number: 5 (DW_TAG_pointer_type) <1e5> DW_AT_type : <0x1e9> <1><1e9>: Abbrev Number: 4 (DW_TAG_base_type) <1ea> DW_AT_encoding : 7 (unsigned) <1eb> DW_AT_byte_size : 4 <1ec> DW_AT_name : u32 ```

4 files changed, 66 insertions(+), 21 deletions(-)

src/link.zig+6-1
...@@ -235,7 +235,12 @@ pub const File = struct {...@@ -235,7 +235,12 @@ pub const File = struct {
235 };235 };
236236
237 /// For DWARF .debug_info.237 /// For DWARF .debug_info.
238 pub const DbgInfoTypeRelocsTable = std.HashMapUnmanaged(Type, DbgInfoTypeReloc, Type.HashContext64, std.hash_map.default_max_load_percentage);238 pub const DbgInfoTypeRelocsTable = std.ArrayHashMapUnmanaged(
239 Type,
240 DbgInfoTypeReloc,
241 Type.HashContext32,
242 true,
243 );
239244
240 /// For DWARF .debug_info.245 /// For DWARF .debug_info.
241 pub const DbgInfoTypeReloc = struct {246 pub const DbgInfoTypeReloc = struct {
src/link/Elf.zig+57-14
...@@ -783,8 +783,9 @@ pub const abbrev_compile_unit = 1;...@@ -783,8 +783,9 @@ pub const abbrev_compile_unit = 1;
783pub const abbrev_subprogram = 2;783pub const abbrev_subprogram = 2;
784pub const abbrev_subprogram_retvoid = 3;784pub const abbrev_subprogram_retvoid = 3;
785pub const abbrev_base_type = 4;785pub const abbrev_base_type = 4;
786pub const abbrev_pad1 = 5;786pub const abbrev_ptr_type = 5;
787pub const abbrev_parameter = 6;787pub const abbrev_pad1 = 6;
788pub const abbrev_parameter = 7;
788789
789pub fn flush(self: *Elf, comp: *Compilation) !void {790pub fn flush(self: *Elf, comp: *Compilation) !void {
790 if (self.base.options.emit == null) {791 if (self.base.options.emit == null) {
...@@ -871,9 +872,21 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {...@@ -871,9 +872,21 @@ pub fn flushModule(self: *Elf, comp: *Compilation) !void {
871 DW.AT.byte_size,872 DW.AT.byte_size,
872 DW.FORM.data1,873 DW.FORM.data1,
873 DW.AT.name,874 DW.AT.name,
874 DW.FORM.string, 0, 0, // table sentinel875 DW.FORM.string,
875 abbrev_pad1, DW.TAG.unspecified_type, DW.CHILDREN.no, // header876 0,
876 0, 0, // table sentinel877 0, // table sentinel
878 abbrev_ptr_type,
879 DW.TAG.pointer_type,
880 DW.CHILDREN.no, // header
881 DW.AT.type,
882 DW.FORM.ref4,
883 0,
884 0, // table sentinel
885 abbrev_pad1,
886 DW.TAG.unspecified_type,
887 DW.CHILDREN.no, // header
888 0,
889 0, // table sentinel
877 abbrev_parameter,890 abbrev_parameter,
878 DW.TAG.formal_parameter, DW.CHILDREN.no, // header891 DW.TAG.formal_parameter, DW.CHILDREN.no, // header
879 DW.AT.location, DW.FORM.exprloc,892 DW.AT.location, DW.FORM.exprloc,
...@@ -2309,8 +2322,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {...@@ -2309,8 +2322,7 @@ pub fn freeDecl(self: *Elf, decl: *Module.Decl) void {
2309}2322}
23102323
2311fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {2324fn deinitRelocs(gpa: Allocator, table: *File.DbgInfoTypeRelocsTable) void {
2312 var it = table.valueIterator();2325 for (table.values()) |*value| {
2313 while (it.next()) |value| {
2314 value.relocs.deinit(gpa);2326 value.relocs.deinit(gpa);
2315 }2327 }
2316 table.deinit(gpa);2328 table.deinit(gpa);
...@@ -2387,10 +2399,12 @@ fn finishUpdateDecl(...@@ -2387,10 +2399,12 @@ fn finishUpdateDecl(
2387 // the buffer, so we have to do it before computing the offset, and we can't perform the actual2399 // the buffer, so we have to do it before computing the offset, and we can't perform the actual
2388 // relocations yet.2400 // relocations yet.
2389 {2401 {
2390 var it = dbg_info_type_relocs.iterator();2402 var it: usize = 0;
2391 while (it.next()) |entry| {2403 while (it < dbg_info_type_relocs.count()) : (it += 1) {
2392 entry.value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);2404 const ty = dbg_info_type_relocs.keys()[it];
2393 try self.addDbgInfoType(entry.key_ptr.*, dbg_info_buffer);2405 const value_ptr = dbg_info_type_relocs.getPtr(ty).?;
2406 value_ptr.off = @intCast(u32, dbg_info_buffer.items.len);
2407 try self.addDbgInfoType(ty, dbg_info_buffer, dbg_info_type_relocs);
2394 }2408 }
2395 }2409 }
23962410
...@@ -2401,8 +2415,7 @@ fn finishUpdateDecl(...@@ -2401,8 +2415,7 @@ fn finishUpdateDecl(
24012415
2402 {2416 {
2403 // Now that we have the offset assigned we can finally perform type relocations.2417 // Now that we have the offset assigned we can finally perform type relocations.
2404 var it = dbg_info_type_relocs.valueIterator();2418 for (dbg_info_type_relocs.values()) |value| {
2405 while (it.next()) |value| {
2406 for (value.relocs.items) |off| {2419 for (value.relocs.items) |off| {
2407 mem.writeInt(2420 mem.writeInt(
2408 u32,2421 u32,
...@@ -2706,7 +2719,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {...@@ -2706,7 +2719,14 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
2706}2719}
27072720
2708/// Asserts the type has codegen bits.2721/// Asserts the type has codegen bits.
2709fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !void {2722fn addDbgInfoType(
2723 self: *Elf,
2724 ty: Type,
2725 dbg_info_buffer: *std.ArrayList(u8),
2726 dbg_info_type_relocs: *File.DbgInfoTypeRelocsTable,
2727) error{OutOfMemory}!void {
2728 var reloc: ?struct { ty: Type, reloc: u32 } = null;
2729
2710 switch (ty.zigTypeTag()) {2730 switch (ty.zigTypeTag()) {
2711 .Void => unreachable,2731 .Void => unreachable,
2712 .NoReturn => unreachable,2732 .NoReturn => unreachable,
...@@ -2747,11 +2767,34 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo...@@ -2747,11 +2767,34 @@ fn addDbgInfoType(self: *Elf, ty: Type, dbg_info_buffer: *std.ArrayList(u8)) !vo
2747 try dbg_info_buffer.append(abbrev_pad1);2767 try dbg_info_buffer.append(abbrev_pad1);
2748 }2768 }
2749 },2769 },
2770 .Pointer => blk: {
2771 if (ty.isSlice()) {
2772 log.debug("TODO implement .debug_info for type '{}'", .{ty});
2773 try dbg_info_buffer.append(abbrev_pad1);
2774 break :blk;
2775 }
2776 try dbg_info_buffer.ensureUnusedCapacity(5);
2777 dbg_info_buffer.appendAssumeCapacity(abbrev_ptr_type);
2778 const index = dbg_info_buffer.items.len;
2779 try dbg_info_buffer.resize(index + 4); // DW.AT.type, DW.FORM.ref4
2780 reloc = .{ .ty = ty.childType(), .reloc = @intCast(u32, index) };
2781 },
2750 else => {2782 else => {
2751 log.debug("TODO implement .debug_info for type '{}'", .{ty});2783 log.debug("TODO implement .debug_info for type '{}'", .{ty});
2752 try dbg_info_buffer.append(abbrev_pad1);2784 try dbg_info_buffer.append(abbrev_pad1);
2753 },2785 },
2754 }2786 }
2787
2788 if (reloc) |rel| {
2789 const gop = try dbg_info_type_relocs.getOrPut(self.base.allocator, rel.ty);
2790 if (!gop.found_existing) {
2791 gop.value_ptr.* = .{
2792 .off = undefined,
2793 .relocs = .{},
2794 };
2795 }
2796 try gop.value_ptr.relocs.append(self.base.allocator, rel.reloc);
2797 }
2755}2798}
27562799
2757fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void {2800fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !void {
src/link/MachO.zig+2-4
...@@ -3578,8 +3578,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv...@@ -3578,8 +3578,7 @@ pub fn updateFunc(self: *MachO, module: *Module, func: *Module.Fn, air: Air, liv
3578 if (debug_buffers) |dbg| {3578 if (debug_buffers) |dbg| {
3579 dbg.dbg_line_buffer.deinit();3579 dbg.dbg_line_buffer.deinit();
3580 dbg.dbg_info_buffer.deinit();3580 dbg.dbg_info_buffer.deinit();
3581 var it = dbg.dbg_info_type_relocs.valueIterator();3581 for (dbg.dbg_info_type_relocs.values()) |*value| {
3582 while (it.next()) |value| {
3583 value.relocs.deinit(self.base.allocator);3582 value.relocs.deinit(self.base.allocator);
3584 }3583 }
3585 dbg.dbg_info_type_relocs.deinit(self.base.allocator);3584 dbg.dbg_info_type_relocs.deinit(self.base.allocator);
...@@ -3659,8 +3658,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {...@@ -3659,8 +3658,7 @@ pub fn updateDecl(self: *MachO, module: *Module, decl: *Module.Decl) !void {
3659 if (debug_buffers) |dbg| {3658 if (debug_buffers) |dbg| {
3660 dbg.dbg_line_buffer.deinit();3659 dbg.dbg_line_buffer.deinit();
3661 dbg.dbg_info_buffer.deinit();3660 dbg.dbg_info_buffer.deinit();
3662 var it = dbg.dbg_info_type_relocs.valueIterator();3661 for (dbg.dbg_info_type_relocs.values()) |*value| {
3663 while (it.next()) |value| {
3664 value.relocs.deinit(self.base.allocator);3662 value.relocs.deinit(self.base.allocator);
3665 }3663 }
3666 dbg.dbg_info_type_relocs.deinit(self.base.allocator);3664 dbg.dbg_info_type_relocs.deinit(self.base.allocator);
src/link/MachO/DebugSymbols.zig+1-2
...@@ -1112,8 +1112,7 @@ pub fn commitDeclDebugInfo(...@@ -1112,8 +1112,7 @@ pub fn commitDeclDebugInfo(
11121112
1113 {1113 {
1114 // Now that we have the offset assigned we can finally perform type relocations.1114 // Now that we have the offset assigned we can finally perform type relocations.
1115 var it = dbg_info_type_relocs.valueIterator();1115 for (dbg_info_type_relocs.values()) |value| {
1116 while (it.next()) |value| {
1117 for (value.relocs.items) |off| {1116 for (value.relocs.items) |off| {
1118 mem.writeIntLittle(1117 mem.writeIntLittle(
1119 u32,1118 u32,