feat(asm): encode indirect JMP and CALL on all four architectures
Assisted-by: GLM 5.3 Flash
This commit is contained in:
+38
-5
@@ -208,6 +208,18 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
|
||||
}
|
||||
op := ops[0]
|
||||
if op.Addr.Sym == nil || op.Addr.Sym.Pseudo != "SB" {
|
||||
// CALL (X5): an indirect call, the toolchain's JALR X1, 0(X5).
|
||||
if op.Addr.Sym == nil && op.Addr.Base != "" {
|
||||
if op.Addr.Offset != 0 || op.Addr.Index != "" {
|
||||
return nil, fmt.Errorf("CALL: invalid indirect operand %q", op.Raw)
|
||||
}
|
||||
rs1 := riscvRegNum(op.Addr.Base)
|
||||
if rs1 < 0 {
|
||||
return nil, fmt.Errorf("CALL: unknown branch register %q", op.Addr.Base)
|
||||
}
|
||||
word = riscvIType(riscvEnc{0x67, 0x0, 0x00}, 1, rs1, 0)
|
||||
return []byte{byte(word), byte(word >> 8), byte(word >> 16), byte(word >> 24)}, nil
|
||||
}
|
||||
return nil, fmt.Errorf("CALL: local branch target is not supported (use CALL sym(SB))")
|
||||
}
|
||||
if relocs != nil {
|
||||
@@ -229,6 +241,18 @@ func encodeRISCVInstr(instr *ast.Instr, pc int, offsets map[string]int, fi riscv
|
||||
return []byte{byte(word), byte(word >> 8), byte(word >> 16), byte(word >> 24)}, nil
|
||||
}
|
||||
target = labelFromOperand(ops[0])
|
||||
// JMP (X5): an indirect branch, the toolchain's JALR X0, 0(X5).
|
||||
if ops[0].Addr.Sym == nil && ops[0].Addr.Base != "" {
|
||||
if ops[0].Addr.Offset != 0 || ops[0].Addr.Index != "" {
|
||||
return nil, fmt.Errorf("JMP: invalid indirect operand %q", ops[0].Raw)
|
||||
}
|
||||
rs1 := riscvRegNum(ops[0].Addr.Base)
|
||||
if rs1 < 0 {
|
||||
return nil, fmt.Errorf("JMP: unknown branch register %q", ops[0].Addr.Base)
|
||||
}
|
||||
word = riscvIType(riscvEnc{0x67, 0x0, 0x00}, 0, rs1, 0)
|
||||
return []byte{byte(word), byte(word >> 8), byte(word >> 16), byte(word >> 24)}, nil
|
||||
}
|
||||
}
|
||||
targetOff, ok := offsets[target]
|
||||
if !ok {
|
||||
@@ -886,25 +910,34 @@ func word16(w uint16) []byte {
|
||||
}
|
||||
|
||||
// encodeRISCVJALR encodes the JALR indirect jump/call instruction.
|
||||
// Plan 9: JALR rs1, rd (2 regs) or JALR offset(rs1) (memory → rd=X1).
|
||||
// Plan 9: JALR rs1, rd (2 regs), JALR rd, offset(rs1) (the trampoline
|
||||
// form), or JALR offset(rs1) (memory → rd=X1).
|
||||
func encodeRISCVJALR(instr *ast.Instr, fi riscvFrameInfo) ([]byte, error) {
|
||||
ops := instr.Operands
|
||||
// JALR rd, offset(rs1): the memory operand's base is the jump-target
|
||||
// register, not the destination.
|
||||
if len(ops) == 2 && isMemOperand(ops[1]) {
|
||||
rd := regFromOperand(ops[0])
|
||||
rs1, imm := memFromOperandWithFrame(ops[1], fi)
|
||||
if rd < 0 || rs1 < 0 {
|
||||
return nil, fmt.Errorf("JALR: invalid register operand")
|
||||
}
|
||||
return wordLE(riscvIType(riscvEnc{0x67, 0x0, 0x00}, rd, rs1, imm)), nil
|
||||
}
|
||||
if len(ops) == 2 {
|
||||
rs1 := regFromOperand(ops[0])
|
||||
rd := regFromOperand(ops[1])
|
||||
if rd < 0 || rs1 < 0 {
|
||||
return nil, fmt.Errorf("JALR: invalid register operand")
|
||||
}
|
||||
word := riscvIType(riscvEnc{0x67, 0x0, 0x00}, rd, rs1, 0)
|
||||
return wordLE(word), nil
|
||||
return wordLE(riscvIType(riscvEnc{0x67, 0x0, 0x00}, rd, rs1, 0)), nil
|
||||
}
|
||||
if len(ops) == 1 {
|
||||
rs1, imm := memFromOperandWithFrame(ops[0], fi)
|
||||
if rs1 < 0 {
|
||||
return nil, fmt.Errorf("JALR: invalid memory operand")
|
||||
}
|
||||
word := riscvIType(riscvEnc{0x67, 0x0, 0x00}, 1, rs1, imm)
|
||||
return wordLE(word), nil
|
||||
return wordLE(riscvIType(riscvEnc{0x67, 0x0, 0x00}, 1, rs1, imm)), nil
|
||||
}
|
||||
return nil, fmt.Errorf("JALR expects 1 or 2 operands, got %d", len(ops))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user