diff --git a/asm/arm64_assemble.go b/asm/arm64_assemble.go index b9b178b..e121887 100644 --- a/asm/arm64_assemble.go +++ b/asm/arm64_assemble.go @@ -2856,8 +2856,14 @@ func encodeARM64Sys(mnem string, ops []*ast.Operand) ([]byte, error) { } return a64wordLE(0xd503201f | uint32(v)<<5), nil case "BTI": + // The toolchain requires the landing-pad kind: bare BTI is + // rejected ("missing operand"), and only the uppercase C/J/JC + // spellings assemble (0xd503245f/49f/4df). + if len(ops) != 1 { + return nil, fmt.Errorf("%s expects C, J, or JC", mnem) + } op := operandRegName(ops[0]) - base, ok := map[string]uint32{"C": 0xd503245f}[op] + base, ok := map[string]uint32{"C": 0xd503245f, "J": 0xd503249f, "JC": 0xd50324df}[op] if !ok { return nil, fmt.Errorf("%s: unknown kind %q", mnem, op) } diff --git a/asm/arm64_encode_test.go b/asm/arm64_encode_test.go index 8b25270..374a7de 100644 --- a/asm/arm64_encode_test.go +++ b/asm/arm64_encode_test.go @@ -675,6 +675,36 @@ func TestArm64AcquireRelease(t *testing.T) { } } +// TestArm64BTI pins the landing-pad family against the toolchain words: +// only the uppercase C/J/JC spellings assemble, and bare BTI is a +// diagnostic, never a panic. +func TestArm64BTI(t *testing.T) { + got := arm64Words(t, "\tBTI C\n\tBTI J\n\tBTI JC\n") + want := []uint32{ + 0xd503245f, // BTI C + 0xd503249f, // BTI J + 0xd50324df, // BTI JC + 0xd65f03c0, // RET + } + if len(got) != len(want) { + t.Fatalf("got %d words, want %d", len(got), len(want)) + } + for i := range want { + if got[i] != want[i] { + t.Errorf("word %d = %#x, want %#x", i, got[i], want[i]) + } + } + for _, src := range []string{"\tBTI\n", "\tBTI c\n", "\tBTI B\n"} { + f, errs := parser.Parse("test_arm64.s", "#include \"textflag.h\"\n\nTEXT ·f(SB), NOSPLIT, $0-0\n"+src+"\tRET\n") + if len(errs) > 0 { + continue + } + if _, err := AssembleFileARM64(f); err == nil { + t.Errorf("BTI spelling %q should be rejected, as go tool asm rejects it", src) + } + } +} + // TestArm64System pins BRK, SVC, the barriers, cache maintenance and the // system register accesses. func TestArm64System(t *testing.T) {