mirror of
https://github.com/ziglang/zig.git
synced 2026-02-03 21:23:36 +00:00
wasm linker: handle extern functions in updateNav
This commit is contained in:
parent
766284fec8
commit
23d0882b54
@ -209,7 +209,17 @@ functions: std.AutoArrayHashMapUnmanaged(FunctionImport.Resolution, void) = .emp
|
||||
/// Tracks the value at the end of prelink, at which point `functions`
|
||||
/// contains only object file functions, and nothing from the Zcu yet.
|
||||
functions_end_prelink: u32 = 0,
|
||||
/// Entries are deleted as they are satisfied by the Zcu.
|
||||
/// At the end of prelink, this is populated with needed functions from
|
||||
/// objects.
|
||||
///
|
||||
/// During the Zcu phase, entries are not deleted from this table
|
||||
/// because doing so would be irreversible when a `deleteExport` call is
|
||||
/// handled. However, entries are added during the Zcu phase when extern
|
||||
/// functions are passed to `updateNav`.
|
||||
///
|
||||
/// `flush` gets a copy of this table, and then Zcu exports are applied to
|
||||
/// remove elements from the table, and the remainder are either undefined
|
||||
/// symbol errors, or import section entries depending on the output mode.
|
||||
function_imports: std.AutoArrayHashMapUnmanaged(String, FunctionImportId) = .empty,
|
||||
|
||||
/// Ordered list of non-import globals that will appear in the final binary.
|
||||
@ -1156,11 +1166,6 @@ pub const ObjectTableIndex = enum(u32) {
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into `global_imports`.
|
||||
pub const GlobalImportIndex = enum(u32) {
|
||||
_,
|
||||
};
|
||||
|
||||
/// Index into `Wasm.object_globals`.
|
||||
pub const ObjectGlobalIndex = enum(u32) {
|
||||
_,
|
||||
@ -1662,6 +1667,10 @@ pub const FunctionImportId = enum(u32) {
|
||||
return pack(.{ .object_function_import = function_import_index }, wasm);
|
||||
}
|
||||
|
||||
pub fn fromZcuImport(zcu_import: ZcuImportIndex, wasm: *const Wasm) FunctionImportId {
|
||||
return pack(.{ .zcu_import = zcu_import }, wasm);
|
||||
}
|
||||
|
||||
/// This function is allowed O(N) lookup because it is only called during
|
||||
/// diagnostic generation.
|
||||
pub fn sourceLocation(id: FunctionImportId, wasm: *const Wasm) SourceLocation {
|
||||
@ -2297,13 +2306,21 @@ pub fn updateNav(wasm: *Wasm, pt: Zcu.PerThread, nav_index: InternPool.Nav.Index
|
||||
|
||||
const nav_init = switch (ip.indexToKey(nav.status.resolved.val)) {
|
||||
.func => return, // global const which is a function alias
|
||||
.@"extern" => {
|
||||
.@"extern" => |ext| {
|
||||
if (is_obj) {
|
||||
assert(!wasm.navs_obj.contains(nav_index));
|
||||
} else {
|
||||
assert(!wasm.navs_exe.contains(nav_index));
|
||||
}
|
||||
try wasm.imports.put(gpa, nav_index, {});
|
||||
const name = try wasm.internString(ext.name.toSlice(ip));
|
||||
try wasm.imports.ensureUnusedCapacity(gpa, 1);
|
||||
if (ip.isFunctionType(nav.typeOf(ip))) {
|
||||
try wasm.function_imports.ensureUnusedCapacity(gpa, 1);
|
||||
const zcu_import = wasm.addZcuImportReserved(ext.owner_nav);
|
||||
wasm.function_imports.putAssumeCapacity(name, .fromZcuImport(zcu_import, wasm));
|
||||
} else {
|
||||
@panic("TODO extern data");
|
||||
}
|
||||
return;
|
||||
},
|
||||
.variable => |variable| variable.init,
|
||||
@ -3464,3 +3481,9 @@ fn pointerAlignment(wasm: *const Wasm) Alignment {
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn addZcuImportReserved(wasm: *Wasm, nav_index: InternPool.Nav.Index) ZcuImportIndex {
|
||||
const gop = wasm.imports.getOrPutAssumeCapacity(nav_index);
|
||||
gop.value_ptr.* = {};
|
||||
return @enumFromInt(gop.index);
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
|
||||
.function_index = Wasm.FunctionIndex.fromIpNav(wasm, nav_export.nav_index).?,
|
||||
});
|
||||
_ = f.missing_exports.swapRemove(nav_export.name);
|
||||
_ = wasm.function_imports.swapRemove(nav_export.name);
|
||||
_ = f.function_imports.swapRemove(nav_export.name);
|
||||
|
||||
if (nav_export.name.toOptional() == entry_name)
|
||||
wasm.entry_resolution = .fromIpNav(wasm, nav_export.nav_index);
|
||||
@ -86,7 +86,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
|
||||
.global_index = Wasm.GlobalIndex.fromIpNav(wasm, nav_export.nav_index).?,
|
||||
});
|
||||
_ = f.missing_exports.swapRemove(nav_export.name);
|
||||
_ = wasm.global_imports.swapRemove(nav_export.name);
|
||||
_ = f.global_imports.swapRemove(nav_export.name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,11 +104,11 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
|
||||
}
|
||||
|
||||
if (!allow_undefined) {
|
||||
for (wasm.function_imports.keys(), wasm.function_imports.values()) |name, function_import_id| {
|
||||
for (f.function_imports.keys(), f.function_imports.values()) |name, function_import_id| {
|
||||
const src_loc = function_import_id.sourceLocation(wasm);
|
||||
src_loc.addError(wasm, "undefined function: {s}", .{name.slice(wasm)});
|
||||
}
|
||||
for (wasm.global_imports.keys(), wasm.global_imports.values()) |name, global_import_id| {
|
||||
for (f.global_imports.keys(), f.global_imports.values()) |name, global_import_id| {
|
||||
const src_loc = global_import_id.sourceLocation(wasm);
|
||||
src_loc.addError(wasm, "undefined global: {s}", .{name.slice(wasm)});
|
||||
}
|
||||
@ -391,12 +391,18 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
|
||||
section_index += 1;
|
||||
}
|
||||
|
||||
if (!is_obj) {
|
||||
// TODO: sort function_imports by ref count descending for optimal LEB encodings
|
||||
// TODO: sort global_imports by ref count descending for optimal LEB encodings
|
||||
// TODO: sort output functions by ref count descending for optimal LEB encodings
|
||||
}
|
||||
|
||||
// Import section
|
||||
{
|
||||
var total_imports: usize = 0;
|
||||
const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
|
||||
|
||||
for (wasm.function_imports.values()) |id| {
|
||||
for (f.function_imports.values()) |id| {
|
||||
const module_name = id.moduleName(wasm).slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
|
||||
try binary_writer.writeAll(module_name);
|
||||
@ -408,7 +414,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
|
||||
try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function));
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(id.functionType(wasm)));
|
||||
}
|
||||
total_imports += wasm.function_imports.entries.len;
|
||||
total_imports += f.function_imports.entries.len;
|
||||
|
||||
for (wasm.table_imports.values()) |id| {
|
||||
const table_import = id.value(wasm);
|
||||
@ -441,7 +447,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
|
||||
total_imports += 1;
|
||||
}
|
||||
|
||||
for (wasm.global_imports.values()) |id| {
|
||||
for (f.global_imports.values()) |id| {
|
||||
const module_name = id.moduleName(wasm).slice(wasm);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len)));
|
||||
try binary_writer.writeAll(module_name);
|
||||
@ -455,7 +461,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype)));
|
||||
try binary_writer.writeByte(@intFromBool(global_type.mutable));
|
||||
}
|
||||
total_imports += wasm.global_imports.entries.len;
|
||||
total_imports += f.global_imports.entries.len;
|
||||
|
||||
if (total_imports > 0) {
|
||||
replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports));
|
||||
@ -757,6 +763,7 @@ fn emitNameSection(
|
||||
data_segments: *const std.AutoArrayHashMapUnmanaged(Wasm.DataSegment.Id, u32),
|
||||
binary_bytes: *std.ArrayListUnmanaged(u8),
|
||||
) !void {
|
||||
const f = &wasm.flush_buffer;
|
||||
const comp = wasm.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
|
||||
@ -771,16 +778,16 @@ fn emitNameSection(
|
||||
const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
|
||||
defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function));
|
||||
|
||||
const total_functions: u32 = @intCast(wasm.function_imports.entries.len + wasm.functions.entries.len);
|
||||
const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), total_functions);
|
||||
|
||||
for (wasm.function_imports.keys(), 0..) |name_index, function_index| {
|
||||
for (f.function_imports.keys(), 0..) |name_index, function_index| {
|
||||
const name = name_index.slice(wasm);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
|
||||
try binary_bytes.appendSlice(gpa, name);
|
||||
}
|
||||
for (wasm.functions.keys(), wasm.function_imports.entries.len..) |resolution, function_index| {
|
||||
for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| {
|
||||
const name = resolution.name(wasm).?;
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index)));
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
|
||||
@ -792,16 +799,16 @@ fn emitNameSection(
|
||||
const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
|
||||
defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global));
|
||||
|
||||
const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len);
|
||||
const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), total_globals);
|
||||
|
||||
for (wasm.global_imports.keys(), 0..) |name_index, global_index| {
|
||||
for (f.global_imports.keys(), 0..) |name_index, global_index| {
|
||||
const name = name_index.slice(wasm);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
|
||||
try binary_bytes.appendSlice(gpa, name);
|
||||
}
|
||||
for (wasm.globals.keys(), wasm.global_imports.entries.len..) |resolution, global_index| {
|
||||
for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| {
|
||||
const name = resolution.name(wasm).?;
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index)));
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len)));
|
||||
@ -813,7 +820,7 @@ fn emitNameSection(
|
||||
const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes);
|
||||
defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment));
|
||||
|
||||
const total_globals: u32 = @intCast(wasm.global_imports.entries.len + wasm.globals.entries.len);
|
||||
const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len);
|
||||
try leb.writeUleb128(binary_bytes.writer(gpa), total_globals);
|
||||
|
||||
for (data_segments.keys(), 0..) |ds, i| {
|
||||
@ -1356,7 +1363,7 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
|
||||
// .FUNCTION_INDEX_LEB => if (symbol.flags.undefined)
|
||||
// @intFromEnum(symbol.pointee.function_import)
|
||||
// else
|
||||
// @intFromEnum(symbol.pointee.function) + wasm.function_imports.items.len,
|
||||
// @intFromEnum(symbol.pointee.function) + f.function_imports.items.len,
|
||||
// .TABLE_NUMBER_LEB => if (symbol.flags.undefined)
|
||||
// @intFromEnum(symbol.pointee.table_import)
|
||||
// else
|
||||
@ -1371,7 +1378,7 @@ fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void {
|
||||
// .GLOBAL_INDEX_I32, .GLOBAL_INDEX_LEB => if (symbol.flags.undefined)
|
||||
// @intFromEnum(symbol.pointee.global_import)
|
||||
// else
|
||||
// @intFromEnum(symbol.pointee.global) + wasm.global_imports.items.len,
|
||||
// @intFromEnum(symbol.pointee.global) + f.global_imports.items.len,
|
||||
//
|
||||
// .MEMORY_ADDR_I32,
|
||||
// .MEMORY_ADDR_I64,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user