authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-08-29 20:13:55+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-09-07 18:53:12+02:00
log9a92f3d290694bfefbc7d71b5ba1823edb6c547f
treea2b6759748a3c0d561d0bccdcbe43f14e7d20c4b
parent924679abc46deeaae9284ab6ce928aaddb0fae95
signaturelock-open Commit is signed but in an unrecognized format.

wasm/Object: parse debug sections into reloc data

Rather than storing the name of a debug section into the structure `RelocatableData`, we use the `index` field as an offset into the debug names table. This means we do not have to store an extra 16 bytes for non-debug sections which can be massive for object files where each data symbol has its own data section. The name of a debug section can then be retrieved again when needed by using the offset and then reading until the 0-delimiter.

2 files changed, 45 insertions(+), 8 deletions(-)

src/link/Wasm.zig+1-1
......@@ -1782,7 +1782,7 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32
17821782 });
17831783 break :blk index;
17841784 },
1785 .custom => return error.@"TODO: Custom section relocations for wasm",
1785 .debug => return error.@"TODO: Custom section relocations for wasm",
17861786 }
17871787}
17881788
src/link/Wasm/Object.zig+44-7
......@@ -63,16 +63,21 @@ relocatable_data: []const RelocatableData = &.{},
6363/// import name, module name and export names. Each string will be deduplicated
6464/// and returns an offset into the table.
6565string_table: Wasm.StringTable = .{},
66/// All the names of each debug section found in the current object file.
67/// Each name is terminated by a null-terminator. The name can be found,
68/// from the `index` offset within the `RelocatableData`.
69debug_names: [:0]const u8,
6670
6771/// Represents a single item within a section (depending on its `type`)
6872const RelocatableData = struct {
6973 /// The type of the relocatable data
70 type: enum { data, code, custom },
74 type: enum { data, code, debug },
7175 /// Pointer to the data of the segment, where its length is written to `size`
7276 data: [*]u8,
7377 /// The size in bytes of the data representing the segment within the section
7478 size: u32,
75 /// The index within the section itself
79 /// The index within the section itself, or in case of a debug section,
80 /// the offset within the `debug_names` table.
7681 index: u32,
7782 /// The offset within the section where the data starts
7883 offset: u32,
......@@ -96,7 +101,7 @@ const RelocatableData = struct {
96101 return switch (self.type) {
97102 .data => .data,
98103 .code => .function,
99 .custom => .section,
104 .debug => unreachable, // illegal, debug sections are not represented by a symbol
100105 };
101106 }
102107};
......@@ -111,6 +116,7 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz
111116 var object: Object = .{
112117 .file = file,
113118 .name = try gpa.dupe(u8, name),
119 .debug_names = &.{},
114120 };
115121
116122 var is_object_file: bool = false;
......@@ -197,6 +203,11 @@ pub fn importedCountByKind(self: *const Object, kind: std.wasm.ExternalKind) u32
197203 } else i;
198204}
199205
206/// From a given `RelocatableDate`, find the corresponding debug section name
207pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []const u8 {
208 return std.mem.sliceTo(self.debug_names[relocatable_data.index..], 0);
209}
210
200211/// Checks if the object file is an MVP version.
201212/// When that's the case, we check if there's an import table definiton with its name
202213/// set to '__indirect_function_table". When that's also the case,
......@@ -328,10 +339,15 @@ fn Parser(comptime ReaderType: type) type {
328339
329340 self.object.version = version;
330341 var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
331
332 errdefer while (relocatable_data.popOrNull()) |rel_data| {
333 gpa.free(rel_data.data[0..rel_data.size]);
334 } else relocatable_data.deinit();
342 var debug_names = std.ArrayList(u8).init(gpa);
343
344 errdefer {
345 while (relocatable_data.popOrNull()) |rel_data| {
346 gpa.free(rel_data.data[0..rel_data.size]);
347 } else relocatable_data.deinit();
348 gpa.free(debug_names.items);
349 debug_names.deinit();
350 }
335351
336352 var section_index: u32 = 0;
337353 while (self.reader.reader().readByte()) |byte| : (section_index += 1) {
......@@ -352,6 +368,24 @@ fn Parser(comptime ReaderType: type) type {
352368 try self.parseRelocations(gpa);
353369 } else if (std.mem.eql(u8, name, "target_features")) {
354370 try self.parseFeatures(gpa);
371 } else if (std.mem.startsWith(u8, name, ".debug")) {
372 const debug_size = @intCast(u32, reader.context.bytes_left);
373 const debug_content = try gpa.alloc(u8, debug_size);
374 errdefer gpa.free(debug_content);
375 try reader.readNoEof(debug_content);
376
377 const debug_name_index = @intCast(u32, debug_names.items.len);
378 try debug_names.ensureUnusedCapacity(name.len + 1);
379 debug_names.appendSliceAssumeCapacity(try gpa.dupe(u8, name));
380 debug_names.appendAssumeCapacity(0);
381 try relocatable_data.append(.{
382 .type = .debug,
383 .data = debug_content.ptr,
384 .size = debug_size,
385 .index = debug_name_index,
386 .offset = len - debug_size,
387 .section_index = section_index,
388 });
355389 } else {
356390 try reader.skipBytes(reader.context.bytes_left, .{});
357391 }
......@@ -517,6 +551,9 @@ fn Parser(comptime ReaderType: type) type {
517551 else => |e| return e,
518552 }
519553 self.object.relocatable_data = relocatable_data.toOwnedSlice();
554
555 const names = debug_names.toOwnedSlice();
556 self.object.debug_names = names[0 .. names.len - 1 :0];
520557 }
521558
522559 /// Based on the "features" custom section, parses it into a list of