authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-11-16 19:29:57+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2023-11-28 15:47:07+01:00
log8856ba75059f74a326d1f8d3af40a30c5a3ac1ed
tree35ceb0bd2015c4bf89dda04c8ffc2bc49633c3bf
parentc986c6c90a5746cb671177e486a77bd78a5946b0
signature Commit is signed but in an unrecognized format.

wasm-linker: parse symbols into atoms lazily

Rather than parsing every symbol into an atom, we now only parse them into an atom when such atom is marked. This means garbage-collected symbols will also not be parsed into atoms, and neither are discarded symbols which have been resolved by other symbols. (Such as multiple weak symbols). This also introduces a binary search for finding the start index into the list of relocations. This speeds up finding the corresponding relocations tremendously as they're ordered ascended by address. Lastly, we re-use the memory of atom's data as well as relocations instead of duplicating it. This means we half the memory usage of atom's data and relocations for linked object files. As we are aware of decls and synthetic atoms, we free the memory of those atoms indepedently of the atoms of object files to prevent double-frees.

3 files changed, 208 insertions(+), 200 deletions(-)

src/link/Wasm.zig+75-51
...@@ -1309,6 +1309,31 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1309,6 +1309,31 @@ pub fn deinit(wasm: *Wasm) void {
1309 archive.deinit(gpa);1309 archive.deinit(gpa);
1310 }1310 }
13111311
1312 // For decls and anon decls we free the memory of its atoms.
1313 // The memory of atoms parsed from object files is managed by
1314 // the object file itself, and therefore we can skip those.
1315 {
1316 var it = wasm.decls.valueIterator();
1317 while (it.next()) |atom_index_ptr| {
1318 const atom = wasm.getAtomPtr(atom_index_ptr.*);
1319 for (atom.locals.items) |local_index| {
1320 const local_atom = wasm.getAtomPtr(local_index);
1321 local_atom.deinit(gpa);
1322 }
1323 atom.deinit(gpa);
1324 }
1325 }
1326 {
1327 for (wasm.anon_decls.values()) |atom_index| {
1328 const atom = wasm.getAtomPtr(atom_index);
1329 for (atom.locals.items) |local_index| {
1330 const local_atom = wasm.getAtomPtr(local_index);
1331 local_atom.deinit(gpa);
1332 }
1333 atom.deinit(gpa);
1334 }
1335 }
1336
1312 wasm.decls.deinit(gpa);1337 wasm.decls.deinit(gpa);
1313 wasm.anon_decls.deinit(gpa);1338 wasm.anon_decls.deinit(gpa);
1314 wasm.atom_types.deinit(gpa);1339 wasm.atom_types.deinit(gpa);
...@@ -1321,9 +1346,6 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1321,9 +1346,6 @@ pub fn deinit(wasm: *Wasm) void {
1321 wasm.symbol_atom.deinit(gpa);1346 wasm.symbol_atom.deinit(gpa);
1322 wasm.export_names.deinit(gpa);1347 wasm.export_names.deinit(gpa);
1323 wasm.atoms.deinit(gpa);1348 wasm.atoms.deinit(gpa);
1324 for (wasm.managed_atoms.items) |*managed_atom| {
1325 managed_atom.deinit(wasm);
1326 }
1327 wasm.managed_atoms.deinit(gpa);1349 wasm.managed_atoms.deinit(gpa);
1328 wasm.segments.deinit(gpa);1350 wasm.segments.deinit(gpa);
1329 wasm.data_segments.deinit(gpa);1351 wasm.data_segments.deinit(gpa);
...@@ -1342,6 +1364,10 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1342,6 +1364,10 @@ pub fn deinit(wasm: *Wasm) void {
1342 wasm.exports.deinit(gpa);1364 wasm.exports.deinit(gpa);
13431365
1344 wasm.string_table.deinit(gpa);1366 wasm.string_table.deinit(gpa);
1367 for (wasm.synthetic_functions.items) |atom_index| {
1368 const atom = wasm.getAtomPtr(atom_index);
1369 atom.deinit(gpa);
1370 }
1345 wasm.synthetic_functions.deinit(gpa);1371 wasm.synthetic_functions.deinit(gpa);
13461372
1347 if (wasm.dwarf) |*dwarf| {1373 if (wasm.dwarf) |*dwarf| {
...@@ -2406,7 +2432,7 @@ fn setupErrorsLen(wasm: *Wasm) !void {...@@ -2406,7 +2432,7 @@ fn setupErrorsLen(wasm: *Wasm) !void {
2406 prev_atom.next = atom.next;2432 prev_atom.next = atom.next;
2407 atom.prev = null;2433 atom.prev = null;
2408 }2434 }
2409 atom.deinit(wasm);2435 atom.deinit(wasm.base.allocator);
2410 break :blk index;2436 break :blk index;
2411 } else new_atom: {2437 } else new_atom: {
2412 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);2438 const atom_index: Atom.Index = @intCast(wasm.managed_atoms.items.len);
...@@ -2509,6 +2535,7 @@ fn createSyntheticFunction(...@@ -2509,6 +2535,7 @@ fn createSyntheticFunction(
2509 .next = null,2535 .next = null,
2510 .prev = null,2536 .prev = null,
2511 .code = function_body.moveToUnmanaged(),2537 .code = function_body.moveToUnmanaged(),
2538 .original_offset = 0,
2512 };2539 };
2513 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);2540 try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
2514 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);2541 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, loc, atom_index);
...@@ -2545,6 +2572,7 @@ pub fn createFunction(...@@ -2545,6 +2572,7 @@ pub fn createFunction(
2545 .prev = null,2572 .prev = null,
2546 .code = function_body.moveToUnmanaged(),2573 .code = function_body.moveToUnmanaged(),
2547 .relocs = relocations.moveToUnmanaged(),2574 .relocs = relocations.moveToUnmanaged(),
2575 .original_offset = 0,
2548 };2576 };
2549 const symbol = loc.getSymbol(wasm);2577 const symbol = loc.getSymbol(wasm);
2550 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); // ensure function does not get exported2578 symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); // ensure function does not get exported
...@@ -3016,14 +3044,14 @@ fn setupMemory(wasm: *Wasm) !void {...@@ -3016,14 +3044,14 @@ fn setupMemory(wasm: *Wasm) !void {
3016/// From a given object's index and the index of the segment, returns the corresponding3044/// From a given object's index and the index of the segment, returns the corresponding
3017/// index of the segment within the final data section. When the segment does not yet3045/// index of the segment within the final data section. When the segment does not yet
3018/// exist, a new one will be initialized and appended. The new index will be returned in that case.3046/// exist, a new one will be initialized and appended. The new index will be returned in that case.
3019pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32) !?u32 {3047pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, symbol_index: u32) !u32 {
3020 const object: Object = wasm.objects.items[object_index];3048 const object: Object = wasm.objects.items[object_index];
3021 const relocatable_data = object.relocatable_data[relocatable_index];3049 const symbol = object.symtable[symbol_index];
3022 const index = @as(u32, @intCast(wasm.segments.items.len));3050 const index = @as(u32, @intCast(wasm.segments.items.len));
30233051
3024 switch (relocatable_data.type) {3052 switch (symbol.tag) {
3025 .data => {3053 .data => {
3026 const segment_info = object.segment_info[relocatable_data.index];3054 const segment_info = object.segment_info[symbol.index];
3027 const merge_segment = wasm.base.options.output_mode != .Obj;3055 const merge_segment = wasm.base.options.output_mode != .Obj;
3028 const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment));3056 const result = try wasm.data_segments.getOrPut(wasm.base.allocator, segment_info.outputName(merge_segment));
3029 if (!result.found_existing) {3057 if (!result.found_existing) {
...@@ -3041,67 +3069,67 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32...@@ -3041,67 +3069,67 @@ pub fn getMatchingSegment(wasm: *Wasm, object_index: u16, relocatable_index: u32
3041 return index;3069 return index;
3042 } else return result.value_ptr.*;3070 } else return result.value_ptr.*;
3043 },3071 },
3044 .code => return wasm.code_section_index orelse blk: {3072 .function => return wasm.code_section_index orelse blk: {
3045 wasm.code_section_index = index;3073 wasm.code_section_index = index;
3046 try wasm.appendDummySegment();3074 try wasm.appendDummySegment();
3047 break :blk index;3075 break :blk index;
3048 },3076 },
3049 .debug => {3077 .section => {
3050 const debug_name = object.getDebugName(relocatable_data);3078 const section_name = object.string_table.get(symbol.name);
3051 if (mem.eql(u8, debug_name, ".debug_info")) {3079 if (mem.eql(u8, section_name, ".debug_info")) {
3052 return wasm.debug_info_index orelse blk: {3080 return wasm.debug_info_index orelse blk: {
3053 wasm.debug_info_index = index;3081 wasm.debug_info_index = index;
3054 try wasm.appendDummySegment();3082 try wasm.appendDummySegment();
3055 break :blk index;3083 break :blk index;
3056 };3084 };
3057 } else if (mem.eql(u8, debug_name, ".debug_line")) {3085 } else if (mem.eql(u8, section_name, ".debug_line")) {
3058 return wasm.debug_line_index orelse blk: {3086 return wasm.debug_line_index orelse blk: {
3059 wasm.debug_line_index = index;3087 wasm.debug_line_index = index;
3060 try wasm.appendDummySegment();3088 try wasm.appendDummySegment();
3061 break :blk index;3089 break :blk index;
3062 };3090 };
3063 } else if (mem.eql(u8, debug_name, ".debug_loc")) {3091 } else if (mem.eql(u8, section_name, ".debug_loc")) {
3064 return wasm.debug_loc_index orelse blk: {3092 return wasm.debug_loc_index orelse blk: {
3065 wasm.debug_loc_index = index;3093 wasm.debug_loc_index = index;
3066 try wasm.appendDummySegment();3094 try wasm.appendDummySegment();
3067 break :blk index;3095 break :blk index;
3068 };3096 };
3069 } else if (mem.eql(u8, debug_name, ".debug_ranges")) {3097 } else if (mem.eql(u8, section_name, ".debug_ranges")) {
3070 return wasm.debug_line_index orelse blk: {3098 return wasm.debug_line_index orelse blk: {
3071 wasm.debug_ranges_index = index;3099 wasm.debug_ranges_index = index;
3072 try wasm.appendDummySegment();3100 try wasm.appendDummySegment();
3073 break :blk index;3101 break :blk index;
3074 };3102 };
3075 } else if (mem.eql(u8, debug_name, ".debug_pubnames")) {3103 } else if (mem.eql(u8, section_name, ".debug_pubnames")) {
3076 return wasm.debug_pubnames_index orelse blk: {3104 return wasm.debug_pubnames_index orelse blk: {
3077 wasm.debug_pubnames_index = index;3105 wasm.debug_pubnames_index = index;
3078 try wasm.appendDummySegment();3106 try wasm.appendDummySegment();
3079 break :blk index;3107 break :blk index;
3080 };3108 };
3081 } else if (mem.eql(u8, debug_name, ".debug_pubtypes")) {3109 } else if (mem.eql(u8, section_name, ".debug_pubtypes")) {
3082 return wasm.debug_pubtypes_index orelse blk: {3110 return wasm.debug_pubtypes_index orelse blk: {
3083 wasm.debug_pubtypes_index = index;3111 wasm.debug_pubtypes_index = index;
3084 try wasm.appendDummySegment();3112 try wasm.appendDummySegment();
3085 break :blk index;3113 break :blk index;
3086 };3114 };
3087 } else if (mem.eql(u8, debug_name, ".debug_abbrev")) {3115 } else if (mem.eql(u8, section_name, ".debug_abbrev")) {
3088 return wasm.debug_abbrev_index orelse blk: {3116 return wasm.debug_abbrev_index orelse blk: {
3089 wasm.debug_abbrev_index = index;3117 wasm.debug_abbrev_index = index;
3090 try wasm.appendDummySegment();3118 try wasm.appendDummySegment();
3091 break :blk index;3119 break :blk index;
3092 };3120 };
3093 } else if (mem.eql(u8, debug_name, ".debug_str")) {3121 } else if (mem.eql(u8, section_name, ".debug_str")) {
3094 return wasm.debug_str_index orelse blk: {3122 return wasm.debug_str_index orelse blk: {
3095 wasm.debug_str_index = index;3123 wasm.debug_str_index = index;
3096 try wasm.appendDummySegment();3124 try wasm.appendDummySegment();
3097 break :blk index;3125 break :blk index;
3098 };3126 };
3099 } else {3127 } else {
3100 log.warn("found unknown debug section '{s}'", .{debug_name});3128 log.warn("found unknown section '{s}'", .{section_name});
3101 log.warn(" debug section will be skipped", .{});3129 return error.UnexpectedValue;
3102 return null;
3103 }3130 }
3104 },3131 },
3132 else => unreachable,
3105 }3133 }
3106}3134}
31073135
...@@ -3468,11 +3496,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l...@@ -3468,11 +3496,7 @@ fn linkWithZld(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Node) l
3468 try wasm.setupInitFunctions();3496 try wasm.setupInitFunctions();
3469 try wasm.setupStart();3497 try wasm.setupStart();
34703498
3471 for (wasm.objects.items, 0..) |*object, object_index| {3499 try wasm.markReferences();
3472 try object.parseIntoAtoms(gpa, @as(u16, @intCast(object_index)), wasm);
3473 }
3474
3475 wasm.markReferences();
3476 try wasm.setupImports();3500 try wasm.setupImports();
3477 try wasm.allocateAtoms();3501 try wasm.allocateAtoms();
3478 try wasm.setupMemory();3502 try wasm.setupMemory();
...@@ -3558,7 +3582,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -3558,7 +3582,7 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
3558 try wasm.setupInitFunctions();3582 try wasm.setupInitFunctions();
3559 try wasm.setupErrorsLen();3583 try wasm.setupErrorsLen();
3560 try wasm.setupStart();3584 try wasm.setupStart();
3561 wasm.markReferences();3585 try wasm.markReferences();
3562 try wasm.setupImports();3586 try wasm.setupImports();
3563 if (wasm.base.options.module) |mod| {3587 if (wasm.base.options.module) |mod| {
3564 var decl_it = wasm.decls.iterator();3588 var decl_it = wasm.decls.iterator();
...@@ -3615,10 +3639,6 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -3615,10 +3639,6 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
3615 }3639 }
3616 }3640 }
36173641
3618 for (wasm.objects.items, 0..) |*object, object_index| {
3619 try object.parseIntoAtoms(wasm.base.allocator, @as(u16, @intCast(object_index)), wasm);
3620 }
3621
3622 try wasm.allocateAtoms();3642 try wasm.allocateAtoms();
3623 try wasm.setupMemory();3643 try wasm.setupMemory();
3624 wasm.allocateVirtualAddresses();3644 wasm.allocateVirtualAddresses();
...@@ -3885,18 +3905,15 @@ fn writeToFile(...@@ -3885,18 +3905,15 @@ fn writeToFile(
3885 var atom_index = wasm.atoms.get(code_index).?;3905 var atom_index = wasm.atoms.get(code_index).?;
38863906
3887 // The code section must be sorted in line with the function order.3907 // The code section must be sorted in line with the function order.
3888 var sorted_atoms = try std.ArrayList(*Atom).initCapacity(wasm.base.allocator, wasm.functions.count());3908 var sorted_atoms = try std.ArrayList(*const Atom).initCapacity(wasm.base.allocator, wasm.functions.count());
3889 defer sorted_atoms.deinit();3909 defer sorted_atoms.deinit();
38903910
3891 while (true) {3911 while (true) {
3892 var atom = wasm.getAtomPtr(atom_index);3912 const atom = wasm.getAtomPtr(atom_index);
3893 if (wasm.resolved_symbols.contains(atom.symbolLoc())) {3913 if (!is_obj) {
3894 if (!is_obj) {3914 atom.resolveRelocs(wasm);
3895 atom.resolveRelocs(wasm);
3896 }
3897 sorted_atoms.appendAssumeCapacity(atom);
3898 }3915 }
3899 // atom = if (atom.prev) |prev| wasm.getAtomPtr(prev) else break;3916 sorted_atoms.appendAssumeCapacity(atom); // found more code atoms than functions
3900 atom_index = atom.prev orelse break;3917 atom_index = atom.prev orelse break;
3901 }3918 }
39023919
...@@ -3908,7 +3925,7 @@ fn writeToFile(...@@ -3908,7 +3925,7 @@ fn writeToFile(
3908 }3925 }
3909 }.sort;3926 }.sort;
39103927
3911 mem.sort(*Atom, sorted_atoms.items, wasm, atom_sort_fn);3928 mem.sort(*const Atom, sorted_atoms.items, wasm, atom_sort_fn);
39123929
3913 for (sorted_atoms.items) |sorted_atom| {3930 for (sorted_atoms.items) |sorted_atom| {
3914 try leb.writeULEB128(binary_writer, sorted_atom.size);3931 try leb.writeULEB128(binary_writer, sorted_atom.size);
...@@ -5060,20 +5077,20 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s...@@ -5060,20 +5077,20 @@ pub fn storeDeclType(wasm: *Wasm, decl_index: InternPool.DeclIndex, func_type: s
50605077
5061/// Verifies all resolved symbols and checks whether itself needs to be marked alive,5078/// Verifies all resolved symbols and checks whether itself needs to be marked alive,
5062/// as well as any of its references.5079/// as well as any of its references.
5063fn markReferences(wasm: *Wasm) void {5080fn markReferences(wasm: *Wasm) !void {
5064 const tracy = trace(@src());5081 const tracy = trace(@src());
5065 defer tracy.end();5082 defer tracy.end();
5066 for (wasm.resolved_symbols.keys()) |sym_loc| {5083 for (wasm.resolved_symbols.keys()) |sym_loc| {
5067 const sym = sym_loc.getSymbol(wasm);5084 const sym = sym_loc.getSymbol(wasm);
5068 if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip()) {5085 if (sym.isExported(wasm.base.options.rdynamic) or sym.isNoStrip()) {
5069 wasm.mark(sym_loc);5086 try wasm.mark(sym_loc);
5070 }5087 }
5071 }5088 }
5072}5089}
50735090
5074/// Marks a symbol as 'alive' recursively so itself and any references it contains to5091/// Marks a symbol as 'alive' recursively so itself and any references it contains to
5075/// other symbols will not be omit from the binary.5092/// other symbols will not be omit from the binary.
5076fn mark(wasm: *Wasm, loc: SymbolLoc) void {5093fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
5077 const symbol = loc.getSymbol(wasm);5094 const symbol = loc.getSymbol(wasm);
5078 if (symbol.isAlive()) {5095 if (symbol.isAlive()) {
5079 // Symbol is already marked alive, including its references.5096 // Symbol is already marked alive, including its references.
...@@ -5082,13 +5099,20 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) void {...@@ -5082,13 +5099,20 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) void {
5082 return;5099 return;
5083 }5100 }
5084 symbol.mark();5101 symbol.mark();
5102 if (symbol.isUndefined()) {
5103 // undefined symbols do not have an associated `Atom` and therefore also
5104 // do not contain relocations.
5105 return;
5106 }
50855107
5086 if (wasm.symbol_atom.get(loc)) |atom_index| {5108 const file = loc.file orelse return; // Marking synthetic and Zig symbols is done seperately
5087 const atom = wasm.getAtom(atom_index);5109 const object = &wasm.objects.items[file];
5088 const relocations: []const types.Relocation = atom.relocs.items;5110 const atom_index = try Object.parseSymbolIntoAtom(object, file, loc.index, wasm);
5089 for (relocations) |reloc| {5111
5090 const target_loc: SymbolLoc = .{ .index = reloc.index, .file = loc.file };5112 const atom = wasm.getAtom(atom_index);
5091 wasm.mark(target_loc.finalLoc(wasm));5113 const relocations: []const types.Relocation = atom.relocs.items;
5092 }5114 for (relocations) |reloc| {
5115 const target_loc: SymbolLoc = .{ .index = reloc.index, .file = file };
5116 try wasm.mark(target_loc.finalLoc(wasm));
5093 }5117 }
5094}5118}
src/link/Wasm/Atom.zig+11-7
...@@ -23,6 +23,10 @@ alignment: Wasm.Alignment,...@@ -23,6 +23,10 @@ alignment: Wasm.Alignment,
23/// Offset into the section where the atom lives, this already accounts23/// Offset into the section where the atom lives, this already accounts
24/// for alignment.24/// for alignment.
25offset: u32,25offset: u32,
26/// The original offset within the object file. This value is substracted from
27/// relocation offsets to determine where in the `data` to rewrite the value
28original_offset: u32,
29
26/// Represents the index of the file this atom was generated from.30/// Represents the index of the file this atom was generated from.
27/// This is 'null' when the atom was generated by a Decl from Zig code.31/// This is 'null' when the atom was generated by a Decl from Zig code.
28file: ?u16,32file: ?u16,
...@@ -50,11 +54,11 @@ pub const empty: Atom = .{...@@ -50,11 +54,11 @@ pub const empty: Atom = .{
50 .prev = null,54 .prev = null,
51 .size = 0,55 .size = 0,
52 .sym_index = 0,56 .sym_index = 0,
57 .original_offset = 0,
53};58};
5459
55/// Frees all resources owned by this `Atom`.60/// Frees all resources owned by this `Atom`.
56pub fn deinit(atom: *Atom, wasm: *Wasm) void {61pub fn deinit(atom: *Atom, gpa: std.mem.Allocator) void {
57 const gpa = wasm.base.allocator;
58 atom.relocs.deinit(gpa);62 atom.relocs.deinit(gpa);
59 atom.code.deinit(gpa);63 atom.code.deinit(gpa);
60 atom.locals.deinit(gpa);64 atom.locals.deinit(gpa);
...@@ -114,10 +118,10 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {...@@ -114,10 +118,10 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
114 .R_WASM_GLOBAL_INDEX_I32,118 .R_WASM_GLOBAL_INDEX_I32,
115 .R_WASM_MEMORY_ADDR_I32,119 .R_WASM_MEMORY_ADDR_I32,
116 .R_WASM_SECTION_OFFSET_I32,120 .R_WASM_SECTION_OFFSET_I32,
117 => std.mem.writeInt(u32, atom.code.items[reloc.offset..][0..4], @as(u32, @intCast(value)), .little),121 => std.mem.writeInt(u32, atom.code.items[reloc.offset - atom.original_offset ..][0..4], @as(u32, @intCast(value)), .little),
118 .R_WASM_TABLE_INDEX_I64,122 .R_WASM_TABLE_INDEX_I64,
119 .R_WASM_MEMORY_ADDR_I64,123 .R_WASM_MEMORY_ADDR_I64,
120 => std.mem.writeInt(u64, atom.code.items[reloc.offset..][0..8], value, .little),124 => std.mem.writeInt(u64, atom.code.items[reloc.offset - atom.original_offset ..][0..8], value, .little),
121 .R_WASM_GLOBAL_INDEX_LEB,125 .R_WASM_GLOBAL_INDEX_LEB,
122 .R_WASM_EVENT_INDEX_LEB,126 .R_WASM_EVENT_INDEX_LEB,
123 .R_WASM_FUNCTION_INDEX_LEB,127 .R_WASM_FUNCTION_INDEX_LEB,
...@@ -127,12 +131,12 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {...@@ -127,12 +131,12 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
127 .R_WASM_TABLE_NUMBER_LEB,131 .R_WASM_TABLE_NUMBER_LEB,
128 .R_WASM_TYPE_INDEX_LEB,132 .R_WASM_TYPE_INDEX_LEB,
129 .R_WASM_MEMORY_ADDR_TLS_SLEB,133 .R_WASM_MEMORY_ADDR_TLS_SLEB,
130 => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @as(u32, @intCast(value))),134 => leb.writeUnsignedFixed(5, atom.code.items[reloc.offset - atom.original_offset ..][0..5], @as(u32, @intCast(value))),
131 .R_WASM_MEMORY_ADDR_LEB64,135 .R_WASM_MEMORY_ADDR_LEB64,
132 .R_WASM_MEMORY_ADDR_SLEB64,136 .R_WASM_MEMORY_ADDR_SLEB64,
133 .R_WASM_TABLE_INDEX_SLEB64,137 .R_WASM_TABLE_INDEX_SLEB64,
134 .R_WASM_MEMORY_ADDR_TLS_SLEB64,138 .R_WASM_MEMORY_ADDR_TLS_SLEB64,
135 => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value),139 => leb.writeUnsignedFixed(10, atom.code.items[reloc.offset - atom.original_offset ..][0..10], value),
136 }140 }
137 }141 }
138}142}
...@@ -150,7 +154,7 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa...@@ -150,7 +154,7 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
150 .R_WASM_TABLE_INDEX_I64,154 .R_WASM_TABLE_INDEX_I64,
151 .R_WASM_TABLE_INDEX_SLEB,155 .R_WASM_TABLE_INDEX_SLEB,
152 .R_WASM_TABLE_INDEX_SLEB64,156 .R_WASM_TABLE_INDEX_SLEB64,
153 => return wasm_bin.function_table.get(target_loc) orelse 0,157 => return wasm_bin.function_table.get(.{ .file = atom.file, .index = relocation.index }) orelse 0,
154 .R_WASM_TYPE_INDEX_LEB => {158 .R_WASM_TYPE_INDEX_LEB => {
155 const file_index = atom.file orelse {159 const file_index = atom.file orelse {
156 return relocation.index;160 return relocation.index;
src/link/Wasm/Object.zig+122-142
...@@ -59,20 +59,16 @@ init_funcs: []const types.InitFunc = &.{},...@@ -59,20 +59,16 @@ init_funcs: []const types.InitFunc = &.{},
59comdat_info: []const types.Comdat = &.{},59comdat_info: []const types.Comdat = &.{},
60/// Represents non-synthetic sections that can essentially be mem-cpy'd into place60/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
61/// after performing relocations.61/// after performing relocations.
62relocatable_data: []const RelocatableData = &.{},62relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .{},
63/// String table for all strings required by the object file, such as symbol names,63/// String table for all strings required by the object file, such as symbol names,
64/// import name, module name and export names. Each string will be deduplicated64/// import name, module name and export names. Each string will be deduplicated
65/// and returns an offset into the table.65/// and returns an offset into the table.
66string_table: Wasm.StringTable = .{},66string_table: Wasm.StringTable = .{},
67/// All the names of each debug section found in the current object file.
68/// Each name is terminated by a null-terminator. The name can be found,
69/// from the `index` offset within the `RelocatableData`.
70debug_names: [:0]const u8,
7167
72/// Represents a single item within a section (depending on its `type`)68/// Represents a single item within a section (depending on its `type`)
73const RelocatableData = struct {69const RelocatableData = struct {
74 /// The type of the relocatable data70 /// The type of the relocatable data
75 type: enum { data, code, debug },71 type: Tag,
76 /// Pointer to the data of the segment, where its length is written to `size`72 /// Pointer to the data of the segment, where its length is written to `size`
77 data: [*]u8,73 data: [*]u8,
78 /// The size in bytes of the data representing the segment within the section74 /// The size in bytes of the data representing the segment within the section
...@@ -85,6 +81,8 @@ const RelocatableData = struct {...@@ -85,6 +81,8 @@ const RelocatableData = struct {
85 /// Represents the index of the section it belongs to81 /// Represents the index of the section it belongs to
86 section_index: u32,82 section_index: u32,
8783
84 const Tag = enum { data, code, custom };
85
88 /// Returns the alignment of the segment, by retrieving it from the segment86 /// Returns the alignment of the segment, by retrieving it from the segment
89 /// meta data of the given object file.87 /// meta data of the given object file.
90 /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's88 /// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's
...@@ -99,14 +97,14 @@ const RelocatableData = struct {...@@ -99,14 +97,14 @@ const RelocatableData = struct {
99 return switch (relocatable_data.type) {97 return switch (relocatable_data.type) {
100 .data => .data,98 .data => .data,
101 .code => .function,99 .code => .function,
102 .debug => .section,100 .custom => .section,
103 };101 };
104 }102 }
105103
106 /// Returns the index within a section itrelocatable_data, or in case of a debug section,104 /// Returns the index within a section, or in case of a custom section,
107 /// returns the section index within the object file.105 /// returns the section index within the object file.
108 pub fn getIndex(relocatable_data: RelocatableData) u32 {106 pub fn getIndex(relocatable_data: RelocatableData) u32 {
109 if (relocatable_data.type == .debug) return relocatable_data.section_index;107 if (relocatable_data.type == .custom) return relocatable_data.section_index;
110 return relocatable_data.index;108 return relocatable_data.index;
111 }109 }
112};110};
...@@ -121,7 +119,6 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz...@@ -121,7 +119,6 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz
121 var object: Object = .{119 var object: Object = .{
122 .file = file,120 .file = file,
123 .name = try gpa.dupe(u8, name),121 .name = try gpa.dupe(u8, name),
124 .debug_names = &.{},
125 };122 };
126123
127 var is_object_file: bool = false;124 var is_object_file: bool = false;
...@@ -182,10 +179,16 @@ pub fn deinit(object: *Object, gpa: Allocator) void {...@@ -182,10 +179,16 @@ pub fn deinit(object: *Object, gpa: Allocator) void {
182 gpa.free(info.name);179 gpa.free(info.name);
183 }180 }
184 gpa.free(object.segment_info);181 gpa.free(object.segment_info);
185 for (object.relocatable_data) |rel_data| {182 {
186 gpa.free(rel_data.data[0..rel_data.size]);183 var it = object.relocatable_data.valueIterator();
184 while (it.next()) |relocatable_data| {
185 for (relocatable_data.*) |rel_data| {
186 gpa.free(rel_data.data[0..rel_data.size]);
187 }
188 gpa.free(relocatable_data.*);
189 }
187 }190 }
188 gpa.free(object.relocatable_data);191 object.relocatable_data.deinit(gpa);
189 object.string_table.deinit(gpa);192 object.string_table.deinit(gpa);
190 gpa.free(object.name);193 gpa.free(object.name);
191 object.* = undefined;194 object.* = undefined;
...@@ -345,23 +348,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -345,23 +348,7 @@ fn Parser(comptime ReaderType: type) type {
345 errdefer parser.object.deinit(gpa);348 errdefer parser.object.deinit(gpa);
346 try parser.verifyMagicBytes();349 try parser.verifyMagicBytes();
347 const version = try parser.reader.reader().readInt(u32, .little);350 const version = try parser.reader.reader().readInt(u32, .little);
348
349 parser.object.version = version;351 parser.object.version = version;
350 var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
351 var debug_names = std.ArrayList(u8).init(gpa);
352
353 errdefer {
354 // only free the inner contents of relocatable_data if we didn't
355 // assign it to the object yet.
356 if (parser.object.relocatable_data.len == 0) {
357 for (relocatable_data.items) |rel_data| {
358 gpa.free(rel_data.data[0..rel_data.size]);
359 }
360 relocatable_data.deinit();
361 }
362 gpa.free(debug_names.items);
363 debug_names.deinit();
364 }
365352
366 var section_index: u32 = 0;353 var section_index: u32 = 0;
367 while (parser.reader.reader().readByte()) |byte| : (section_index += 1) {354 while (parser.reader.reader().readByte()) |byte| : (section_index += 1) {
...@@ -377,26 +364,34 @@ fn Parser(comptime ReaderType: type) type {...@@ -377,26 +364,34 @@ fn Parser(comptime ReaderType: type) type {
377364
378 if (std.mem.eql(u8, name, "linking")) {365 if (std.mem.eql(u8, name, "linking")) {
379 is_object_file.* = true;366 is_object_file.* = true;
380 parser.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them.
381 try parser.parseMetadata(gpa, @as(usize, @intCast(reader.context.bytes_left)));367 try parser.parseMetadata(gpa, @as(usize, @intCast(reader.context.bytes_left)));
382 } else if (std.mem.startsWith(u8, name, "reloc")) {368 } else if (std.mem.startsWith(u8, name, "reloc")) {
383 try parser.parseRelocations(gpa);369 try parser.parseRelocations(gpa);
384 } else if (std.mem.eql(u8, name, "target_features")) {370 } else if (std.mem.eql(u8, name, "target_features")) {
385 try parser.parseFeatures(gpa);371 try parser.parseFeatures(gpa);
386 } else if (std.mem.startsWith(u8, name, ".debug")) {372 } else if (std.mem.startsWith(u8, name, ".debug")) {
373 const gop = try parser.object.relocatable_data.getOrPut(gpa, .custom);
374 var relocatable_data: std.ArrayListUnmanaged(RelocatableData) = .{};
375 defer relocatable_data.deinit(gpa);
376 if (!gop.found_existing) {
377 gop.value_ptr.* = &.{};
378 } else {
379 relocatable_data = std.ArrayListUnmanaged(RelocatableData).fromOwnedSlice(gop.value_ptr.*);
380 }
387 const debug_size = @as(u32, @intCast(reader.context.bytes_left));381 const debug_size = @as(u32, @intCast(reader.context.bytes_left));
388 const debug_content = try gpa.alloc(u8, debug_size);382 const debug_content = try gpa.alloc(u8, debug_size);
389 errdefer gpa.free(debug_content);383 errdefer gpa.free(debug_content);
390 try reader.readNoEof(debug_content);384 try reader.readNoEof(debug_content);
391385
392 try relocatable_data.append(.{386 try relocatable_data.append(gpa, .{
393 .type = .debug,387 .type = .custom,
394 .data = debug_content.ptr,388 .data = debug_content.ptr,
395 .size = debug_size,389 .size = debug_size,
396 .index = try parser.object.string_table.put(gpa, name),390 .index = try parser.object.string_table.put(gpa, name),
397 .offset = 0, // debug sections only contain 1 entry, so no need to calculate offset391 .offset = 0, // debug sections only contain 1 entry, so no need to calculate offset
398 .section_index = section_index,392 .section_index = section_index,
399 });393 });
394 gop.value_ptr.* = try relocatable_data.toOwnedSlice(gpa);
400 } else {395 } else {
401 try reader.skipBytes(reader.context.bytes_left, .{});396 try reader.skipBytes(reader.context.bytes_left, .{});
402 }397 }
...@@ -515,26 +510,32 @@ fn Parser(comptime ReaderType: type) type {...@@ -515,26 +510,32 @@ fn Parser(comptime ReaderType: type) type {
515 const start = reader.context.bytes_left;510 const start = reader.context.bytes_left;
516 var index: u32 = 0;511 var index: u32 = 0;
517 const count = try readLeb(u32, reader);512 const count = try readLeb(u32, reader);
513 const imported_function_count = parser.object.importedCountByKind(.function);
514 var relocatable_data = try std.ArrayList(RelocatableData).initCapacity(gpa, count);
515 defer relocatable_data.deinit();
518 while (index < count) : (index += 1) {516 while (index < count) : (index += 1) {
519 const code_len = try readLeb(u32, reader);517 const code_len = try readLeb(u32, reader);
520 const offset = @as(u32, @intCast(start - reader.context.bytes_left));518 const offset = @as(u32, @intCast(start - reader.context.bytes_left));
521 const data = try gpa.alloc(u8, code_len);519 const data = try gpa.alloc(u8, code_len);
522 errdefer gpa.free(data);520 errdefer gpa.free(data);
523 try reader.readNoEof(data);521 try reader.readNoEof(data);
524 try relocatable_data.append(.{522 relocatable_data.appendAssumeCapacity(.{
525 .type = .code,523 .type = .code,
526 .data = data.ptr,524 .data = data.ptr,
527 .size = code_len,525 .size = code_len,
528 .index = parser.object.importedCountByKind(.function) + index,526 .index = imported_function_count + index,
529 .offset = offset,527 .offset = offset,
530 .section_index = section_index,528 .section_index = section_index,
531 });529 });
532 }530 }
531 try parser.object.relocatable_data.put(gpa, .code, try relocatable_data.toOwnedSlice());
533 },532 },
534 .data => {533 .data => {
535 const start = reader.context.bytes_left;534 const start = reader.context.bytes_left;
536 var index: u32 = 0;535 var index: u32 = 0;
537 const count = try readLeb(u32, reader);536 const count = try readLeb(u32, reader);
537 var relocatable_data = try std.ArrayList(RelocatableData).initCapacity(gpa, count);
538 defer relocatable_data.deinit();
538 while (index < count) : (index += 1) {539 while (index < count) : (index += 1) {
539 const flags = try readLeb(u32, reader);540 const flags = try readLeb(u32, reader);
540 const data_offset = try readInit(reader);541 const data_offset = try readInit(reader);
...@@ -545,7 +546,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -545,7 +546,7 @@ fn Parser(comptime ReaderType: type) type {
545 const data = try gpa.alloc(u8, data_len);546 const data = try gpa.alloc(u8, data_len);
546 errdefer gpa.free(data);547 errdefer gpa.free(data);
547 try reader.readNoEof(data);548 try reader.readNoEof(data);
548 try relocatable_data.append(.{549 relocatable_data.appendAssumeCapacity(.{
549 .type = .data,550 .type = .data,
550 .data = data.ptr,551 .data = data.ptr,
551 .size = data_len,552 .size = data_len,
...@@ -554,6 +555,7 @@ fn Parser(comptime ReaderType: type) type {...@@ -554,6 +555,7 @@ fn Parser(comptime ReaderType: type) type {
554 .section_index = section_index,555 .section_index = section_index,
555 });556 });
556 }557 }
558 try parser.object.relocatable_data.put(gpa, .data, try relocatable_data.toOwnedSlice());
557 },559 },
558 else => try parser.reader.reader().skipBytes(len, .{}),560 else => try parser.reader.reader().skipBytes(len, .{}),
559 }561 }
...@@ -561,7 +563,6 @@ fn Parser(comptime ReaderType: type) type {...@@ -561,7 +563,6 @@ fn Parser(comptime ReaderType: type) type {
561 error.EndOfStream => {}, // finished parsing the file563 error.EndOfStream => {}, // finished parsing the file
562 else => |e| return e,564 else => |e| return e,
563 }565 }
564 parser.object.relocatable_data = try relocatable_data.toOwnedSlice();
565 }566 }
566567
567 /// Based on the "features" custom section, parses it into a list of568 /// Based on the "features" custom section, parses it into a list of
...@@ -789,7 +790,8 @@ fn Parser(comptime ReaderType: type) type {...@@ -789,7 +790,8 @@ fn Parser(comptime ReaderType: type) type {
789 },790 },
790 .section => {791 .section => {
791 symbol.index = try leb.readULEB128(u32, reader);792 symbol.index = try leb.readULEB128(u32, reader);
792 for (parser.object.relocatable_data) |data| {793 const section_data = parser.object.relocatable_data.get(.custom).?;
794 for (section_data) |data| {
793 if (data.section_index == symbol.index) {795 if (data.section_index == symbol.index) {
794 symbol.name = data.index;796 symbol.name = data.index;
795 break;797 break;
...@@ -798,22 +800,15 @@ fn Parser(comptime ReaderType: type) type {...@@ -798,22 +800,15 @@ fn Parser(comptime ReaderType: type) type {
798 },800 },
799 else => {801 else => {
800 symbol.index = try leb.readULEB128(u32, reader);802 symbol.index = try leb.readULEB128(u32, reader);
801 var maybe_import: ?types.Import = null;
802
803 const is_undefined = symbol.isUndefined();803 const is_undefined = symbol.isUndefined();
804 if (is_undefined) {
805 maybe_import = parser.object.findImport(symbol.tag.externalType(), symbol.index);
806 }
807 const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);804 const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);
808 if (!(is_undefined and !explicit_name)) {805 symbol.name = if (!is_undefined or (is_undefined and explicit_name)) name: {
809 const name_len = try leb.readULEB128(u32, reader);806 const name_len = try leb.readULEB128(u32, reader);
810 const name = try gpa.alloc(u8, name_len);807 const name = try gpa.alloc(u8, name_len);
811 defer gpa.free(name);808 defer gpa.free(name);
812 try reader.readNoEof(name);809 try reader.readNoEof(name);
813 symbol.name = try parser.object.string_table.put(gpa, name);810 break :name try parser.object.string_table.put(gpa, name);
814 } else {811 } else parser.object.findImport(symbol.tag.externalType(), symbol.index).name;
815 symbol.name = maybe_import.?.name;
816 }
817 },812 },
818 }813 }
819 return symbol;814 return symbol;
...@@ -887,110 +882,95 @@ fn assertEnd(reader: anytype) !void {...@@ -887,110 +882,95 @@ fn assertEnd(reader: anytype) !void {
887}882}
888883
889/// Parses an object file into atoms, for code and data sections884/// Parses an object file into atoms, for code and data sections
890pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_bin: *Wasm) !void {885pub fn parseSymbolIntoAtom(object: *Object, object_index: u16, symbol_index: u32, wasm: *Wasm) !Atom.Index {
891 const Key = struct {886 const symbol = &object.symtable[symbol_index];
892 kind: Symbol.Tag,887 const relocatable_data: RelocatableData = switch (symbol.tag) {
893 index: u32,888 .function => object.relocatable_data.get(.code).?[symbol.index - object.importedCountByKind(.function)],
894 };889 .data => object.relocatable_data.get(.data).?[symbol.index],
895 var symbol_for_segment = std.AutoArrayHashMap(Key, std.ArrayList(u32)).init(gpa);890 .section => blk: {
896 defer for (symbol_for_segment.values()) |*list| {891 const data = object.relocatable_data.get(.custom).?;
897 list.deinit();892 for (data) |dat| {
898 } else symbol_for_segment.deinit();893 if (dat.section_index == symbol.index) {
899894 break :blk dat;
900 for (object.symtable, 0..) |symbol, symbol_index| {
901 switch (symbol.tag) {
902 .function, .data, .section => if (!symbol.isUndefined()) {
903 const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });
904 const sym_idx = @as(u32, @intCast(symbol_index));
905 if (!gop.found_existing) {
906 gop.value_ptr.* = std.ArrayList(u32).init(gpa);
907 }895 }
908 try gop.value_ptr.*.append(sym_idx);896 }
909 },897 unreachable;
910 else => continue,898 },
911 }899 else => unreachable,
900 };
901 const final_index = try wasm.getMatchingSegment(object_index, symbol_index);
902 const atom_index = @as(Atom.Index, @intCast(wasm.managed_atoms.items.len));
903 const atom = try wasm.managed_atoms.addOne(wasm.base.allocator);
904 atom.* = Atom.empty;
905 try wasm.appendAtomAtIndex(final_index, atom_index);
906
907 atom.sym_index = symbol_index;
908 atom.file = object_index;
909 atom.size = relocatable_data.size;
910 atom.alignment = relocatable_data.getAlignment(object);
911 atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
912 atom.original_offset = relocatable_data.offset;
913 try wasm.symbol_atom.putNoClobber(wasm.base.allocator, atom.symbolLoc(), atom_index);
914 const segment: *Wasm.Segment = &wasm.segments.items[final_index];
915 if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
916 segment.alignment = segment.alignment.max(atom.alignment);
912 }917 }
913918
914 for (object.relocatable_data, 0..) |relocatable_data, index| {919 if (object.relocations.get(relocatable_data.section_index)) |relocations| {
915 const final_index = (try wasm_bin.getMatchingSegment(object_index, @as(u32, @intCast(index)))) orelse {920 const start = searchRelocStart(relocations, relocatable_data.offset);
916 continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.921 const len = searchRelocEnd(relocations[start..], relocatable_data.offset + atom.size);
917 };922 atom.relocs = std.ArrayListUnmanaged(types.Relocation).fromOwnedSlice(relocations[start..][0..len]);
918923 for (atom.relocs.items) |*reloc| {
919 const atom_index: Atom.Index = @intCast(wasm_bin.managed_atoms.items.len);924 switch (reloc.relocation_type) {
920 const atom = try wasm_bin.managed_atoms.addOne(gpa);925 .R_WASM_TABLE_INDEX_I32,
921 atom.* = Atom.empty;926 .R_WASM_TABLE_INDEX_I64,
922 atom.file = object_index;927 .R_WASM_TABLE_INDEX_SLEB,
923 atom.size = relocatable_data.size;928 .R_WASM_TABLE_INDEX_SLEB64,
924 atom.alignment = relocatable_data.getAlignment(object);929 => {
925930 try wasm.function_table.put(wasm.base.allocator, .{
926 const relocations: []types.Relocation = object.relocations.get(relocatable_data.section_index) orelse &.{};931 .file = object_index,
927 for (relocations) |relocation| {932 .index = reloc.index,
928 if (isInbetween(relocatable_data.offset, atom.size, relocation.offset)) {933 }, 0);
929 // set the offset relative to the offset of the segment itobject,934 },
930 // rather than within the entire section.935 .R_WASM_GLOBAL_INDEX_I32,
931 var reloc = relocation;936 .R_WASM_GLOBAL_INDEX_LEB,
932 reloc.offset -= relocatable_data.offset;937 => {
933 try atom.relocs.append(gpa, reloc);938 const sym = object.symtable[reloc.index];
934939 if (sym.tag != .global) {
935 switch (relocation.relocation_type) {940 try wasm.got_symbols.append(
936 .R_WASM_TABLE_INDEX_I32,941 wasm.base.allocator,
937 .R_WASM_TABLE_INDEX_I64,942 .{ .file = object_index, .index = reloc.index },
938 .R_WASM_TABLE_INDEX_SLEB,943 );
939 .R_WASM_TABLE_INDEX_SLEB64,944 }
940 => {945 },
941 try wasm_bin.function_table.put(gpa, .{946 else => {},
942 .file = object_index,
943 .index = relocation.index,
944 }, 0);
945 },
946 .R_WASM_GLOBAL_INDEX_I32,
947 .R_WASM_GLOBAL_INDEX_LEB,
948 => {
949 const sym = object.symtable[relocation.index];
950 if (sym.tag != .global) {
951 try wasm_bin.got_symbols.append(
952 wasm_bin.base.allocator,
953 .{ .file = object_index, .index = relocation.index },
954 );
955 }
956 },
957 else => {},
958 }
959 }947 }
960 }948 }
949 }
961950
962 try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);951 return atom_index;
963952}
964 if (symbol_for_segment.getPtr(.{
965 .kind = relocatable_data.getSymbolKind(),
966 .index = relocatable_data.getIndex(),
967 })) |symbols| {
968 atom.sym_index = symbols.pop();
969 try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom_index);
970
971 // symbols referencing the same atom will be added as alias
972 // or as 'parent' when they are global.
973 while (symbols.popOrNull()) |idx| {
974 try wasm_bin.symbol_atom.putNoClobber(gpa, .{ .file = atom.file, .index = idx }, atom_index);
975 const alias_symbol = object.symtable[idx];
976 if (alias_symbol.isGlobal()) {
977 atom.sym_index = idx;
978 }
979 }
980 }
981953
982 const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];954fn searchRelocStart(relocs: []const types.Relocation, address: u32) usize {
983 if (relocatable_data.type == .data) { //code section and debug sections are 1-byte aligned955 var min: usize = 0;
984 segment.alignment = segment.alignment.max(atom.alignment);956 var max: usize = relocs.len;
957 while (min < max) {
958 const index = (min + max) / 2;
959 const curr = relocs[index];
960 if (curr.offset < address) {
961 min = index + 1;
962 } else {
963 max = index;
985 }964 }
986
987 try wasm_bin.appendAtomAtIndex(final_index, atom_index);
988 log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });
989 }965 }
966 return min;
990}967}
991968
992/// Verifies if a given value is in between a minimum -and maximum value.969fn searchRelocEnd(relocs: []const types.Relocation, address: u32) usize {
993/// The maxmimum value is calculated using the length, both start and end are inclusive.970 for (relocs, 0..relocs.len) |reloc, index| {
994inline fn isInbetween(min: u32, length: u32, value: u32) bool {971 if (reloc.offset > address) {
995 return value >= min and value <= min + length;972 return index;
973 }
974 }
975 return relocs.len;
996}976}