mirror of
https://codeberg.org/ziglang/zig.git
synced 2026-04-30 06:42:48 +03:00
Merge pull request #21874 from ziglang/wasm-linker
link.File.Wasm: unify the string tables
This commit is contained in:
+374
-386
@@ -36,11 +36,16 @@ const Value = @import("../Value.zig");
|
||||
const ZigObject = @import("Wasm/ZigObject.zig");
|
||||
|
||||
base: link.File,
|
||||
/// Null-terminated strings, indexes have type String and string_table provides
|
||||
/// lookup.
|
||||
string_bytes: std.ArrayListUnmanaged(u8),
|
||||
/// Omitted when serializing linker state.
|
||||
string_table: String.Table,
|
||||
/// Symbol name of the entry function to export
|
||||
entry_name: ?[]const u8,
|
||||
entry_name: OptionalString,
|
||||
/// When true, will allow undefined symbols
|
||||
import_symbols: bool,
|
||||
/// List of *global* symbol names to export to the host environment.
|
||||
/// Set of *global* symbol names to export to the host environment.
|
||||
export_symbol_names: []const []const u8,
|
||||
/// When defined, sets the start of the data section.
|
||||
global_base: ?u64,
|
||||
@@ -63,32 +68,14 @@ objects: std.ArrayListUnmanaged(Object) = .{},
|
||||
/// LLVM uses "env" by default when none is given. This would be a good default for Zig
|
||||
/// to support existing code.
|
||||
/// TODO: Allow setting this through a flag?
|
||||
host_name: []const u8 = "env",
|
||||
host_name: String,
|
||||
/// List of symbols generated by the linker.
|
||||
synthetic_symbols: std.ArrayListUnmanaged(Symbol) = .empty,
|
||||
/// Maps atoms to their segment index
|
||||
atoms: std.AutoHashMapUnmanaged(u32, Atom.Index) = .empty,
|
||||
atoms: std.AutoHashMapUnmanaged(Segment.Index, Atom.Index) = .empty,
|
||||
/// List of all atoms.
|
||||
managed_atoms: std.ArrayListUnmanaged(Atom) = .empty,
|
||||
/// Represents the index into `segments` where the 'code' section
|
||||
/// lives.
|
||||
code_section_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_info' section.
|
||||
debug_info_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_line' section.
|
||||
debug_line_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_loc' section.
|
||||
debug_loc_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_ranges' section.
|
||||
debug_ranges_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_pubnames' section.
|
||||
debug_pubnames_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_pubtypes' section.
|
||||
debug_pubtypes_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_pubtypes' section.
|
||||
debug_str_index: ?u32 = null,
|
||||
/// The index of the segment representing the custom '.debug_pubtypes' section.
|
||||
debug_abbrev_index: ?u32 = null,
|
||||
|
||||
/// The count of imported functions. This number will be appended
|
||||
/// to the function indexes as their index starts at the lowest non-extern function.
|
||||
imported_functions_count: u32 = 0,
|
||||
@@ -104,13 +91,11 @@ imports: std.AutoHashMapUnmanaged(SymbolLoc, Import) = .empty,
|
||||
/// Used for code, data and custom sections.
|
||||
segments: std.ArrayListUnmanaged(Segment) = .empty,
|
||||
/// Maps a data segment key (such as .rodata) to the index into `segments`.
|
||||
data_segments: std.StringArrayHashMapUnmanaged(u32) = .empty,
|
||||
data_segments: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty,
|
||||
/// A table of `NamedSegment` which provide meta data
|
||||
/// about a data symbol such as its name where the key is
|
||||
/// the segment index, which can be found from `data_segments`
|
||||
segment_info: std.AutoArrayHashMapUnmanaged(u32, NamedSegment) = .empty,
|
||||
/// Deduplicated string table for strings used by symbols, imports and exports.
|
||||
string_table: StringTable = .{},
|
||||
segment_info: std.AutoArrayHashMapUnmanaged(Segment.Index, NamedSegment) = .empty,
|
||||
|
||||
// Output sections
|
||||
/// Output type section
|
||||
@@ -158,8 +143,8 @@ function_table: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .empty,
|
||||
/// e.g. when an undefined symbol references a symbol from the archive.
|
||||
lazy_archives: std.ArrayListUnmanaged(LazyArchive) = .empty,
|
||||
|
||||
/// A map of global names (read: offset into string table) to their symbol location
|
||||
globals: std.AutoHashMapUnmanaged(u32, SymbolLoc) = .empty,
|
||||
/// A map of global names to their symbol location
|
||||
globals: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty,
|
||||
/// The list of GOT symbols and their location
|
||||
got_symbols: std.ArrayListUnmanaged(SymbolLoc) = .empty,
|
||||
/// Maps discarded symbols and their positions to the location of the symbol
|
||||
@@ -169,8 +154,7 @@ discarded: std.AutoHashMapUnmanaged(SymbolLoc, SymbolLoc) = .empty,
|
||||
/// into the final binary.
|
||||
resolved_symbols: std.AutoArrayHashMapUnmanaged(SymbolLoc, void) = .empty,
|
||||
/// Symbols that remain undefined after symbol resolution.
|
||||
/// Note: The key represents an offset into the string table, rather than the actual string.
|
||||
undefs: std.AutoArrayHashMapUnmanaged(u32, SymbolLoc) = .empty,
|
||||
undefs: std.AutoArrayHashMapUnmanaged(String, SymbolLoc) = .empty,
|
||||
/// Maps a symbol's location to an atom. This can be used to find meta
|
||||
/// data of a symbol, such as its size, or its offset to perform a relocation.
|
||||
/// Undefined (and synthetic) symbols do not have an Atom and therefore cannot be mapped.
|
||||
@@ -178,8 +162,103 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, Atom.Index) = .empty,
|
||||
|
||||
/// `--verbose-link` output.
|
||||
/// Initialized on creation, appended to as inputs are added, printed during `flush`.
|
||||
/// String data is allocated into Compilation arena.
|
||||
dump_argv_list: std.ArrayListUnmanaged([]const u8),
|
||||
|
||||
/// Represents the index into `segments` where the 'code' section lives.
|
||||
code_section_index: Segment.OptionalIndex = .none,
|
||||
custom_sections: CustomSections,
|
||||
preloaded_strings: PreloadedStrings,
|
||||
|
||||
/// Type reflection is used on the field names to autopopulate each field
|
||||
/// during initialization.
|
||||
const PreloadedStrings = struct {
|
||||
__heap_base: String,
|
||||
__heap_end: String,
|
||||
__indirect_function_table: String,
|
||||
__linear_memory: String,
|
||||
__stack_pointer: String,
|
||||
__tls_align: String,
|
||||
__tls_base: String,
|
||||
__tls_size: String,
|
||||
__wasm_apply_global_tls_relocs: String,
|
||||
__wasm_call_ctors: String,
|
||||
__wasm_init_memory: String,
|
||||
__wasm_init_memory_flag: String,
|
||||
__wasm_init_tls: String,
|
||||
__zig_err_name_table: String,
|
||||
__zig_err_names: String,
|
||||
__zig_errors_len: String,
|
||||
_initialize: String,
|
||||
_start: String,
|
||||
memory: String,
|
||||
};
|
||||
|
||||
/// Type reflection is used on the field names to autopopulate each inner `name` field.
|
||||
const CustomSections = struct {
|
||||
@".debug_info": CustomSection,
|
||||
@".debug_pubtypes": CustomSection,
|
||||
@".debug_abbrev": CustomSection,
|
||||
@".debug_line": CustomSection,
|
||||
@".debug_str": CustomSection,
|
||||
@".debug_pubnames": CustomSection,
|
||||
@".debug_loc": CustomSection,
|
||||
@".debug_ranges": CustomSection,
|
||||
};
|
||||
|
||||
const CustomSection = struct {
|
||||
name: String,
|
||||
index: Segment.OptionalIndex,
|
||||
};
|
||||
|
||||
/// Index into string_bytes
|
||||
pub const String = enum(u32) {
|
||||
_,
|
||||
|
||||
const Table = std.HashMapUnmanaged(String, void, TableContext, std.hash_map.default_max_load_percentage);
|
||||
|
||||
const TableContext = struct {
|
||||
bytes: []const u8,
|
||||
|
||||
pub fn eql(_: @This(), a: String, b: String) bool {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
pub fn hash(ctx: @This(), key: String) u64 {
|
||||
return std.hash_map.hashString(mem.sliceTo(ctx.bytes[@intFromEnum(key)..], 0));
|
||||
}
|
||||
};
|
||||
|
||||
const TableIndexAdapter = struct {
|
||||
bytes: []const u8,
|
||||
|
||||
pub fn eql(ctx: @This(), a: []const u8, b: String) bool {
|
||||
return mem.eql(u8, a, mem.sliceTo(ctx.bytes[@intFromEnum(b)..], 0));
|
||||
}
|
||||
|
||||
pub fn hash(_: @This(), adapted_key: []const u8) u64 {
|
||||
assert(mem.indexOfScalar(u8, adapted_key, 0) == null);
|
||||
return std.hash_map.hashString(adapted_key);
|
||||
}
|
||||
};
|
||||
|
||||
pub fn toOptional(i: String) OptionalString {
|
||||
const result: OptionalString = @enumFromInt(@intFromEnum(i));
|
||||
assert(result != .none);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
pub const OptionalString = enum(u32) {
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
|
||||
pub fn unwrap(i: OptionalString) ?String {
|
||||
if (i == .none) return null;
|
||||
return @enumFromInt(@intFromEnum(i));
|
||||
}
|
||||
};
|
||||
|
||||
/// Index into objects array or the zig object.
|
||||
pub const ObjectId = enum(u16) {
|
||||
zig_object = std.math.maxInt(u16) - 1,
|
||||
@@ -222,6 +301,26 @@ pub const Segment = struct {
|
||||
offset: u32,
|
||||
flags: u32,
|
||||
|
||||
const Index = enum(u32) {
|
||||
_,
|
||||
|
||||
pub fn toOptional(i: Index) OptionalIndex {
|
||||
const result: OptionalIndex = @enumFromInt(@intFromEnum(i));
|
||||
assert(result != .none);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
const OptionalIndex = enum(u32) {
|
||||
none = std.math.maxInt(u32),
|
||||
_,
|
||||
|
||||
pub fn unwrap(i: OptionalIndex) ?Index {
|
||||
if (i == .none) return null;
|
||||
return @enumFromInt(@intFromEnum(i));
|
||||
}
|
||||
};
|
||||
|
||||
pub const Flag = enum(u32) {
|
||||
WASM_DATA_SEGMENT_IS_PASSIVE = 0x01,
|
||||
WASM_DATA_SEGMENT_HAS_MEMINDEX = 0x02,
|
||||
@@ -260,26 +359,8 @@ pub fn symbolLocSymbol(wasm: *const Wasm, loc: SymbolLoc) *Symbol {
|
||||
}
|
||||
|
||||
/// From a given location, returns the name of the symbol.
|
||||
pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) []const u8 {
|
||||
if (wasm.discarded.get(loc)) |new_loc| {
|
||||
return wasm.symbolLocName(new_loc);
|
||||
}
|
||||
switch (loc.file) {
|
||||
.none => {
|
||||
const sym = wasm.synthetic_symbols.items[@intFromEnum(loc.index)];
|
||||
return wasm.string_table.get(sym.name);
|
||||
},
|
||||
.zig_object => {
|
||||
const zo = wasm.zig_object.?;
|
||||
const sym = zo.symbols.items[@intFromEnum(loc.index)];
|
||||
return zo.string_table.get(sym.name).?;
|
||||
},
|
||||
_ => {
|
||||
const obj = &wasm.objects.items[@intFromEnum(loc.file)];
|
||||
const sym = obj.symtable[@intFromEnum(loc.index)];
|
||||
return obj.string_table.get(sym.name);
|
||||
},
|
||||
}
|
||||
pub fn symbolLocName(wasm: *const Wasm, loc: SymbolLoc) [:0]const u8 {
|
||||
return wasm.stringSlice(wasm.symbolLocSymbol(loc).name);
|
||||
}
|
||||
|
||||
/// From a given symbol location, returns the final location.
|
||||
@@ -325,75 +406,6 @@ pub const InitFuncLoc = struct {
|
||||
return lhs.priority < rhs.priority;
|
||||
}
|
||||
};
|
||||
/// Generic string table that duplicates strings
|
||||
/// and converts them into offsets instead.
|
||||
pub const StringTable = struct {
|
||||
/// Table that maps string offsets, which is used to de-duplicate strings.
|
||||
/// Rather than having the offset map to the data, the `StringContext` holds all bytes of the string.
|
||||
/// The strings are stored as a contigious array where each string is zero-terminated.
|
||||
string_table: std.HashMapUnmanaged(
|
||||
u32,
|
||||
void,
|
||||
std.hash_map.StringIndexContext,
|
||||
std.hash_map.default_max_load_percentage,
|
||||
) = .{},
|
||||
/// Holds the actual data of the string table.
|
||||
string_data: std.ArrayListUnmanaged(u8) = .empty,
|
||||
|
||||
/// Accepts a string and searches for a corresponding string.
|
||||
/// When found, de-duplicates the string and returns the existing offset instead.
|
||||
/// When the string is not found in the `string_table`, a new entry will be inserted
|
||||
/// and the new offset to its data will be returned.
|
||||
pub fn put(table: *StringTable, allocator: Allocator, string: []const u8) !u32 {
|
||||
const gop = try table.string_table.getOrPutContextAdapted(
|
||||
allocator,
|
||||
string,
|
||||
std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
|
||||
.{ .bytes = &table.string_data },
|
||||
);
|
||||
if (gop.found_existing) {
|
||||
const off = gop.key_ptr.*;
|
||||
log.debug("reusing string '{s}' at offset 0x{x}", .{ string, off });
|
||||
return off;
|
||||
}
|
||||
|
||||
try table.string_data.ensureUnusedCapacity(allocator, string.len + 1);
|
||||
const offset: u32 = @intCast(table.string_data.items.len);
|
||||
|
||||
log.debug("writing new string '{s}' at offset 0x{x}", .{ string, offset });
|
||||
|
||||
table.string_data.appendSliceAssumeCapacity(string);
|
||||
table.string_data.appendAssumeCapacity(0);
|
||||
|
||||
gop.key_ptr.* = offset;
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
/// From a given offset, returns its corresponding string value.
|
||||
/// Asserts offset does not exceed bounds.
|
||||
pub fn get(table: StringTable, off: u32) []const u8 {
|
||||
assert(off < table.string_data.items.len);
|
||||
return mem.sliceTo(@as([*:0]const u8, @ptrCast(table.string_data.items.ptr + off)), 0);
|
||||
}
|
||||
|
||||
/// Returns the offset of a given string when it exists.
|
||||
/// Will return null if the given string does not yet exist within the string table.
|
||||
pub fn getOffset(table: *StringTable, string: []const u8) ?u32 {
|
||||
return table.string_table.getKeyAdapted(
|
||||
string,
|
||||
std.hash_map.StringIndexAdapter{ .bytes = &table.string_data },
|
||||
);
|
||||
}
|
||||
|
||||
/// Frees all resources of the string table. Any references pointing
|
||||
/// to the strings will be invalid.
|
||||
pub fn deinit(table: *StringTable, allocator: Allocator) void {
|
||||
table.string_data.deinit(allocator);
|
||||
table.string_table.deinit(allocator);
|
||||
table.* = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
pub fn open(
|
||||
arena: Allocator,
|
||||
@@ -451,6 +463,8 @@ pub fn createEmpty(
|
||||
.build_id = options.build_id,
|
||||
},
|
||||
.name = undefined,
|
||||
.string_table = .empty,
|
||||
.string_bytes = .empty,
|
||||
.import_table = options.import_table,
|
||||
.export_table = options.export_table,
|
||||
.import_symbols = options.import_symbols,
|
||||
@@ -459,20 +473,38 @@ pub fn createEmpty(
|
||||
.initial_memory = options.initial_memory,
|
||||
.max_memory = options.max_memory,
|
||||
|
||||
.entry_name = switch (options.entry) {
|
||||
.disabled => null,
|
||||
.default => if (output_mode != .Exe) null else defaultEntrySymbolName(wasi_exec_model),
|
||||
.enabled => defaultEntrySymbolName(wasi_exec_model),
|
||||
.named => |name| name,
|
||||
},
|
||||
.entry_name = undefined,
|
||||
.zig_object = null,
|
||||
.dump_argv_list = .empty,
|
||||
.host_name = undefined,
|
||||
.custom_sections = undefined,
|
||||
.preloaded_strings = undefined,
|
||||
};
|
||||
if (use_llvm and comp.config.have_zcu) {
|
||||
wasm.llvm_object = try LlvmObject.create(arena, comp);
|
||||
}
|
||||
errdefer wasm.base.destroy();
|
||||
|
||||
wasm.host_name = try wasm.internString("env");
|
||||
|
||||
inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
|
||||
@field(wasm.custom_sections, field.name) = .{
|
||||
.index = .none,
|
||||
.name = try wasm.internString(field.name),
|
||||
};
|
||||
}
|
||||
|
||||
inline for (@typeInfo(PreloadedStrings).@"struct".fields) |field| {
|
||||
@field(wasm.preloaded_strings, field.name) = try wasm.internString(field.name);
|
||||
}
|
||||
|
||||
wasm.entry_name = switch (options.entry) {
|
||||
.disabled => .none,
|
||||
.default => if (output_mode != .Exe) .none else defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(),
|
||||
.enabled => defaultEntrySymbolName(&wasm.preloaded_strings, wasi_exec_model).toOptional(),
|
||||
.named => |name| (try wasm.internString(name)).toOptional(),
|
||||
};
|
||||
|
||||
if (use_lld and (use_llvm or !comp.config.have_zcu)) {
|
||||
// LLVM emits the object file (if any); LLD links it into the final product.
|
||||
return wasm;
|
||||
@@ -498,22 +530,18 @@ pub fn createEmpty(
|
||||
|
||||
// create stack pointer symbol
|
||||
{
|
||||
const loc = try wasm.createSyntheticSymbol("__stack_pointer", .global);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__stack_pointer, .global);
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
// For object files we will import the stack pointer symbol
|
||||
if (output_mode == .Obj) {
|
||||
symbol.setUndefined(true);
|
||||
symbol.index = @intCast(wasm.imported_globals_count);
|
||||
wasm.imported_globals_count += 1;
|
||||
try wasm.imports.putNoClobber(
|
||||
gpa,
|
||||
loc,
|
||||
.{
|
||||
.module_name = try wasm.string_table.put(gpa, wasm.host_name),
|
||||
.name = symbol.name,
|
||||
.kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
|
||||
},
|
||||
);
|
||||
try wasm.imports.putNoClobber(gpa, loc, .{
|
||||
.module_name = wasm.host_name,
|
||||
.name = symbol.name,
|
||||
.kind = .{ .global = .{ .valtype = .i32, .mutable = true } },
|
||||
});
|
||||
} else {
|
||||
symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
@@ -530,7 +558,7 @@ pub fn createEmpty(
|
||||
|
||||
// create indirect function pointer symbol
|
||||
{
|
||||
const loc = try wasm.createSyntheticSymbol("__indirect_function_table", .table);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__indirect_function_table, .table);
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
const table: std.wasm.Table = .{
|
||||
.limits = .{ .flags = 0, .min = 0, .max = undefined }, // will be overwritten during `mapFunctionTable`
|
||||
@@ -541,7 +569,7 @@ pub fn createEmpty(
|
||||
symbol.index = @intCast(wasm.imported_tables_count);
|
||||
wasm.imported_tables_count += 1;
|
||||
try wasm.imports.put(gpa, loc, .{
|
||||
.module_name = try wasm.string_table.put(gpa, wasm.host_name),
|
||||
.module_name = wasm.host_name,
|
||||
.name = symbol.name,
|
||||
.kind = .{ .table = table },
|
||||
});
|
||||
@@ -558,7 +586,7 @@ pub fn createEmpty(
|
||||
|
||||
// create __wasm_call_ctors
|
||||
{
|
||||
const loc = try wasm.createSyntheticSymbol("__wasm_call_ctors", .function);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_call_ctors, .function);
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
// we do not know the function index until after we merged all sections.
|
||||
@@ -569,7 +597,7 @@ pub fn createEmpty(
|
||||
// shared-memory symbols for TLS support
|
||||
if (shared_memory) {
|
||||
{
|
||||
const loc = try wasm.createSyntheticSymbol("__tls_base", .global);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_base, .global);
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
|
||||
@@ -580,7 +608,7 @@ pub fn createEmpty(
|
||||
});
|
||||
}
|
||||
{
|
||||
const loc = try wasm.createSyntheticSymbol("__tls_size", .global);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_size, .global);
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
|
||||
@@ -591,7 +619,7 @@ pub fn createEmpty(
|
||||
});
|
||||
}
|
||||
{
|
||||
const loc = try wasm.createSyntheticSymbol("__tls_align", .global);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__tls_align, .global);
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
symbol.index = @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len);
|
||||
@@ -602,7 +630,7 @@ pub fn createEmpty(
|
||||
});
|
||||
}
|
||||
{
|
||||
const loc = try wasm.createSyntheticSymbol("__wasm_init_tls", .function);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_tls, .function);
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
}
|
||||
@@ -655,13 +683,11 @@ pub fn addOrUpdateImport(
|
||||
|
||||
/// For a given name, creates a new global synthetic symbol.
|
||||
/// Leaves index undefined and the default flags (0).
|
||||
fn createSyntheticSymbol(wasm: *Wasm, name: []const u8, tag: Symbol.Tag) !SymbolLoc {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const name_offset = try wasm.string_table.put(gpa, name);
|
||||
return wasm.createSyntheticSymbolOffset(name_offset, tag);
|
||||
fn createSyntheticSymbol(wasm: *Wasm, name: String, tag: Symbol.Tag) !SymbolLoc {
|
||||
return wasm.createSyntheticSymbolOffset(name, tag);
|
||||
}
|
||||
|
||||
fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: u32, tag: Symbol.Tag) !SymbolLoc {
|
||||
fn createSyntheticSymbolOffset(wasm: *Wasm, name_offset: String, tag: Symbol.Tag) !SymbolLoc {
|
||||
const sym_index: Symbol.Index = @enumFromInt(wasm.synthetic_symbols.items.len);
|
||||
const loc: SymbolLoc = .{ .index = sym_index, .file = .none };
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
@@ -803,16 +829,6 @@ fn objectSymbol(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) *Sy
|
||||
return &obj.symtable[@intFromEnum(index)];
|
||||
}
|
||||
|
||||
fn objectSymbolName(wasm: *const Wasm, object_id: ObjectId, index: Symbol.Index) []const u8 {
|
||||
const obj = wasm.objectById(object_id) orelse {
|
||||
const zo = wasm.zig_object.?;
|
||||
const sym = zo.symbols.items[@intFromEnum(index)];
|
||||
return zo.string_table.get(sym.name).?;
|
||||
};
|
||||
const sym = obj.symtable[@intFromEnum(index)];
|
||||
return obj.string_table.get(sym.name);
|
||||
}
|
||||
|
||||
fn objectFunction(wasm: *const Wasm, object_id: ObjectId, sym_index: Symbol.Index) std.wasm.Func {
|
||||
const obj = wasm.objectById(object_id) orelse {
|
||||
const zo = wasm.zig_object.?;
|
||||
@@ -850,13 +866,6 @@ fn objectImport(wasm: *const Wasm, object_id: ObjectId, symbol_index: Symbol.Ind
|
||||
return obj.findImport(obj.symtable[@intFromEnum(symbol_index)]);
|
||||
}
|
||||
|
||||
/// For a given offset, returns its string value.
|
||||
/// Asserts string exists in the object string table.
|
||||
fn objectString(wasm: *const Wasm, object_id: ObjectId, offset: u32) []const u8 {
|
||||
const obj = wasm.objectById(object_id) orelse return wasm.zig_object.?.string_table.get(offset).?;
|
||||
return obj.string_table.get(offset);
|
||||
}
|
||||
|
||||
/// Returns the object element pointer, or null if it is the ZigObject.
|
||||
fn objectById(wasm: *const Wasm, object_id: ObjectId) ?*Object {
|
||||
if (object_id == .zig_object) return null;
|
||||
@@ -876,27 +885,25 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
|
||||
.file = object_id.toOptional(),
|
||||
.index = sym_index,
|
||||
};
|
||||
const sym_name = objectString(wasm, object_id, symbol.name);
|
||||
if (mem.eql(u8, sym_name, "__indirect_function_table")) {
|
||||
continue;
|
||||
}
|
||||
const sym_name_index = try wasm.string_table.put(gpa, sym_name);
|
||||
if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue;
|
||||
|
||||
if (symbol.isLocal()) {
|
||||
if (symbol.isUndefined()) {
|
||||
diags.addParseError(obj_path, "local symbol '{s}' references import", .{sym_name});
|
||||
diags.addParseError(obj_path, "local symbol '{s}' references import", .{
|
||||
wasm.stringSlice(symbol.name),
|
||||
});
|
||||
}
|
||||
try wasm.resolved_symbols.putNoClobber(gpa, location, {});
|
||||
continue;
|
||||
}
|
||||
|
||||
const maybe_existing = try wasm.globals.getOrPut(gpa, sym_name_index);
|
||||
const maybe_existing = try wasm.globals.getOrPut(gpa, symbol.name);
|
||||
if (!maybe_existing.found_existing) {
|
||||
maybe_existing.value_ptr.* = location;
|
||||
try wasm.resolved_symbols.putNoClobber(gpa, location, {});
|
||||
|
||||
if (symbol.isUndefined()) {
|
||||
try wasm.undefs.putNoClobber(gpa, sym_name_index, location);
|
||||
try wasm.undefs.putNoClobber(gpa, symbol.name, location);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
@@ -918,7 +925,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
|
||||
}
|
||||
// both are defined and weak, we have a symbol collision.
|
||||
var err = try diags.addErrorWithNotes(2);
|
||||
try err.addMsg("symbol '{s}' defined multiple times", .{sym_name});
|
||||
try err.addMsg("symbol '{s}' defined multiple times", .{wasm.stringSlice(symbol.name)});
|
||||
try err.addNote("first definition in '{'}'", .{existing_file_path});
|
||||
try err.addNote("next definition in '{'}'", .{obj_path});
|
||||
}
|
||||
@@ -929,7 +936,9 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
|
||||
|
||||
if (symbol.tag != existing_sym.tag) {
|
||||
var err = try diags.addErrorWithNotes(2);
|
||||
try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{ sym_name, @tagName(symbol.tag), @tagName(existing_sym.tag) });
|
||||
try err.addMsg("symbol '{s}' mismatching types '{s}' and '{s}'", .{
|
||||
wasm.stringSlice(symbol.name), @tagName(symbol.tag), @tagName(existing_sym.tag),
|
||||
});
|
||||
try err.addNote("first definition in '{'}'", .{existing_file_path});
|
||||
try err.addNote("next definition in '{'}'", .{obj_path});
|
||||
}
|
||||
@@ -937,22 +946,18 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
|
||||
if (existing_sym.isUndefined() and symbol.isUndefined()) {
|
||||
// only verify module/import name for function symbols
|
||||
if (symbol.tag == .function) {
|
||||
const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id| blk: {
|
||||
const imp = objectImport(wasm, existing_obj_id, existing_loc.index);
|
||||
break :blk objectString(wasm, existing_obj_id, imp.module_name);
|
||||
} else blk: {
|
||||
const name_index = wasm.imports.get(existing_loc).?.module_name;
|
||||
break :blk wasm.string_table.get(name_index);
|
||||
};
|
||||
const existing_name = if (existing_loc.file.unwrap()) |existing_obj_id|
|
||||
objectImport(wasm, existing_obj_id, existing_loc.index).module_name
|
||||
else
|
||||
wasm.imports.get(existing_loc).?.module_name;
|
||||
|
||||
const imp = objectImport(wasm, object_id, sym_index);
|
||||
const module_name = objectString(wasm, object_id, imp.module_name);
|
||||
if (!mem.eql(u8, existing_name, module_name)) {
|
||||
const module_name = objectImport(wasm, object_id, sym_index).module_name;
|
||||
if (existing_name != module_name) {
|
||||
var err = try diags.addErrorWithNotes(2);
|
||||
try err.addMsg("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{
|
||||
sym_name,
|
||||
existing_name,
|
||||
module_name,
|
||||
wasm.stringSlice(symbol.name),
|
||||
wasm.stringSlice(existing_name),
|
||||
wasm.stringSlice(module_name),
|
||||
});
|
||||
try err.addNote("first definition in '{'}'", .{existing_file_path});
|
||||
try err.addNote("next definition in '{'}'", .{obj_path});
|
||||
@@ -969,7 +974,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
|
||||
const new_ty = wasm.getGlobalType(location);
|
||||
if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) {
|
||||
var err = try diags.addErrorWithNotes(2);
|
||||
try err.addMsg("symbol '{s}' mismatching global types", .{sym_name});
|
||||
try err.addMsg("symbol '{s}' mismatching global types", .{wasm.stringSlice(symbol.name)});
|
||||
try err.addNote("first definition in '{'}'", .{existing_file_path});
|
||||
try err.addNote("next definition in '{'}'", .{obj_path});
|
||||
}
|
||||
@@ -980,7 +985,7 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
|
||||
const new_ty = wasm.getFunctionSignature(location);
|
||||
if (!existing_ty.eql(new_ty)) {
|
||||
var err = try diags.addErrorWithNotes(3);
|
||||
try err.addMsg("symbol '{s}' mismatching function signatures.", .{sym_name});
|
||||
try err.addMsg("symbol '{s}' mismatching function signatures.", .{wasm.stringSlice(symbol.name)});
|
||||
try err.addNote("expected signature {}, but found signature {}", .{ existing_ty, new_ty });
|
||||
try err.addNote("first definition in '{'}'", .{existing_file_path});
|
||||
try err.addNote("next definition in '{'}'", .{obj_path});
|
||||
@@ -996,16 +1001,16 @@ fn resolveSymbolsInObject(wasm: *Wasm, object_id: ObjectId) !void {
|
||||
}
|
||||
|
||||
// simply overwrite with the new symbol
|
||||
log.debug("Overwriting symbol '{s}'", .{sym_name});
|
||||
log.debug("Overwriting symbol '{s}'", .{wasm.stringSlice(symbol.name)});
|
||||
log.debug(" old definition in '{'}'", .{existing_file_path});
|
||||
log.debug(" new definition in '{'}'", .{obj_path});
|
||||
try wasm.discarded.putNoClobber(gpa, existing_loc, location);
|
||||
maybe_existing.value_ptr.* = location;
|
||||
try wasm.globals.put(gpa, sym_name_index, location);
|
||||
try wasm.globals.put(gpa, symbol.name, location);
|
||||
try wasm.resolved_symbols.put(gpa, location, {});
|
||||
assert(wasm.resolved_symbols.swapRemove(existing_loc));
|
||||
if (existing_sym.isUndefined()) {
|
||||
_ = wasm.undefs.swapRemove(sym_name_index);
|
||||
_ = wasm.undefs.swapRemove(symbol.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1021,7 +1026,7 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void {
|
||||
const sym_name_index = wasm.undefs.keys()[index];
|
||||
|
||||
for (wasm.lazy_archives.items) |lazy_archive| {
|
||||
const sym_name = wasm.string_table.get(sym_name_index);
|
||||
const sym_name = wasm.stringSlice(sym_name_index);
|
||||
log.debug("Detected symbol '{s}' in archive '{'}', parsing objects..", .{
|
||||
sym_name, lazy_archive.path,
|
||||
});
|
||||
@@ -1066,13 +1071,13 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
|
||||
if (!wasm.hasPassiveInitializationSegments()) {
|
||||
return;
|
||||
}
|
||||
const sym_loc = try wasm.createSyntheticSymbol("__wasm_init_memory", .function);
|
||||
const sym_loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory, .function);
|
||||
wasm.symbolLocSymbol(sym_loc).mark();
|
||||
|
||||
const flag_address: u32 = if (shared_memory) address: {
|
||||
// when we have passive initialization segments and shared memory
|
||||
// `setupMemory` will create this symbol and set its virtual address.
|
||||
const loc = wasm.findGlobalSymbol("__wasm_init_memory_flag").?;
|
||||
const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory_flag).?;
|
||||
break :address wasm.symbolLocSymbol(loc).virtual_address;
|
||||
} else 0;
|
||||
|
||||
@@ -1113,31 +1118,30 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
|
||||
try writer.writeByte(std.wasm.opcode(.end));
|
||||
}
|
||||
|
||||
var it = wasm.data_segments.iterator();
|
||||
var segment_index: u32 = 0;
|
||||
while (it.next()) |entry| : (segment_index += 1) {
|
||||
const segment: Segment = wasm.segments.items[entry.value_ptr.*];
|
||||
if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
|
||||
for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |key, value, segment_index_usize| {
|
||||
const segment_index: u32 = @intCast(segment_index_usize);
|
||||
const segment = wasm.segmentPtr(value);
|
||||
if (segment.needsPassiveInitialization(import_memory, key)) {
|
||||
// For passive BSS segments we can simple issue a memory.fill(0).
|
||||
// For non-BSS segments we do a memory.init. Both these
|
||||
// instructions take as their first argument the destination
|
||||
// address.
|
||||
try writeI32Const(writer, segment.offset);
|
||||
|
||||
if (shared_memory and std.mem.eql(u8, entry.key_ptr.*, ".tdata")) {
|
||||
if (shared_memory and std.mem.eql(u8, key, ".tdata")) {
|
||||
// When we initialize the TLS segment we also set the `__tls_base`
|
||||
// global. This allows the runtime to use this static copy of the
|
||||
// TLS data for the first/main thread.
|
||||
try writeI32Const(writer, segment.offset);
|
||||
try writer.writeByte(std.wasm.opcode(.global_set));
|
||||
const loc = wasm.findGlobalSymbol("__tls_base").?;
|
||||
const loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?;
|
||||
try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
|
||||
}
|
||||
|
||||
try writeI32Const(writer, 0);
|
||||
try writeI32Const(writer, segment.size);
|
||||
try writer.writeByte(std.wasm.opcode(.misc_prefix));
|
||||
if (std.mem.eql(u8, entry.key_ptr.*, ".bss")) {
|
||||
if (std.mem.eql(u8, key, ".bss")) {
|
||||
// fill bss segment with zeroes
|
||||
try leb.writeUleb128(writer, std.wasm.miscOpcode(.memory_fill));
|
||||
} else {
|
||||
@@ -1187,11 +1191,9 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
|
||||
try writer.writeByte(std.wasm.opcode(.end)); // end $drop
|
||||
}
|
||||
|
||||
it.reset();
|
||||
segment_index = 0;
|
||||
while (it.next()) |entry| : (segment_index += 1) {
|
||||
const name = entry.key_ptr.*;
|
||||
const segment: Segment = wasm.segments.items[entry.value_ptr.*];
|
||||
for (wasm.data_segments.keys(), wasm.data_segments.values(), 0..) |name, value, segment_index_usize| {
|
||||
const segment_index: u32 = @intCast(segment_index_usize);
|
||||
const segment = wasm.segmentPtr(value);
|
||||
if (segment.needsPassiveInitialization(import_memory, name) and
|
||||
!std.mem.eql(u8, name, ".bss"))
|
||||
{
|
||||
@@ -1211,7 +1213,7 @@ fn setupInitMemoryFunction(wasm: *Wasm) !void {
|
||||
try writer.writeByte(std.wasm.opcode(.end));
|
||||
|
||||
try wasm.createSyntheticFunction(
|
||||
"__wasm_init_memory",
|
||||
wasm.preloaded_strings.__wasm_init_memory,
|
||||
std.wasm.Type{ .params = &.{}, .returns = &.{} },
|
||||
&function_body,
|
||||
);
|
||||
@@ -1230,7 +1232,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
|
||||
return;
|
||||
}
|
||||
|
||||
const loc = try wasm.createSyntheticSymbol("__wasm_apply_global_tls_relocs", .function);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_apply_global_tls_relocs, .function);
|
||||
wasm.symbolLocSymbol(loc).mark();
|
||||
var function_body = std.ArrayList(u8).init(gpa);
|
||||
defer function_body.deinit();
|
||||
@@ -1244,7 +1246,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
|
||||
if (sym.tag == .data and sym.isDefined()) {
|
||||
// get __tls_base
|
||||
try writer.writeByte(std.wasm.opcode(.global_get));
|
||||
try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.findGlobalSymbol("__tls_base").?).index);
|
||||
try leb.writeUleb128(writer, wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__tls_base).?).index);
|
||||
|
||||
// add the virtual address of the symbol
|
||||
try writer.writeByte(std.wasm.opcode(.i32_const));
|
||||
@@ -1260,7 +1262,7 @@ fn setupTLSRelocationsFunction(wasm: *Wasm) !void {
|
||||
try writer.writeByte(std.wasm.opcode(.end));
|
||||
|
||||
try wasm.createSyntheticFunction(
|
||||
"__wasm_apply_global_tls_relocs",
|
||||
wasm.preloaded_strings.__wasm_apply_global_tls_relocs,
|
||||
std.wasm.Type{ .params = &.{}, .returns = &.{} },
|
||||
&function_body,
|
||||
);
|
||||
@@ -1422,7 +1424,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
|
||||
const gpa = comp.gpa;
|
||||
const shared_memory = comp.config.shared_memory;
|
||||
|
||||
if (wasm.string_table.getOffset("__heap_base")) |name_offset| {
|
||||
if (wasm.getExistingString("__heap_base")) |name_offset| {
|
||||
if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
|
||||
const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
|
||||
try wasm.discarded.putNoClobber(gpa, kv.value, loc);
|
||||
@@ -1430,7 +1432,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
|
||||
}
|
||||
}
|
||||
|
||||
if (wasm.string_table.getOffset("__heap_end")) |name_offset| {
|
||||
if (wasm.getExistingString("__heap_end")) |name_offset| {
|
||||
if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
|
||||
const loc = try wasm.createSyntheticSymbolOffset(name_offset, .data);
|
||||
try wasm.discarded.putNoClobber(gpa, kv.value, loc);
|
||||
@@ -1439,7 +1441,7 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
|
||||
}
|
||||
|
||||
if (!shared_memory) {
|
||||
if (wasm.string_table.getOffset("__tls_base")) |name_offset| {
|
||||
if (wasm.getExistingString("__tls_base")) |name_offset| {
|
||||
if (wasm.undefs.fetchSwapRemove(name_offset)) |kv| {
|
||||
const loc = try wasm.createSyntheticSymbolOffset(name_offset, .global);
|
||||
try wasm.discarded.putNoClobber(gpa, kv.value, loc);
|
||||
@@ -1456,11 +1458,9 @@ fn resolveLazySymbols(wasm: *Wasm) !void {
|
||||
}
|
||||
}
|
||||
|
||||
// Tries to find a global symbol by its name. Returns null when not found,
|
||||
/// and its location when it is found.
|
||||
pub fn findGlobalSymbol(wasm: *Wasm, name: []const u8) ?SymbolLoc {
|
||||
const offset = wasm.string_table.getOffset(name) orelse return null;
|
||||
return wasm.globals.get(offset);
|
||||
pub fn findGlobalSymbol(wasm: *const Wasm, name: []const u8) ?SymbolLoc {
|
||||
const name_index = wasm.getExistingString(name) orelse return null;
|
||||
return wasm.globals.get(name_index);
|
||||
}
|
||||
|
||||
fn checkUndefinedSymbols(wasm: *const Wasm) !void {
|
||||
@@ -1516,7 +1516,7 @@ pub fn deinit(wasm: *Wasm) void {
|
||||
for (wasm.lazy_archives.items) |*lazy_archive| lazy_archive.deinit(gpa);
|
||||
wasm.lazy_archives.deinit(gpa);
|
||||
|
||||
if (wasm.findGlobalSymbol("__wasm_init_tls")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls)) |loc| {
|
||||
const atom = wasm.symbol_atom.get(loc).?;
|
||||
wasm.getAtomPtr(atom).deinit(gpa);
|
||||
}
|
||||
@@ -1544,6 +1544,7 @@ pub fn deinit(wasm: *Wasm) void {
|
||||
wasm.init_funcs.deinit(gpa);
|
||||
wasm.exports.deinit(gpa);
|
||||
|
||||
wasm.string_bytes.deinit(gpa);
|
||||
wasm.string_table.deinit(gpa);
|
||||
wasm.dump_argv_list.deinit(gpa);
|
||||
}
|
||||
@@ -1649,7 +1650,8 @@ fn getFunctionSignature(wasm: *const Wasm, loc: SymbolLoc) std.wasm.Type {
|
||||
/// and then returns the index to it.
|
||||
pub fn getGlobalSymbol(wasm: *Wasm, name: []const u8, lib_name: ?[]const u8) !Symbol.Index {
|
||||
_ = lib_name;
|
||||
return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name);
|
||||
const name_index = try wasm.internString(name);
|
||||
return wasm.zig_object.?.getGlobalSymbol(wasm.base.comp.gpa, name_index);
|
||||
}
|
||||
|
||||
/// For a given `Nav`, find the given symbol index's atom, and create a relocation for the type.
|
||||
@@ -1721,12 +1723,12 @@ fn mapFunctionTable(wasm: *Wasm) void {
|
||||
}
|
||||
|
||||
if (wasm.import_table or wasm.base.comp.config.output_mode == .Obj) {
|
||||
const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
|
||||
const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
|
||||
const import = wasm.imports.getPtr(sym_loc).?;
|
||||
import.kind.table.limits.min = index - 1; // we start at index 1.
|
||||
} else if (index > 1) {
|
||||
log.debug("Appending indirect function table", .{});
|
||||
const sym_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
|
||||
const sym_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
|
||||
const symbol = wasm.symbolLocSymbol(sym_loc);
|
||||
const table = &wasm.tables.items[symbol.index - wasm.imported_tables_count];
|
||||
table.limits = .{ .min = index, .max = index, .flags = 0x1 };
|
||||
@@ -1735,7 +1737,7 @@ fn mapFunctionTable(wasm: *Wasm) void {
|
||||
|
||||
/// From a given index, append the given `Atom` at the back of the linked list.
|
||||
/// Simply inserts it into the map of atoms when it doesn't exist yet.
|
||||
pub fn appendAtomAtIndex(wasm: *Wasm, index: u32, atom_index: Atom.Index) !void {
|
||||
pub fn appendAtomAtIndex(wasm: *Wasm, index: Segment.Index, atom_index: Atom.Index) !void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
if (wasm.atoms.getPtr(index)) |last_index_ptr| {
|
||||
@@ -1752,9 +1754,9 @@ fn allocateAtoms(wasm: *Wasm) !void {
|
||||
|
||||
var it = wasm.atoms.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const segment = &wasm.segments.items[entry.key_ptr.*];
|
||||
const segment = wasm.segmentPtr(entry.key_ptr.*);
|
||||
var atom_index = entry.value_ptr.*;
|
||||
if (entry.key_ptr.* == wasm.code_section_index) {
|
||||
if (entry.key_ptr.toOptional() == wasm.code_section_index) {
|
||||
// Code section is allocated upon writing as they are required to be ordered
|
||||
// to synchronise with the function section.
|
||||
continue;
|
||||
@@ -1825,7 +1827,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
|
||||
};
|
||||
const segment_name = segment_info[symbol.index].outputName(merge_segment);
|
||||
const segment_index = wasm.data_segments.get(segment_name).?;
|
||||
const segment = wasm.segments.items[segment_index];
|
||||
const segment = wasm.segmentPtr(segment_index);
|
||||
|
||||
// TLS symbols have their virtual address set relative to their own TLS segment,
|
||||
// rather than the entire Data section.
|
||||
@@ -1839,7 +1841,7 @@ fn allocateVirtualAddresses(wasm: *Wasm) void {
|
||||
|
||||
fn sortDataSegments(wasm: *Wasm) !void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .empty;
|
||||
var new_mapping: std.StringArrayHashMapUnmanaged(Segment.Index) = .empty;
|
||||
try new_mapping.ensureUnusedCapacity(gpa, wasm.data_segments.count());
|
||||
errdefer new_mapping.deinit(gpa);
|
||||
|
||||
@@ -1894,9 +1896,9 @@ fn setupInitFunctions(wasm: *Wasm) !void {
|
||||
};
|
||||
if (ty.params.len != 0) {
|
||||
var err = try diags.addErrorWithNotes(0);
|
||||
try err.addMsg("constructor functions cannot take arguments: '{s}'", .{object.string_table.get(symbol.name)});
|
||||
try err.addMsg("constructor functions cannot take arguments: '{s}'", .{wasm.stringSlice(symbol.name)});
|
||||
}
|
||||
log.debug("appended init func '{s}'\n", .{object.string_table.get(symbol.name)});
|
||||
log.debug("appended init func '{s}'\n", .{wasm.stringSlice(symbol.name)});
|
||||
wasm.init_funcs.appendAssumeCapacity(.{
|
||||
.index = @enumFromInt(init_func.symbol_index),
|
||||
.file = @enumFromInt(object_index),
|
||||
@@ -1913,7 +1915,7 @@ fn setupInitFunctions(wasm: *Wasm) !void {
|
||||
mem.sort(InitFuncLoc, wasm.init_funcs.items, {}, InitFuncLoc.lessThan);
|
||||
|
||||
if (wasm.init_funcs.items.len > 0) {
|
||||
const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
|
||||
const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?;
|
||||
try wasm.mark(loc);
|
||||
}
|
||||
}
|
||||
@@ -1927,10 +1929,10 @@ fn setupInitFunctions(wasm: *Wasm) !void {
|
||||
fn initializeCallCtorsFunction(wasm: *Wasm) !void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
// No code to emit, so also no ctors to call
|
||||
if (wasm.code_section_index == null) {
|
||||
if (wasm.code_section_index == .none) {
|
||||
// Make sure to remove it from the resolved symbols so we do not emit
|
||||
// it within any section. TODO: Remove this once we implement garbage collection.
|
||||
const loc = wasm.findGlobalSymbol("__wasm_call_ctors").?;
|
||||
const loc = wasm.globals.get(wasm.preloaded_strings.__wasm_call_ctors).?;
|
||||
assert(wasm.resolved_symbols.swapRemove(loc));
|
||||
return;
|
||||
}
|
||||
@@ -1965,7 +1967,7 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
|
||||
}
|
||||
|
||||
try wasm.createSyntheticFunction(
|
||||
"__wasm_call_ctors",
|
||||
wasm.preloaded_strings.__wasm_call_ctors,
|
||||
std.wasm.Type{ .params = &.{}, .returns = &.{} },
|
||||
&function_body,
|
||||
);
|
||||
@@ -1973,12 +1975,12 @@ fn initializeCallCtorsFunction(wasm: *Wasm) !void {
|
||||
|
||||
fn createSyntheticFunction(
|
||||
wasm: *Wasm,
|
||||
symbol_name: []const u8,
|
||||
symbol_name: String,
|
||||
func_ty: std.wasm.Type,
|
||||
function_body: *std.ArrayList(u8),
|
||||
) !void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const loc = wasm.findGlobalSymbol(symbol_name).?; // forgot to create symbol?
|
||||
const loc = wasm.globals.get(symbol_name).?;
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
if (symbol.isDead()) {
|
||||
return;
|
||||
@@ -1998,7 +2000,7 @@ fn createSyntheticFunction(
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
atom.size = @intCast(function_body.items.len);
|
||||
atom.code = function_body.moveToUnmanaged();
|
||||
try wasm.appendAtomAtIndex(wasm.code_section_index.?, atom_index);
|
||||
try wasm.appendAtomAtIndex(wasm.code_section_index.unwrap().?, atom_index);
|
||||
}
|
||||
|
||||
/// Unlike `createSyntheticFunction` this function is to be called by
|
||||
@@ -2016,7 +2018,7 @@ pub fn createFunction(
|
||||
|
||||
/// If required, sets the function index in the `start` section.
|
||||
fn setupStartSection(wasm: *Wasm) !void {
|
||||
if (wasm.findGlobalSymbol("__wasm_init_memory")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__wasm_init_memory)) |loc| {
|
||||
wasm.entry = wasm.symbolLocSymbol(loc).index;
|
||||
}
|
||||
}
|
||||
@@ -2029,7 +2031,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
|
||||
if (!shared_memory) return;
|
||||
|
||||
// ensure function is marked as we must emit it
|
||||
wasm.symbolLocSymbol(wasm.findGlobalSymbol("__wasm_init_tls").?).mark();
|
||||
wasm.symbolLocSymbol(wasm.globals.get(wasm.preloaded_strings.__wasm_init_tls).?).mark();
|
||||
|
||||
var function_body = std.ArrayList(u8).init(gpa);
|
||||
defer function_body.deinit();
|
||||
@@ -2041,14 +2043,14 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
|
||||
// If there's a TLS segment, initialize it during runtime using the bulk-memory feature
|
||||
if (wasm.data_segments.getIndex(".tdata")) |data_index| {
|
||||
const segment_index = wasm.data_segments.entries.items(.value)[data_index];
|
||||
const segment = wasm.segments.items[segment_index];
|
||||
const segment = wasm.segmentPtr(segment_index);
|
||||
|
||||
const param_local: u32 = 0;
|
||||
|
||||
try writer.writeByte(std.wasm.opcode(.local_get));
|
||||
try leb.writeUleb128(writer, param_local);
|
||||
|
||||
const tls_base_loc = wasm.findGlobalSymbol("__tls_base").?;
|
||||
const tls_base_loc = wasm.globals.get(wasm.preloaded_strings.__tls_base).?;
|
||||
try writer.writeByte(std.wasm.opcode(.global_set));
|
||||
try leb.writeUleb128(writer, wasm.symbolLocSymbol(tls_base_loc).index);
|
||||
|
||||
@@ -2076,7 +2078,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
|
||||
// If we have to perform any TLS relocations, call the corresponding function
|
||||
// which performs all runtime TLS relocations. This is a synthetic function,
|
||||
// generated by the linker.
|
||||
if (wasm.findGlobalSymbol("__wasm_apply_global_tls_relocs")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__wasm_apply_global_tls_relocs)) |loc| {
|
||||
try writer.writeByte(std.wasm.opcode(.call));
|
||||
try leb.writeUleb128(writer, wasm.symbolLocSymbol(loc).index);
|
||||
wasm.symbolLocSymbol(loc).mark();
|
||||
@@ -2085,7 +2087,7 @@ fn initializeTLSFunction(wasm: *Wasm) !void {
|
||||
try writer.writeByte(std.wasm.opcode(.end));
|
||||
|
||||
try wasm.createSyntheticFunction(
|
||||
"__wasm_init_tls",
|
||||
wasm.preloaded_strings.__wasm_init_tls,
|
||||
std.wasm.Type{ .params = &.{.i32}, .returns = &.{} },
|
||||
&function_body,
|
||||
);
|
||||
@@ -2101,21 +2103,18 @@ fn setupImports(wasm: *Wasm) !void {
|
||||
};
|
||||
|
||||
const symbol = wasm.symbolLocSymbol(symbol_loc);
|
||||
if (symbol.isDead() or
|
||||
!symbol.requiresImport() or
|
||||
std.mem.eql(u8, wasm.symbolLocName(symbol_loc), "__indirect_function_table"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (symbol.isDead()) continue;
|
||||
if (!symbol.requiresImport()) continue;
|
||||
if (symbol.name == wasm.preloaded_strings.__indirect_function_table) continue;
|
||||
|
||||
log.debug("Symbol '{s}' will be imported from the host", .{wasm.symbolLocName(symbol_loc)});
|
||||
log.debug("Symbol '{s}' will be imported from the host", .{wasm.stringSlice(symbol.name)});
|
||||
const import = objectImport(wasm, object_id, symbol_loc.index);
|
||||
|
||||
// We copy the import to a new import to ensure the names contain references
|
||||
// to the internal string table, rather than of the object file.
|
||||
const new_imp: Import = .{
|
||||
.module_name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.module_name)),
|
||||
.name = try wasm.string_table.put(gpa, objectString(wasm, object_id, import.name)),
|
||||
.module_name = import.module_name,
|
||||
.name = import.name,
|
||||
.kind = import.kind,
|
||||
};
|
||||
// TODO: De-duplicate imports when they contain the same names and type
|
||||
@@ -2283,7 +2282,8 @@ fn checkExportNames(wasm: *Wasm) !void {
|
||||
var failed_exports = false;
|
||||
|
||||
for (force_exp_names) |exp_name| {
|
||||
const loc = wasm.findGlobalSymbol(exp_name) orelse {
|
||||
const exp_name_interned = try wasm.internString(exp_name);
|
||||
const loc = wasm.globals.get(exp_name_interned) orelse {
|
||||
var err = try diags.addErrorWithNotes(0);
|
||||
try err.addMsg("could not export '{s}', symbol not found", .{exp_name});
|
||||
failed_exports = true;
|
||||
@@ -2310,11 +2310,6 @@ fn setupExports(wasm: *Wasm) !void {
|
||||
const symbol = wasm.symbolLocSymbol(sym_loc);
|
||||
if (!symbol.isExported(comp.config.rdynamic)) continue;
|
||||
|
||||
const sym_name = wasm.symbolLocName(sym_loc);
|
||||
const export_name = if (sym_loc.file == .none)
|
||||
symbol.name
|
||||
else
|
||||
try wasm.string_table.put(gpa, sym_name);
|
||||
const exp: Export = if (symbol.tag == .data) exp: {
|
||||
const global_index = @as(u32, @intCast(wasm.imported_globals_count + wasm.wasm_globals.items.len));
|
||||
try wasm.wasm_globals.append(gpa, .{
|
||||
@@ -2322,18 +2317,18 @@ fn setupExports(wasm: *Wasm) !void {
|
||||
.init = .{ .i32_const = @as(i32, @intCast(symbol.virtual_address)) },
|
||||
});
|
||||
break :exp .{
|
||||
.name = export_name,
|
||||
.name = symbol.name,
|
||||
.kind = .global,
|
||||
.index = global_index,
|
||||
};
|
||||
} else .{
|
||||
.name = export_name,
|
||||
.name = symbol.name,
|
||||
.kind = symbol.tag.externalType(),
|
||||
.index = symbol.index,
|
||||
};
|
||||
log.debug("Exporting symbol '{s}' as '{s}' at index: ({d})", .{
|
||||
sym_name,
|
||||
wasm.string_table.get(exp.name),
|
||||
wasm.stringSlice(symbol.name),
|
||||
wasm.stringSlice(exp.name),
|
||||
exp.index,
|
||||
});
|
||||
try wasm.exports.append(gpa, exp);
|
||||
@@ -2346,20 +2341,18 @@ fn setupStart(wasm: *Wasm) !void {
|
||||
const comp = wasm.base.comp;
|
||||
const diags = &wasm.base.comp.link_diags;
|
||||
// do not export entry point if user set none or no default was set.
|
||||
const entry_name = wasm.entry_name orelse return;
|
||||
const entry_name = wasm.entry_name.unwrap() orelse return;
|
||||
|
||||
const symbol_loc = wasm.findGlobalSymbol(entry_name) orelse {
|
||||
var err = try diags.addErrorWithNotes(0);
|
||||
try err.addMsg("Entry symbol '{s}' missing, use '-fno-entry' to suppress", .{entry_name});
|
||||
return error.FlushFailure;
|
||||
const symbol_loc = wasm.globals.get(entry_name) orelse {
|
||||
var err = try diags.addErrorWithNotes(1);
|
||||
try err.addMsg("entry symbol '{s}' missing", .{wasm.stringSlice(entry_name)});
|
||||
try err.addNote("'-fno-entry' suppresses this error", .{});
|
||||
return error.LinkFailure;
|
||||
};
|
||||
|
||||
const symbol = wasm.symbolLocSymbol(symbol_loc);
|
||||
if (symbol.tag != .function) {
|
||||
var err = try diags.addErrorWithNotes(0);
|
||||
try err.addMsg("Entry symbol '{s}' is not a function", .{entry_name});
|
||||
return error.FlushFailure;
|
||||
}
|
||||
if (symbol.tag != .function)
|
||||
return diags.fail("entry symbol '{s}' is not a function", .{wasm.stringSlice(entry_name)});
|
||||
|
||||
// Ensure the symbol is exported so host environment can access it
|
||||
if (comp.config.output_mode != .Obj) {
|
||||
@@ -2387,7 +2380,7 @@ fn setupMemory(wasm: *Wasm) !void {
|
||||
|
||||
const is_obj = comp.config.output_mode == .Obj;
|
||||
|
||||
const stack_ptr = if (wasm.findGlobalSymbol("__stack_pointer")) |loc| index: {
|
||||
const stack_ptr = if (wasm.globals.get(wasm.preloaded_strings.__stack_pointer)) |loc| index: {
|
||||
const sym = wasm.symbolLocSymbol(loc);
|
||||
break :index sym.index - wasm.imported_globals_count;
|
||||
} else null;
|
||||
@@ -2404,20 +2397,20 @@ fn setupMemory(wasm: *Wasm) !void {
|
||||
var offset: u32 = @as(u32, @intCast(memory_ptr));
|
||||
var data_seg_it = wasm.data_segments.iterator();
|
||||
while (data_seg_it.next()) |entry| {
|
||||
const segment = &wasm.segments.items[entry.value_ptr.*];
|
||||
const segment = wasm.segmentPtr(entry.value_ptr.*);
|
||||
memory_ptr = segment.alignment.forward(memory_ptr);
|
||||
|
||||
// set TLS-related symbols
|
||||
if (mem.eql(u8, entry.key_ptr.*, ".tdata")) {
|
||||
if (wasm.findGlobalSymbol("__tls_size")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__tls_size)) |loc| {
|
||||
const sym = wasm.symbolLocSymbol(loc);
|
||||
wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.size);
|
||||
}
|
||||
if (wasm.findGlobalSymbol("__tls_align")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__tls_align)) |loc| {
|
||||
const sym = wasm.symbolLocSymbol(loc);
|
||||
wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = @intCast(segment.alignment.toByteUnits().?);
|
||||
}
|
||||
if (wasm.findGlobalSymbol("__tls_base")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__tls_base)) |loc| {
|
||||
const sym = wasm.symbolLocSymbol(loc);
|
||||
wasm.wasm_globals.items[sym.index - wasm.imported_globals_count].init.i32_const = if (shared_memory)
|
||||
@as(i32, 0)
|
||||
@@ -2435,7 +2428,7 @@ fn setupMemory(wasm: *Wasm) !void {
|
||||
if (shared_memory and wasm.hasPassiveInitializationSegments()) {
|
||||
// align to pointer size
|
||||
memory_ptr = mem.alignForward(u64, memory_ptr, 4);
|
||||
const loc = try wasm.createSyntheticSymbol("__wasm_init_memory_flag", .data);
|
||||
const loc = try wasm.createSyntheticSymbol(wasm.preloaded_strings.__wasm_init_memory_flag, .data);
|
||||
const sym = wasm.symbolLocSymbol(loc);
|
||||
sym.mark();
|
||||
sym.virtual_address = @as(u32, @intCast(memory_ptr));
|
||||
@@ -2452,7 +2445,7 @@ fn setupMemory(wasm: *Wasm) !void {
|
||||
|
||||
// One of the linked object files has a reference to the __heap_base symbol.
|
||||
// We must set its virtual address so it can be used in relocations.
|
||||
if (wasm.findGlobalSymbol("__heap_base")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__heap_base)) |loc| {
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
symbol.virtual_address = @intCast(heap_alignment.forward(memory_ptr));
|
||||
}
|
||||
@@ -2482,7 +2475,7 @@ fn setupMemory(wasm: *Wasm) !void {
|
||||
wasm.memories.limits.min = @as(u32, @intCast(memory_ptr / page_size));
|
||||
log.debug("Total memory pages: {d}", .{wasm.memories.limits.min});
|
||||
|
||||
if (wasm.findGlobalSymbol("__heap_end")) |loc| {
|
||||
if (wasm.globals.get(wasm.preloaded_strings.__heap_end)) |loc| {
|
||||
const symbol = wasm.symbolLocSymbol(loc);
|
||||
symbol.virtual_address = @as(u32, @intCast(memory_ptr));
|
||||
}
|
||||
@@ -2512,12 +2505,12 @@ fn setupMemory(wasm: *Wasm) !void {
|
||||
/// From a given object's index and the index of the segment, returns the corresponding
|
||||
/// index of the segment within the final data section. When the segment does not yet
|
||||
/// exist, a new one will be initialized and appended. The new index will be returned in that case.
|
||||
pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !u32 {
|
||||
pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.Index) !Segment.Index {
|
||||
const comp = wasm.base.comp;
|
||||
const gpa = comp.gpa;
|
||||
const diags = &wasm.base.comp.link_diags;
|
||||
const symbol = objectSymbols(wasm, object_id)[@intFromEnum(symbol_index)];
|
||||
const index: u32 = @intCast(wasm.segments.items.len);
|
||||
const index: Segment.Index = @enumFromInt(wasm.segments.items.len);
|
||||
const shared_memory = comp.config.shared_memory;
|
||||
|
||||
switch (symbol.tag) {
|
||||
@@ -2545,66 +2538,27 @@ pub fn getMatchingSegment(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol
|
||||
return index;
|
||||
} else return result.value_ptr.*;
|
||||
},
|
||||
.function => return wasm.code_section_index orelse blk: {
|
||||
wasm.code_section_index = index;
|
||||
.function => return wasm.code_section_index.unwrap() orelse blk: {
|
||||
wasm.code_section_index = index.toOptional();
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
},
|
||||
.section => {
|
||||
const section_name = objectSymbolName(wasm, object_id, symbol_index);
|
||||
if (mem.eql(u8, section_name, ".debug_info")) {
|
||||
return wasm.debug_info_index orelse blk: {
|
||||
wasm.debug_info_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
} else if (mem.eql(u8, section_name, ".debug_line")) {
|
||||
return wasm.debug_line_index orelse blk: {
|
||||
wasm.debug_line_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
} else if (mem.eql(u8, section_name, ".debug_loc")) {
|
||||
return wasm.debug_loc_index orelse blk: {
|
||||
wasm.debug_loc_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
} else if (mem.eql(u8, section_name, ".debug_ranges")) {
|
||||
return wasm.debug_ranges_index orelse blk: {
|
||||
wasm.debug_ranges_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
} else if (mem.eql(u8, section_name, ".debug_pubnames")) {
|
||||
return wasm.debug_pubnames_index orelse blk: {
|
||||
wasm.debug_pubnames_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
} else if (mem.eql(u8, section_name, ".debug_pubtypes")) {
|
||||
return wasm.debug_pubtypes_index orelse blk: {
|
||||
wasm.debug_pubtypes_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
} else if (mem.eql(u8, section_name, ".debug_abbrev")) {
|
||||
return wasm.debug_abbrev_index orelse blk: {
|
||||
wasm.debug_abbrev_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
} else if (mem.eql(u8, section_name, ".debug_str")) {
|
||||
return wasm.debug_str_index orelse blk: {
|
||||
wasm.debug_str_index = index;
|
||||
try wasm.appendDummySegment();
|
||||
break :blk index;
|
||||
};
|
||||
const section_name = wasm.objectSymbol(object_id, symbol_index).name;
|
||||
|
||||
inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
|
||||
if (@field(wasm.custom_sections, field.name).name == section_name) {
|
||||
const field_ptr = &@field(wasm.custom_sections, field.name).index;
|
||||
return field_ptr.unwrap() orelse {
|
||||
field_ptr.* = index.toOptional();
|
||||
try wasm.appendDummySegment();
|
||||
return index;
|
||||
};
|
||||
}
|
||||
} else {
|
||||
var err = try diags.addErrorWithNotes(1);
|
||||
try err.addMsg("found unknown section '{s}'", .{section_name});
|
||||
try err.addNote("defined in '{'}'", .{objectPath(wasm, object_id)});
|
||||
return error.UnexpectedValue;
|
||||
return diags.failParse(objectPath(wasm, object_id), "unknown section: {s}", .{
|
||||
wasm.stringSlice(section_name),
|
||||
});
|
||||
}
|
||||
},
|
||||
else => unreachable,
|
||||
@@ -2803,10 +2757,9 @@ fn writeToFile(
|
||||
}
|
||||
|
||||
if (import_memory) {
|
||||
const mem_name = if (is_obj) "__linear_memory" else "memory";
|
||||
const mem_imp: Import = .{
|
||||
.module_name = try wasm.string_table.put(gpa, wasm.host_name),
|
||||
.name = try wasm.string_table.put(gpa, mem_name),
|
||||
.module_name = wasm.host_name,
|
||||
.name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory,
|
||||
.kind = .{ .memory = wasm.memories.limits },
|
||||
};
|
||||
try wasm.emitImport(binary_writer, mem_imp);
|
||||
@@ -2898,7 +2851,7 @@ fn writeToFile(
|
||||
const header_offset = try reserveVecSectionHeader(&binary_bytes);
|
||||
|
||||
for (wasm.exports.items) |exp| {
|
||||
const name = wasm.string_table.get(exp.name);
|
||||
const name = wasm.stringSlice(exp.name);
|
||||
try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len)));
|
||||
try binary_writer.writeAll(name);
|
||||
try leb.writeUleb128(binary_writer, @intFromEnum(exp.kind));
|
||||
@@ -2937,7 +2890,7 @@ fn writeToFile(
|
||||
if (wasm.function_table.count() > 0) {
|
||||
const header_offset = try reserveVecSectionHeader(&binary_bytes);
|
||||
|
||||
const table_loc = wasm.findGlobalSymbol("__indirect_function_table").?;
|
||||
const table_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
|
||||
const table_sym = wasm.symbolLocSymbol(table_loc);
|
||||
|
||||
const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually
|
||||
@@ -2982,7 +2935,7 @@ fn writeToFile(
|
||||
}
|
||||
|
||||
// Code section
|
||||
if (wasm.code_section_index != null) {
|
||||
if (wasm.code_section_index != .none) {
|
||||
const header_offset = try reserveVecSectionHeader(&binary_bytes);
|
||||
const start_offset = binary_bytes.items.len - 5; // minus 5 so start offset is 5 to include entry count
|
||||
|
||||
@@ -3022,7 +2975,7 @@ fn writeToFile(
|
||||
// want to guarantee the data is zero initialized
|
||||
if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue;
|
||||
const segment_index = entry.value_ptr.*;
|
||||
const segment = wasm.segments.items[segment_index];
|
||||
const segment = wasm.segmentPtr(segment_index);
|
||||
if (segment.size == 0) continue; // do not emit empty segments
|
||||
segment_count += 1;
|
||||
var atom_index = wasm.atoms.get(segment_index).?;
|
||||
@@ -3133,24 +3086,8 @@ fn writeToFile(
|
||||
var debug_bytes = std.ArrayList(u8).init(gpa);
|
||||
defer debug_bytes.deinit();
|
||||
|
||||
const DebugSection = struct {
|
||||
name: []const u8,
|
||||
index: ?u32,
|
||||
};
|
||||
|
||||
const debug_sections: []const DebugSection = &.{
|
||||
.{ .name = ".debug_info", .index = wasm.debug_info_index },
|
||||
.{ .name = ".debug_pubtypes", .index = wasm.debug_pubtypes_index },
|
||||
.{ .name = ".debug_abbrev", .index = wasm.debug_abbrev_index },
|
||||
.{ .name = ".debug_line", .index = wasm.debug_line_index },
|
||||
.{ .name = ".debug_str", .index = wasm.debug_str_index },
|
||||
.{ .name = ".debug_pubnames", .index = wasm.debug_pubnames_index },
|
||||
.{ .name = ".debug_loc", .index = wasm.debug_loc_index },
|
||||
.{ .name = ".debug_ranges", .index = wasm.debug_ranges_index },
|
||||
};
|
||||
|
||||
for (debug_sections) |item| {
|
||||
if (item.index) |index| {
|
||||
inline for (@typeInfo(CustomSections).@"struct".fields) |field| {
|
||||
if (@field(wasm.custom_sections, field.name).index.unwrap()) |index| {
|
||||
var atom = wasm.getAtomPtr(wasm.atoms.get(index).?);
|
||||
while (true) {
|
||||
atom.resolveRelocs(wasm);
|
||||
@@ -3158,7 +3095,7 @@ fn writeToFile(
|
||||
if (atom.prev == .null) break;
|
||||
atom = wasm.getAtomPtr(atom.prev);
|
||||
}
|
||||
try emitDebugSection(&binary_bytes, debug_bytes.items, item.name);
|
||||
try emitDebugSection(&binary_bytes, debug_bytes.items, field.name);
|
||||
debug_bytes.clearRetainingCapacity();
|
||||
}
|
||||
}
|
||||
@@ -3430,11 +3367,11 @@ fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void {
|
||||
}
|
||||
|
||||
fn emitImport(wasm: *Wasm, writer: anytype, import: Import) !void {
|
||||
const module_name = wasm.string_table.get(import.module_name);
|
||||
const module_name = wasm.stringSlice(import.module_name);
|
||||
try leb.writeUleb128(writer, @as(u32, @intCast(module_name.len)));
|
||||
try writer.writeAll(module_name);
|
||||
|
||||
const name = wasm.string_table.get(import.name);
|
||||
const name = wasm.stringSlice(import.name);
|
||||
try leb.writeUleb128(writer, @as(u32, @intCast(name.len)));
|
||||
try writer.writeAll(name);
|
||||
|
||||
@@ -3515,7 +3452,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
}
|
||||
try man.addOptionalFile(module_obj_path);
|
||||
try man.addOptionalFilePath(compiler_rt_path);
|
||||
man.hash.addOptionalBytes(wasm.entry_name);
|
||||
man.hash.addOptionalBytes(wasm.optionalStringSlice(wasm.entry_name));
|
||||
man.hash.add(wasm.base.stack_size);
|
||||
man.hash.add(wasm.base.build_id);
|
||||
man.hash.add(import_memory);
|
||||
@@ -3664,7 +3601,7 @@ fn linkWithLLD(wasm: *Wasm, arena: Allocator, tid: Zcu.PerThread.Id, prog_node:
|
||||
try argv.append("--export-dynamic");
|
||||
}
|
||||
|
||||
if (wasm.entry_name) |entry_name| {
|
||||
if (wasm.optionalStringSlice(wasm.entry_name)) |entry_name| {
|
||||
try argv.appendSlice(&.{ "--entry", entry_name });
|
||||
} else {
|
||||
try argv.append("--no-entry");
|
||||
@@ -4009,7 +3946,7 @@ fn emitCodeRelocations(
|
||||
section_index: u32,
|
||||
symbol_table: std.AutoArrayHashMap(SymbolLoc, u32),
|
||||
) !void {
|
||||
const code_index = wasm.code_section_index orelse return;
|
||||
const code_index = wasm.code_section_index.unwrap() orelse return;
|
||||
const writer = binary_bytes.writer();
|
||||
const header_offset = try reserveCustomSectionHeader(binary_bytes);
|
||||
|
||||
@@ -4106,7 +4043,7 @@ fn hasPassiveInitializationSegments(wasm: *const Wasm) bool {
|
||||
|
||||
var it = wasm.data_segments.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const segment: Segment = wasm.segments.items[entry.value_ptr.*];
|
||||
const segment = wasm.segmentPtr(entry.value_ptr.*);
|
||||
if (segment.needsPassiveInitialization(import_memory, entry.key_ptr.*)) {
|
||||
return true;
|
||||
}
|
||||
@@ -4213,10 +4150,13 @@ fn mark(wasm: *Wasm, loc: SymbolLoc) !void {
|
||||
}
|
||||
}
|
||||
|
||||
fn defaultEntrySymbolName(wasi_exec_model: std.builtin.WasiExecModel) []const u8 {
|
||||
fn defaultEntrySymbolName(
|
||||
preloaded_strings: *const PreloadedStrings,
|
||||
wasi_exec_model: std.builtin.WasiExecModel,
|
||||
) String {
|
||||
return switch (wasi_exec_model) {
|
||||
.reactor => "_initialize",
|
||||
.command => "_start",
|
||||
.reactor => preloaded_strings._initialize,
|
||||
.command => preloaded_strings._start,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -4352,7 +4292,7 @@ pub const Atom = struct {
|
||||
symbol.tag != .section and
|
||||
symbol.isDead())
|
||||
{
|
||||
const val = atom.thombstone(wasm) orelse relocation.addend;
|
||||
const val = atom.tombstone(wasm) orelse relocation.addend;
|
||||
return @bitCast(val);
|
||||
}
|
||||
switch (relocation.relocation_type) {
|
||||
@@ -4394,7 +4334,7 @@ pub const Atom = struct {
|
||||
},
|
||||
.R_WASM_FUNCTION_OFFSET_I32 => {
|
||||
if (symbol.isUndefined()) {
|
||||
const val = atom.thombstone(wasm) orelse relocation.addend;
|
||||
const val = atom.tombstone(wasm) orelse relocation.addend;
|
||||
return @bitCast(val);
|
||||
}
|
||||
const target_atom_index = wasm.symbol_atom.get(target_loc).?;
|
||||
@@ -4411,16 +4351,19 @@ pub const Atom = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// For a given `Atom` returns whether it has a thombstone value or not.
|
||||
// For a given `Atom` returns whether it has a tombstone value or not.
|
||||
/// This defines whether we want a specific value when a section is dead.
|
||||
fn thombstone(atom: Atom, wasm: *const Wasm) ?i64 {
|
||||
const atom_name = wasm.symbolLocName(atom.symbolLoc());
|
||||
if (std.mem.eql(u8, atom_name, ".debug_ranges") or std.mem.eql(u8, atom_name, ".debug_loc")) {
|
||||
fn tombstone(atom: Atom, wasm: *const Wasm) ?i64 {
|
||||
const atom_name = wasm.symbolLocSymbol(atom.symbolLoc()).name;
|
||||
if (atom_name == wasm.custom_sections.@".debug_ranges".name or
|
||||
atom_name == wasm.custom_sections.@".debug_loc".name)
|
||||
{
|
||||
return -2;
|
||||
} else if (std.mem.startsWith(u8, atom_name, ".debug_")) {
|
||||
} else if (std.mem.startsWith(u8, wasm.stringSlice(atom_name), ".debug_")) {
|
||||
return -1;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -4509,8 +4452,8 @@ pub const Relocation = struct {
|
||||
/// of the import using offsets into a string table, rather than the slices itself.
|
||||
/// This saves us (potentially) 24 bytes per import on 64bit machines.
|
||||
pub const Import = struct {
|
||||
module_name: u32,
|
||||
name: u32,
|
||||
module_name: String,
|
||||
name: String,
|
||||
kind: std.wasm.Import.Kind,
|
||||
};
|
||||
|
||||
@@ -4519,7 +4462,7 @@ pub const Import = struct {
|
||||
/// of the export using offsets into a string table, rather than the slice itself.
|
||||
/// This saves us (potentially) 12 bytes per export on 64bit machines.
|
||||
pub const Export = struct {
|
||||
name: u32,
|
||||
name: String,
|
||||
index: u32,
|
||||
kind: std.wasm.ExternalKind,
|
||||
};
|
||||
@@ -4719,7 +4662,7 @@ fn parseSymbolIntoAtom(wasm: *Wasm, object_id: ObjectId, symbol_index: Symbol.In
|
||||
atom.code = std.ArrayListUnmanaged(u8).fromOwnedSlice(relocatable_data.data[0..relocatable_data.size]);
|
||||
atom.original_offset = relocatable_data.offset;
|
||||
|
||||
const segment: *Wasm.Segment = &wasm.segments.items[final_index];
|
||||
const segment = wasm.segmentPtr(final_index);
|
||||
if (relocatable_data.type == .data) { //code section and custom sections are 1-byte aligned
|
||||
segment.alignment = segment.alignment.max(atom.alignment);
|
||||
}
|
||||
@@ -4782,3 +4725,48 @@ fn searchRelocEnd(relocs: []const Wasm.Relocation, address: u32) usize {
|
||||
}
|
||||
return relocs.len;
|
||||
}
|
||||
|
||||
pub fn internString(wasm: *Wasm, bytes: []const u8) error{OutOfMemory}!String {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const gop = try wasm.string_table.getOrPutContextAdapted(
|
||||
gpa,
|
||||
@as([]const u8, bytes),
|
||||
@as(String.TableIndexAdapter, .{ .bytes = wasm.string_bytes.items }),
|
||||
@as(String.TableContext, .{ .bytes = wasm.string_bytes.items }),
|
||||
);
|
||||
if (gop.found_existing) return gop.key_ptr.*;
|
||||
|
||||
try wasm.string_bytes.ensureUnusedCapacity(gpa, bytes.len + 1);
|
||||
const new_off: String = @enumFromInt(wasm.string_bytes.items.len);
|
||||
|
||||
wasm.string_bytes.appendSliceAssumeCapacity(bytes);
|
||||
wasm.string_bytes.appendAssumeCapacity(0);
|
||||
|
||||
gop.key_ptr.* = new_off;
|
||||
|
||||
return new_off;
|
||||
}
|
||||
|
||||
pub fn getExistingString(wasm: *const Wasm, bytes: []const u8) ?String {
|
||||
return wasm.string_table.getKeyAdapted(bytes, @as(String.TableIndexAdapter, .{
|
||||
.bytes = wasm.string_bytes.items,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn stringSlice(wasm: *const Wasm, index: String) [:0]const u8 {
|
||||
const slice = wasm.string_bytes.items[@intFromEnum(index)..];
|
||||
return slice[0..mem.indexOfScalar(u8, slice, 0).? :0];
|
||||
}
|
||||
|
||||
pub fn optionalStringSlice(wasm: *const Wasm, index: OptionalString) ?[:0]const u8 {
|
||||
return stringSlice(wasm, index.unwrap() orelse return null);
|
||||
}
|
||||
|
||||
pub fn castToString(wasm: *const Wasm, index: u32) String {
|
||||
assert(index == 0 or wasm.string_bytes.items[index - 1] == 0);
|
||||
return @enumFromInt(index);
|
||||
}
|
||||
|
||||
fn segmentPtr(wasm: *const Wasm, index: Segment.Index) *Segment {
|
||||
return &wasm.segments.items[@intFromEnum(index)];
|
||||
}
|
||||
|
||||
+30
-44
@@ -1,5 +1,3 @@
|
||||
header: ar_hdr,
|
||||
|
||||
/// A list of long file names, delimited by a LF character (0x0a).
|
||||
/// This is stored as a single slice of bytes, as the header-names
|
||||
/// point to the character index of a file name, rather than the index
|
||||
@@ -14,65 +12,54 @@ toc: Toc,
|
||||
const Toc = std.StringArrayHashMapUnmanaged(std.ArrayListUnmanaged(u32));
|
||||
|
||||
// Archive files start with the ARMAG identifying string. Then follows a
|
||||
// `struct ar_hdr', and as many bytes of member file data as its `ar_size'
|
||||
// `struct Header', and as many bytes of member file data as its `size'
|
||||
// member indicates, for each member file.
|
||||
/// String that begins an archive file.
|
||||
const ARMAG: *const [SARMAG:0]u8 = "!<arch>\n";
|
||||
/// Size of that string.
|
||||
const SARMAG: u4 = 8;
|
||||
|
||||
/// String in ar_fmag at the end of each header.
|
||||
/// String in fmag at the end of each header.
|
||||
const ARFMAG: *const [2:0]u8 = "`\n";
|
||||
|
||||
const ar_hdr = extern struct {
|
||||
const Header = extern struct {
|
||||
/// Member file name, sometimes / terminated.
|
||||
ar_name: [16]u8,
|
||||
|
||||
name: [16]u8,
|
||||
/// File date, decimal seconds since Epoch.
|
||||
ar_date: [12]u8,
|
||||
|
||||
date: [12]u8,
|
||||
/// User ID, in ASCII format.
|
||||
ar_uid: [6]u8,
|
||||
|
||||
uid: [6]u8,
|
||||
/// Group ID, in ASCII format.
|
||||
ar_gid: [6]u8,
|
||||
|
||||
gid: [6]u8,
|
||||
/// File mode, in ASCII octal.
|
||||
ar_mode: [8]u8,
|
||||
|
||||
mode: [8]u8,
|
||||
/// File size, in ASCII decimal.
|
||||
ar_size: [10]u8,
|
||||
|
||||
size: [10]u8,
|
||||
/// Always contains ARFMAG.
|
||||
ar_fmag: [2]u8,
|
||||
fmag: [2]u8,
|
||||
|
||||
const NameOrIndex = union(enum) {
|
||||
name: []const u8,
|
||||
index: u32,
|
||||
};
|
||||
|
||||
fn nameOrIndex(archive: ar_hdr) !NameOrIndex {
|
||||
const value = getValue(&archive.ar_name);
|
||||
fn nameOrIndex(archive: Header) !NameOrIndex {
|
||||
const value = getValue(&archive.name);
|
||||
const slash_index = mem.indexOfScalar(u8, value, '/') orelse return error.MalformedArchive;
|
||||
const len = value.len;
|
||||
if (slash_index == len - 1) {
|
||||
// Name stored directly
|
||||
return NameOrIndex{ .name = value };
|
||||
return .{ .name = value };
|
||||
} else {
|
||||
// Name follows the header directly and its length is encoded in
|
||||
// the name field.
|
||||
const index = try std.fmt.parseInt(u32, value[slash_index + 1 ..], 10);
|
||||
return NameOrIndex{ .index = index };
|
||||
return .{ .index = index };
|
||||
}
|
||||
}
|
||||
|
||||
fn date(archive: ar_hdr) !u64 {
|
||||
const value = getValue(&archive.ar_date);
|
||||
return std.fmt.parseInt(u64, value, 10);
|
||||
}
|
||||
|
||||
fn size(archive: ar_hdr) !u32 {
|
||||
const value = getValue(&archive.ar_size);
|
||||
fn parsedSize(archive: Header) !u32 {
|
||||
const value = getValue(&archive.size);
|
||||
return std.fmt.parseInt(u32, value, 10);
|
||||
}
|
||||
|
||||
@@ -100,8 +87,8 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {
|
||||
const magic = try reader.readBytesNoEof(SARMAG);
|
||||
if (!mem.eql(u8, &magic, ARMAG)) return error.BadArchiveMagic;
|
||||
|
||||
const header = try reader.readStruct(ar_hdr);
|
||||
if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) return error.BadHeaderDelimiter;
|
||||
const header = try reader.readStruct(Header);
|
||||
if (!mem.eql(u8, &header.fmag, ARFMAG)) return error.BadHeaderDelimiter;
|
||||
|
||||
var toc = try parseTableOfContents(gpa, header, reader);
|
||||
errdefer deinitToc(gpa, &toc);
|
||||
@@ -110,13 +97,12 @@ pub fn parse(gpa: Allocator, file_contents: []const u8) !Archive {
|
||||
errdefer gpa.free(long_file_names);
|
||||
|
||||
return .{
|
||||
.header = header,
|
||||
.toc = toc,
|
||||
.long_file_names = long_file_names,
|
||||
};
|
||||
}
|
||||
|
||||
fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {
|
||||
fn parseName(archive: *const Archive, header: Header) ![]const u8 {
|
||||
const name_or_index = try header.nameOrIndex();
|
||||
switch (name_or_index) {
|
||||
.name => |name| return name,
|
||||
@@ -127,10 +113,10 @@ fn parseName(archive: *const Archive, header: ar_hdr) ![]const u8 {
|
||||
}
|
||||
}
|
||||
|
||||
fn parseTableOfContents(gpa: Allocator, header: ar_hdr, reader: anytype) !Toc {
|
||||
fn parseTableOfContents(gpa: Allocator, header: Header, reader: anytype) !Toc {
|
||||
// size field can have extra spaces padded in front as well as the end,
|
||||
// so we trim those first before parsing the ASCII value.
|
||||
const size_trimmed = mem.trim(u8, &header.ar_size, " ");
|
||||
const size_trimmed = mem.trim(u8, &header.size, " ");
|
||||
const sym_tab_size = try std.fmt.parseInt(u32, size_trimmed, 10);
|
||||
|
||||
const num_symbols = try reader.readInt(u32, .big);
|
||||
@@ -170,14 +156,14 @@ fn parseTableOfContents(gpa: Allocator, header: ar_hdr, reader: anytype) !Toc {
|
||||
}
|
||||
|
||||
fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {
|
||||
const header: ar_hdr = try reader.readStruct(ar_hdr);
|
||||
if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) {
|
||||
const header: Header = try reader.readStruct(Header);
|
||||
if (!mem.eql(u8, &header.fmag, ARFMAG)) {
|
||||
return error.InvalidHeaderDelimiter;
|
||||
}
|
||||
if (!mem.eql(u8, header.ar_name[0..2], "//")) {
|
||||
if (!mem.eql(u8, header.name[0..2], "//")) {
|
||||
return error.MissingTableName;
|
||||
}
|
||||
const table_size = try header.size();
|
||||
const table_size = try header.parsedSize();
|
||||
const long_file_names = try gpa.alloc(u8, table_size);
|
||||
errdefer gpa.free(long_file_names);
|
||||
try reader.readNoEof(long_file_names);
|
||||
@@ -187,16 +173,16 @@ fn parseNameTable(gpa: Allocator, reader: anytype) ![]const u8 {
|
||||
|
||||
/// From a given file offset, starts reading for a file header.
|
||||
/// When found, parses the object file into an `Object` and returns it.
|
||||
pub fn parseObject(archive: Archive, wasm: *const Wasm, file_contents: []const u8, path: Path) !Object {
|
||||
pub fn parseObject(archive: Archive, wasm: *Wasm, file_contents: []const u8, path: Path) !Object {
|
||||
var fbs = std.io.fixedBufferStream(file_contents);
|
||||
const header = try fbs.reader().readStruct(ar_hdr);
|
||||
const header = try fbs.reader().readStruct(Header);
|
||||
|
||||
if (!mem.eql(u8, &header.ar_fmag, ARFMAG)) return error.BadArchiveHeaderDelimiter;
|
||||
if (!mem.eql(u8, &header.fmag, ARFMAG)) return error.BadArchiveHeaderDelimiter;
|
||||
|
||||
const object_name = try archive.parseName(header);
|
||||
const object_file_size = try header.size();
|
||||
const object_file_size = try header.parsedSize();
|
||||
|
||||
return Object.create(wasm, file_contents[@sizeOf(ar_hdr)..][0..object_file_size], path, object_name);
|
||||
return Object.create(wasm, file_contents[@sizeOf(Header)..][0..object_file_size], path, object_name);
|
||||
}
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
+23
-21
@@ -63,10 +63,6 @@ comdat_info: []const Wasm.Comdat = &.{},
|
||||
/// Represents non-synthetic sections that can essentially be mem-cpy'd into place
|
||||
/// after performing relocations.
|
||||
relocatable_data: std.AutoHashMapUnmanaged(RelocatableData.Tag, []RelocatableData) = .empty,
|
||||
/// String table for all strings required by the object file, such as symbol names,
|
||||
/// import name, module name and export names. Each string will be deduplicated
|
||||
/// and returns an offset into the table.
|
||||
string_table: Wasm.StringTable = .{},
|
||||
/// Amount of functions in the `import` sections.
|
||||
imported_functions_count: u32 = 0,
|
||||
/// Amount of globals in the `import` section.
|
||||
@@ -126,7 +122,7 @@ pub const RelocatableData = struct {
|
||||
/// When a max size is given, will only parse up to the given size,
|
||||
/// else will read until the end of the file.
|
||||
pub fn create(
|
||||
wasm: *const Wasm,
|
||||
wasm: *Wasm,
|
||||
file_contents: []const u8,
|
||||
path: Path,
|
||||
archive_member_name: ?[]const u8,
|
||||
@@ -187,7 +183,6 @@ pub fn deinit(object: *Object, gpa: Allocator) void {
|
||||
}
|
||||
}
|
||||
object.relocatable_data.deinit(gpa);
|
||||
object.string_table.deinit(gpa);
|
||||
object.* = undefined;
|
||||
}
|
||||
|
||||
@@ -242,9 +237,9 @@ fn checkLegacyIndirectFunctionTable(object: *Object, wasm: *const Wasm) !?Symbol
|
||||
}
|
||||
} else unreachable;
|
||||
|
||||
if (!std.mem.eql(u8, object.string_table.get(table_import.name), "__indirect_function_table")) {
|
||||
if (table_import.name != wasm.preloaded_strings.__indirect_function_table) {
|
||||
return diags.failParse(object.path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{
|
||||
object.string_table.get(table_import.name),
|
||||
wasm.stringSlice(table_import.name),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -264,10 +259,12 @@ const Parser = struct {
|
||||
reader: std.io.FixedBufferStream([]const u8),
|
||||
/// Object file we're building
|
||||
object: *Object,
|
||||
/// Read-only reference to the WebAssembly linker
|
||||
wasm: *const Wasm,
|
||||
/// Mutable so that the string table can be modified.
|
||||
wasm: *Wasm,
|
||||
|
||||
fn parseObject(parser: *Parser, gpa: Allocator) anyerror!void {
|
||||
const wasm = parser.wasm;
|
||||
|
||||
{
|
||||
var magic_bytes: [4]u8 = undefined;
|
||||
try parser.reader.reader().readNoEof(&magic_bytes);
|
||||
@@ -316,7 +313,7 @@ const Parser = struct {
|
||||
.type = .custom,
|
||||
.data = debug_content.ptr,
|
||||
.size = debug_size,
|
||||
.index = try parser.object.string_table.put(gpa, name),
|
||||
.index = @intFromEnum(try wasm.internString(name)),
|
||||
.offset = 0, // debug sections only contain 1 entry, so no need to calculate offset
|
||||
.section_index = section_index,
|
||||
});
|
||||
@@ -375,8 +372,8 @@ const Parser = struct {
|
||||
};
|
||||
|
||||
import.* = .{
|
||||
.module_name = try parser.object.string_table.put(gpa, module_name),
|
||||
.name = try parser.object.string_table.put(gpa, name),
|
||||
.module_name = try wasm.internString(module_name),
|
||||
.name = try wasm.internString(name),
|
||||
.kind = kind_value,
|
||||
};
|
||||
}
|
||||
@@ -422,7 +419,7 @@ const Parser = struct {
|
||||
defer gpa.free(name);
|
||||
try reader.readNoEof(name);
|
||||
exp.* = .{
|
||||
.name = try parser.object.string_table.put(gpa, name),
|
||||
.name = try wasm.internString(name),
|
||||
.kind = try readEnum(std.wasm.ExternalKind, reader),
|
||||
.index = try readLeb(u32, reader),
|
||||
};
|
||||
@@ -587,6 +584,7 @@ const Parser = struct {
|
||||
/// `parser` is used to provide access to other sections that may be needed,
|
||||
/// such as access to the `import` section to find the name of a symbol.
|
||||
fn parseSubsection(parser: *Parser, gpa: Allocator, reader: anytype) !void {
|
||||
const wasm = parser.wasm;
|
||||
const sub_type = try leb.readUleb128(u8, reader);
|
||||
log.debug("Found subsection: {s}", .{@tagName(@as(Wasm.SubsectionType, @enumFromInt(sub_type)))});
|
||||
const payload_len = try leb.readUleb128(u32, reader);
|
||||
@@ -680,7 +678,7 @@ const Parser = struct {
|
||||
symbol.* = try parser.parseSymbol(gpa, reader);
|
||||
log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{
|
||||
@tagName(symbol.tag),
|
||||
parser.object.string_table.get(symbol.name),
|
||||
wasm.stringSlice(symbol.name),
|
||||
symbol.flags,
|
||||
});
|
||||
}
|
||||
@@ -697,15 +695,18 @@ const Parser = struct {
|
||||
if (parser.object.relocatable_data.get(.custom)) |custom_sections| {
|
||||
for (custom_sections) |*data| {
|
||||
if (!data.represented) {
|
||||
const name = wasm.castToString(data.index);
|
||||
try symbols.append(.{
|
||||
.name = data.index,
|
||||
.name = name,
|
||||
.flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
|
||||
.tag = .section,
|
||||
.virtual_address = 0,
|
||||
.index = data.section_index,
|
||||
});
|
||||
data.represented = true;
|
||||
log.debug("Created synthetic custom section symbol for '{s}'", .{parser.object.string_table.get(data.index)});
|
||||
log.debug("Created synthetic custom section symbol for '{s}'", .{
|
||||
wasm.stringSlice(name),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -719,7 +720,8 @@ const Parser = struct {
|
||||
/// requires access to `Object` to find the name of a symbol when it's
|
||||
/// an import and flag `WASM_SYM_EXPLICIT_NAME` is not set.
|
||||
fn parseSymbol(parser: *Parser, gpa: Allocator, reader: anytype) !Symbol {
|
||||
const tag = @as(Symbol.Tag, @enumFromInt(try leb.readUleb128(u8, reader)));
|
||||
const wasm = parser.wasm;
|
||||
const tag: Symbol.Tag = @enumFromInt(try leb.readUleb128(u8, reader));
|
||||
const flags = try leb.readUleb128(u32, reader);
|
||||
var symbol: Symbol = .{
|
||||
.flags = flags,
|
||||
@@ -735,7 +737,7 @@ const Parser = struct {
|
||||
const name = try gpa.alloc(u8, name_len);
|
||||
defer gpa.free(name);
|
||||
try reader.readNoEof(name);
|
||||
symbol.name = try parser.object.string_table.put(gpa, name);
|
||||
symbol.name = try wasm.internString(name);
|
||||
|
||||
// Data symbols only have the following fields if the symbol is defined
|
||||
if (symbol.isDefined()) {
|
||||
@@ -750,7 +752,7 @@ const Parser = struct {
|
||||
const section_data = parser.object.relocatable_data.get(.custom).?;
|
||||
for (section_data) |*data| {
|
||||
if (data.section_index == symbol.index) {
|
||||
symbol.name = data.index;
|
||||
symbol.name = wasm.castToString(data.index);
|
||||
data.represented = true;
|
||||
break;
|
||||
}
|
||||
@@ -765,7 +767,7 @@ const Parser = struct {
|
||||
const name = try gpa.alloc(u8, name_len);
|
||||
defer gpa.free(name);
|
||||
try reader.readNoEof(name);
|
||||
break :name try parser.object.string_table.put(gpa, name);
|
||||
break :name try wasm.internString(name);
|
||||
} else parser.object.findImport(symbol).name;
|
||||
},
|
||||
}
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
/// Can contain any of the flags defined in `Flag`
|
||||
flags: u32,
|
||||
/// Symbol name, when the symbol is undefined the name will be taken from the import.
|
||||
/// Note: This is an index into the string table.
|
||||
name: u32,
|
||||
/// Note: This is an index into the wasm string table.
|
||||
name: wasm.String,
|
||||
/// Index into the list of objects based on set `tag`
|
||||
/// NOTE: This will be set to `undefined` when `tag` is `data`
|
||||
/// and the symbol is undefined.
|
||||
@@ -207,3 +207,4 @@ pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatO
|
||||
|
||||
const std = @import("std");
|
||||
const Symbol = @This();
|
||||
const wasm = @import("../Wasm.zig");
|
||||
|
||||
+32
-50
@@ -23,16 +23,14 @@ globals: std.ArrayListUnmanaged(std.wasm.Global) = .empty,
|
||||
atom_types: std.AutoHashMapUnmanaged(Atom.Index, u32) = .empty,
|
||||
/// List of all symbols generated by Zig code.
|
||||
symbols: std.ArrayListUnmanaged(Symbol) = .empty,
|
||||
/// Map from symbol name offset to their index into the `symbols` list.
|
||||
global_syms: std.AutoHashMapUnmanaged(u32, Symbol.Index) = .empty,
|
||||
/// Map from symbol name to their index into the `symbols` list.
|
||||
global_syms: std.AutoHashMapUnmanaged(Wasm.String, Symbol.Index) = .empty,
|
||||
/// List of symbol indexes which are free to be used.
|
||||
symbols_free_list: std.ArrayListUnmanaged(Symbol.Index) = .empty,
|
||||
/// Extra metadata about the linking section, such as alignment of segments and their name.
|
||||
segment_info: std.ArrayListUnmanaged(Wasm.NamedSegment) = .empty,
|
||||
/// List of indexes which contain a free slot in the `segment_info` list.
|
||||
segment_free_list: std.ArrayListUnmanaged(u32) = .empty,
|
||||
/// File encapsulated string table, used to deduplicate strings within the generated file.
|
||||
string_table: StringTable = .{},
|
||||
/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
|
||||
uavs: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .empty,
|
||||
/// List of atom indexes of functions that are generated by the backend.
|
||||
@@ -88,13 +86,9 @@ const NavInfo = struct {
|
||||
atom: Atom.Index = .null,
|
||||
exports: std.ArrayListUnmanaged(Symbol.Index) = .empty,
|
||||
|
||||
fn @"export"(ni: NavInfo, zig_object: *const ZigObject, name: []const u8) ?Symbol.Index {
|
||||
fn @"export"(ni: NavInfo, zo: *const ZigObject, name: Wasm.String) ?Symbol.Index {
|
||||
for (ni.exports.items) |sym_index| {
|
||||
const sym_name_index = zig_object.symbol(sym_index).name;
|
||||
const sym_name = zig_object.string_table.getAssumeExists(sym_name_index);
|
||||
if (std.mem.eql(u8, name, sym_name)) {
|
||||
return sym_index;
|
||||
}
|
||||
if (zo.symbol(sym_index).name == name) return sym_index;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@@ -126,14 +120,14 @@ pub fn init(zig_object: *ZigObject, wasm: *Wasm) !void {
|
||||
|
||||
fn createStackPointer(zig_object: *ZigObject, wasm: *Wasm) !void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const sym_index = try zig_object.getGlobalSymbol(gpa, "__stack_pointer");
|
||||
const sym_index = try zig_object.getGlobalSymbol(gpa, wasm.preloaded_strings.__stack_pointer);
|
||||
const sym = zig_object.symbol(sym_index);
|
||||
sym.index = zig_object.imported_globals_count;
|
||||
sym.tag = .global;
|
||||
const is_wasm32 = wasm.base.comp.root_mod.resolved_target.result.cpu.arch == .wasm32;
|
||||
try zig_object.imports.putNoClobber(gpa, sym_index, .{
|
||||
.name = sym.name,
|
||||
.module_name = try zig_object.string_table.insert(gpa, wasm.host_name),
|
||||
.module_name = wasm.host_name,
|
||||
.kind = .{ .global = .{ .valtype = if (is_wasm32) .i32 else .i64, .mutable = true } },
|
||||
});
|
||||
zig_object.imported_globals_count += 1;
|
||||
@@ -174,7 +168,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
|
||||
atom.deinit(gpa);
|
||||
}
|
||||
}
|
||||
if (zig_object.findGlobalSymbol("__zig_errors_len")) |sym_index| {
|
||||
if (zig_object.global_syms.get(wasm.preloaded_strings.__zig_errors_len)) |sym_index| {
|
||||
const atom_index = wasm.symbol_atom.get(.{ .file = .zig_object, .index = sym_index }).?;
|
||||
wasm.getAtomPtr(atom_index).deinit(gpa);
|
||||
}
|
||||
@@ -206,7 +200,6 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
|
||||
zig_object.segment_info.deinit(gpa);
|
||||
zig_object.segment_free_list.deinit(gpa);
|
||||
|
||||
zig_object.string_table.deinit(gpa);
|
||||
if (zig_object.dwarf) |*dwarf| {
|
||||
dwarf.deinit();
|
||||
}
|
||||
@@ -219,7 +212,7 @@ pub fn deinit(zig_object: *ZigObject, wasm: *Wasm) void {
|
||||
pub fn allocateSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator) !Symbol.Index {
|
||||
try zig_object.symbols.ensureUnusedCapacity(gpa, 1);
|
||||
const sym: Symbol = .{
|
||||
.name = std.math.maxInt(u32), // will be set after updateDecl as well as during atom creation for decls
|
||||
.name = undefined, // will be set after updateDecl as well as during atom creation for decls
|
||||
.flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
|
||||
.tag = .undefined, // will be set after updateDecl
|
||||
.index = std.math.maxInt(u32), // will be set during atom parsing
|
||||
@@ -345,7 +338,7 @@ fn finishUpdateNav(
|
||||
const atom_index = nav_info.atom;
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
const sym = zig_object.symbol(atom.sym_index);
|
||||
sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
|
||||
sym.name = try wasm.internString(nav.fqn.toSlice(ip));
|
||||
try atom.code.appendSlice(gpa, code);
|
||||
atom.size = @intCast(code.len);
|
||||
|
||||
@@ -432,7 +425,7 @@ pub fn getOrCreateAtomForNav(
|
||||
gop.value_ptr.* = .{ .atom = try wasm.createAtom(sym_index, .zig_object) };
|
||||
const nav = ip.getNav(nav_index);
|
||||
const sym = zig_object.symbol(sym_index);
|
||||
sym.name = try zig_object.string_table.insert(gpa, nav.fqn.toSlice(ip));
|
||||
sym.name = try wasm.internString(nav.fqn.toSlice(ip));
|
||||
}
|
||||
return gop.value_ptr.atom;
|
||||
}
|
||||
@@ -500,7 +493,7 @@ fn lowerConst(
|
||||
const segment_name = try std.mem.concat(gpa, u8, &.{ ".rodata.", name });
|
||||
errdefer gpa.free(segment_name);
|
||||
zig_object.symbol(sym_index).* = .{
|
||||
.name = try zig_object.string_table.insert(gpa, name),
|
||||
.name = try wasm.internString(name),
|
||||
.flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
|
||||
.tag = .data,
|
||||
.index = try zig_object.createDataSegment(
|
||||
@@ -551,11 +544,10 @@ pub fn getErrorTableSymbol(zig_object: *ZigObject, wasm: *Wasm, pt: Zcu.PerThrea
|
||||
const slice_ty = Type.slice_const_u8_sentinel_0;
|
||||
atom.alignment = slice_ty.abiAlignment(pt.zcu);
|
||||
|
||||
const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_name_table");
|
||||
const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_name_table");
|
||||
const sym = zig_object.symbol(sym_index);
|
||||
sym.* = .{
|
||||
.name = sym_name,
|
||||
.name = wasm.preloaded_strings.__zig_err_name_table,
|
||||
.tag = .data,
|
||||
.flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
|
||||
.index = try zig_object.createDataSegment(gpa, segment_name, atom.alignment),
|
||||
@@ -583,11 +575,10 @@ fn populateErrorNameTable(zig_object: *ZigObject, wasm: *Wasm, tid: Zcu.PerThrea
|
||||
const names_atom_index = try wasm.createAtom(names_sym_index, .zig_object);
|
||||
const names_atom = wasm.getAtomPtr(names_atom_index);
|
||||
names_atom.alignment = .@"1";
|
||||
const sym_name = try zig_object.string_table.insert(gpa, "__zig_err_names");
|
||||
const segment_name = try gpa.dupe(u8, ".rodata.__zig_err_names");
|
||||
const names_symbol = zig_object.symbol(names_sym_index);
|
||||
names_symbol.* = .{
|
||||
.name = sym_name,
|
||||
.name = wasm.preloaded_strings.__zig_err_names,
|
||||
.tag = .data,
|
||||
.flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
|
||||
.index = try zig_object.createDataSegment(gpa, segment_name, names_atom.alignment),
|
||||
@@ -661,14 +652,14 @@ pub fn addOrUpdateImport(
|
||||
// For the import name, we use the decl's name, rather than the fully qualified name
|
||||
// Also mangle the name when the lib name is set and not equal to "C" so imports with the same
|
||||
// name but different module can be resolved correctly.
|
||||
const mangle_name = lib_name != null and
|
||||
!std.mem.eql(u8, lib_name.?, "c");
|
||||
const full_name = if (mangle_name) full_name: {
|
||||
break :full_name try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? });
|
||||
} else name;
|
||||
const mangle_name = if (lib_name) |n| !std.mem.eql(u8, n, "c") else false;
|
||||
const full_name = if (mangle_name)
|
||||
try std.fmt.allocPrint(gpa, "{s}|{s}", .{ name, lib_name.? })
|
||||
else
|
||||
name;
|
||||
defer if (mangle_name) gpa.free(full_name);
|
||||
|
||||
const decl_name_index = try zig_object.string_table.insert(gpa, full_name);
|
||||
const decl_name_index = try wasm.internString(full_name);
|
||||
const sym: *Symbol = &zig_object.symbols.items[@intFromEnum(symbol_index)];
|
||||
sym.setUndefined(true);
|
||||
sym.setGlobal(true);
|
||||
@@ -680,13 +671,11 @@ pub fn addOrUpdateImport(
|
||||
|
||||
if (type_index) |ty_index| {
|
||||
const gop = try zig_object.imports.getOrPut(gpa, symbol_index);
|
||||
const module_name = if (lib_name) |l_name| l_name else wasm.host_name;
|
||||
if (!gop.found_existing) {
|
||||
zig_object.imported_functions_count += 1;
|
||||
}
|
||||
const module_name = if (lib_name) |n| try wasm.internString(n) else wasm.host_name;
|
||||
if (!gop.found_existing) zig_object.imported_functions_count += 1;
|
||||
gop.value_ptr.* = .{
|
||||
.module_name = try zig_object.string_table.insert(gpa, module_name),
|
||||
.name = try zig_object.string_table.insert(gpa, name),
|
||||
.module_name = module_name,
|
||||
.name = try wasm.internString(name),
|
||||
.kind = .{ .function = ty_index },
|
||||
};
|
||||
sym.tag = .function;
|
||||
@@ -699,8 +688,7 @@ pub fn addOrUpdateImport(
|
||||
/// such as an exported or imported symbol.
|
||||
/// If the symbol does not yet exist, creates a new one symbol instead
|
||||
/// and then returns the index to it.
|
||||
pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name: []const u8) !Symbol.Index {
|
||||
const name_index = try zig_object.string_table.insert(gpa, name);
|
||||
pub fn getGlobalSymbol(zig_object: *ZigObject, gpa: std.mem.Allocator, name_index: Wasm.String) !Symbol.Index {
|
||||
const gop = try zig_object.global_syms.getOrPut(gpa, name_index);
|
||||
if (gop.found_existing) {
|
||||
return gop.value_ptr.*;
|
||||
@@ -840,7 +828,8 @@ pub fn deleteExport(
|
||||
.uav => @panic("TODO: implement Wasm linker code for exporting a constant value"),
|
||||
};
|
||||
const nav_info = zig_object.navs.getPtr(nav_index) orelse return;
|
||||
if (nav_info.@"export"(zig_object, name.toSlice(&zcu.intern_pool))) |sym_index| {
|
||||
const name_interned = wasm.getExistingString(name.toSlice(&zcu.intern_pool)).?;
|
||||
if (nav_info.@"export"(zig_object, name_interned)) |sym_index| {
|
||||
const sym = zig_object.symbol(sym_index);
|
||||
nav_info.deleteExport(sym_index);
|
||||
std.debug.assert(zig_object.global_syms.remove(sym.name));
|
||||
@@ -886,14 +875,13 @@ pub fn updateExports(
|
||||
continue;
|
||||
}
|
||||
|
||||
const export_string = exp.opts.name.toSlice(ip);
|
||||
const sym_index = if (nav_info.@"export"(zig_object, export_string)) |idx| idx else index: {
|
||||
const export_name = try wasm.internString(exp.opts.name.toSlice(ip));
|
||||
const sym_index = if (nav_info.@"export"(zig_object, export_name)) |idx| idx else index: {
|
||||
const sym_index = try zig_object.allocateSymbol(gpa);
|
||||
try nav_info.appendExport(gpa, sym_index);
|
||||
break :index sym_index;
|
||||
};
|
||||
|
||||
const export_name = try zig_object.string_table.insert(gpa, export_string);
|
||||
const sym = zig_object.symbol(sym_index);
|
||||
sym.setGlobal(true);
|
||||
sym.setUndefined(false);
|
||||
@@ -922,7 +910,7 @@ pub fn updateExports(
|
||||
if (exp.opts.visibility == .hidden) {
|
||||
sym.setFlag(.WASM_SYM_VISIBILITY_HIDDEN);
|
||||
}
|
||||
log.debug(" with name '{s}' - {}", .{ export_string, sym });
|
||||
log.debug(" with name '{s}' - {}", .{ wasm.stringSlice(export_name), sym });
|
||||
try zig_object.global_syms.put(gpa, export_name, sym_index);
|
||||
try wasm.symbol_atom.put(gpa, .{ .file = .zig_object, .index = sym_index }, atom_index);
|
||||
}
|
||||
@@ -1014,7 +1002,7 @@ pub fn putOrGetFuncType(zig_object: *ZigObject, gpa: std.mem.Allocator, func_typ
|
||||
/// This will only be generated if the symbol exists.
|
||||
fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
|
||||
const gpa = wasm.base.comp.gpa;
|
||||
const sym_index = zig_object.findGlobalSymbol("__zig_errors_len") orelse return;
|
||||
const sym_index = zig_object.global_syms.get(wasm.preloaded_strings.__zig_errors_len) orelse return;
|
||||
|
||||
const errors_len = 1 + wasm.base.comp.zcu.?.intern_pool.global_error_set.getNamesFromMainThread().len;
|
||||
// overwrite existing atom if it already exists (maybe the error set has increased)
|
||||
@@ -1045,11 +1033,6 @@ fn setupErrorsLen(zig_object: *ZigObject, wasm: *Wasm) !void {
|
||||
try atom.code.writer(gpa).writeInt(u16, @intCast(errors_len), .little);
|
||||
}
|
||||
|
||||
fn findGlobalSymbol(zig_object: *ZigObject, name: []const u8) ?Symbol.Index {
|
||||
const offset = zig_object.string_table.getOffset(name) orelse return null;
|
||||
return zig_object.global_syms.get(offset);
|
||||
}
|
||||
|
||||
/// Initializes symbols and atoms for the debug sections
|
||||
/// Initialization is only done when compiling Zig code.
|
||||
/// When Zig is invoked as a linker instead, the atoms
|
||||
@@ -1082,7 +1065,7 @@ pub fn createDebugSectionForIndex(zig_object: *ZigObject, wasm: *Wasm, index: *?
|
||||
const atom = wasm.getAtomPtr(atom_index);
|
||||
zig_object.symbols.items[sym_index] = .{
|
||||
.tag = .section,
|
||||
.name = try zig_object.string_table.put(gpa, name),
|
||||
.name = try wasm.internString(name),
|
||||
.index = 0,
|
||||
.flags = @intFromEnum(Symbol.Flag.WASM_SYM_BINDING_LOCAL),
|
||||
};
|
||||
@@ -1197,7 +1180,7 @@ pub fn createFunction(
|
||||
const sym_index = try zig_object.allocateSymbol(gpa);
|
||||
const sym = zig_object.symbol(sym_index);
|
||||
sym.tag = .function;
|
||||
sym.name = try zig_object.string_table.insert(gpa, symbol_name);
|
||||
sym.name = try wasm.internString(symbol_name);
|
||||
const type_index = try zig_object.putOrGetFuncType(gpa, func_ty);
|
||||
sym.index = try zig_object.appendFunction(gpa, .{ .type_index = type_index });
|
||||
|
||||
@@ -1244,7 +1227,6 @@ const Dwarf = @import("../Dwarf.zig");
|
||||
const InternPool = @import("../../InternPool.zig");
|
||||
const Liveness = @import("../../Liveness.zig");
|
||||
const Zcu = @import("../../Zcu.zig");
|
||||
const StringTable = @import("../StringTable.zig");
|
||||
const Symbol = @import("Symbol.zig");
|
||||
const Type = @import("../../Type.zig");
|
||||
const Value = @import("../../Value.zig");
|
||||
|
||||
Reference in New Issue
Block a user