feat(asm): encode indirect JMP and CALL on all four architectures
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -6,6 +6,7 @@ package asm
|
||||
import (
|
||||
"fmt"
|
||||
"math/bits"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"sourcedock.dev/petrbalvin/gasm-devkit/ast"
|
||||
@@ -258,6 +259,9 @@ func encodeLOONG64Instr(instr *ast.Instr, pc int, offsets map[string]int, fi loo
|
||||
|
||||
// 16-bit branches (BEQ/BNE/BLT/BGE/BLTU/BGEU) and JIRL.
|
||||
if op, ok := l64branchTable[mnem]; ok {
|
||||
if mnem == "JIRL" {
|
||||
return encodeLOONG64Jirl(op, ops)
|
||||
}
|
||||
return encodeLOONG64Branch16(mnem, op, ops, pc, offsets, resolve)
|
||||
}
|
||||
// Single-register branches with 21-bit offsets (BLTZ/BGEZ/BLEZ/BGTZ,
|
||||
@@ -554,6 +558,46 @@ func encodeLOONG64Branch(instr *ast.Instr, mnem string, pc int, offsets map[stri
|
||||
return l64wordLE(l64bbl(opc, v)), nil
|
||||
}
|
||||
|
||||
// encodeLOONG64Jirl encodes the raw JIRL spelling, JIRL rd, rj, offset, the
|
||||
// form the verify trampolines use. The (rj) indirect form without an offset
|
||||
// is handled by encodeLOONG64Branch.
|
||||
func encodeLOONG64Jirl(op uint32, ops []*ast.Operand) ([]byte, error) {
|
||||
if len(ops) != 3 {
|
||||
return nil, fmt.Errorf("JIRL expects 3 operands, got %d", len(ops))
|
||||
}
|
||||
rd := l64Reg(ops[0])
|
||||
rj := l64Reg(ops[1])
|
||||
if rd < 0 || rj < 0 {
|
||||
return nil, fmt.Errorf("invalid register operand")
|
||||
}
|
||||
off, ok := l64offsetOperand(ops[2])
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("JIRL expects an immediate offset, got %q", ops[2].Raw)
|
||||
}
|
||||
if (int64(off)<<16)>>16 != int64(off) {
|
||||
return nil, fmt.Errorf("JIRL offset %d out of the 16-bit range", off)
|
||||
}
|
||||
return l64wordLE(l64irr16(op, int(off), rj, rd)), nil
|
||||
}
|
||||
|
||||
// l64offsetOperand reads a bare numeric branch offset: an immediate ($n) or a
|
||||
// plain number, which parses as an empty address carrying the digits in Raw.
|
||||
func l64offsetOperand(op *ast.Operand) (int32, bool) {
|
||||
if op.Imm.HasVal {
|
||||
v := op.Imm.Val
|
||||
if op.Imm.Neg {
|
||||
v = -v
|
||||
}
|
||||
return int32(v), true
|
||||
}
|
||||
if op.Kind == ast.OpAddr && op.Addr.Sym == nil && op.Addr.Base == "" && op.Addr.Index == "" {
|
||||
if v, err := strconv.ParseInt(op.Raw, 0, 64); err == nil {
|
||||
return int32(v), true
|
||||
}
|
||||
}
|
||||
return 0, false
|
||||
}
|
||||
|
||||
// encodeLOONG64Branch16 encodes a 16-bit branch (BEQ/BNE/BLT/BGE/BLTU/BGEU):
|
||||
// INSTR rj, rd, label, or INSTR rj, label with rd = R0, which the toolchain
|
||||
// turns into the 21-bit BEQZ/BNEZ form when the register is the only operand.
|
||||
|
||||
Reference in New Issue
Block a user