link: Implement API to get global symbol index
This commit is contained in:
@@ -1737,7 +1737,12 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
|
||||
var func_type = try genFunctype(self.gpa, ext_decl.ty.fnInfo(), self.target);
|
||||
defer func_type.deinit(self.gpa);
|
||||
ext_decl.fn_link.wasm.type_index = try self.bin_file.putOrGetFuncType(func_type);
|
||||
try self.bin_file.addOrUpdateImport(ext_decl);
|
||||
try self.bin_file.addOrUpdateImport(
|
||||
mem.sliceTo(ext_decl.name, 0),
|
||||
ext_decl.link.wasm.sym_index,
|
||||
ext_decl.getExternFn().?.lib_name,
|
||||
ext_decl.fn_link.wasm.type_index,
|
||||
);
|
||||
break :blk ext_decl;
|
||||
} else if (func_val.castTag(.decl_ref)) |decl_ref| {
|
||||
break :blk module.declPtr(decl_ref.data);
|
||||
@@ -5107,13 +5112,15 @@ fn callIntrinsic(
|
||||
args: []const WValue,
|
||||
) InnerError!WValue {
|
||||
assert(param_types.len == args.len);
|
||||
const symbol_index = @intCast(u32, try self.bin_file.getIntrinsicSymbol(name));
|
||||
var pt_tmp = try self.gpa.dupe(Type, param_types);
|
||||
defer self.gpa.free(pt_tmp);
|
||||
const symbol_index = self.bin_file.base.getGlobalSymbol(name) catch |err| {
|
||||
return self.fail("Could not find or create global symbol '{s}'", .{@errorName(err)});
|
||||
};
|
||||
|
||||
// TODO: have genFunctype accept individual params so we don't,
|
||||
// need to initialize a fake Fn.Data instance.
|
||||
const func_type = try genFunctype(self.base.allocator, .{
|
||||
var pt_tmp = try self.gpa.dupe(Type, param_types);
|
||||
defer self.gpa.free(pt_tmp);
|
||||
var func_type = try genFunctype(self.gpa, .{
|
||||
.param_types = pt_tmp,
|
||||
.comptime_params = undefined,
|
||||
.return_type = return_type,
|
||||
@@ -5122,9 +5129,9 @@ fn callIntrinsic(
|
||||
.is_var_args = false,
|
||||
.is_generic = false,
|
||||
}, self.target);
|
||||
defer func_type.deinit(self.base.allocator);
|
||||
defer func_type.deinit(self.gpa);
|
||||
const func_type_index = try self.bin_file.putOrGetFuncType(func_type);
|
||||
try self.bin_file.addOrUpdateImport(symbol_index, func_type_index);
|
||||
try self.bin_file.addOrUpdateImport(name, symbol_index, null, func_type_index);
|
||||
|
||||
const want_sret_param = firstParamSRet(.C, return_type, self.target);
|
||||
// if we want return as first param, we allocate a pointer to stack,
|
||||
|
||||
18
src/link.zig
18
src/link.zig
@@ -438,6 +438,24 @@ pub const File = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// Called from within CodeGen to retrieve the symbol index of a global symbol.
|
||||
/// If no symbol exists yet with this name, a new one will be created instead.
|
||||
pub fn getGlobalSymbol(base: *File, name: []const u8) UpdateDeclError!u32 {
|
||||
log.debug("getGlobalSymbol '{s}'", .{name});
|
||||
switch (base.tag) {
|
||||
// zig fmt: off
|
||||
.coff => unreachable,
|
||||
.elf => unreachable,
|
||||
.macho => unreachable,
|
||||
.plan9 => unreachable,
|
||||
.spirv => unreachable,
|
||||
.c => unreachable,
|
||||
.wasm => return @fieldParentPtr(Wasm, "base", base).getGlobalSymbol(name),
|
||||
.nvptx => unreachable,
|
||||
// zig fmt: on
|
||||
}
|
||||
}
|
||||
|
||||
/// May be called before or after updateDeclExports but must be called
|
||||
/// after allocateDeclIndexes for any given Decl.
|
||||
pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void {
|
||||
|
||||
@@ -433,6 +433,13 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void {
|
||||
continue; // Do not overwrite defined symbols with undefined symbols
|
||||
}
|
||||
|
||||
if (symbol.tag != existing_sym.tag) {
|
||||
log.err("symbol '{s}' mismatching type '{s}", .{ sym_name, @tagName(symbol.tag) });
|
||||
log.err(" first definition in '{s}'", .{existing_file_path});
|
||||
log.err(" next definition in '{s}'", .{object.name});
|
||||
return error.SymbolMismatchingType;
|
||||
}
|
||||
|
||||
// when both symbols are weak, we skip overwriting
|
||||
if (existing_sym.isWeak() and symbol.isWeak()) {
|
||||
continue;
|
||||
@@ -755,7 +762,7 @@ pub fn lowerUnnamedConst(self: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
|
||||
/// Returns the symbol index from the name of an intrinsic.
|
||||
/// If the symbol does not yet exist, creates a new one symbol instead
|
||||
/// and then returns the index to it.
|
||||
pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
|
||||
pub fn getGlobalSymbol(self: *Wasm, name: []const u8) !u32 {
|
||||
const name_index = try self.string_table.put(self.base.allocator, name);
|
||||
const gop = try self.globals.getOrPut(self.base.allocator, name_index);
|
||||
if (gop.found_existing) {
|
||||
@@ -769,7 +776,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
|
||||
.tag = .function,
|
||||
};
|
||||
symbol.setGlobal(true);
|
||||
symbol.setFlag(.WASM_SYM_UNDEFINED);
|
||||
symbol.setUndefined(true);
|
||||
|
||||
const sym_index = if (self.symbols_free_list.popOrNull()) |index| index else blk: {
|
||||
var index = @intCast(u32, self.symbols.items.len);
|
||||
@@ -779,7 +786,7 @@ pub fn getIntrinsicSymbol(self: *Wasm, name: []const u8) !u64 {
|
||||
};
|
||||
self.symbols.items[sym_index] = symbol;
|
||||
gop.value_ptr.* = .{ .index = sym_index, .file = null };
|
||||
|
||||
try self.resolved_symbols.put(self.base.allocator, gop.value_ptr.*, {});
|
||||
return sym_index;
|
||||
}
|
||||
|
||||
@@ -982,10 +989,24 @@ fn mapFunctionTable(self: *Wasm) void {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
|
||||
/// Either creates a new import, or updates one if existing.
|
||||
/// When `type_index` is non-null, we assume an external function.
|
||||
/// In all other cases, a data-symbol will be created instead.
|
||||
pub fn addOrUpdateImport(
|
||||
self: *Wasm,
|
||||
/// Name of the import
|
||||
name: []const u8,
|
||||
/// Symbol index that is external
|
||||
symbol_index: u32,
|
||||
/// Optional library name (i.e. `extern "c" fn foo() void`
|
||||
lib_name: ?[*:0]const u8,
|
||||
/// The index of the type that represents the function signature
|
||||
/// when the extern is a function. When this is null, a data-symbol
|
||||
/// is asserted instead.
|
||||
type_index: ?u32,
|
||||
) !void {
|
||||
// For the import name itself, we use the decl's name, rather than the fully qualified name
|
||||
const decl_name_index = try self.string_table.put(self.base.allocator, mem.sliceTo(decl.name, 0));
|
||||
const symbol_index = decl.link.wasm.sym_index;
|
||||
const decl_name_index = try self.string_table.put(self.base.allocator, name);
|
||||
const symbol: *Symbol = &self.symbols.items[symbol_index];
|
||||
symbol.setUndefined(true);
|
||||
symbol.setGlobal(true);
|
||||
@@ -996,22 +1017,19 @@ pub fn addOrUpdateImport(self: *Wasm, decl: *Module.Decl) !void {
|
||||
try self.resolved_symbols.put(self.base.allocator, loc, {});
|
||||
}
|
||||
|
||||
switch (decl.ty.zigTypeTag()) {
|
||||
.Fn => {
|
||||
const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null });
|
||||
const module_name = if (decl.getExternFn().?.lib_name) |lib_name| blk: {
|
||||
break :blk mem.sliceTo(lib_name, 0);
|
||||
} else self.host_name;
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{
|
||||
.module_name = try self.string_table.put(self.base.allocator, module_name),
|
||||
.name = decl_name_index,
|
||||
.kind = .{ .function = decl.fn_link.wasm.type_index },
|
||||
};
|
||||
}
|
||||
},
|
||||
else => @panic("TODO: Implement undefined symbols for non-function declarations"),
|
||||
}
|
||||
if (type_index) |ty_index| {
|
||||
const gop = try self.imports.getOrPut(self.base.allocator, .{ .index = symbol_index, .file = null });
|
||||
const module_name = if (lib_name) |l_name| blk: {
|
||||
break :blk mem.sliceTo(l_name, 0);
|
||||
} else self.host_name;
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = .{
|
||||
.module_name = try self.string_table.put(self.base.allocator, module_name),
|
||||
.name = decl_name_index,
|
||||
.kind = .{ .function = ty_index },
|
||||
};
|
||||
}
|
||||
} else @panic("TODO: Implement undefined symbols for non-function declarations");
|
||||
}
|
||||
|
||||
const Kind = union(enum) {
|
||||
@@ -1251,7 +1269,7 @@ fn mergeSections(self: *Wasm) !void {
|
||||
symbol.index = @intCast(u32, self.tables.items.len) + self.imported_tables_count;
|
||||
try self.tables.append(self.base.allocator, original_table);
|
||||
},
|
||||
else => {},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -171,7 +171,10 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
|
||||
}
|
||||
std.debug.assert(symbol.tag == .data);
|
||||
const merge_segment = wasm_bin.base.options.output_mode != .Obj;
|
||||
const segment_name = wasm_bin.segment_info.items[symbol.index].outputName(merge_segment);
|
||||
const segment_info = if (self.file) |object_index| blk: {
|
||||
break :blk wasm_bin.objects.items[object_index].segment_info;
|
||||
} else wasm_bin.segment_info.items;
|
||||
const segment_name = segment_info[symbol.index].outputName(merge_segment);
|
||||
const atom_index = wasm_bin.data_segments.get(segment_name).?;
|
||||
const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
|
||||
const segment = wasm_bin.segments.items[atom_index];
|
||||
|
||||
@@ -302,12 +302,16 @@ fn Parser(comptime ReaderType: type) type {
|
||||
}
|
||||
|
||||
fn parseObject(self: *Self, gpa: Allocator, is_object_file: *bool) Error!void {
|
||||
errdefer self.object.deinit(gpa);
|
||||
try self.verifyMagicBytes();
|
||||
const version = try self.reader.reader().readIntLittle(u32);
|
||||
|
||||
self.object.version = version;
|
||||
var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
|
||||
defer relocatable_data.deinit();
|
||||
|
||||
errdefer while (relocatable_data.popOrNull()) |rel_data| {
|
||||
gpa.free(rel_data.data[0..rel_data.size]);
|
||||
} else relocatable_data.deinit();
|
||||
|
||||
var section_index: u32 = 0;
|
||||
while (self.reader.reader().readByte()) |byte| : (section_index += 1) {
|
||||
@@ -808,26 +812,29 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
|
||||
kind: Symbol.Tag,
|
||||
index: u32,
|
||||
};
|
||||
var symbol_for_segment = std.AutoArrayHashMap(Key, u32).init(gpa);
|
||||
var symbol_for_segment = std.AutoArrayHashMap(Key, std.ArrayList(u32)).init(gpa);
|
||||
defer symbol_for_segment.deinit();
|
||||
|
||||
for (self.symtable) |symbol, symbol_index| {
|
||||
switch (symbol.tag) {
|
||||
.function, .data => if (!symbol.isUndefined()) {
|
||||
try symbol_for_segment.putNoClobber(
|
||||
.{ .kind = symbol.tag, .index = symbol.index },
|
||||
@intCast(u32, symbol_index),
|
||||
);
|
||||
const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });
|
||||
const sym_idx = @intCast(u32, symbol_index);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = std.ArrayList(u32).init(gpa);
|
||||
}
|
||||
try gop.value_ptr.*.append(sym_idx);
|
||||
},
|
||||
else => continue,
|
||||
}
|
||||
}
|
||||
|
||||
for (self.relocatable_data) |relocatable_data, index| {
|
||||
const sym_index = symbol_for_segment.get(.{
|
||||
const symbols = symbol_for_segment.getPtr(.{
|
||||
.kind = relocatable_data.getSymbolKind(),
|
||||
.index = @intCast(u32, relocatable_data.index),
|
||||
}) orelse continue; // encountered a segment we do not create an atom for
|
||||
const sym_index = symbols.pop();
|
||||
const final_index = try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index));
|
||||
|
||||
const atom = try gpa.create(Atom);
|
||||
@@ -862,6 +869,16 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
|
||||
}
|
||||
|
||||
try atom.code.appendSlice(gpa, relocatable_data.data[0..relocatable_data.size]);
|
||||
|
||||
// symbols referencing the same atom will be added as alias
|
||||
// or as 'parent' when they are global.
|
||||
while (symbols.popOrNull()) |idx| {
|
||||
const alias_symbol = self.symtable[idx];
|
||||
const symbol = self.symtable[atom.sym_index];
|
||||
if (alias_symbol.isGlobal() and symbol.isLocal()) {
|
||||
atom.sym_index = idx;
|
||||
}
|
||||
}
|
||||
try wasm_bin.symbol_atom.putNoClobber(gpa, atom.symbolLoc(), atom);
|
||||
|
||||
const segment: *Wasm.Segment = &wasm_bin.segments.items[final_index];
|
||||
|
||||
Reference in New Issue
Block a user