mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
wasm-linker: Emit symbol table for object file
When creating a relocatable object file, emit the symbol table. We do this by iterating over all atoms, and finding the corresponding symbols of those. This provides us all the meta information such as size, and offset as well. This data is required for defined data symbols. When we emit an object file, the "Names" section does not have to be emitted, as all symbol names are already in the symbol table, so the names section is redundant.
This commit is contained in:
parent
91a88a789f
commit
f7f3678b48
@ -1132,6 +1132,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
||||
|
||||
const file = self.base.file.?;
|
||||
const header_size = 5 + 1;
|
||||
const is_obj = self.base.options.output_mode == .Obj;
|
||||
|
||||
// No need to rewrite the magic/version header
|
||||
try file.setEndPos(@sizeOf(@TypeOf(wasm.magic ++ wasm.version)));
|
||||
@ -1443,7 +1444,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
||||
}
|
||||
|
||||
// Custom section "name" which contains symbol names
|
||||
{
|
||||
if (!is_obj) {
|
||||
const Name = struct {
|
||||
index: u32,
|
||||
name: []const u8,
|
||||
@ -1492,6 +1493,10 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void {
|
||||
@intCast(u32, (try file.getPos()) - header_offset - header_size),
|
||||
);
|
||||
}
|
||||
|
||||
if (is_obj) {
|
||||
try self.emitLinkSection(file, arena);
|
||||
}
|
||||
}
|
||||
|
||||
fn emitNameSubsection(self: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void {
|
||||
@ -2030,6 +2035,87 @@ fn writeCustomSectionHeader(file: fs.File, offset: u64, size: u32) !void {
|
||||
try file.pwriteAll(&buf, offset);
|
||||
}
|
||||
|
||||
fn emitLinkSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
|
||||
const offset = try reserveCustomSectionHeader(file);
|
||||
const writer = file.writer();
|
||||
// emit "linking" custom section name
|
||||
const section_name = "linking";
|
||||
try leb.writeULEB128(writer, section_name.len);
|
||||
try writer.writeAll(section_name);
|
||||
|
||||
// meta data version, which is currently '2'
|
||||
try leb.writeULEB128(writer, @as(u32, 2));
|
||||
|
||||
// For each subsection type (found in types.Subsection) we can emit a section.
|
||||
// Currently, we only support emitting segment info and the symbol table.
|
||||
try self.emitSymbolTable(file, arena);
|
||||
|
||||
const size = @intCast(u32, (try file.getPos()) - offset - 6);
|
||||
try writeCustomSectionHeader(file, offset, size);
|
||||
}
|
||||
|
||||
fn emitSymbolTable(self: *Wasm, file: fs.File, arena: Allocator) !void {
|
||||
// After emitting the subtype, we must emit the subsection's length
|
||||
// so first write it to a temporary arraylist to calculate the length
|
||||
// and then write all data at once.
|
||||
var payload = std.ArrayList(u8).init(arena);
|
||||
const writer = payload.writer();
|
||||
|
||||
try leb.writeULEB128(file.writer(), @enumToInt(types.SubsectionType.WASM_SYMBOL_TABLE));
|
||||
|
||||
var symbol_count: u32 = 0;
|
||||
|
||||
var atom_it = self.atoms.valueIterator();
|
||||
while (atom_it.next()) |next_atom| {
|
||||
var atom: ?*Atom = next_atom.*.getFirst();
|
||||
while (atom) |current_atom| {
|
||||
const sym_loc: SymbolLoc = .{ .file = current_atom.file, .index = current_atom.sym_index };
|
||||
const symbol = sym_loc.getSymbol(self).*;
|
||||
if (symbol.tag == .dead) continue; // Do not emit dead symbols
|
||||
symbol_count += 1;
|
||||
try leb.writeULEB128(writer, @enumToInt(symbol.tag));
|
||||
try leb.writeULEB128(writer, symbol.flags);
|
||||
|
||||
switch (symbol.tag) {
|
||||
.data => {
|
||||
const name = mem.sliceTo(symbol.name, 0);
|
||||
try leb.writeULEB128(writer, @intCast(u32, name.len));
|
||||
try writer.writeAll(name);
|
||||
|
||||
if (symbol.isDefined()) {
|
||||
try leb.writeULEB128(writer, symbol.index);
|
||||
try leb.writeULEB128(writer, @as(u32, current_atom.offset));
|
||||
try leb.writeULEB128(writer, @as(u32, current_atom.size));
|
||||
}
|
||||
},
|
||||
.section => {
|
||||
try leb.writeULEB128(writer, symbol.index);
|
||||
},
|
||||
else => {
|
||||
try leb.writeULEB128(writer, symbol.index);
|
||||
if (symbol.isDefined()) {
|
||||
const name = mem.sliceTo(symbol.name, 0);
|
||||
try leb.writeULEB128(writer, @intCast(u32, name.len));
|
||||
try writer.writeAll(name);
|
||||
}
|
||||
},
|
||||
}
|
||||
atom = current_atom.next orelse break;
|
||||
}
|
||||
}
|
||||
|
||||
var buf: [5]u8 = undefined;
|
||||
leb.writeUnsignedFixed(5, &buf, symbol_count);
|
||||
try payload.insertSlice(0, &buf);
|
||||
try leb.writeULEB128(file.writer(), @intCast(u32, payload.items.len));
|
||||
|
||||
const iovec: std.os.iovec_const = .{
|
||||
.iov_base = payload.items.ptr,
|
||||
.iov_len = payload.items.len,
|
||||
};
|
||||
try file.writevAll(&.{iovec});
|
||||
}
|
||||
|
||||
/// Searches for an a matching function signature, when not found
|
||||
/// a new entry will be made. The index of the existing/new signature will be returned.
|
||||
pub fn putOrGetFuncType(self: *Wasm, func_type: wasm.Type) !u32 {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user