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,...@@ -67,6 +67,18 @@ code_section_index: ?u32 = null,
67debug_info_index: ?u32 = null,67debug_info_index: ?u32 = null,
68/// The index of the segment representing the custom '.debug_line' section.68/// The index of the segment representing the custom '.debug_line' section.
69debug_line_index: ?u32 = null,69debug_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,
70/// The count of imported functions. This number will be appended82/// The count of imported functions. This number will be appended
71/// to the function indexes as their index starts at the lowest non-extern function.83/// to the function indexes as their index starts at the lowest non-extern function.
72imported_functions_count: u32 = 0,84imported_functions_count: u32 = 0,
...@@ -1753,7 +1765,7 @@ fn setupMemory(self: *Wasm) !void {...@@ -1753,7 +1765,7 @@ fn setupMemory(self: *Wasm) !void {
1753/// From a given object's index and the index of the segment, returns the corresponding1765/// From a given object's index and the index of the segment, returns the corresponding
1754/// index of the segment within the final data section. When the segment does not yet1766/// index of the segment within the final data section. When the segment does not yet
1755/// exist, a new one will be initialized and appended. The new index will be returned in that case.1767/// 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 {
1757 const object: Object = self.objects.items[object_index];1769 const object: Object = self.objects.items[object_index];
1758 const relocatable_data = object.relocatable_data[relocatable_index];1770 const relocatable_data = object.relocatable_data[relocatable_index];
1759 const index = @intCast(u32, self.segments.items.len);1771 const index = @intCast(u32, self.segments.items.len);
...@@ -1765,27 +1777,83 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32...@@ -1765,27 +1777,83 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32
1765 const result = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName(merge_segment));1777 const result = try self.data_segments.getOrPut(self.base.allocator, segment_info.outputName(merge_segment));
1766 if (!result.found_existing) {1778 if (!result.found_existing) {
1767 result.value_ptr.* = index;1779 result.value_ptr.* = index;
1768 try self.segments.append(self.base.allocator, .{1780 try self.appendDummySegment();
1769 .alignment = 1,
1770 .size = 0,
1771 .offset = 0,
1772 });
1773 return index;1781 return index;
1774 } else return result.value_ptr.*;1782 } else return result.value_ptr.*;
1775 },1783 },
1776 .code => return self.code_section_index orelse blk: {1784 .code => return self.code_section_index orelse blk: {
1777 self.code_section_index = index;1785 self.code_section_index = index;
1778 try self.segments.append(self.base.allocator, .{1786 try self.appendDummySegment();
1779 .alignment = 1,
1780 .size = 0,
1781 .offset = 0,
1782 });
1783 break :blk index;1787 break :blk index;
1784 },1788 },
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 },
1786 }1845 }
1787}1846}
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
1789/// Returns the symbol index of the error name table.1857/// Returns the symbol index of the error name table.
1790///1858///
1791/// When the symbol does not yet exist, it will create a new one instead.1859/// When the symbol does not yet exist, it will create a new one instead.
...@@ -1936,17 +2004,18 @@ fn resetState(self: *Wasm) void {...@@ -1936,17 +2004,18 @@ fn resetState(self: *Wasm) void {
1936 for (self.segment_info.items) |*segment_info| {2004 for (self.segment_info.items) |*segment_info| {
1937 self.base.allocator.free(segment_info.name);2005 self.base.allocator.free(segment_info.name);
1938 }2006 }
1939 const mod = self.base.options.module.?;2007 if (self.base.options.module) |mod| {
1940 var decl_it = self.decls.keyIterator();2008 var decl_it = self.decls.keyIterator();
1941 while (decl_it.next()) |decl_index_ptr| {2009 while (decl_it.next()) |decl_index_ptr| {
1942 const decl = mod.declPtr(decl_index_ptr.*);2010 const decl = mod.declPtr(decl_index_ptr.*);
1943 const atom = &decl.link.wasm;2011 const atom = &decl.link.wasm;
1944 atom.next = null;2012 atom.next = null;
1945 atom.prev = null;2013 atom.prev = null;
19462014
1947 for (atom.locals.items) |*local_atom| {2015 for (atom.locals.items) |*local_atom| {
1948 local_atom.next = null;2016 local_atom.next = null;
1949 local_atom.prev = null;2017 local_atom.prev = null;
2018 }
1950 }2019 }
1951 }2020 }
1952 self.functions.clearRetainingCapacity();2021 self.functions.clearRetainingCapacity();
...@@ -2036,29 +2105,34 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2036,29 +2105,34 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2036 defer self.resetState();2105 defer self.resetState();
2037 try self.setupStart();2106 try self.setupStart();
2038 try self.setupImports();2107 try self.setupImports();
2039 const mod = self.base.options.module.?;2108 if (self.base.options.module) |mod| {
2040 var decl_it = self.decls.keyIterator();2109 var decl_it = self.decls.keyIterator();
2041 while (decl_it.next()) |decl_index_ptr| {2110 while (decl_it.next()) |decl_index_ptr| {
2042 const decl = mod.declPtr(decl_index_ptr.*);2111 const decl = mod.declPtr(decl_index_ptr.*);
2043 if (decl.isExtern()) continue;2112 if (decl.isExtern()) continue;
2044 const atom = &decl.*.link.wasm;2113 const atom = &decl.*.link.wasm;
2045 if (decl.ty.zigTypeTag() == .Fn) {2114 if (decl.ty.zigTypeTag() == .Fn) {
2046 try self.parseAtom(atom, .{ .function = decl.fn_link.wasm });2115 try self.parseAtom(atom, .{ .function = decl.fn_link.wasm });
2047 } else if (decl.getVariable()) |variable| {2116 } else if (decl.getVariable()) |variable| {
2048 if (!variable.is_mutable) {2117 if (!variable.is_mutable) {
2049 try self.parseAtom(atom, .{ .data = .read_only });2118 try self.parseAtom(atom, .{ .data = .read_only });
2050 } else if (variable.init.isUndefDeep()) {2119 } else if (variable.init.isUndefDeep()) {
2051 try self.parseAtom(atom, .{ .data = .uninitialized });2120 try self.parseAtom(atom, .{ .data = .uninitialized });
2121 } else {
2122 try self.parseAtom(atom, .{ .data = .initialized });
2123 }
2052 } else {2124 } 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 });
2054 }2131 }
2055 } else {
2056 try self.parseAtom(atom, .{ .data = .read_only });
2057 }2132 }
20582133
2059 // also parse atoms for a decl's locals2134 if (self.dwarf) |*dwarf| {
2060 for (atom.locals.items) |*local_atom| {2135 try dwarf.flushModule(&self.base, self.base.options.module.?);
2061 try self.parseAtom(local_atom, .{ .data = .read_only });
2062 }2136 }
2063 }2137 }
20642138
...@@ -2066,9 +2140,6 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2066,9 +2140,6 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2066 try object.parseIntoAtoms(self.base.allocator, @intCast(u16, object_index), self);2140 try object.parseIntoAtoms(self.base.allocator, @intCast(u16, object_index), self);
2067 }2141 }
20682142
2069 if (self.dwarf) |*dwarf| {
2070 try dwarf.flushModule(&self.base, self.base.options.module.?);
2071 }
2072 try self.allocateAtoms();2143 try self.allocateAtoms();
2073 try self.setupMemory();2144 try self.setupMemory();
2074 self.mapFunctionTable();2145 self.mapFunctionTable();
...@@ -2425,12 +2496,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -2425,12 +2496,14 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
2425 } else if (!self.base.options.strip) {2496 } else if (!self.base.options.strip) {
2426 if (self.dwarf) |*dwarf| {2497 if (self.dwarf) |*dwarf| {
2427 if (self.debug_info_index != null) {2498 if (self.debug_info_index != null) {
2428 try dwarf.writeDbgAbbrev(&self.base);2499 if (self.base.options.module) |mod| {
2429 // for debug info and ranges, the address is always 0,2500 try dwarf.writeDbgAbbrev(&self.base);
2430 // as locations are always offsets relative to 'code' section.2501 // for debug info and ranges, the address is always 0,
2431 try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size);2502 // as locations are always offsets relative to 'code' section.
2432 try dwarf.writeDbgAranges(&self.base, 0, code_section_size);2503 try dwarf.writeDbgInfoHeader(&self.base, mod, 0, code_section_size);
2433 try dwarf.writeDbgLineHeader(&self.base, mod);2504 try dwarf.writeDbgAranges(&self.base, 0, code_section_size);
2505 try dwarf.writeDbgLineHeader(&self.base, mod);
2506 }
24342507
2435 try emitDebugSection(file, self.debug_info.items, ".debug_info");2508 try emitDebugSection(file, self.debug_info.items, ".debug_info");
2436 try emitDebugSection(file, self.debug_aranges.items, ".debug_ranges");2509 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...@@ -889,12 +889,9 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
889 }889 }
890890
891 for (self.relocatable_data) |relocatable_data, index| {891 for (self.relocatable_data) |relocatable_data, index| {
892 const symbols = symbol_for_segment.getPtr(.{892 const final_index = (try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index))) orelse {
893 .kind = relocatable_data.getSymbolKind(),893 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
894 .index = @intCast(u32, relocatable_data.index),894 };
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));
898895
899 const atom = try gpa.create(Atom);896 const atom = try gpa.create(Atom);
900 atom.* = Atom.empty;897 atom.* = Atom.empty;
...@@ -907,7 +904,6 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -907,7 +904,6 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
907 atom.file = object_index;904 atom.file = object_index;
908 atom.size = relocatable_data.size;905 atom.size = relocatable_data.size;
909 atom.alignment = relocatable_data.getAlignment(self);906 atom.alignment = relocatable_data.getAlignment(self);
910 atom.sym_index = sym_index;
911907
912 const relocations: []types.Relocation = self.relocations.get(relocatable_data.section_index) orelse &.{};908 const relocations: []types.Relocation = self.relocations.get(relocatable_data.section_index) orelse &.{};
913 for (relocations) |relocation| {909 for (relocations) |relocation| {
...@@ -929,19 +925,30 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin...@@ -929,19 +925,30 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
929925
930 try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);926 try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);
931927
932 // symbols referencing the same atom will be added as alias928 if (relocatable_data.type != .debug) {
933 // or as 'parent' when they are global.929 const symbols = symbol_for_segment.getPtr(.{
934 while (symbols.popOrNull()) |idx| {930 .kind = relocatable_data.getSymbolKind(),
935 const alias_symbol = self.symtable[idx];931 .index = @intCast(u32, relocatable_data.index),
936 const symbol = self.symtable[atom.sym_index];932 }) orelse continue; // encountered a segment we do not create an atom for
937 if (alias_symbol.isGlobal() and symbol.isLocal()) {933 const sym_index = symbols.pop();
938 atom.sym_index = idx;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 }
939 }944 }
945 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
940 }946 }
941 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
942947
943 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];948 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
946 if (wasm_bin.atoms.getPtr(final_index)) |last| {953 if (wasm_bin.atoms.getPtr(final_index)) |last| {
947 last.*.next = atom;954 last.*.next = atom;