Skip to content

Commit bb084e2

Browse files
committed
implement function relocations
not all relocation types are implemented yet
1 parent fb08459 commit bb084e2

File tree

2 files changed

+188
-14
lines changed

2 files changed

+188
-14
lines changed

src/link/Wasm.zig

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,10 @@ pub const OutputFunctionIndex = enum(u32) {
349349
return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));
350350
}
351351

352+
pub fn fromObjectFunction(wasm: *const Wasm, index: ObjectFunctionIndex) OutputFunctionIndex {
353+
return fromResolution(wasm, .fromObjectFunction(wasm, index)).?;
354+
}
355+
352356
pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) OutputFunctionIndex {
353357
const zcu = wasm.base.comp.zcu.?;
354358
const ip = &zcu.intern_pool;
@@ -401,6 +405,33 @@ pub const GlobalIndex = enum(u32) {
401405
const i = wasm.globals.getIndex(.fromIpNav(wasm, nav_index)) orelse return null;
402406
return @enumFromInt(i);
403407
}
408+
409+
pub fn fromObjectGlobal(wasm: *const Wasm, i: ObjectGlobalIndex) GlobalIndex {
410+
return @enumFromInt(wasm.globals.getIndex(.fromObjectGlobal(wasm, i)).?);
411+
}
412+
413+
pub fn fromSymbolName(wasm: *const Wasm, name: String) GlobalIndex {
414+
const import = wasm.object_global_imports.getPtr(name).?;
415+
return @enumFromInt(wasm.globals.getIndex(import.resolution).?);
416+
}
417+
};
418+
419+
/// Index into `tables`.
420+
pub const TableIndex = enum(u32) {
421+
_,
422+
423+
pub fn ptr(index: TableIndex, f: *const Flush) *Wasm.TableImport.Resolution {
424+
return &f.tables.items[@intFromEnum(index)];
425+
}
426+
427+
pub fn fromObjectTable(wasm: *const Wasm, i: ObjectTableIndex) TableIndex {
428+
return @enumFromInt(wasm.tables.getIndex(.fromObjectTable(i)).?);
429+
}
430+
431+
pub fn fromSymbolName(wasm: *const Wasm, name: String) TableIndex {
432+
const import = wasm.object_table_imports.getPtr(name).?;
433+
return @enumFromInt(wasm.tables.getIndex(import.resolution).?);
434+
}
404435
};
405436

