feat(asm): encode indirect JMP and CALL on all four architectures
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -236,6 +236,11 @@ func encodeARM64Instr(instr *ast.Instr, pc int, offsets map[string]int, fi arm64
|
||||
return encodeARM64BranchCond(mnem, enc.op, ops, pc, offsets, resolve)
|
||||
}
|
||||
|
||||
// Unconditional register branches (BR, BLR).
|
||||
if enc, ok := a64InstrTable[mnem]; ok && enc.format == a64FUncondBranch {
|
||||
return encodeARM64RegBranch(mnem, enc.op, ops)
|
||||
}
|
||||
|
||||
// ADD/SUB immediate.
|
||||
if mnem == "ADD" || mnem == "ADDW" || mnem == "SUB" || mnem == "SUBW" ||
|
||||
mnem == "CMP" || mnem == "CMPW" || mnem == "CMN" || mnem == "CMNW" {
|
||||
@@ -337,6 +342,24 @@ func encodeARM64Branch(mnem string, ops []*ast.Operand, pc int, offsets map[stri
|
||||
}
|
||||
op := ops[0]
|
||||
|
||||
// Register-indirect: JMP (R0) is BR R0, CALL (R0) is BLR R0. The
|
||||
// toolchain's spelling carries no offset and no index; anything else
|
||||
// is reported rather than silently dropped.
|
||||
if op.Addr.Sym == nil && op.Addr.Base != "" {
|
||||
if op.Addr.Offset != 0 || op.Addr.Index != "" {
|
||||
return nil, fmt.Errorf("%s: invalid indirect branch operand %q", mnem, op.Raw)
|
||||
}
|
||||
rn := arm64RegNum(op.Addr.Base)
|
||||
if rn < 0 {
|
||||
return nil, fmt.Errorf("%s: unknown branch register %q", mnem, op.Addr.Base)
|
||||
}
|
||||
opc := uint32(0) // BR
|
||||
if link {
|
||||
opc = 1 // BLR
|
||||
}
|
||||
return a64wordLE(a64UncondBranch(opc, uint32(rn), 0)), nil
|
||||
}
|
||||
|
||||
// Symbol reference: BL sym(SB), or B sym(SB) for a tail call, against a
|
||||
// relocation (R_CALLARM64 either way).
|
||||
if op.Addr.Sym != nil && op.Addr.Sym.Pseudo == "SB" {
|
||||
@@ -373,6 +396,19 @@ func encodeARM64Branch(mnem string, ops []*ast.Operand, pc int, offsets map[stri
|
||||
return a64wordLE(a64Branch(bop, int32(rel))), nil
|
||||
}
|
||||
|
||||
// encodeARM64RegBranch encodes BR/BLR through a register operand:
|
||||
// BR Xn = 0xd61f0000 | Rn<<5, BLR Xn = 0xd63f0000 | Rn<<5.
|
||||
func encodeARM64RegBranch(mnem string, baseOp uint32, ops []*ast.Operand) ([]byte, error) {
|
||||
if len(ops) != 1 {
|
||||
return nil, fmt.Errorf("%s expects 1 operand, got %d", mnem, len(ops))
|
||||
}
|
||||
rn := arm64RegNum(operandRegName(ops[0]))
|
||||
if rn < 0 {
|
||||
return nil, fmt.Errorf("%s expects a register operand", mnem)
|
||||
}
|
||||
return a64wordLE(uint32(baseOp) | 31<<16 | uint32(rn)<<5), nil
|
||||
}
|
||||
|
||||
// encodeARM64BranchCond encodes a conditional branch (B.cond) to a label.
|
||||
func encodeARM64BranchCond(mnem string, baseOp uint32, ops []*ast.Operand, pc int, offsets map[string]int, resolve func(string) string) ([]byte, error) {
|
||||
if len(ops) != 1 {
|
||||
|
||||
Reference in New Issue
Block a user