wasm linker: fix relocation parsing

This commit is contained in:
Andrew Kelley 2024-12-23 13:53:13 -08:00
parent 9cd7cad42e
commit 4b9dc2922f
2 changed files with 62 additions and 7 deletions

View File

@ -1955,6 +1955,8 @@ pub const ObjectRelocation = struct {
symbol_name: String,
type_index: FunctionType.Index,
section: ObjectSectionIndex,
data_segment: ObjectDataSegmentIndex,
function: Wasm.ObjectFunctionIndex,
};
pub const Slice = extern struct {
@ -1968,14 +1970,17 @@ pub const ObjectRelocation = struct {
};
pub const Tag = enum(u8) {
/// Uses `symbol_name`.
/// Uses `function`.
FUNCTION_INDEX_LEB = 0,
/// Uses `table_index`.
TABLE_INDEX_SLEB = 1,
/// Uses `table_index`.
TABLE_INDEX_I32 = 2,
/// Uses `data_segment`.
MEMORY_ADDR_LEB = 3,
/// Uses `data_segment`.
MEMORY_ADDR_SLEB = 4,
/// Uses `data_segment`.
MEMORY_ADDR_I32 = 5,
/// Uses `type_index`.
TYPE_INDEX_LEB = 6,
@ -1984,23 +1989,31 @@ pub const ObjectRelocation = struct {
FUNCTION_OFFSET_I32 = 8,
SECTION_OFFSET_I32 = 9,
TAG_INDEX_LEB = 10,
/// Uses `data_segment`.
MEMORY_ADDR_REL_SLEB = 11,
TABLE_INDEX_REL_SLEB = 12,
/// Uses `symbol_name`.
GLOBAL_INDEX_I32 = 13,
/// Uses `data_segment`.
MEMORY_ADDR_LEB64 = 14,
/// Uses `data_segment`.
MEMORY_ADDR_SLEB64 = 15,
/// Uses `data_segment`.
MEMORY_ADDR_I64 = 16,
/// Uses `data_segment`.
MEMORY_ADDR_REL_SLEB64 = 17,
/// Uses `table_index`.
TABLE_INDEX_SLEB64 = 18,
/// Uses `table_index`.
TABLE_INDEX_I64 = 19,
TABLE_NUMBER_LEB = 20,
/// Uses `data_segment`.
MEMORY_ADDR_TLS_SLEB = 21,
FUNCTION_OFFSET_I64 = 22,
/// Uses `data_segment`.
MEMORY_ADDR_LOCREL_I32 = 23,
TABLE_INDEX_REL_SLEB64 = 24,
/// Uses `data_segment`.
MEMORY_ADDR_TLS_SLEB64 = 25,
/// Uses `symbol_name`.
FUNCTION_INDEX_I32 = 26,
@ -2282,6 +2295,7 @@ fn openParseObjectReportingFailure(wasm: *Wasm, path: Path) void {
}
fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
log.debug("parseObject {}", .{obj.path});
const gpa = wasm.base.comp.gpa;
const gc_sections = wasm.base.gc_sections;
@ -2305,6 +2319,7 @@ fn parseObject(wasm: *Wasm, obj: link.Input.Object) !void {
}
fn parseArchive(wasm: *Wasm, obj: link.Input.Object) !void {
log.debug("parseArchive {}", .{obj.path});
const gpa = wasm.base.comp.gpa;
const gc_sections = wasm.base.gc_sections;
@ -2567,7 +2582,9 @@ pub fn loadInput(wasm: *Wasm, input: link.Input) !void {
.res => unreachable,
.dso_exact => unreachable,
.dso => unreachable,
.object, .archive => |obj| try argv.append(gpa, try obj.path.toString(comp.arena)),
.object, .archive => |obj| {
try argv.append(gpa, try obj.path.toString(comp.arena));
},
}
}

View File

@ -140,7 +140,7 @@ pub const ScratchSpace = struct {
const FuncImportIndex = enum(u32) {
_,
fn ptr(index: FunctionImport, ss: *const ScratchSpace) *FunctionImport {
fn ptr(index: FuncImportIndex, ss: *const ScratchSpace) *FunctionImport {
return &ss.func_imports.items[@intFromEnum(index)];
}
};
@ -351,10 +351,13 @@ pub fn parse(
.function => {
const local_index, pos = readLeb(u32, bytes, pos);
if (symbol.flags.undefined) {
symbol.pointee = .{ .function_import = @enumFromInt(local_index) };
const function_import: ScratchSpace.FuncImportIndex = @enumFromInt(local_index);
symbol.pointee = .{ .function_import = function_import };
if (symbol.flags.explicit_name) {
const name, pos = readBytes(bytes, pos);
symbol.name = (try wasm.internString(name)).toOptional();
} else {
symbol.name = function_import.ptr(ss).name.toOptional();
}
} else {
symbol.pointee = .{ .function = @enumFromInt(functions_start + local_index) };
@ -365,10 +368,13 @@ pub fn parse(
.global => {
const local_index, pos = readLeb(u32, bytes, pos);
if (symbol.flags.undefined) {
symbol.pointee = .{ .global_import = @enumFromInt(global_imports_start + local_index) };
const global_import: Wasm.GlobalImport.Index = @enumFromInt(global_imports_start + local_index);
symbol.pointee = .{ .global_import = global_import };
if (symbol.flags.explicit_name) {
const name, pos = readBytes(bytes, pos);
symbol.name = (try wasm.internString(name)).toOptional();
} else {
symbol.name = global_import.key(wasm).toOptional();
}
} else {
symbol.pointee = .{ .global = @enumFromInt(globals_start + local_index) };
@ -380,10 +386,13 @@ pub fn parse(
table_count += 1;
const local_index, pos = readLeb(u32, bytes, pos);
if (symbol.flags.undefined) {
symbol.pointee = .{ .table_import = @enumFromInt(table_imports_start + local_index) };
const table_import: Wasm.TableImport.Index = @enumFromInt(table_imports_start + local_index);
symbol.pointee = .{ .table_import = table_import };
if (symbol.flags.explicit_name) {
const name, pos = readBytes(bytes, pos);
symbol.name = (try wasm.internString(name)).toOptional();
} else {
symbol.name = table_import.key(wasm).toOptional();
}
} else {
symbol.pointee = .{ .table = @enumFromInt(tables_start + local_index) };
@ -439,10 +448,39 @@ pub fn parse(
.MEMORY_ADDR_TLS_SLEB,
.MEMORY_ADDR_LOCREL_I32,
.MEMORY_ADDR_TLS_SLEB64,
=> {
const addend: i32, pos = readLeb(i32, bytes, pos);
const sym_section = ss.symbol_table.items[index].pointee.data;
if (sym_section.segment_offset != 0) {
return diags.failParse(path, "data symbol {d} has nonzero offset {d}", .{
index, sym_section.segment_offset,
});
}
const seg_size = sym_section.segment_index.ptr(wasm).payload.len;
if (sym_section.size != seg_size) {
return diags.failParse(path, "data symbol {d} has size {d}, inequal to corresponding data segment {d} size {d}", .{
index, sym_section.size, @intFromEnum(sym_section.segment_index), seg_size,
});
}
wasm.object_relocations.appendAssumeCapacity(.{
.tag = tag,
.offset = offset,
.pointee = .{ .data_segment = sym_section.segment_index },
.addend = addend,
});
},
.FUNCTION_OFFSET_I32,
.SECTION_OFFSET_I32,
.FUNCTION_OFFSET_I64,
=> {
const addend: i32, pos = readLeb(i32, bytes, pos);
wasm.object_relocations.appendAssumeCapacity(.{
.tag = tag,
.offset = offset,
.pointee = .{ .function = ss.symbol_table.items[index].pointee.function },
.addend = addend,
});
},
.SECTION_OFFSET_I32 => {
const addend: i32, pos = readLeb(i32, bytes, pos);
wasm.object_relocations.appendAssumeCapacity(.{
.tag = tag,