wasm-linker: rename self to descriptive name

This commit is contained in:
Luuk de Gram 2022-09-11 17:41:56 +02:00
parent 6dbf5f1d86
commit 61f317e386
No known key found for this signature in database
GPG Key ID: A8CFE58E4DC7D664
6 changed files with 957 additions and 959 deletions

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,6 @@ const std = @import("std");
const assert = std.debug.assert;
const fs = std.fs;
const log = std.log.scoped(.archive);
const macho = std.macho;
const mem = std.mem;
const Allocator = mem.Allocator;

View File

@ -55,37 +55,37 @@ pub const empty: Atom = .{
};
/// Frees all resources owned by this `Atom`.
pub fn deinit(self: *Atom, gpa: Allocator) void {
self.relocs.deinit(gpa);
self.code.deinit(gpa);
pub fn deinit(atom: *Atom, gpa: Allocator) void {
atom.relocs.deinit(gpa);
atom.code.deinit(gpa);
for (self.locals.items) |*local| {
for (atom.locals.items) |*local| {
local.deinit(gpa);
}
self.locals.deinit(gpa);
atom.locals.deinit(gpa);
}
/// Sets the length of relocations and code to '0',
/// effectively resetting them and allowing them to be re-populated.
pub fn clear(self: *Atom) void {
self.relocs.clearRetainingCapacity();
self.code.clearRetainingCapacity();
pub fn clear(atom: *Atom) void {
atom.relocs.clearRetainingCapacity();
atom.code.clearRetainingCapacity();
}
pub fn format(self: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
pub fn format(atom: Atom, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
_ = fmt;
_ = options;
try writer.print("Atom{{ .sym_index = {d}, .alignment = {d}, .size = {d}, .offset = 0x{x:0>8} }}", .{
self.sym_index,
self.alignment,
self.size,
self.offset,
atom.sym_index,
atom.alignment,
atom.size,
atom.offset,
});
}
/// Returns the first `Atom` from a given atom
pub fn getFirst(self: *Atom) *Atom {
var tmp = self;
pub fn getFirst(atom: *Atom) *Atom {
var tmp = atom;
while (tmp.prev) |prev| tmp = prev;
return tmp;
}
@ -94,9 +94,9 @@ pub fn getFirst(self: *Atom) *Atom {
/// produced from Zig code, rather than an object file.
/// This is useful for debug sections where we want to extend
/// the bytes, and don't want to overwrite existing Atoms.
pub fn getFirstZigAtom(self: *Atom) *Atom {
if (self.file == null) return self;
var tmp = self;
pub fn getFirstZigAtom(atom: *Atom) *Atom {
if (atom.file == null) return atom;
var tmp = atom;
return while (tmp.prev) |prev| {
if (prev.file == null) break prev;
tmp = prev;
@ -104,24 +104,24 @@ pub fn getFirstZigAtom(self: *Atom) *Atom {
}
/// Returns the location of the symbol that represents this `Atom`
pub fn symbolLoc(self: Atom) Wasm.SymbolLoc {
return .{ .file = self.file, .index = self.sym_index };
pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
return .{ .file = atom.file, .index = atom.sym_index };
}
/// Resolves the relocations within the atom, writing the new value
/// at the calculated offset.
pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {
if (self.relocs.items.len == 0) return;
const symbol_name = self.symbolLoc().getName(wasm_bin);
pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
if (atom.relocs.items.len == 0) return;
const symbol_name = atom.symbolLoc().getName(wasm_bin);
log.debug("Resolving relocs in atom '{s}' count({d})", .{
symbol_name,
self.relocs.items.len,
atom.relocs.items.len,
});
for (self.relocs.items) |reloc| {
const value = self.relocationValue(reloc, wasm_bin);
for (atom.relocs.items) |reloc| {
const value = atom.relocationValue(reloc, wasm_bin);
log.debug("Relocating '{s}' referenced in '{s}' offset=0x{x:0>8} value={d}", .{
(Wasm.SymbolLoc{ .file = self.file, .index = reloc.index }).getName(wasm_bin),
(Wasm.SymbolLoc{ .file = atom.file, .index = reloc.index }).getName(wasm_bin),
symbol_name,
reloc.offset,
value,
@ -133,10 +133,10 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {
.R_WASM_GLOBAL_INDEX_I32,
.R_WASM_MEMORY_ADDR_I32,
.R_WASM_SECTION_OFFSET_I32,
=> std.mem.writeIntLittle(u32, self.code.items[reloc.offset..][0..4], @intCast(u32, value)),
=> std.mem.writeIntLittle(u32, atom.code.items[reloc.offset..][0..4], @intCast(u32, value)),
.R_WASM_TABLE_INDEX_I64,
.R_WASM_MEMORY_ADDR_I64,
=> std.mem.writeIntLittle(u64, self.code.items[reloc.offset..][0..8], value),
=> std.mem.writeIntLittle(u64, atom.code.items[reloc.offset..][0..8], value),
.R_WASM_GLOBAL_INDEX_LEB,
.R_WASM_EVENT_INDEX_LEB,
.R_WASM_FUNCTION_INDEX_LEB,
@ -145,11 +145,11 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {
.R_WASM_TABLE_INDEX_SLEB,
.R_WASM_TABLE_NUMBER_LEB,
.R_WASM_TYPE_INDEX_LEB,
=> leb.writeUnsignedFixed(5, self.code.items[reloc.offset..][0..5], @intCast(u32, value)),
=> leb.writeUnsignedFixed(5, atom.code.items[reloc.offset..][0..5], @intCast(u32, value)),
.R_WASM_MEMORY_ADDR_LEB64,
.R_WASM_MEMORY_ADDR_SLEB64,
.R_WASM_TABLE_INDEX_SLEB64,
=> leb.writeUnsignedFixed(10, self.code.items[reloc.offset..][0..10], value),
=> leb.writeUnsignedFixed(10, atom.code.items[reloc.offset..][0..10], value),
}
}
}
@ -157,8 +157,8 @@ pub fn resolveRelocs(self: *Atom, wasm_bin: *const Wasm) void {
/// From a given `relocation` will return the new value to be written.
/// All values will be represented as a `u64` as all values can fit within it.
/// The final value must be casted to the correct size.
fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 {
const target_loc = (Wasm.SymbolLoc{ .file = self.file, .index = relocation.index }).finalLoc(wasm_bin);
fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 {
const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = relocation.index }).finalLoc(wasm_bin);
const symbol = target_loc.getSymbol(wasm_bin).*;
switch (relocation.relocation_type) {
.R_WASM_FUNCTION_INDEX_LEB => return symbol.index,
@ -203,7 +203,7 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
},
.R_WASM_FUNCTION_OFFSET_I32 => {
const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
var atom = target_atom.getFirst();
var current_atom = target_atom.getFirst();
var offset: u32 = 0;
// TODO: Calculate this during atom allocation, rather than
// this linear calculation. For now it's done here as atoms
@ -211,8 +211,8 @@ fn relocationValue(self: Atom, relocation: types.Relocation, wasm_bin: *const Wa
// merged until later.
while (true) {
offset += 5; // each atom uses 5 bytes to store its body's size
if (atom == target_atom) break;
atom = atom.next.?;
if (current_atom == target_atom) break;
current_atom = current_atom.next.?;
}
return target_atom.offset + offset + (relocation.addend orelse 0);
},

View File

@ -88,28 +88,28 @@ const RelocatableData = struct {
/// meta data of the given object file.
/// NOTE: Alignment is encoded as a power of 2, so we shift the symbol's
/// alignment to retrieve the natural alignment.
pub fn getAlignment(self: RelocatableData, object: *const Object) u32 {
if (self.type != .data) return 1;
const data_alignment = object.segment_info[self.index].alignment;
pub fn getAlignment(relocatable_data: RelocatableData, object: *const Object) u32 {
if (relocatable_data.type != .data) return 1;
const data_alignment = object.segment_info[relocatable_data.index].alignment;
if (data_alignment == 0) return 1;
// Decode from power of 2 to natural alignment
return @as(u32, 1) << @intCast(u5, data_alignment);
}
/// Returns the symbol kind that corresponds to the relocatable section
pub fn getSymbolKind(self: RelocatableData) Symbol.Tag {
return switch (self.type) {
pub fn getSymbolKind(relocatable_data: RelocatableData) Symbol.Tag {
return switch (relocatable_data.type) {
.data => .data,
.code => .function,
.debug => .section,
};
}
/// Returns the index within a section itself, or in case of a debug section,
/// Returns the index within a section itrelocatable_data, or in case of a debug section,
/// returns the section index within the object file.
pub fn getIndex(self: RelocatableData) u32 {
if (self.type == .debug) return self.section_index;
return self.index;
pub fn getIndex(relocatable_data: RelocatableData) u32 {
if (relocatable_data.type == .debug) return relocatable_data.section_index;
return relocatable_data.index;
}
};
@ -153,51 +153,51 @@ pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_siz
/// Frees all memory of `Object` at once. The given `Allocator` must be
/// the same allocator that was used when `init` was called.
pub fn deinit(self: *Object, gpa: Allocator) void {
if (self.file) |file| {
pub fn deinit(object: *Object, gpa: Allocator) void {
if (object.file) |file| {
file.close();
}
for (self.func_types) |func_ty| {
for (object.func_types) |func_ty| {
gpa.free(func_ty.params);
gpa.free(func_ty.returns);
}
gpa.free(self.func_types);
gpa.free(self.functions);
gpa.free(self.imports);
gpa.free(self.tables);
gpa.free(self.memories);
gpa.free(self.globals);
gpa.free(self.exports);
for (self.elements) |el| {
gpa.free(object.func_types);
gpa.free(object.functions);
gpa.free(object.imports);
gpa.free(object.tables);
gpa.free(object.memories);
gpa.free(object.globals);
gpa.free(object.exports);
for (object.elements) |el| {
gpa.free(el.func_indexes);
}
gpa.free(self.elements);
gpa.free(self.features);
for (self.relocations.values()) |val| {
gpa.free(object.elements);
gpa.free(object.features);
for (object.relocations.values()) |val| {
gpa.free(val);
}
self.relocations.deinit(gpa);
gpa.free(self.symtable);
gpa.free(self.comdat_info);
gpa.free(self.init_funcs);
for (self.segment_info) |info| {
object.relocations.deinit(gpa);
gpa.free(object.symtable);
gpa.free(object.comdat_info);
gpa.free(object.init_funcs);
for (object.segment_info) |info| {
gpa.free(info.name);
}
gpa.free(self.segment_info);
for (self.relocatable_data) |rel_data| {
gpa.free(object.segment_info);
for (object.relocatable_data) |rel_data| {
gpa.free(rel_data.data[0..rel_data.size]);
}
gpa.free(self.relocatable_data);
self.string_table.deinit(gpa);
gpa.free(self.name);
self.* = undefined;
gpa.free(object.relocatable_data);
object.string_table.deinit(gpa);
gpa.free(object.name);
object.* = undefined;
}
/// Finds the import within the list of imports from a given kind and index of that kind.
/// Asserts the import exists
pub fn findImport(self: *const Object, import_kind: std.wasm.ExternalKind, index: u32) types.Import {
pub fn findImport(object: *const Object, import_kind: std.wasm.ExternalKind, index: u32) types.Import {
var i: u32 = 0;
return for (self.imports) |import| {
return for (object.imports) |import| {
if (std.meta.activeTag(import.kind) == import_kind) {
if (i == index) return import;
i += 1;
@ -206,16 +206,16 @@ pub fn findImport(self: *const Object, import_kind: std.wasm.ExternalKind, index
}
/// Counts the entries of imported `kind` and returns the result
pub fn importedCountByKind(self: *const Object, kind: std.wasm.ExternalKind) u32 {
pub fn importedCountByKind(object: *const Object, kind: std.wasm.ExternalKind) u32 {
var i: u32 = 0;
return for (self.imports) |imp| {
return for (object.imports) |imp| {
if (@as(std.wasm.ExternalKind, imp.kind) == kind) i += 1;
} else i;
}
/// From a given `RelocatableDate`, find the corresponding debug section name
pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []const u8 {
return self.string_table.get(relocatable_data.index);
pub fn getDebugName(object: *const Object, relocatable_data: RelocatableData) []const u8 {
return object.string_table.get(relocatable_data.index);
}
/// Checks if the object file is an MVP version.
@ -224,13 +224,13 @@ pub fn getDebugName(self: *const Object, relocatable_data: RelocatableData) []co
/// we initialize a new table symbol that corresponds to that import and return that symbol.
///
/// When the object file is *NOT* MVP, we return `null`.
fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {
fn checkLegacyIndirectFunctionTable(object: *Object) !?Symbol {
var table_count: usize = 0;
for (self.symtable) |sym| {
for (object.symtable) |sym| {
if (sym.tag == .table) table_count += 1;
}
const import_table_count = self.importedCountByKind(.table);
const import_table_count = object.importedCountByKind(.table);
// For each import table, we also have a symbol so this is not a legacy object file
if (import_table_count == table_count) return null;
@ -244,7 +244,7 @@ fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {
}
// MVP object files cannot have any table definitions, only imports (for the indirect function table).
if (self.tables.len > 0) {
if (object.tables.len > 0) {
log.err("Unexpected table definition without representing table symbols.", .{});
return error.UnexpectedTable;
}
@ -254,14 +254,14 @@ fn checkLegacyIndirectFunctionTable(self: *Object) !?Symbol {
return error.MissingTableSymbols;
}
var table_import: types.Import = for (self.imports) |imp| {
var table_import: types.Import = for (object.imports) |imp| {
if (imp.kind == .table) {
break imp;
}
} else unreachable;
if (!std.mem.eql(u8, self.string_table.get(table_import.name), "__indirect_function_table")) {
log.err("Non-indirect function table import '{s}' is missing a corresponding symbol", .{self.string_table.get(table_import.name)});
if (!std.mem.eql(u8, object.string_table.get(table_import.name), "__indirect_function_table")) {
log.err("Non-indirect function table import '{s}' is missing a corresponding symbol", .{object.string_table.get(table_import.name)});
return error.MissingTableSymbols;
}
@ -313,41 +313,41 @@ pub const ParseError = error{
UnknownFeature,
};
fn parse(self: *Object, gpa: Allocator, reader: anytype, is_object_file: *bool) Parser(@TypeOf(reader)).Error!void {
var parser = Parser(@TypeOf(reader)).init(self, reader);
fn parse(object: *Object, gpa: Allocator, reader: anytype, is_object_file: *bool) Parser(@TypeOf(reader)).Error!void {
var parser = Parser(@TypeOf(reader)).init(object, reader);
return parser.parseObject(gpa, is_object_file);
}
fn Parser(comptime ReaderType: type) type {
return struct {
const Self = @This();
const ObjectParser = @This();
const Error = ReaderType.Error || ParseError;
reader: std.io.CountingReader(ReaderType),
/// Object file we're building
object: *Object,
fn init(object: *Object, reader: ReaderType) Self {
fn init(object: *Object, reader: ReaderType) ObjectParser {
return .{ .object = object, .reader = std.io.countingReader(reader) };
}
/// Verifies that the first 4 bytes contains \0Asm
fn verifyMagicBytes(self: *Self) Error!void {
fn verifyMagicBytes(parser: *ObjectParser) Error!void {
var magic_bytes: [4]u8 = undefined;
try self.reader.reader().readNoEof(&magic_bytes);
try parser.reader.reader().readNoEof(&magic_bytes);
if (!std.mem.eql(u8, &magic_bytes, &std.wasm.magic)) {
log.debug("Invalid magic bytes '{s}'", .{&magic_bytes});
return error.InvalidMagicByte;
}
}
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);
fn parseObject(parser: *ObjectParser, gpa: Allocator, is_object_file: *bool) Error!void {
errdefer parser.object.deinit(gpa);
try parser.verifyMagicBytes();
const version = try parser.reader.reader().readIntLittle(u32);
self.object.version = version;
parser.object.version = version;
var relocatable_data = std.ArrayList(RelocatableData).init(gpa);
var debug_names = std.ArrayList(u8).init(gpa);
@ -360,9 +360,9 @@ fn Parser(comptime ReaderType: type) type {
}
var section_index: u32 = 0;
while (self.reader.reader().readByte()) |byte| : (section_index += 1) {
const len = try readLeb(u32, self.reader.reader());
var limited_reader = std.io.limitedReader(self.reader.reader(), len);
while (parser.reader.reader().readByte()) |byte| : (section_index += 1) {
const len = try readLeb(u32, parser.reader.reader());
var limited_reader = std.io.limitedReader(parser.reader.reader(), len);
const reader = limited_reader.reader();
switch (@intToEnum(std.wasm.Section, byte)) {
.custom => {
@ -373,12 +373,12 @@ fn Parser(comptime ReaderType: type) type {
if (std.mem.eql(u8, name, "linking")) {
is_object_file.* = true;
self.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them.
try self.parseMetadata(gpa, @intCast(usize, reader.context.bytes_left));
parser.object.relocatable_data = relocatable_data.items; // at this point no new relocatable sections will appear so we're free to store them.
try parser.parseMetadata(gpa, @intCast(usize, reader.context.bytes_left));
} else if (std.mem.startsWith(u8, name, "reloc")) {
try self.parseRelocations(gpa);
try parser.parseRelocations(gpa);
} else if (std.mem.eql(u8, name, "target_features")) {
try self.parseFeatures(gpa);
try parser.parseFeatures(gpa);
} else if (std.mem.startsWith(u8, name, ".debug")) {
const debug_size = @intCast(u32, reader.context.bytes_left);
const debug_content = try gpa.alloc(u8, debug_size);
@ -389,7 +389,7 @@ fn Parser(comptime ReaderType: type) type {
.type = .debug,
.data = debug_content.ptr,
.size = debug_size,
.index = try self.object.string_table.put(gpa, name),
.index = try parser.object.string_table.put(gpa, name),
.offset = 0, // debug sections only contain 1 entry, so no need to calculate offset
.section_index = section_index,
});
@ -398,7 +398,7 @@ fn Parser(comptime ReaderType: type) type {
}
},
.type => {
for (try readVec(&self.object.func_types, reader, gpa)) |*type_val| {
for (try readVec(&parser.object.func_types, reader, gpa)) |*type_val| {
if ((try reader.readByte()) != std.wasm.function_type) return error.ExpectedFuncType;
for (try readVec(&type_val.params, reader, gpa)) |*param| {
@ -412,7 +412,7 @@ fn Parser(comptime ReaderType: type) type {
try assertEnd(reader);
},
.import => {
for (try readVec(&self.object.imports, reader, gpa)) |*import| {
for (try readVec(&parser.object.imports, reader, gpa)) |*import| {
const module_len = try readLeb(u32, reader);
const module_name = try gpa.alloc(u8, module_len);
defer gpa.free(module_name);
@ -438,21 +438,21 @@ fn Parser(comptime ReaderType: type) type {
};
import.* = .{
.module_name = try self.object.string_table.put(gpa, module_name),
.name = try self.object.string_table.put(gpa, name),
.module_name = try parser.object.string_table.put(gpa, module_name),
.name = try parser.object.string_table.put(gpa, name),
.kind = kind_value,
};
}
try assertEnd(reader);
},
.function => {
for (try readVec(&self.object.functions, reader, gpa)) |*func| {
for (try readVec(&parser.object.functions, reader, gpa)) |*func| {
func.* = .{ .type_index = try readLeb(u32, reader) };
}
try assertEnd(reader);
},
.table => {
for (try readVec(&self.object.tables, reader, gpa)) |*table| {
for (try readVec(&parser.object.tables, reader, gpa)) |*table| {
table.* = .{
.reftype = try readEnum(std.wasm.RefType, reader),
.limits = try readLimits(reader),
@ -461,13 +461,13 @@ fn Parser(comptime ReaderType: type) type {
try assertEnd(reader);
},
.memory => {
for (try readVec(&self.object.memories, reader, gpa)) |*memory| {
for (try readVec(&parser.object.memories, reader, gpa)) |*memory| {
memory.* = .{ .limits = try readLimits(reader) };
}
try assertEnd(reader);
},
.global => {
for (try readVec(&self.object.globals, reader, gpa)) |*global| {
for (try readVec(&parser.object.globals, reader, gpa)) |*global| {
global.* = .{
.global_type = .{
.valtype = try readEnum(std.wasm.Valtype, reader),
@ -479,13 +479,13 @@ fn Parser(comptime ReaderType: type) type {
try assertEnd(reader);
},
.@"export" => {
for (try readVec(&self.object.exports, reader, gpa)) |*exp| {
for (try readVec(&parser.object.exports, reader, gpa)) |*exp| {
const name_len = try readLeb(u32, reader);
const name = try gpa.alloc(u8, name_len);
defer gpa.free(name);
try reader.readNoEof(name);
exp.* = .{
.name = try self.object.string_table.put(gpa, name),
.name = try parser.object.string_table.put(gpa, name),
.kind = try readEnum(std.wasm.ExternalKind, reader),
.index = try readLeb(u32, reader),
};
@ -493,11 +493,11 @@ fn Parser(comptime ReaderType: type) type {
try assertEnd(reader);
},
.start => {
self.object.start = try readLeb(u32, reader);
parser.object.start = try readLeb(u32, reader);
try assertEnd(reader);
},
.element => {
for (try readVec(&self.object.elements, reader, gpa)) |*elem| {
for (try readVec(&parser.object.elements, reader, gpa)) |*elem| {
elem.table_index = try readLeb(u32, reader);
elem.offset = try readInit(reader);
@ -521,7 +521,7 @@ fn Parser(comptime ReaderType: type) type {
.type = .code,
.data = data.ptr,
.size = code_len,
.index = self.object.importedCountByKind(.function) + index,
.index = parser.object.importedCountByKind(.function) + index,
.offset = offset,
.section_index = section_index,
});
@ -551,22 +551,22 @@ fn Parser(comptime ReaderType: type) type {
});
}
},
else => try self.reader.reader().skipBytes(len, .{}),
else => try parser.reader.reader().skipBytes(len, .{}),
}
} else |err| switch (err) {
error.EndOfStream => {}, // finished parsing the file
else => |e| return e,
}
self.object.relocatable_data = relocatable_data.toOwnedSlice();
parser.object.relocatable_data = relocatable_data.toOwnedSlice();
}
/// Based on the "features" custom section, parses it into a list of
/// features that tell the linker what features were enabled and may be mandatory
/// to be able to link.
/// Logs an info message when an undefined feature is detected.
fn parseFeatures(self: *Self, gpa: Allocator) !void {
const reader = self.reader.reader();
for (try readVec(&self.object.features, reader, gpa)) |*feature| {
fn parseFeatures(parser: *ObjectParser, gpa: Allocator) !void {
const reader = parser.reader.reader();
for (try readVec(&parser.object.features, reader, gpa)) |*feature| {
const prefix = try readEnum(types.Feature.Prefix, reader);
const name_len = try leb.readULEB128(u32, reader);
const name = try gpa.alloc(u8, name_len);
@ -587,8 +587,8 @@ fn Parser(comptime ReaderType: type) type {
/// Parses a "reloc" custom section into a list of relocations.
/// The relocations are mapped into `Object` where the key is the section
/// they apply to.
fn parseRelocations(self: *Self, gpa: Allocator) !void {
const reader = self.reader.reader();
fn parseRelocations(parser: *ObjectParser, gpa: Allocator) !void {
const reader = parser.reader.reader();
const section = try leb.readULEB128(u32, reader);
const count = try leb.readULEB128(u32, reader);
const relocations = try gpa.alloc(types.Relocation, count);
@ -616,15 +616,15 @@ fn Parser(comptime ReaderType: type) type {
});
}
try self.object.relocations.putNoClobber(gpa, section, relocations);
try parser.object.relocations.putNoClobber(gpa, section, relocations);
}
/// Parses the "linking" custom section. Versions that are not
/// supported will be an error. `payload_size` is required to be able
/// to calculate the subsections we need to parse, as that data is not
/// available within the section itself.
fn parseMetadata(self: *Self, gpa: Allocator, payload_size: usize) !void {
var limited = std.io.limitedReader(self.reader.reader(), payload_size);
/// available within the section itparser.
fn parseMetadata(parser: *ObjectParser, gpa: Allocator, payload_size: usize) !void {
var limited = std.io.limitedReader(parser.reader.reader(), payload_size);
const limited_reader = limited.reader();
const version = try leb.readULEB128(u32, limited_reader);
@ -632,7 +632,7 @@ fn Parser(comptime ReaderType: type) type {
if (version != 2) return error.UnsupportedVersion;
while (limited.bytes_left > 0) {
try self.parseSubsection(gpa, limited_reader);
try parser.parseSubsection(gpa, limited_reader);
}
}
@ -640,9 +640,9 @@ fn Parser(comptime ReaderType: type) type {
/// The `reader` param for this is to provide a `LimitedReader`, which allows
/// us to only read until a max length.
///
/// `self` is used to provide access to other sections that may be needed,
/// `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(self: *Self, gpa: Allocator, reader: anytype) !void {
fn parseSubsection(parser: *ObjectParser, gpa: Allocator, reader: anytype) !void {
const sub_type = try leb.readULEB128(u8, reader);
log.debug("Found subsection: {s}", .{@tagName(@intToEnum(types.SubsectionType, sub_type))});
const payload_len = try leb.readULEB128(u32, reader);
@ -674,7 +674,7 @@ fn Parser(comptime ReaderType: type) type {
segment.flags,
});
}
self.object.segment_info = segments;
parser.object.segment_info = segments;
},
.WASM_INIT_FUNCS => {
const funcs = try gpa.alloc(types.InitFunc, count);
@ -686,7 +686,7 @@ fn Parser(comptime ReaderType: type) type {
};
log.debug("Found function - prio: {d}, index: {d}", .{ func.priority, func.symbol_index });
}
self.object.init_funcs = funcs;
parser.object.init_funcs = funcs;
},
.WASM_COMDAT_INFO => {
const comdats = try gpa.alloc(types.Comdat, count);
@ -719,7 +719,7 @@ fn Parser(comptime ReaderType: type) type {
};
}
self.object.comdat_info = comdats;
parser.object.comdat_info = comdats;
},
.WASM_SYMBOL_TABLE => {
var symbols = try std.ArrayList(Symbol).initCapacity(gpa, count);
@ -727,22 +727,22 @@ fn Parser(comptime ReaderType: type) type {
var i: usize = 0;
while (i < count) : (i += 1) {
const symbol = symbols.addOneAssumeCapacity();
symbol.* = try self.parseSymbol(gpa, reader);
symbol.* = try parser.parseSymbol(gpa, reader);
log.debug("Found symbol: type({s}) name({s}) flags(0b{b:0>8})", .{
@tagName(symbol.tag),
self.object.string_table.get(symbol.name),
parser.object.string_table.get(symbol.name),
symbol.flags,
});
}
// we found all symbols, check for indirect function table
// in case of an MVP object file
if (try self.object.checkLegacyIndirectFunctionTable()) |symbol| {
if (try parser.object.checkLegacyIndirectFunctionTable()) |symbol| {
try symbols.append(symbol);
log.debug("Found legacy indirect function table. Created symbol", .{});
}
self.object.symtable = symbols.toOwnedSlice();
parser.object.symtable = symbols.toOwnedSlice();
},
}
}
@ -750,7 +750,7 @@ fn Parser(comptime ReaderType: type) type {
/// Parses the symbol information based on its kind,
/// 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(self: *Self, gpa: Allocator, reader: anytype) !Symbol {
fn parseSymbol(parser: *ObjectParser, gpa: Allocator, reader: anytype) !Symbol {
const tag = @intToEnum(Symbol.Tag, try leb.readULEB128(u8, reader));
const flags = try leb.readULEB128(u32, reader);
var symbol: Symbol = .{
@ -766,7 +766,7 @@ fn Parser(comptime ReaderType: type) type {
const name = try gpa.alloc(u8, name_len);
defer gpa.free(name);
try reader.readNoEof(name);
symbol.name = try self.object.string_table.put(gpa, name);
symbol.name = try parser.object.string_table.put(gpa, name);
// Data symbols only have the following fields if the symbol is defined
if (symbol.isDefined()) {
@ -778,7 +778,7 @@ fn Parser(comptime ReaderType: type) type {
},
.section => {
symbol.index = try leb.readULEB128(u32, reader);
for (self.object.relocatable_data) |data| {
for (parser.object.relocatable_data) |data| {
if (data.section_index == symbol.index) {
symbol.name = data.index;
break;
@ -791,7 +791,7 @@ fn Parser(comptime ReaderType: type) type {
const is_undefined = symbol.isUndefined();
if (is_undefined) {
maybe_import = self.object.findImport(symbol.tag.externalType(), symbol.index);
maybe_import = parser.object.findImport(symbol.tag.externalType(), symbol.index);
}
const explicit_name = symbol.hasFlag(.WASM_SYM_EXPLICIT_NAME);
if (!(is_undefined and !explicit_name)) {
@ -799,7 +799,7 @@ fn Parser(comptime ReaderType: type) type {
const name = try gpa.alloc(u8, name_len);
defer gpa.free(name);
try reader.readNoEof(name);
symbol.name = try self.object.string_table.put(gpa, name);
symbol.name = try parser.object.string_table.put(gpa, name);
} else {
symbol.name = maybe_import.?.name;
}
@ -872,7 +872,7 @@ fn assertEnd(reader: anytype) !void {
}
/// Parses an object file into atoms, for code and data sections
pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin: *Wasm) !void {
pub fn parseIntoAtoms(object: *Object, gpa: Allocator, object_index: u16, wasm_bin: *Wasm) !void {
const Key = struct {
kind: Symbol.Tag,
index: u32,
@ -882,7 +882,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
list.deinit();
} else symbol_for_segment.deinit();
for (self.symtable) |symbol, symbol_index| {
for (object.symtable) |symbol, symbol_index| {
switch (symbol.tag) {
.function, .data, .section => if (!symbol.isUndefined()) {
const gop = try symbol_for_segment.getOrPut(.{ .kind = symbol.tag, .index = symbol.index });
@ -896,7 +896,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
}
}
for (self.relocatable_data) |relocatable_data, index| {
for (object.relocatable_data) |relocatable_data, index| {
const final_index = (try wasm_bin.getMatchingSegment(object_index, @intCast(u32, index))) orelse {
continue; // found unknown section, so skip parsing into atom as we do not know how to handle it.
};
@ -911,12 +911,12 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
try wasm_bin.managed_atoms.append(gpa, atom);
atom.file = object_index;
atom.size = relocatable_data.size;
atom.alignment = relocatable_data.getAlignment(self);
atom.alignment = relocatable_data.getAlignment(object);
const relocations: []types.Relocation = self.relocations.get(relocatable_data.section_index) orelse &.{};
const relocations: []types.Relocation = object.relocations.get(relocatable_data.section_index) orelse &.{};
for (relocations) |relocation| {
if (isInbetween(relocatable_data.offset, atom.size, relocation.offset)) {
// set the offset relative to the offset of the segment itself,
// set the offset relative to the offset of the segment itobject,
// rather than within the entire section.
var reloc = relocation;
reloc.offset -= relocatable_data.offset;
@ -942,8 +942,8 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
// 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];
const alias_symbol = object.symtable[idx];
const symbol = object.symtable[atom.sym_index];
if (alias_symbol.isGlobal() and symbol.isLocal()) {
atom.sym_index = idx;
}
@ -957,7 +957,7 @@ pub fn parseIntoAtoms(self: *Object, gpa: Allocator, object_index: u16, wasm_bin
}
try wasm_bin.appendAtomAtIndex(final_index, atom);
log.debug("Parsed into atom: '{s}' at segment index {d}", .{ self.string_table.get(self.symtable[atom.sym_index].name), final_index });
log.debug("Parsed into atom: '{s}' at segment index {d}", .{ object.string_table.get(object.symtable[atom.sym_index].name), final_index });
}
}

View File

@ -34,8 +34,8 @@ pub const Tag = enum {
/// From a given symbol tag, returns the `ExternalType`
/// Asserts the given tag can be represented as an external type.
pub fn externalType(self: Tag) std.wasm.ExternalKind {
return switch (self) {
pub fn externalType(tag: Tag) std.wasm.ExternalKind {
return switch (tag) {
.function => .function,
.global => .global,
.data => .memory,
@ -78,85 +78,85 @@ pub const Flag = enum(u32) {
/// Verifies if the given symbol should be imported from the
/// host environment or not
pub fn requiresImport(self: Symbol) bool {
if (self.tag == .data) return false;
if (!self.isUndefined()) return false;
if (self.isWeak()) return false;
// if (self.isDefined() and self.isWeak()) return true; //TODO: Only when building shared lib
pub fn requiresImport(symbol: Symbol) bool {
if (symbol.tag == .data) return false;
if (!symbol.isUndefined()) return false;
if (symbol.isWeak()) return false;
// if (symbol.isDefined() and symbol.isWeak()) return true; //TODO: Only when building shared lib
return true;
}
pub fn hasFlag(self: Symbol, flag: Flag) bool {
return self.flags & @enumToInt(flag) != 0;
pub fn hasFlag(symbol: Symbol, flag: Flag) bool {
return symbol.flags & @enumToInt(flag) != 0;
}
pub fn setFlag(self: *Symbol, flag: Flag) void {
self.flags |= @enumToInt(flag);
pub fn setFlag(symbol: *Symbol, flag: Flag) void {
symbol.flags |= @enumToInt(flag);
}
pub fn isUndefined(self: Symbol) bool {
return self.flags & @enumToInt(Flag.WASM_SYM_UNDEFINED) != 0;
pub fn isUndefined(symbol: Symbol) bool {
return symbol.flags & @enumToInt(Flag.WASM_SYM_UNDEFINED) != 0;
}
pub fn setUndefined(self: *Symbol, is_undefined: bool) void {
pub fn setUndefined(symbol: *Symbol, is_undefined: bool) void {
if (is_undefined) {
self.setFlag(.WASM_SYM_UNDEFINED);
symbol.setFlag(.WASM_SYM_UNDEFINED);
} else {
self.flags &= ~@enumToInt(Flag.WASM_SYM_UNDEFINED);
symbol.flags &= ~@enumToInt(Flag.WASM_SYM_UNDEFINED);
}
}
pub fn setGlobal(self: *Symbol, is_global: bool) void {
pub fn setGlobal(symbol: *Symbol, is_global: bool) void {
if (is_global) {
self.flags &= ~@enumToInt(Flag.WASM_SYM_BINDING_LOCAL);
symbol.flags &= ~@enumToInt(Flag.WASM_SYM_BINDING_LOCAL);
} else {
self.setFlag(.WASM_SYM_BINDING_LOCAL);
symbol.setFlag(.WASM_SYM_BINDING_LOCAL);
}
}
pub fn isDefined(self: Symbol) bool {
return !self.isUndefined();
pub fn isDefined(symbol: Symbol) bool {
return !symbol.isUndefined();
}
pub fn isVisible(self: Symbol) bool {
return self.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) == 0;
pub fn isVisible(symbol: Symbol) bool {
return symbol.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) == 0;
}
pub fn isLocal(self: Symbol) bool {
return self.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) != 0;
pub fn isLocal(symbol: Symbol) bool {
return symbol.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) != 0;
}
pub fn isGlobal(self: Symbol) bool {
return self.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) == 0;
pub fn isGlobal(symbol: Symbol) bool {
return symbol.flags & @enumToInt(Flag.WASM_SYM_BINDING_LOCAL) == 0;
}
pub fn isHidden(self: Symbol) bool {
return self.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) != 0;
pub fn isHidden(symbol: Symbol) bool {
return symbol.flags & @enumToInt(Flag.WASM_SYM_VISIBILITY_HIDDEN) != 0;
}
pub fn isNoStrip(self: Symbol) bool {
return self.flags & @enumToInt(Flag.WASM_SYM_NO_STRIP) != 0;
pub fn isNoStrip(symbol: Symbol) bool {
return symbol.flags & @enumToInt(Flag.WASM_SYM_NO_STRIP) != 0;
}
pub fn isExported(self: Symbol) bool {
if (self.isUndefined() or self.isLocal()) return false;
if (self.isHidden()) return false;
if (self.hasFlag(.WASM_SYM_EXPORTED)) return true;
if (self.hasFlag(.WASM_SYM_BINDING_WEAK)) return false;
pub fn isExported(symbol: Symbol) bool {
if (symbol.isUndefined() or symbol.isLocal()) return false;
if (symbol.isHidden()) return false;
if (symbol.hasFlag(.WASM_SYM_EXPORTED)) return true;
if (symbol.hasFlag(.WASM_SYM_BINDING_WEAK)) return false;
return true;
}
pub fn isWeak(self: Symbol) bool {
return self.flags & @enumToInt(Flag.WASM_SYM_BINDING_WEAK) != 0;
pub fn isWeak(symbol: Symbol) bool {
return symbol.flags & @enumToInt(Flag.WASM_SYM_BINDING_WEAK) != 0;
}
/// Formats the symbol into human-readable text
pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
pub fn format(symbol: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
_ = fmt;
_ = options;
const kind_fmt: u8 = switch (self.tag) {
const kind_fmt: u8 = switch (symbol.tag) {
.function => 'F',
.data => 'D',
.global => 'G',
@ -165,12 +165,12 @@ pub fn format(self: Symbol, comptime fmt: []const u8, options: std.fmt.FormatOpt
.table => 'T',
.dead => '-',
};
const visible: []const u8 = if (self.isVisible()) "yes" else "no";
const binding: []const u8 = if (self.isLocal()) "local" else "global";
const undef: []const u8 = if (self.isUndefined()) "undefined" else "";
const visible: []const u8 = if (symbol.isVisible()) "yes" else "no";
const binding: []const u8 = if (symbol.isLocal()) "local" else "global";
const undef: []const u8 = if (symbol.isUndefined()) "undefined" else "";
try writer.print(
"{c} binding={s} visible={s} id={d} name_offset={d} {s}",
.{ kind_fmt, binding, visible, self.index, self.name, undef },
.{ kind_fmt, binding, visible, symbol.index, symbol.name, undef },
);
}

View File

@ -202,22 +202,22 @@ pub const Feature = struct {
required = '=',
};
pub fn toString(self: Feature) []const u8 {
return switch (self.tag) {
pub fn toString(feature: Feature) []const u8 {
return switch (feature.tag) {
.bulk_memory => "bulk-memory",
.exception_handling => "exception-handling",
.mutable_globals => "mutable-globals",
.nontrapping_fptoint => "nontrapping-fptoint",
.sign_ext => "sign-ext",
.tail_call => "tail-call",
else => @tagName(self),
else => @tagName(feature),
};
}
pub fn format(self: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
pub fn format(feature: Feature, comptime fmt: []const u8, opt: std.fmt.FormatOptions, writer: anytype) !void {
_ = opt;
_ = fmt;
try writer.print("{c} {s}", .{ self.prefix, self.toString() });
try writer.print("{c} {s}", .{ feature.prefix, feature.toString() });
}
};