#ifndef _ASM_INST_H
 #define _ASM_INST_H
 
+#include <linux/bitops.h>
 #include <linux/types.h>
 #include <asm/asm.h>
 #include <asm/ptrace.h>
 #define ADDR_IMMMASK_LU52ID    0xFFF0000000000000
 #define ADDR_IMMMASK_LU32ID    0x000FFFFF00000000
 #define ADDR_IMMMASK_LU12IW    0x00000000FFFFF000
+#define ADDR_IMMMASK_ORI       0x0000000000000FFF
 #define ADDR_IMMMASK_ADDU16ID  0x00000000FFFF0000
 
 #define ADDR_IMMSHIFT_LU52ID   52
+#define ADDR_IMMSBIDX_LU52ID   11
 #define ADDR_IMMSHIFT_LU32ID   32
+#define ADDR_IMMSBIDX_LU32ID   19
 #define ADDR_IMMSHIFT_LU12IW   12
+#define ADDR_IMMSBIDX_LU12IW   19
+#define ADDR_IMMSHIFT_ORI      0
+#define ADDR_IMMSBIDX_ORI      63
 #define ADDR_IMMSHIFT_ADDU16ID 16
+#define ADDR_IMMSBIDX_ADDU16ID 15
 
-#define ADDR_IMM(addr, INSN)   ((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN)
+#define ADDR_IMM(addr, INSN)   \
+       (sign_extend64(((addr & ADDR_IMMMASK_##INSN) >> ADDR_IMMSHIFT_##INSN), ADDR_IMMSBIDX_##INSN))
 
 enum reg0i15_op {
        break_op        = 0x54,
 u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm);
 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm);
 u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
-u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest);
+u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
 
 static inline bool signed_imm_check(long val, unsigned int bit)
 {
 
        lu12iw = larch_insn_gen_lu12iw(LOONGARCH_GPR_T1, ADDR_IMM(val, LU12IW));
        lu32id = larch_insn_gen_lu32id(LOONGARCH_GPR_T1, ADDR_IMM(val, LU32ID));
        lu52id = larch_insn_gen_lu52id(LOONGARCH_GPR_T1, LOONGARCH_GPR_T1, ADDR_IMM(val, LU52ID));
-       jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, 0, (val & 0xfff));
+       jirl = larch_insn_gen_jirl(0, LOONGARCH_GPR_T1, ADDR_IMM(val, ORI));
 
        return (struct plt_entry) { lu12iw, lu32id, lu52id, jirl };
 }
 
 {
        union loongarch_instruction insn;
 
+       if (imm < -SZ_512K || imm >= SZ_512K) {
+               pr_warn("The generated lu12i.w instruction is out of range.\n");
+               return INSN_BREAK;
+       }
+
        emit_lu12iw(&insn, rd, imm);
 
        return insn.word;
 {
        union loongarch_instruction insn;
 
+       if (imm < -SZ_512K || imm >= SZ_512K) {
+               pr_warn("The generated lu32i.d instruction is out of range.\n");
+               return INSN_BREAK;
+       }
+
        emit_lu32id(&insn, rd, imm);
 
        return insn.word;
 {
        union loongarch_instruction insn;
 
+       if (imm < -SZ_2K || imm >= SZ_2K) {
+               pr_warn("The generated lu52i.d instruction is out of range.\n");
+               return INSN_BREAK;
+       }
+
        emit_lu52id(&insn, rd, rj, imm);
 
        return insn.word;
 }
 
-u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest)
+u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
 {
        union loongarch_instruction insn;
 
-       emit_jirl(&insn, rj, rd, (dest - pc) >> 2);
+       if ((imm & 3) || imm < -SZ_128K || imm >= SZ_128K) {
+               pr_warn("The generated jirl instruction is out of range.\n");
+               return INSN_BREAK;
+       }
+
+       emit_jirl(&insn, rj, rd, imm >> 2);
 
        return insn.word;
 }