authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-08-30 21:47:05+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-09-07 18:53:16+02:00
logf060edb0f3e23a18b17af9b619f7f499ac8e4e7f
tree15274e170925be77869c4a81c1517269b02eba6f
parent9a92f3d290694bfefbc7d71b5ba1823edb6c547f
signaturelock-open Commit is signed but in an unrecognized format.

wasm-linker: create atoms from debug sections


2 files changed, 146 insertions(+), 66 deletions(-)

src/link/Wasm.zig+123-50
......@@ -67,6 +67,18 @@ code_section_index: ?u32 = null,
6767debug_info_index: ?u32 = null,
6868/// The index of the segment representing the custom '.debug_line' section.
6969debug_line_index: ?u32 = null,
70/// The index of the segment representing the custom '.debug_loc' section.
71debug_loc_index: ?u32 = null,
72/// The index of the segment representing the custom '.debug_ranges' section.
73debug_ranges_index: ?u32 = null,
74/// The index of the segment representing the custom '.debug_pubnames' section.
75debug_pubnames_index: ?u32 = null,
76/// The index of the segment representing the custom '.debug_pubtypes' section.
77debug_pubtypes_index: ?u32 = null,
78/// The index of the segment representing the custom '.debug_pubtypes' section.
79debug_str_index: ?u32 = null,
80/// The index of the segment representing the custom '.debug_pubtypes' section.
81debug_abbrev_index: ?u32 = null,
7082/// The count of imported functions. This number will be appended
7183/// to the function indexes as their index starts at the lowest non-extern function.
7284imported_functions_count: u32 = 0,
......@@ -1753,7 +1765,7 @@ fn setupMemory(self: *Wasm) !void {
17531765/// From a given object's index and the index of the segment, returns the corresponding
17541766/// index of the segment within the final data section. When the segment does not yet
17551767/// exist, a new one will be initialized and appended. The new index will be returned in that case.
1756pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32) !u32 {
1768pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32) !?u32 {
17571769 const object: Object = self.objects.items[object_index];
17581770 const relocatable_data = object.relocatable_data[relocatable_index];
17591771 const index = @intCast(u32, self.segments.items.len);
......@@ -1765,27 +1777,83 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32
17651777 const result = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName(merge_segment));
17661778 if (!result.found_existing) {
17671779 result.value_ptr.* = index;
1768 try self.segments.append(self.base.allocator, .{
1769 .alignment = 1,
1770 .size = 0,
1771 .offset = 0,
1772 });
1780 try self.appendDummySegment();
17731781 return index;
17741782 } else return result.value_ptr.*;
17751783 },
17761784 .code => return self.code_section_index orelse blk: {
17771785 self.code_section_index = index;
1778 try self.segments.append(self.base.allocator, .{
1779 .alignment = 1,
1780 .size = 0,
1781 .offset = 0,
1782 });
1786 try self.appendDummySegment();
17831787 break :blk index;
17841788 },
1785 .debug => return error.@"TODO: Custom section relocations for wasm",
1789 .debug => {
1790 const debug_name = object.getDebugName(relocatable_data);
1791 if (mem.eql(u8, debug_name, ".debug_info")) {
1792 return self.debug_info_index orelse blk: {
1793 self.debug_info_index = index;
1794 try self.appendDummySegment();
1795 break :blk index;
1796 };
1797 } else if (mem.eql(u8, debug_name, ".debug_line")) {
1798 return self.debug_line_index orelse blk: {
1799 self.debug_line_index = index;
1800 try self.appendDummySegment();
1801 break :blk index;
1802 };
1803 } else if (mem.eql(u8, debug_name, ".debug_loc")) {
1804 return self.debug_loc_index orelse blk: {
1805 self.debug_loc_index = index;
1806 try self.appendDummySegment();
1807 break :blk index;
1808 };
1809 } else if (mem.eql(u8, debug_name, ".debug_ranges")) {
1810 return self.debug_line_index orelse blk: {
1811 self.debug_ranges_index = index;
1812 try self.appendDummySegment();
1813 break :blk index;
1814 };
1815 } else if (mem.eql(u8, debug_name, ".debug_pubnames")) {
1816 return self.debug_pubnames_index orelse blk: {
1817 self.debug_pubnames_index = index;
1818 try self.appendDummySegment();
1819 break :blk index;
1820 };
1821 } else if (mem.eql(u8, debug_name, ".debug_pubtypes")) {
1822 return self.debug_pubtypes_index orelse blk: {
1823 self.debug_pubtypes_index = index;
1824 try self.appendDummySegment();
1825 break :blk index;
1826 };
1827 } else if (mem.eql(u8, debug_name, ".debug_abbrev")) {
1828 return self.debug_abbrev_index orelse blk: {
1829 self.debug_abbrev_index = index;
1830 try self.appendDummySegment();
1831 break :blk index;
1832 };
1833 } else if (mem.eql(u8, debug_name, ".debug_str")) {
1834 return self.debug_str_index orelse blk: {
1835 self.debug_str_index = index;
1836 try self.appendDummySegment();
1837 break :blk index;
1838 };
1839 } else {
1840 log.warn("found unknown debug section '{s}'", .{debug_name});
1841 log.warn(" debug section will be skipped", .{});
1842 return null;
1843 }
1844 },
17861845 }
17871846}
17881847
1848/// Appends a new segment with default field values
1849fn appendDummySegment(self: *Wasm) !void {
1850 try self.segments.append(self.base.allocator, .{
1851 .alignment = 1,
1852 .size = 0,
1853 .offset = 0,
1854 });
1855}
1856
17891857/// Returns the symbol index of the error name table.
17901858///
17911859/// When the symbol does not yet exist, it will create a new one instead.
......@@ -1936,17 +2004,18 @@ fn resetState(self: *Wasm) void {
19362004 for (self.segment_info.items) |*segment_info| {
19372005 self.base.allocator.free(segment_info.name);
19382006 }
1939 const mod = self.base.options.module.?;
1940 var decl_it = self.decls.keyIterator();
1941 while (decl_it.next()) |decl_index_ptr| {
1942 const decl = mod.declPtr(decl_index_ptr.*);
1943 const atom = &decl.link.wasm;
1944 atom.next = null;
1945 atom.prev = null;
2007 if (self.base.options.module) |mod| {
2008 var decl_it = self.decls.keyIterator();
2009 while (decl_it.next()) |decl_index_ptr| {
2010 const decl = mod.declPtr(decl_index_ptr.*);
2011 const atom = &decl.link.wasm;
2012 atom.next = null;
2013 atom.prev = null;
19462014
1947 for (atom.locals.items) |*local_atom| {
1948 local_atom.next = null;
1949 local_atom.prev = null;
2015 for (atom.locals.items) |*local_atom| {
2016 local_atom.next = null;
2017 local_atom.prev = null;
2018 }
19502019 }
19512020 }
19522021 self.functions.clearRetainingCapacity();
......@@ -2036,29 +2105,34 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
20362105 defer self.resetState();
20372106 try self.setupStart();
20382107 try self.setupImports();
2039 const mod = self.base.options.module.?;
2040 var decl_it = self.decls.keyIterator();
2041 while (decl_it.next()) |decl_index_ptr| {
2042 const decl = mod.declPtr(decl_index_ptr.*);
2043 if (decl.isExtern()) continue;
2044 const atom = &decl.*.link.wasm;
2045 if (decl.ty.zigTypeTag() == .Fn) {
2046 try self.parseAtom(atom, .{ .function = decl.fn_link.wasm });
2047 } else if (decl.getVariable()) |variable| {
2048 if (!variable.is_mutable) {
2049 try self.parseAtom(atom, .{ .data = .read_only });
2050 } else if (variable.init.isUndefDeep()) {
2051 try self.parseAtom(atom, .{ .data = .uninitialized });
2108 if (self.base.options.module) |mod| {
2109 var decl_it = self.decls.keyIterator();
2110 while (decl_it.next()) |decl_index_ptr| {
2111 const decl = mod.declPtr(decl_index_ptr.*);
2112 if (decl.isExtern()) continue;
2113 const atom = &decl.*.link.wasm;
2114 if (decl.ty.zigTypeTag() == .Fn) {
2115 try self.parseAtom(atom, .{ .function = decl.fn_link.wasm });
2116 } else if (decl.getVariable()) |variable| {
2117 if (!variable.is_mutable) {
2118 try self.parseAtom(atom, .{ .data = .read_only });
2119 } else if (variable.init.isUndefDeep()) {
2120 try self.parseAtom(atom, .{ .data = .uninitialized });
2121 } else {
2122 try self.parseAtom(atom, .{ .data = .initialized });
2123 }
20522124 } else {
2053 try self.parseAtom(atom, .{ .data = .initialized });
2125 try self.parseAtom(atom, .{ .data = .read_only });
2126 }
2127
2128 // also parse atoms for a decl's locals
2129 for (atom.locals.items) |*local_atom| {
2130 try self.parseAtom(local_atom, .{ .data = .read_only });
20542131 }
2055 } else {
2056 try self.parseAtom(atom, .{ .data = .read_only });
20572132 }
20582133
2059 // also parse atoms for a decl's locals
2060 for (atom.locals.items) |*local_atom| {
2061 try self.parseAtom(local_atom, .{ .data = .read_only });
2134 if (self.dwarf) |*dwarf| {
2135 try dwarf.flushModule(&self.base, self.base.options.module.?);
20622136 }
20632137 }
20642138
......@@ -2066,9 +2140,6 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
20662140 try object.parseIntoAtoms(self.base.allocator, @intCast(u16, object_index), self);
20672141 }
20682142
2069 if (self.dwarf) |*dwarf| {
2070 try dwarf.flushModule(&self.base, self.base.options.module.?);
2071 }
20722143 try self.allocateAtoms();
20732144 try self.setupMemory();
20742145 self.mapFunctionTable();
......@@ -2425,12 +2496,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
24252496 } else if (!self.base.options.strip) {
24262497 if (self.dwarf) |*dwarf| {
24272498 if (self.debug_info_index != null) {
2428 try dwarf.writeDbgAbbrev(&self.base);
2429 // for debug info and ranges, the address is always 0,
2430 // as locations are always offsets relative to 'code' section.
2431 try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size);
2432 try dwarf.writeDbgAranges(&self.base, 0, code_section_size);
2433 try dwarf.writeDbgLineHeader(&self.base, mod);
2499 if (self.base.options.module) |mod| {
2500 try dwarf.writeDbgAbbrev(&self.base);
2501 // for debug info and ranges, the address is always 0,
2502 // as locations are always offsets relative to 'code' section.
2503 try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size);
2504 try dwarf.writeDbgAranges(&self.base, 0, code_section_size);
2505 try dwarf.writeDbgLineHeader(&self.base, mod);
2506 }
24342507
24352508 try emitDebugSection(file, self.debug_info.items, ".debug_info");
24362509 try emitDebugSection(file, self.debug_aranges.items, ".debug_ranges");
src/link/Wasm/Object.zig+23-16
......@@ -889,12 +889,9 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
889889 }
890890
891891 for (self.relocatable_data) |relocatable_data, index| {
892 const symbols = symbol_for_segment.getPtr(.{
893 .kind = relocatable_data.getSymbolKind(),
894 .index = @intCast(u32, relocatable_data.index),
895 }) orelse continue; // encountered a segment we do not create an atom for
896 const sym_index = symbols.pop();
897 const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index));
892 const final_index = (try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index))) orelse {
893 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
894 };
898895
899896 const atom = try gpa.create(Atom);
900897 atom.* = Atom.empty;
......@@ -907,7 +904,6 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
907904 atom.file = object_index;
908905 atom.size = relocatable_data.size;
909906 atom.alignment = relocatable_data.getAlignment(self);
910 atom.sym_index = sym_index;
911907
912908 const relocations: []types.Relocation = self.relocations.get(relocatable_data.section_index) orelse &.{};
913909 for (relocations) |relocation| {
......@@ -929,19 +925,30 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
929925
930926 try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);
931927
932 // symbols referencing the same atom will be added as alias
933 // or as 'parent' when they are global.
934 while (symbols.popOrNull()) |idx| {
935 const alias_symbol = self.symtable[idx];
936 const symbol = self.symtable[atom.sym_index];
937 if (alias_symbol.isGlobal() and symbol.isLocal()) {
938 atom.sym_index = idx;
928 if (relocatable_data.type != .debug) {
929 const symbols = symbol_for_segment.getPtr(.{
930 .kind = relocatable_data.getSymbolKind(),
931 .index = @intCast(u32, relocatable_data.index),
932 }) orelse continue; // encountered a segment we do not create an atom for
933 const sym_index = symbols.pop();
934 atom.sym_index = sym_index;
935
936 // symbols referencing the same atom will be added as alias
937 // or as 'parent' when they are global.
938 while (symbols.popOrNull()) |idx| {
939 const alias_symbol = self.symtable[idx];
940 const symbol = self.symtable[atom.sym_index];
941 if (alias_symbol.isGlobal() and symbol.isLocal()) {
942 atom.sym_index = idx;
943 }
939944 }
945 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
940946 }
941 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
942947
943948 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];
944 segment.alignment = std.math.max(segment.alignment, atom.alignment);
949 if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned
950 segment.alignment = std.math.max(segment.alignment, atom.alignment);
951 }
945952
946953 if (wasm_bin.atoms.getPtr(final_index)) |last| {
947954 last.*.next = atom;