Skip to content

Commit e475ddb

Browse files
committed
wasm-linker: export symbols by virtual address
When exporting a data symbol, generate a regular global and use the data symbol's virtual addres as the value (init) of the global.
1 parent 86ed96d commit e475ddb

2 files changed

Lines changed: 26 additions & 42 deletions

File tree

src/link/Wasm.zig

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,6 @@ func_types: std.ArrayListUnmanaged(std.wasm.Type) = .{},
112112
functions: std.AutoArrayHashMapUnmanaged(struct { file: ?u16, index: u32 }, std.wasm.Func) = .{},
113113
/// Output global section
114114
wasm_globals: std.ArrayListUnmanaged(std.wasm.Global) = .{},
115-
/// Global symbols for exported data symbols
116-
address_globals: std.ArrayListUnmanaged(SymbolLoc) = .{},
117115
/// Memory section
118116
memories: std.wasm.Memory = .{ .limits = .{ .min = 0, .max = null } },
119117
/// Output table section
@@ -880,7 +878,6 @@ pub fn deinit(wasm: *Wasm) void {
880878
wasm.func_types.deinit(gpa);
881879
wasm.functions.deinit(gpa);
882880
wasm.wasm_globals.deinit(gpa);
883-
wasm.address_globals.deinit(gpa);
884881
wasm.function_table.deinit(gpa);
885882
wasm.tables.deinit(gpa);
886883
wasm.exports.deinit(gpa);
@@ -1879,8 +1876,13 @@ fn setupExports(wasm: *Wasm) !void {
18791876
break :blk try wasm.string_table.put(wasm.base.allocator, sym_name);
18801877
};
18811878
const exp: types.Export = if (symbol.tag == .data) exp: {
1882-
const global_index = @intCast(u32, wasm.wasm_globals.items.len + wasm.address_globals.items.len);
1883-
try wasm.address_globals.append(wasm.base.allocator, sym_loc);
1879+
const atom = wasm.symbol_atom.get(sym_loc).?;
1880+
const va = atom.getVA(wasm, symbol);
1881+
const global_index = @intCast(u32, wasm.imported_globals_count + wasm.wasm_globals.items.len);
1882+
try wasm.wasm_globals.append(wasm.base.allocator, .{
1883+
.global_type = .{ .valtype = .i32, .mutable = false },
1884+
.init = .{ .i32_const = @intCast(i32, va) },
1885+
});
18841886
break :exp .{
18851887
.name = export_name,
18861888
.kind = .global,
@@ -2741,30 +2743,18 @@ fn writeToFile(
27412743
if (wasm.wasm_globals.items.len > 0) {
27422744
const header_offset = try reserveVecSectionHeader(&binary_bytes);
27432745

2744-
var global_count: u32 = 0;
27452746
for (wasm.wasm_globals.items) |global| {
27462747
try binary_writer.writeByte(std.wasm.valtype(global.global_type.valtype));
27472748
try binary_writer.writeByte(@boolToInt(global.global_type.mutable));
27482749
try emitInit(binary_writer, global.init);
2749-
global_count += 1;
2750-
}
2751-
2752-
for (wasm.address_globals.items) |sym_loc| {
2753-
const atom = wasm.symbol_atom.get(sym_loc).?;
2754-
try binary_writer.writeByte(std.wasm.valtype(.i32));
2755-
try binary_writer.writeByte(0); // immutable
2756-
try emitInit(binary_writer, .{
2757-
.i32_const = @bitCast(i32, atom.offset),
2758-
});
2759-
global_count += 1;
27602750
}
27612751

27622752
try writeVecSectionHeader(
27632753
binary_bytes.items,
27642754
header_offset,
27652755
.global,
27662756
@intCast(u32, binary_bytes.items.len - header_offset - header_size),
2767-
@intCast(u32, global_count),
2757+
@intCast(u32, wasm.wasm_globals.items.len),
27682758
);
27692759
section_count += 1;
27702760
}

src/link/Wasm/Atom.zig

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -90,24 +90,26 @@ pub fn getFirst(atom: *Atom) *Atom {
9090
return tmp;
9191
}
9292

93-
/// Unlike `getFirst` this returns the first `*Atom` that was
94-
/// produced from Zig code, rather than an object file.
95-
/// This is useful for debug sections where we want to extend
96-
/// the bytes, and don't want to overwrite existing Atoms.
97-
pub fn getFirstZigAtom(atom: *Atom) *Atom {
98-
if (atom.file == null) return atom;
99-
var tmp = atom;
100-
return while (tmp.prev) |prev| {
101-
if (prev.file == null) break prev;
102-
tmp = prev;
103-
} else unreachable; // must allocate an Atom first!
104-
}
105-
10693
/// Returns the location of the symbol that represents this `Atom`
10794
pub fn symbolLoc(atom: Atom) Wasm.SymbolLoc {
10895
return .{ .file = atom.file, .index = atom.sym_index };
10996
}
11097

98+
/// Returns the virtual address of the `Atom`. This is the address starting
99+
/// from the first entry within a section.
100+
pub fn getVA(atom: Atom, wasm: *const Wasm, symbol: *const Symbol) u32 {
101+
if (symbol.tag == .function) return atom.offset;
102+
std.debug.assert(symbol.tag == .data);
103+
const merge_segment = wasm.base.options.output_mode != .Obj;
104+
const segment_info = if (atom.file) |object_index| blk: {
105+
break :blk wasm.objects.items[object_index].segment_info;
106+
} else wasm.segment_info.values();
107+
const segment_name = segment_info[symbol.index].outputName(merge_segment);
108+
const segment_index = wasm.data_segments.get(segment_name).?;
109+
const segment = wasm.segments.items[segment_index];
110+
return segment.offset + atom.offset;
111+
}
112+
111113
/// Resolves the relocations within the atom, writing the new value
112114
/// at the calculated offset.
113115
pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
@@ -159,7 +161,7 @@ pub fn resolveRelocs(atom: *Atom, wasm_bin: *const Wasm) void {
159161
/// The final value must be casted to the correct size.
160162
fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wasm) u64 {
161163
const target_loc = (Wasm.SymbolLoc{ .file = atom.file, .index = relocation.index }).finalLoc(wasm_bin);
162-
const symbol = target_loc.getSymbol(wasm_bin).*;
164+
const symbol = target_loc.getSymbol(wasm_bin);
163165
switch (relocation.relocation_type) {
164166
.R_WASM_FUNCTION_INDEX_LEB => return symbol.index,
165167
.R_WASM_TABLE_NUMBER_LEB => return symbol.index,
@@ -190,17 +192,9 @@ fn relocationValue(atom: Atom, relocation: types.Relocation, wasm_bin: *const Wa
190192
if (symbol.isUndefined()) {
191193
return 0;
192194
}
193-
194-
const merge_segment = wasm_bin.base.options.output_mode != .Obj;
195195
const target_atom = wasm_bin.symbol_atom.get(target_loc).?;
196-
const segment_info = if (target_atom.file) |object_index| blk: {
197-
break :blk wasm_bin.objects.items[object_index].segment_info;
198-
} else wasm_bin.segment_info.values();
199-
const segment_name = segment_info[symbol.index].outputName(merge_segment);
200-
const segment_index = wasm_bin.data_segments.get(segment_name).?;
201-
const segment = wasm_bin.segments.items[segment_index];
202-
const rel_value = @intCast(i32, target_atom.offset + segment.offset) + relocation.addend;
203-
return @intCast(u32, rel_value);
196+
const va = @intCast(i32, target_atom.getVA(wasm_bin, symbol));
197+
return @intCast(u32, va + relocation.addend);
204198
},
205199
.R_WASM_EVENT_INDEX_LEB => return symbol.index,
206200
.R_WASM_SECTION_OFFSET_I32 => {

0 commit comments

Comments
 (0)