406437
/// The first N indexes correspond to input objects (`objects`) array.
@@ -1019,7 +1050,7 @@ pub const ObjectFunction = extern struct {
10191050

10201051
pub const Code = DataPayload;
10211052

1022-
fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1053+
pub fn relocations(of: *const ObjectFunction, wasm: *const Wasm) ObjectRelocation.IterableSlice {
10231054
const code_section_index = of.object_index.ptr(wasm).code_section_index.?;
10241055
const relocs = wasm.object_relocations_table.get(code_section_index) orelse return .empty;
10251056
return .init(relocs, of.offset, of.code.len, wasm);
@@ -1181,7 +1212,7 @@ pub const ObjectGlobal = extern struct {
11811212
mutable: bool,
11821213
};
11831214

1184-
fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1215+
pub fn relocations(og: *const ObjectGlobal, wasm: *const Wasm) ObjectRelocation.IterableSlice {
11851216
const global_section_index = og.object_index.ptr(wasm).global_section_index.?;
11861217
const relocs = wasm.object_relocations_table.get(global_section_index) orelse return .empty;
11871218
return .init(relocs, og.offset, og.size, wasm);
@@ -1440,7 +1471,7 @@ pub const ObjectDataSegment = extern struct {
14401471
}
14411472
};
14421473

1443-
fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice {
1474+
pub fn relocations(ods: *const ObjectDataSegment, wasm: *const Wasm) ObjectRelocation.IterableSlice {
14441475
const data_section_index = ods.object_index.ptr(wasm).data_section_index.?;
14451476
const relocs = wasm.object_relocations_table.get(data_section_index) orelse return .empty;
14461477
return .init(relocs, ods.offset, ods.payload.len, wasm);
@@ -1563,6 +1594,10 @@ pub const DataId = enum(u32) {
15631594
};
15641595
}
15651596

1597+
pub fn fromObjectDataSegment(wasm: *const Wasm, object_data_segment: ObjectDataSegment.Index) DataId {
1598+
return pack(wasm, .{ .object = object_data_segment });
1599+
}
1600+
15661601
pub fn category(id: DataId, wasm: *const Wasm) Category {
15671602
return switch (unpack(id, wasm)) {
15681603
.__zig_error_names, .__zig_error_name_table => .data,
@@ -2258,19 +2293,19 @@ pub const ObjectRelocation = struct {
22582293

22592294
const empty: Slice = .{ .off = 0, .len = 0 };
22602295

2261-
fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag {
2296+
pub fn tags(s: Slice, wasm: *const Wasm) []const ObjectRelocation.Tag {
22622297
return wasm.object_relocations.items(.tag)[s.off..][0..s.len];
22632298
}
22642299

2265-
fn offsets(s: Slice, wasm: *const Wasm) []const u32 {
2300+
pub fn offsets(s: Slice, wasm: *const Wasm) []const u32 {
22662301
return wasm.object_relocations.items(.offset)[s.off..][0..s.len];
22672302
}
22682303

2269-
fn pointees(s: Slice, wasm: *const Wasm) []const Pointee {
2304+
pub fn pointees(s: Slice, wasm: *const Wasm) []const Pointee {
22702305
return wasm.object_relocations.items(.pointee)[s.off..][0..s.len];
22712306
}
22722307

2273-
fn addends(s: Slice, wasm: *const Wasm) []const i32 {
2308+
pub fn addends(s: Slice, wasm: *const Wasm) []const i32 {
22742309
return wasm.object_relocations.items(.addend)[s.off..][0..s.len];
22752310
}
22762311
};
@@ -3137,7 +3172,7 @@ fn markDataSegment(wasm: *Wasm, segment_index: ObjectDataSegment.Index) link.Fil
31373172
}
31383173

31393174
fn markRelocations(wasm: *Wasm, relocs: ObjectRelocation.IterableSlice) link.File.FlushError!void {
3140-
for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, *pointee, offset| {
3175+
for (relocs.slice.tags(wasm), relocs.slice.pointees(wasm), relocs.slice.offsets(wasm)) |tag, pointee, offset| {
31413176
if (offset >= relocs.end) break;
31423177
switch (tag) {
31433178
.function_import_index_leb,

src/link/Wasm/Flush.zig

Lines changed: 145 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -683,10 +683,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
683683
.__wasm_init_memory => @panic("TODO lower __wasm_init_memory "),
684684
.__wasm_init_tls => @panic("TODO lower __wasm_init_tls "),
685685
.object_function => |i| {
686-
_ = i;
687-
@panic("TODO lower object function code and apply relocations");
688-
//try leb.writeUleb128(binary_writer, atom.code.len);
689-
//try binary_bytes.appendSlice(gpa, atom.code.slice(wasm));
686+
const ptr = i.ptr(wasm);
687+
const code = ptr.code.slice(wasm);
688+
try leb.writeUleb128(binary_writer, code.len);
689+
const code_start = binary_bytes.items.len;
690+
try binary_bytes.appendSlice(gpa, code);
691+
if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm);
690692
},
691693
.zcu_func => |i| {
692694
const code_start = try reserveSize(gpa, binary_bytes);
@@ -699,7 +701,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
699701
};
700702

701703
replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len));
702-
if (is_obj) @panic("TODO apply offset to code relocs");
703704
code_section_index = section_index;
704705
section_index += 1;
705706
}
@@ -801,7 +802,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
801802
}
802803

803804
if (is_obj) {
804-
@panic("TODO emit link section for object file and apply relocations");
805+
@panic("TODO emit link section for object file and emit modified relocations");
805806
//var symbol_table = std.AutoArrayHashMap(SymbolLoc, u32).init(arena);
806807
//try wasm.emitLinkSection(binary_bytes, &symbol_table);
807808
//if (code_section_index) |code_index| {
@@ -1420,3 +1421,141 @@ fn emitErrorNameTable(
14201421
mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little);
14211422
}
14221423
}
1424+
1425+
fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.IterableSlice, wasm: *const Wasm) void {
1426+
for (
1427+
relocs.slice.tags(wasm),
1428+
relocs.slice.pointees(wasm),
1429+
relocs.slice.offsets(wasm),
1430+
relocs.slice.addends(wasm),
1431+
) |tag, pointee, offset, *addend| {
1432+
if (offset >= relocs.end) break;
1433+
const sliced_code = code[offset - code_offset ..];
1434+
switch (tag) {
1435+
.function_index_i32 => reloc_u32_function(sliced_code, .fromObjectFunction(wasm, pointee.function)),
1436+
.function_index_leb => reloc_leb_function(sliced_code, .fromObjectFunction(wasm, pointee.function)),
1437+
.function_offset_i32 => @panic("TODO this value is not known yet"),
1438+
.function_offset_i64 => @panic("TODO this value is not known yet"),
1439+
.table_index_i32 => @panic("TODO indirect function table needs to support object functions too"),
1440+
.table_index_i64 => @panic("TODO indirect function table needs to support object functions too"),
1441+
.table_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"),
1442+
.table_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1443+
.table_index_sleb => @panic("TODO indirect function table needs to support object functions too"),
1444+
.table_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1445+
1446+
.function_import_index_i32 => reloc_u32_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1447+
.function_import_index_leb => reloc_leb_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1448+
.function_import_offset_i32 => @panic("TODO this value is not known yet"),
1449+
.function_import_offset_i64 => @panic("TODO this value is not known yet"),
1450+
.table_import_index_i32 => @panic("TODO indirect function table needs to support object functions too"),
1451+
.table_import_index_i64 => @panic("TODO indirect function table needs to support object functions too"),
1452+
.table_import_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"),
1453+
.table_import_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1454+
.table_import_index_sleb => @panic("TODO indirect function table needs to support object functions too"),
1455+
.table_import_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"),
1456+
1457+
.global_index_i32 => reloc_u32_global(sliced_code, .fromObjectGlobal(wasm, pointee.global)),
1458+
.global_index_leb => reloc_leb_global(sliced_code, .fromObjectGlobal(wasm, pointee.global)),
1459+
1460+
.global_import_index_i32 => reloc_u32_global(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1461+
.global_import_index_leb => reloc_leb_global(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1462+
1463+
.memory_addr_i32 => reloc_u32_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1464+
.memory_addr_i64 => reloc_u64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1465+
.memory_addr_leb => reloc_leb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1466+
.memory_addr_leb64 => reloc_leb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1467+
.memory_addr_locrel_i32 => @panic("TODO implement relocation memory_addr_locrel_i32"),
1468+
.memory_addr_rel_sleb => @panic("TODO implement relocation memory_addr_rel_sleb"),
1469+
.memory_addr_rel_sleb64 => @panic("TODO implement relocation memory_addr_rel_sleb64"),
1470+
.memory_addr_sleb => reloc_sleb_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1471+
.memory_addr_sleb64 => reloc_sleb64_addr(sliced_code, .fromObjectData(wasm, pointee.data, addend.*)),
1472+
.memory_addr_tls_sleb => @panic("TODO implement relocation memory_addr_tls_sleb"),
1473+
.memory_addr_tls_sleb64 => @panic("TODO implement relocation memory_addr_tls_sleb64"),
1474+
1475+
.memory_addr_import_i32 => reloc_u32_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1476+
.memory_addr_import_i64 => reloc_u64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1477+
.memory_addr_import_leb => reloc_leb_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1478+
.memory_addr_import_leb64 => reloc_leb64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1479+
.memory_addr_import_locrel_i32 => @panic("TODO implement relocation memory_addr_import_locrel_i32"),
1480+
.memory_addr_import_rel_sleb => @panic("TODO implement relocation memory_addr_import_rel_sleb"),
1481+
.memory_addr_import_rel_sleb64 => @panic("TODO implement memory_addr_import_rel_sleb64"),
1482+
.memory_addr_import_sleb => reloc_sleb_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1483+
.memory_addr_import_sleb64 => reloc_sleb64_addr(sliced_code, .fromSymbolName(wasm, pointee.symbol_name, addend.*)),
1484+
.memory_addr_import_tls_sleb => @panic("TODO"),
1485+
.memory_addr_import_tls_sleb64 => @panic("TODO"),
1486+
1487+
.section_offset_i32 => @panic("TODO this value is not known yet"),
1488+
1489+
.table_number_leb => reloc_leb_table(sliced_code, .fromObjectTable(wasm, pointee.table)),
1490+
.table_import_number_leb => reloc_leb_table(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)),
1491+
1492+
.type_index_leb => reloc_leb_type(sliced_code, pointee.type_index),
1493+
}
1494+
}
1495+
}
1496+
1497+
fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void {
1498+
mem.writeInt(u32, code[0..4], @intFromEnum(function), .little);
1499+
}
1500+
1501+
fn reloc_leb_function(code: []u8, function: Wasm.OutputFunctionIndex) void {
1502+
leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(function));
1503+
}
1504+
1505+
fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void {
1506+
mem.writeInt(u32, code[0..4], @intFromEnum(global), .little);
1507+
}
1508+
1509+
fn reloc_leb_global(code: []u8, global: Wasm.GlobalIndex) void {
1510+
leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(global));
1511+
}
1512+
1513+
const RelocAddr = struct {
1514+
addr: u32,
1515+
1516+
fn fromObjectData(wasm: *const Wasm, i: Wasm.ObjectData.Index, addend: i32) RelocAddr {
1517+
const ptr = i.ptr(wasm);
1518+
const f = &wasm.flush_buffer;
1519+
const addr = f.data_segments.get(.fromObjectDataSegment(wasm, ptr.segment)).?;
1520+
return .{ .addr = @intCast(@as(i64, addr) + addend) };
1521+
}
1522+
1523+
fn fromSymbolName(wasm: *const Wasm, name: String, addend: i32) RelocAddr {
1524+
_ = wasm;
1525+
_ = name;
1526+
_ = addend;
1527+
@panic("TODO implement data symbol resolution");
1528+
}
1529+
};
1530+
1531+
fn reloc_u32_addr(code: []u8, ra: RelocAddr) void {
1532+
mem.writeInt(u32, code[0..4], ra.addr, .little);
1533+
}
1534+
1535+
fn reloc_u64_addr(code: []u8, ra: RelocAddr) void {
1536+
mem.writeInt(u64, code[0..8], ra.addr, .little);
1537+
}
1538+
1539+
fn reloc_leb_addr(code: []u8, ra: RelocAddr) void {
1540+
leb.writeUnsignedFixed(5, code[0..5], ra.addr);
1541+
}
1542+
1543+
fn reloc_leb64_addr(code: []u8, ra: RelocAddr) void {
1544+
leb.writeUnsignedFixed(11, code[0..11], ra.addr);
1545+
}
1546+
1547+
fn reloc_sleb_addr(code: []u8, ra: RelocAddr) void {
1548+
leb.writeSignedFixed(5, code[0..5], ra.addr);
1549+
}
1550+
1551+
fn reloc_sleb64_addr(code: []u8, ra: RelocAddr) void {
1552+
leb.writeSignedFixed(11, code[0..11], ra.addr);
1553+
}
1554+
1555+
fn reloc_leb_table(code: []u8, table: Wasm.TableIndex) void {
1556+
leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(table));
1557+
}
1558+
1559+
fn reloc_leb_type(code: []u8, index: Wasm.FunctionType.Index) void {
1560+
leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index));
1561+
}

0 commit comments

Comments
 (0)