aarch64: implement some safety checks

Closes #24553
This commit is contained in:
Jacob Young
2025-07-26 03:09:55 -04:00
parent 1274254c48
commit 69abc945e4
124 changed files with 1078 additions and 365 deletions

View File

@@ -47,6 +47,7 @@ pub fn generate(
.literals = .empty,
.nav_relocs = .empty,
.uav_relocs = .empty,
.lazy_relocs = .empty,
.global_relocs = .empty,
.literal_relocs = .empty,
@@ -101,8 +102,8 @@ pub fn generate(
};
switch (passed_vi.parent(&isel)) {
.unallocated => if (!mod.strip) {
var part_it = arg_vi.parts(&isel);
const first_passed_part_vi = part_it.next() orelse passed_vi;
var part_it = passed_vi.parts(&isel);
const first_passed_part_vi = part_it.next().?;
const hint_ra = first_passed_part_vi.hint(&isel).?;
passed_vi.setParent(&isel, .{ .stack_slot = if (hint_ra.isVector())
isel.va_list.__vr_top.withOffset(@as(i8, -16) *
@@ -167,6 +168,7 @@ pub fn generate(
.literals = &.{},
.nav_relocs = &.{},
.uav_relocs = &.{},
.lazy_relocs = &.{},
.global_relocs = &.{},
.literal_relocs = &.{},
};
@@ -174,6 +176,7 @@ pub fn generate(
mir.literals = try isel.literals.toOwnedSlice(gpa);
mir.nav_relocs = try isel.nav_relocs.toOwnedSlice(gpa);
mir.uav_relocs = try isel.uav_relocs.toOwnedSlice(gpa);
mir.lazy_relocs = try isel.lazy_relocs.toOwnedSlice(gpa);
mir.global_relocs = try isel.global_relocs.toOwnedSlice(gpa);
mir.literal_relocs = try isel.literal_relocs.toOwnedSlice(gpa);
return mir;

View File

@@ -6,14 +6,19 @@ pub const Operand = union(enum) {
};
pub fn nextInstruction(as: *Assemble) !?Instruction {
@setEvalBranchQuota(37_000);
@setEvalBranchQuota(42_000);
comptime var ct_token_buf: [token_buf_len]u8 = undefined;
var token_buf: [token_buf_len]u8 = undefined;
const original_source = while (true) {
const original_source = as.source;
const source_token = try as.nextToken(&token_buf, .{});
if (source_token.len == 0) return null;
if (source_token[0] != '\n') break original_source;
switch (source_token.len) {
0 => return null,
else => switch (source_token[0]) {
else => break original_source,
'\n', ';' => {},
},
}
};
log.debug(
\\.
@@ -52,7 +57,13 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
std.zig.fmtString(source_token),
});
if (pattern_token.len == 0) {
if (source_token.len > 0 and source_token[0] != '\n') break :next_pattern;
switch (source_token.len) {
0 => {},
else => switch (source_token[0]) {
else => break :next_pattern,
'\n', ';' => {},
},
}
const encode = @field(Instruction, @tagName(instruction.encode[0]));
const Encode = @TypeOf(encode);
var args: std.meta.ArgsTuple(Encode) = undefined;
@@ -65,7 +76,7 @@ pub fn nextInstruction(as: *Assemble) !?Instruction {
const symbol = &@field(symbols, symbol_name);
symbol.* = zonCast(SymbolSpec, @field(instruction.symbols, symbol_name), .{}).parse(source_token) orelse break :next_pattern;
log.debug("{s} = {any}", .{ symbol_name, symbol.* });
} else if (!std.ascii.eqlIgnoreCase(pattern_token, source_token)) break :next_pattern;
} else if (!toUpperEqlAssertUpper(source_token, pattern_token)) break :next_pattern;
}
}
log.debug("'{s}' not matched...", .{instruction.pattern});
@@ -125,6 +136,15 @@ fn zonCast(comptime Result: type, zon_value: anytype, symbols: anytype) Result {
}
}
fn toUpperEqlAssertUpper(lhs: []const u8, rhs: []const u8) bool {
if (lhs.len != rhs.len) return false;
for (lhs, rhs) |l, r| {
assert(!std.ascii.isLower(r));
if (std.ascii.toUpper(l) != r) return false;
}
return true;
}
const token_buf_len = "v31.b[15]".len;
fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
operands: bool = false,
@@ -134,7 +154,7 @@ fn nextToken(as: *Assemble, buf: *[token_buf_len]u8, comptime opts: struct {
while (true) c: switch (as.source[0]) {
0 => return as.source[0..0],
'\t', '\n' + 1...'\r', ' ' => as.source = as.source[1..],
'\n', '!', '#', ',', '[', ']' => {
'\n', '!', '#', ',', ';', '[', ']' => {
defer as.source = as.source[1..];
return as.source[0..1];
},

View File

@@ -4,6 +4,7 @@ epilogue: []const Instruction,
literals: []const u32,
nav_relocs: []const Reloc.Nav,
uav_relocs: []const Reloc.Uav,
lazy_relocs: []const Reloc.Lazy,
global_relocs: []const Reloc.Global,
literal_relocs: []const Reloc.Literal,
@@ -21,8 +22,13 @@ pub const Reloc = struct {
reloc: Reloc,
};
pub const Lazy = struct {
symbol: link.File.LazySymbol,
reloc: Reloc,
};
pub const Global = struct {
global: [*:0]const u8,
name: [*:0]const u8,
reloc: Reloc,
};
@@ -38,6 +44,7 @@ pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
gpa.free(mir.literals);
gpa.free(mir.nav_relocs);
gpa.free(mir.uav_relocs);
gpa.free(mir.lazy_relocs);
gpa.free(mir.global_relocs);
gpa.free(mir.literal_relocs);
mir.* = undefined;
@@ -119,16 +126,37 @@ pub fn emit(
body_end - Instruction.size * (1 + uav_reloc.reloc.label),
uav_reloc.reloc.addend,
);
for (mir.lazy_relocs) |lazy_reloc| try emitReloc(
lf,
zcu,
func.owner_nav,
if (lf.cast(.elf)) |ef|
ef.zigObjectPtr().?.getOrCreateMetadataForLazySymbol(ef, pt, lazy_reloc.symbol) catch |err|
return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
else if (lf.cast(.macho)) |mf|
mf.getZigObject().?.getOrCreateMetadataForLazySymbol(mf, pt, lazy_reloc.symbol) catch |err|
return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
else if (lf.cast(.coff)) |cf|
if (cf.getOrCreateAtomForLazySymbol(pt, lazy_reloc.symbol)) |atom|
cf.getAtom(atom).getSymbolIndex().?
else |err|
return zcu.codegenFail(func.owner_nav, "{s} creating lazy symbol", .{@errorName(err)})
else
return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
mir.body[lazy_reloc.reloc.label],
body_end - Instruction.size * (1 + lazy_reloc.reloc.label),
lazy_reloc.reloc.addend,
);
for (mir.global_relocs) |global_reloc| try emitReloc(
lf,
zcu,
func.owner_nav,
if (lf.cast(.elf)) |ef|
try ef.getGlobalSymbol(std.mem.span(global_reloc.global), null)
try ef.getGlobalSymbol(std.mem.span(global_reloc.name), null)
else if (lf.cast(.macho)) |mf|
try mf.getGlobalSymbol(std.mem.span(global_reloc.global), null)
try mf.getGlobalSymbol(std.mem.span(global_reloc.name), null)
else if (lf.cast(.coff)) |cf|
try cf.getGlobalSymbol(std.mem.span(global_reloc.global), "compiler_rt")
try cf.getGlobalSymbol(std.mem.span(global_reloc.name), "compiler_rt")
else
return zcu.codegenFail(func.owner_nav, "external symbols unimplemented for {s}", .{@tagName(lf.tag)}),
mir.body[global_reloc.reloc.label],
@@ -172,35 +200,6 @@ fn emitReloc(
const gpa = zcu.gpa;
switch (instruction.decode()) {
else => unreachable,
.branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
const zo = ef.zigObjectPtr().?;
const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
.b => .JUMP26,
.bl => .CALL26,
};
try atom.addReloc(gpa, .{
.r_offset = offset,
.r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
.r_addend = @bitCast(addend),
}, zo);
} else if (lf.cast(.macho)) |mf| {
const zo = mf.getZigObject().?;
const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
try atom.addReloc(mf, .{
.tag = .@"extern",
.offset = offset,
.target = sym_index,
.addend = @bitCast(addend),
.type = .branch,
.meta = .{
.pcrel = true,
.has_subtractor = false,
.length = 2,
.symbolnum = @intCast(sym_index),
},
});
},
.data_processing_immediate => |decoded| if (lf.cast(.elf)) |ef| {
const zo = ef.zigObjectPtr().?;
const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
@@ -259,6 +258,80 @@ fn emitReloc(
},
}
},
.branch_exception_generating_system => |decoded| if (lf.cast(.elf)) |ef| {
const zo = ef.zigObjectPtr().?;
const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
const r_type: std.elf.R_AARCH64 = switch (decoded.decode().unconditional_branch_immediate.group.op) {
.b => .JUMP26,
.bl => .CALL26,
};
try atom.addReloc(gpa, .{
.r_offset = offset,
.r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
.r_addend = @bitCast(addend),
}, zo);
} else if (lf.cast(.macho)) |mf| {
const zo = mf.getZigObject().?;
const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
try atom.addReloc(mf, .{
.tag = .@"extern",
.offset = offset,
.target = sym_index,
.addend = @bitCast(addend),
.type = .branch,
.meta = .{
.pcrel = true,
.has_subtractor = false,
.length = 2,
.symbolnum = @intCast(sym_index),
},
});
},
.load_store => |decoded| if (lf.cast(.elf)) |ef| {
const zo = ef.zigObjectPtr().?;
const atom = zo.symbol(try zo.getOrCreateMetadataForNav(zcu, owner_nav)).atom(ef).?;
const r_type: std.elf.R_AARCH64 = switch (decoded.decode().register_unsigned_immediate.decode()) {
.integer => |integer| switch (integer.decode()) {
.unallocated, .prfm => unreachable,
.strb, .ldrb, .ldrsb => .LDST8_ABS_LO12_NC,
.strh, .ldrh, .ldrsh => .LDST16_ABS_LO12_NC,
.ldrsw => .LDST32_ABS_LO12_NC,
inline .str, .ldr => |encoded| switch (encoded.sf) {
.word => .LDST32_ABS_LO12_NC,
.doubleword => .LDST64_ABS_LO12_NC,
},
},
.vector => |vector| switch (vector.group.opc1.decode(vector.group.size)) {
.byte => .LDST8_ABS_LO12_NC,
.half => .LDST16_ABS_LO12_NC,
.single => .LDST32_ABS_LO12_NC,
.double => .LDST64_ABS_LO12_NC,
.quad => .LDST128_ABS_LO12_NC,
.scalable, .predicate => unreachable,
},
};
try atom.addReloc(gpa, .{
.r_offset = offset,
.r_info = @as(u64, sym_index) << 32 | @intFromEnum(r_type),
.r_addend = @bitCast(addend),
}, zo);
} else if (lf.cast(.macho)) |mf| {
const zo = mf.getZigObject().?;
const atom = zo.symbols.items[try zo.getOrCreateMetadataForNav(mf, owner_nav)].getAtom(mf).?;
try atom.addReloc(mf, .{
.tag = .@"extern",
.offset = offset,
.target = sym_index,
.addend = @bitCast(addend),
.type = .pageoff,
.meta = .{
.pcrel = false,
.has_subtractor = false,
.length = 2,
.symbolnum = @intCast(sym_index),
},
});
},
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -213,6 +213,63 @@
},
.encode = .{ .ands, .Xd, .Xn, .{ .shifted_register_explicit = .{ .register = .Xm, .shift = .shift, .amount = .amount } } },
},
// C6.2.16 ASR (register)
.{
.pattern = "ASR <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .asrv, .Wd, .Wn, .Wm },
},
.{
.pattern = "ASR <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .asrv, .Xd, .Xn, .Xm },
},
// C6.2.17 ASR (immediate)
.{
.pattern = "ASR <Wd>, <Wn>, #<shift>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
},
.encode = .{ .sbfm, .Wd, .Wn, .{ .N = .word, .immr = .shift, .imms = 31 } },
},
.{
.pattern = "ASR <Xd>, <Xn>, #<shift>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
},
.encode = .{ .sbfm, .Xd, .Xn, .{ .N = .doubleword, .immr = .shift, .imms = 63 } },
},
// C6.2.18 ASRV
.{
.pattern = "ASRV <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .asrv, .Wd, .Wn, .Wm },
},
.{
.pattern = "ASRV <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .asrv, .Xd, .Xn, .Xm },
},
// C6.2.35 BLR
.{
.pattern = "BLR <Xn>",
@@ -681,6 +738,82 @@
},
.encode = .{ .ldr, .Xt, .{ .unsigned_offset = .{ .base = .Xn, .offset = .pimm } } },
},
// C6.2.212 LSL (register)
.{
.pattern = "LSL <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .lslv, .Wd, .Wn, .Wm },
},
.{
.pattern = "LSL <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .lslv, .Xd, .Xn, .Xm },
},
// C6.2.214 LSLV
.{
.pattern = "LSLV <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .lslv, .Wd, .Wn, .Wm },
},
.{
.pattern = "LSLV <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .lslv, .Xd, .Xn, .Xm },
},
// C6.2.215 LSR (register)
.{
.pattern = "LSR <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .lsrv, .Wd, .Wn, .Wm },
},
.{
.pattern = "LSR <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .lsrv, .Xd, .Xn, .Xm },
},
// C6.2.217 LSRV
.{
.pattern = "LSRV <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .lsrv, .Wd, .Wn, .Wm },
},
.{
.pattern = "LSRV <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .lsrv, .Xd, .Xn, .Xm },
},
// C6.2.220 MOV (to/from SP)
.{
.pattern = "MOV WSP, <Wn|WSP>",
@@ -964,6 +1097,63 @@
},
.encode = .{ .ret, .Xn },
},
// C6.2.261 ROR (immediate)
.{
.pattern = "ROR <Wd>, <Ws>, #<shift>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Ws = .{ .reg = .{ .format = .{ .integer = .word } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 5 } } },
},
.encode = .{ .extr, .Wd, .Ws, .Ws, .shift },
},
.{
.pattern = "ROR <Xd>, <Xs>, #<shift>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xs = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.shift = .{ .imm = .{ .type = .{ .signedness = .unsigned, .bits = 6 } } },
},
.encode = .{ .extr, .Xd, .Xs, .Xs, .shift },
},
// C6.2.262 ROR (register)
.{
.pattern = "ROR <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .rorv, .Wd, .Wn, .Wm },
},
.{
.pattern = "ROR <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .rorv, .Xd, .Xn, .Xm },
},
// C6.2.263 RORV
.{
.pattern = "RORV <Wd>, <Wn>, <Wm>",
.symbols = .{
.Wd = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wn = .{ .reg = .{ .format = .{ .integer = .word } } },
.Wm = .{ .reg = .{ .format = .{ .integer = .word } } },
},
.encode = .{ .rorv, .Wd, .Wn, .Wm },
},
.{
.pattern = "RORV <Xd>, <Xn>, <Xm>",
.symbols = .{
.Xd = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xn = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
.Xm = .{ .reg = .{ .format = .{ .integer = .doubleword } } },
},
.encode = .{ .rorv, .Xd, .Xn, .Xm },
},
// C6.2.268 SBFM
.{
.pattern = "SBFM <Wd>, <Wn>, #<immr>, #<imms>",