wasm linker: flush export section

This commit is contained in:
Andrew Kelley 2024-12-12 15:28:05 -08:00
parent bf88059591
commit 264a63b000
2 changed files with 71 additions and 24 deletions

View File

@ -187,10 +187,10 @@ missing_exports_init: []String = &.{},
entry_resolution: FunctionImport.Resolution = .unresolved,
/// Empty when outputting an object.
function_exports: std.ArrayListUnmanaged(FunctionIndex) = .empty,
function_exports: std.ArrayListUnmanaged(FunctionExport) = .empty,
/// Tracks the value at the end of prelink.
function_exports_len: u32 = 0,
global_exports: std.ArrayListUnmanaged(GlobalIndex) = .empty,
global_exports: std.ArrayListUnmanaged(GlobalExport) = .empty,
/// Tracks the value at the end of prelink.
global_exports_len: u32 = 0,
@ -262,16 +262,30 @@ pub const ObjectIndex = enum(u32) {
}
};
/// Index into `functions`.
/// Index into `Wasm.functions`.
pub const FunctionIndex = enum(u32) {
_,
pub fn ptr(index: FunctionIndex, wasm: *const Wasm) *FunctionImport.Resolution {
return &wasm.functions.keys()[@intFromEnum(index)];
}
pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) ?FunctionIndex {
const i = wasm.functions.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
return @enumFromInt(i);
}
};
pub const FunctionExport = extern struct {
name: String,
function_index: FunctionIndex,
};
pub const GlobalExport = extern struct {
name: String,
global_index: GlobalIndex,
};
/// 0. Index into `function_imports`
/// 1. Index into `functions`.
///
@ -2232,8 +2246,10 @@ fn markFunction(
} else {
const gop = wasm.functions.getOrPutAssumeCapacity(import.resolution);
if (!is_obj and import.flags.isExported(rdynamic))
try wasm.function_exports.append(gpa, @enumFromInt(gop.index));
if (!is_obj and import.flags.isExported(rdynamic)) try wasm.function_exports.append(gpa, .{
.name = name,
.function_index = @enumFromInt(gop.index),
});
for (try wasm.functionResolutionRelocSlice(import.resolution)) |reloc|
try wasm.markReloc(reloc);
@ -2282,8 +2298,10 @@ fn markGlobal(
} else {
const gop = wasm.globals.getOrPutAssumeCapacity(import.resolution);
if (!is_obj and import.flags.isExported(rdynamic))
try wasm.global_exports.append(gpa, @enumFromInt(gop.index));
if (!is_obj and import.flags.isExported(rdynamic)) try wasm.global_exports.append(gpa, .{
.name = name,
.global_index = @enumFromInt(gop.index),
});
for (try wasm.globalResolutionRelocSlice(import.resolution)) |reloc|
try wasm.markReloc(reloc);

View File

@ -79,14 +79,20 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
for (wasm.nav_exports.keys()) |*nav_export| {
if (ip.isFunctionType(ip.getNav(nav_export.nav_index).typeOf(ip))) {
try wasm.function_exports.append(gpa, Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?);
try wasm.function_exports.append(gpa, .{
.name = nav_export.name,
.function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?,
});
_ = f.missing_exports.swapRemove(nav_export.name);
_ = wasm.function_imports.swapRemove(nav_export.name);
if (nav_export.name.toOptional() == entry_name)
wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);
} else {
try wasm.global_exports.append(gpa, Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?);
try wasm.global_exports.append(gpa, .{
.name = nav_export.name,
.global_index = Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?,
});
_ = f.missing_exports.swapRemove(nav_export.name);
_ = wasm.global_imports.swapRemove(nav_export.name);
}
@ -437,8 +443,12 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
}
total_imports += wasm.global_imports.entries.len;
replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports));
section_index += 1;
if (total_imports > 0) {
replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports));
section_index += 1;
} else {
binary_bytes.shrinkRetainingCapacity(header_offset);
}
}
// Function section
@ -474,7 +484,8 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
}
// Global section (used to emit stack pointer)
if (wasm.globals.entries.len > 0) {
const globals_len: u32 = @intCast(wasm.globals.entries.len);
if (globals_len > 0) {
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
for (wasm.globals.keys()) |global_resolution| {
@ -498,32 +509,50 @@ pub fn finish(f: *Flush, wasm: *Wasm, arena: Allocator) !void {
}
}
replaceVecSectionHeader(binary_bytes, header_offset, .global, @intCast(wasm.globals.entries.len));
replaceVecSectionHeader(binary_bytes, header_offset, .global, globals_len);
section_index += 1;
}
// Export section
if (wasm.exports.items.len != 0 or export_memory) {
{
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
var exports_len: usize = 0;
for (wasm.exports.items) |exp| {
for (wasm.function_exports.items) |exp| {
const name = exp.name.slice(wasm);
try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
try binary_writer.writeAll(name);
try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind));
try leb.writeUleb128(binary_writer, exp.index);
try binary_bytes.appendSlice(gpa, name);
try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function));
try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.function_imports.entries.len + @intFromEnum(exp.function_index))));
}
exports_len += wasm.function_exports.items.len;
// No table exports.
if (export_memory) {
try leb.writeUleb128(binary_writer, @as(u32, @intCast("memory".len)));
try binary_writer.writeAll("memory");
try binary_writer.writeByte(std.wasm.externalKind(.memory));
const name = "memory";
try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
try binary_bytes.appendSlice(gpa, name);
try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory));
try leb.writeUleb128(binary_writer, @as(u32, 0));
exports_len += 1;
}
const n_items: u32 = @intCast(wasm.exports.items.len + @intFromBool(export_memory));
replaceVecSectionHeader(binary_bytes, header_offset, .@"export", n_items);
section_index += 1;
for (wasm.global_exports.items) |exp| {
const name = exp.name.slice(wasm);
try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
try binary_bytes.appendSlice(gpa, name);
try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global));
try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.global_imports.entries.len + @intFromEnum(exp.global_index))));
}
exports_len += wasm.global_exports.items.len;
if (exports_len > 0) {
replaceVecSectionHeader(binary_bytes, header_offset, .@"export", @intCast(exports_len));
section_index += 1;
} else {
binary_bytes.shrinkRetainingCapacity(header_offset);
}
}
if (Wasm.FunctionIndex.fromResolution(wasm.entry_resolution)) |entry_index| {