#include <linux/pgtable.h>
 #include <asm/sections.h>
 
+/*
+ * The auipc+jalr instruction pair can reach any PC-relative offset
+ * in the range [-2^31 - 2^11, 2^31 - 2^11)
+ */
+static bool riscv_insn_valid_32bit_offset(ptrdiff_t val)
+{
+#ifdef CONFIG_32BIT
+       return true;
+#else
+       return (-(1L << 31) - (1L << 11)) <= val && val < ((1L << 31) - (1L << 11));
+#endif
+}
+
 static int apply_r_riscv_32_rela(struct module *me, u32 *location, Elf_Addr v)
 {
        if (v != (u32)v) {
        ptrdiff_t offset = (void *)v - (void *)location;
        s32 hi20;
 
-       if (offset != (s32)offset) {
+       if (!riscv_insn_valid_32bit_offset(offset)) {
                pr_err(
                  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
                  me->name, (long long)v, location);
                                       Elf_Addr v)
 {
        ptrdiff_t offset = (void *)v - (void *)location;
-       s32 fill_v = offset;
        u32 hi20, lo12;
 
-       if (offset != fill_v) {
+       if (!riscv_insn_valid_32bit_offset(offset)) {
                /* Only emit the plt entry if offset over 32-bit range */
                if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) {
                        offset = module_emit_plt_entry(me, v);
                                   Elf_Addr v)
 {
        ptrdiff_t offset = (void *)v - (void *)location;
-       s32 fill_v = offset;
        u32 hi20, lo12;
 
-       if (offset != fill_v) {
+       if (!riscv_insn_valid_32bit_offset(offset)) {
                pr_err(
                  "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n",
                  me->name, (long long)v, location);