@@ -335,41 +335,64 @@ pub fn openPath(allocator: Allocator, sub_path: []const u8, options: link.Option
335335 wasm_bin .base .file = file ;
336336 wasm_bin .name = sub_path ;
337337
338- // As sym_index '0' is reserved, we use it for our stack pointer symbol
339- const sym_name = try wasm_bin .string_table .put (allocator , "__stack_pointer" );
340- const symbol = try wasm_bin .symbols .addOne (allocator );
341- symbol .* = .{
342- .name = sym_name ,
343- .tag = .global ,
344- .flags = 0 ,
345- .index = 0 ,
346- };
347- const loc : SymbolLoc = .{ .file = null , .index = 0 };
348- try wasm_bin .resolved_symbols .putNoClobber (allocator , loc , {});
349- try wasm_bin .globals .putNoClobber (allocator , sym_name , loc );
350-
351- // For object files we will import the stack pointer symbol
352- if (options .output_mode == .Obj ) {
353- symbol .setUndefined (true );
354- try wasm_bin .imports .putNoClobber (
355- allocator ,
356- .{ .file = null , .index = 0 },
357- .{
358- .module_name = try wasm_bin .string_table .put (allocator , wasm_bin .host_name ),
359- .name = sym_name ,
360- .kind = .{ .global = .{ .valtype = .i32 , .mutable = true } },
361- },
362- );
363- } else {
364- symbol .setFlag (.WASM_SYM_VISIBILITY_HIDDEN );
365- const global = try wasm_bin .wasm_globals .addOne (allocator );
366- global .* = .{
367- .global_type = .{
368- .valtype = .i32 ,
369- .mutable = true ,
370- },
371- .init = .{ .i32_const = 0 },
338+ // create stack pointer symbol
339+ {
340+ const loc = try wasm_bin .createSyntheticSymbol ("__stack_pointer" , .global );
341+ const symbol = loc .getSymbol (wasm_bin );
342+ // For object files we will import the stack pointer symbol
343+ if (options .output_mode == .Obj ) {
344+ symbol .setUndefined (true );
345+ symbol .index = @intCast (u32 , wasm_bin .imported_globals_count );
346+ wasm_bin .imported_globals_count += 1 ;
347+ try wasm_bin .imports .putNoClobber (
348+ allocator ,
349+ loc ,
350+ .{
351+ .module_name = try wasm_bin .string_table .put (allocator , wasm_bin .host_name ),
352+ .name = symbol .name ,
353+ .kind = .{ .global = .{ .valtype = .i32 , .mutable = true } },
354+ },
355+ );
356+ } else {
357+ symbol .index = @intCast (u32 , wasm_bin .imported_globals_count + wasm_bin .wasm_globals .items .len );
358+ symbol .setFlag (.WASM_SYM_VISIBILITY_HIDDEN );
359+ const global = try wasm_bin .wasm_globals .addOne (allocator );
360+ global .* = .{
361+ .global_type = .{
362+ .valtype = .i32 ,
363+ .mutable = true ,
364+ },
365+ .init = .{ .i32_const = 0 },
366+ };
367+ }
368+ }
369+
370+ // create indirect function pointer symbol
371+ {
372+ const loc = try wasm_bin .createSyntheticSymbol ("__indirect_function_table" , .table );
373+ const symbol = loc .getSymbol (wasm_bin );
374+ const table : std.wasm.Table = .{
375+ .limits = .{ .min = 0 , .max = null }, // will be overwritten during `mapFunctionTable`
376+ .reftype = .funcref ,
372377 };
378+ if (options .output_mode == .Obj or options .import_table ) {
379+ symbol .setUndefined (true );
380+ symbol .index = @intCast (u32 , wasm_bin .imported_tables_count );
381+ wasm_bin .imported_tables_count += 1 ;
382+ try wasm_bin .imports .put (allocator , loc , .{
383+ .module_name = try wasm_bin .string_table .put (allocator , wasm_bin .host_name ),
384+ .name = symbol .name ,
385+ .kind = .{ .table = table },
386+ });
387+ } else {
388+ symbol .index = @intCast (u32 , wasm_bin .imported_tables_count + wasm_bin .tables .items .len );
389+ try wasm_bin .tables .append (allocator , table );
390+ if (options .export_table ) {
391+ symbol .setFlag (.WASM_SYM_EXPORTED );
392+ } else {
393+ symbol .setFlag (.WASM_SYM_VISIBILITY_HIDDEN );
394+ }
395+ }
373396 }
374397
375398 if (! options .strip and options .module != null ) {
@@ -400,6 +423,22 @@ pub fn createEmpty(gpa: Allocator, options: link.Options) !*Wasm {
400423 return wasm ;
401424}
402425
426+ /// For a given name, creates a new global synthetic symbol.
427+ /// Leaves index undefined and the default flags (0).
428+ fn createSyntheticSymbol (wasm : * Wasm , name : []const u8 , tag : Symbol.Tag ) ! SymbolLoc {
429+ const name_offset = try wasm .string_table .put (wasm .base .allocator , name );
430+ const sym_index = @intCast (u32 , wasm .symbols .items .len );
431+ const loc : SymbolLoc = .{ .index = sym_index , .file = null };
432+ try wasm .symbols .append (wasm .base .allocator , .{
433+ .name = name_offset ,
434+ .flags = 0 ,
435+ .tag = tag ,
436+ .index = undefined ,
437+ });
438+ try wasm .resolved_symbols .putNoClobber (wasm .base .allocator , loc , {});
439+ try wasm .globals .putNoClobber (wasm .base .allocator , name_offset , loc );
440+ return loc ;
441+ }
403442/// Initializes symbols and atoms for the debug sections
404443/// Initialization is only done when compiling Zig code.
405444/// When Zig is invoked as a linker instead, the atoms
@@ -1249,7 +1288,7 @@ pub fn updateDeclExports(
12491288 const existing_sym : Symbol = existing_loc .getSymbol (wasm ).* ;
12501289
12511290 const exp_is_weak = exp .options .linkage == .Internal or exp .options .linkage == .Weak ;
1252- // When both the to-bo -exported symbol and the already existing symbol
1291+ // When both the to-be -exported symbol and the already existing symbol
12531292 // are strong symbols, we have a linker error.
12541293 // In the other case we replace one with the other.
12551294 if (! exp_is_weak and ! existing_sym .isWeak ()) {
@@ -1361,6 +1400,19 @@ fn mapFunctionTable(wasm: *Wasm) void {
13611400 while (it .next ()) | value_ptr | : (index += 1 ) {
13621401 value_ptr .* = index ;
13631402 }
1403+
1404+ if (wasm .base .options .import_table or wasm .base .options .output_mode == .Obj ) {
1405+ const sym_loc = wasm .globals .get (wasm .string_table .getOffset ("__indirect_function_table" ).? ).? ;
1406+ const import = wasm .imports .getPtr (sym_loc ).? ;
1407+ import .kind .table .limits .min = index - 1 ; // we start at index 1.
1408+ } else if (index > 1 ) {
1409+ log .debug ("Appending indirect function table" , .{});
1410+ const offset = wasm .string_table .getOffset ("__indirect_function_table" ).? ;
1411+ const sym_with_loc = wasm .globals .get (offset ).? ;
1412+ const symbol = sym_with_loc .getSymbol (wasm );
1413+ const table = & wasm .tables .items [symbol .index - wasm .imported_tables_count ];
1414+ table .limits = .{ .min = index , .max = index };
1415+ }
13641416}
13651417
13661418/// Either creates a new import, or updates one if existing.
@@ -1700,17 +1752,6 @@ fn setupImports(wasm: *Wasm) !void {
17001752/// Takes the global, function and table section from each linked object file
17011753/// and merges it into a single section for each.
17021754fn mergeSections (wasm : * Wasm ) ! void {
1703- // append the indirect function table if initialized
1704- if (wasm .string_table .getOffset ("__indirect_function_table" )) | offset | {
1705- const sym_loc = wasm .globals .get (offset ).? ;
1706- const table : std.wasm.Table = .{
1707- .limits = .{ .min = @intCast (u32 , wasm .function_table .count ()), .max = null },
1708- .reftype = .funcref ,
1709- };
1710- sym_loc .getSymbol (wasm ).index = @intCast (u32 , wasm .tables .items .len ) + wasm .imported_tables_count ;
1711- try wasm .tables .append (wasm .base .allocator , table );
1712- }
1713-
17141755 for (wasm .resolved_symbols .keys ()) | sym_loc | {
17151756 if (sym_loc .file == null ) {
17161757 // Zig code-generated symbols are already within the sections and do not
@@ -2613,28 +2654,9 @@ fn writeToFile(
26132654
26142655 // Import section
26152656 const import_memory = wasm .base .options .import_memory or is_obj ;
2616- const import_table = wasm .base .options .import_table or is_obj ;
2617- if (wasm .imports .count () != 0 or import_memory or import_table ) {
2657+ if (wasm .imports .count () != 0 or import_memory ) {
26182658 const header_offset = try reserveVecSectionHeader (& binary_bytes );
26192659
2620- // import table is always first table so emit that first
2621- if (import_table ) {
2622- const table_imp : types.Import = .{
2623- .module_name = try wasm .string_table .put (wasm .base .allocator , wasm .host_name ),
2624- .name = try wasm .string_table .put (wasm .base .allocator , "__indirect_function_table" ),
2625- .kind = .{
2626- .table = .{
2627- .limits = .{
2628- .min = @intCast (u32 , wasm .function_table .count ()),
2629- .max = null ,
2630- },
2631- .reftype = .funcref ,
2632- },
2633- },
2634- };
2635- try wasm .emitImport (binary_writer , table_imp );
2636- }
2637-
26382660 var it = wasm .imports .iterator ();
26392661 while (it .next ()) | entry | {
26402662 assert (entry .key_ptr .* .getSymbol (wasm ).isUndefined ());
@@ -2657,7 +2679,7 @@ fn writeToFile(
26572679 header_offset ,
26582680 .import ,
26592681 @intCast (u32 , binary_bytes .items .len - header_offset - header_size ),
2660- @intCast (u32 , wasm .imports .count () + @boolToInt (import_memory ) + @boolToInt ( import_table ) ),
2682+ @intCast (u32 , wasm .imports .count () + @boolToInt (import_memory )),
26612683 );
26622684 section_count += 1 ;
26632685 }
@@ -2680,22 +2702,20 @@ fn writeToFile(
26802702 }
26812703
26822704 // Table section
2683- const export_table = wasm .base .options .export_table ;
2684- if (! import_table and wasm .function_table .count () != 0 ) {
2705+ if (wasm .tables .items .len > 0 ) {
26852706 const header_offset = try reserveVecSectionHeader (& binary_bytes );
26862707
2687- try leb .writeULEB128 (binary_writer , std .wasm .reftype (.funcref ));
2688- try emitLimits (binary_writer , .{
2689- .min = @intCast (u32 , wasm .function_table .count ()) + 1 ,
2690- .max = null ,
2691- });
2708+ for (wasm .tables .items ) | table | {
2709+ try leb .writeULEB128 (binary_writer , std .wasm .reftype (table .reftype ));
2710+ try emitLimits (binary_writer , table .limits );
2711+ }
26922712
26932713 try writeVecSectionHeader (
26942714 binary_bytes .items ,
26952715 header_offset ,
26962716 .table ,
26972717 @intCast (u32 , binary_bytes .items .len - header_offset - header_size ),
2698- @as (u32 , 1 ),
2718+ @intCast (u32 , wasm . tables . items . len ),
26992719 );
27002720 section_count += 1 ;
27012721 }
@@ -2748,7 +2768,7 @@ fn writeToFile(
27482768 }
27492769
27502770 // Export section
2751- if (wasm .exports .items .len != 0 or export_table or ! import_memory ) {
2771+ if (wasm .exports .items .len != 0 or ! import_memory ) {
27522772 const header_offset = try reserveVecSectionHeader (& binary_bytes );
27532773
27542774 for (wasm .exports .items ) | exp | {
@@ -2759,13 +2779,6 @@ fn writeToFile(
27592779 try leb .writeULEB128 (binary_writer , exp .index );
27602780 }
27612781
2762- if (export_table ) {
2763- try leb .writeULEB128 (binary_writer , @intCast (u32 , "__indirect_function_table" .len ));
2764- try binary_writer .writeAll ("__indirect_function_table" );
2765- try binary_writer .writeByte (std .wasm .externalKind (.table ));
2766- try leb .writeULEB128 (binary_writer , @as (u32 , 0 )); // function table is always the first table
2767- }
2768-
27692782 if (! import_memory ) {
27702783 try leb .writeULEB128 (binary_writer , @intCast (u32 , "memory" .len ));
27712784 try binary_writer .writeAll ("memory" );
@@ -2778,7 +2791,7 @@ fn writeToFile(
27782791 header_offset ,
27792792 .@"export" ,
27802793 @intCast (u32 , binary_bytes .items .len - header_offset - header_size ),
2781- @intCast (u32 , wasm .exports .items .len ) + @boolToInt (export_table ) + @boolToInt ( ! import_memory ),
2794+ @intCast (u32 , wasm .exports .items .len ) + @boolToInt (! import_memory ),
27822795 );
27832796 section_count += 1 ;
27842797 }
@@ -2787,11 +2800,18 @@ fn writeToFile(
27872800 if (wasm .function_table .count () > 0 ) {
27882801 const header_offset = try reserveVecSectionHeader (& binary_bytes );
27892802
2790- var flags : u32 = 0x2 ; // Yes we have a table
2803+ const table_loc = wasm .globals .get (wasm .string_table .getOffset ("__indirect_function_table" ).? ).? ;
2804+ const table_sym = table_loc .getSymbol (wasm );
2805+
2806+ var flags : u32 = if (table_sym .index == 0 ) 0x0 else 0x02 ; // passive with implicit 0-index table or set table index manually
27912807 try leb .writeULEB128 (binary_writer , flags );
2792- try leb .writeULEB128 (binary_writer , @as (u32 , 0 )); // index of that table. TODO: Store synthetic symbols
2808+ if (flags == 0x02 ) {
2809+ try leb .writeULEB128 (binary_writer , table_sym .index );
2810+ }
27932811 try emitInit (binary_writer , .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid
2794- try leb .writeULEB128 (binary_writer , @as (u8 , 0 ));
2812+ if (flags == 0x02 ) {
2813+ try leb .writeULEB128 (binary_writer , @as (u8 , 0 )); // represents funcref
2814+ }
27952815 try leb .writeULEB128 (binary_writer , @intCast (u32 , wasm .function_table .count ()));
27962816 var symbol_it = wasm .function_table .keyIterator ();
27972817 while (symbol_it .next ()) | symbol_loc_ptr | {
0 commit comments