diff --git a/arch/loongarch/include/asm/asm-extable.h b/arch/loongarch/include/asm/asm-extable.h
index 4f615bf56727ebfd6e59a51666b5169fc387f38b..74f8bc75472ac9e03c06ec21aee8960f5c5171ac 100644
--- a/arch/loongarch/include/asm/asm-extable.h
+++ b/arch/loongarch/include/asm/asm-extable.h
@@ -6,9 +6,9 @@
 
 #define __ASM_EXTABLE_RAW(insn, fixup)			\
 	.pushsection	__ex_table, "a";		\
-	.balign		8;				\
-	.quad		(insn);				\
-	.quad		(fixup);			\
+	.balign		4;				\
+	.long		((insn) - .);			\
+	.long		((fixup) - .);			\
 	.popsection;
 
 	.macro		_asm_extable, insn, fixup
@@ -22,9 +22,9 @@
 
 #define __ASM_EXTABLE_RAW(insn, fixup)			\
 	".pushsection	__ex_table, \"a\"\n"		\
-	".balign	8\n"				\
-	".quad		((" insn "))\n"			\
-	".quad		((" fixup "))\n"		\
+	".balign	4\n"				\
+	".long		((" insn ") - .)\n"		\
+	".long		((" fixup ") - .)\n"		\
 	".popsection\n"
 
 #define _ASM_EXTABLE(insn, fixup)	\
diff --git a/arch/loongarch/include/asm/extable.h b/arch/loongarch/include/asm/extable.h
new file mode 100644
index 0000000000000000000000000000000000000000..b571c89705d1e7533031f1e0d47084dbae518f72
--- /dev/null
+++ b/arch/loongarch/include/asm/extable.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_LOONGARCH_EXTABLE_H
+#define _ASM_LOONGARCH_EXTABLE_H
+
+/*
+ * The exception table consists of pairs of relative offsets: the first
+ * is the relative offset to an instruction that is allowed to fault,
+ * and the second is the relative offset at which the program should
+ * continue. No registers are modified, so it is entirely up to the
+ * continuation code to figure out what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path.  This means when everything is well,
+ * we don't even have to jump over them.  Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+
+struct exception_table_entry {
+	int insn, fixup;
+};
+
+#define ARCH_HAS_RELATIVE_EXTABLE
+
+bool fixup_exception(struct pt_regs *regs);
+
+#endif
diff --git a/arch/loongarch/include/asm/uaccess.h b/arch/loongarch/include/asm/uaccess.h
index bf9a4e218ac0ed86d278980af2809714b9256e72..e33282e0bdef2c2b5ba554c7a552defec957f532 100644
--- a/arch/loongarch/include/asm/uaccess.h
+++ b/arch/loongarch/include/asm/uaccess.h
@@ -15,8 +15,8 @@
 #include <linux/string.h>
 #include <linux/extable.h>
 #include <asm/pgtable.h>
+#include <asm/extable.h>
 #include <asm/asm-extable.h>
-#include <asm-generic/extable.h>
 #include <asm-generic/access_ok.h>
 
 extern u64 __ua_limit;
diff --git a/arch/loongarch/mm/extable.c b/arch/loongarch/mm/extable.c
index bc20988f2b87cc9af9b93e39ececf2c874df9970..08a9a7d6357a72aaa60bf4f8e2cdf4200d8e2843 100644
--- a/arch/loongarch/mm/extable.c
+++ b/arch/loongarch/mm/extable.c
@@ -3,20 +3,32 @@
  * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
  */
 #include <linux/extable.h>
-#include <linux/spinlock.h>
-#include <asm/branch.h>
 #include <linux/uaccess.h>
+#include <asm/asm-extable.h>
+#include <asm/branch.h>
+
+static inline unsigned long
+get_ex_fixup(const struct exception_table_entry *ex)
+{
+	return ((unsigned long)&ex->fixup + ex->fixup);
+}
 
-int fixup_exception(struct pt_regs *regs)
+static bool ex_handler_fixup(const struct exception_table_entry *ex,
+			     struct pt_regs *regs)
 {
-	const struct exception_table_entry *fixup;
+	regs->csr_era = get_ex_fixup(ex);
 
-	fixup = search_exception_tables(exception_era(regs));
-	if (fixup) {
-		regs->csr_era = fixup->fixup;
+	return true;
+}
+
+
+bool fixup_exception(struct pt_regs *regs)
+{
+	const struct exception_table_entry *ex;
 
-		return 1;
-	}
+	ex = search_exception_tables(exception_era(regs));
+	if (!ex)
+		return false;
 
-	return 0;
+	return ex_handler_fixup(ex, regs);
 }
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 2c80da0220c326efbe4fb7598054cef04ad3566e..9321c0a05ffdcdc114b194e7d78ce987e08ad2cb 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1523,6 +1523,14 @@ static int addend_mips_rel(struct elf_info *elf, Elf_Shdr *sechdr, Elf_Rela *r)
 #define R_RISCV_SUB32		39
 #endif
 
+#ifndef EM_LOONGARCH
+#define EM_LOONGARCH		258
+#endif
+
+#ifndef R_LARCH_SUB32
+#define R_LARCH_SUB32		55
+#endif
+
 static void section_rela(const char *modname, struct elf_info *elf,
 			 Elf_Shdr *sechdr)
 {
@@ -1564,6 +1572,11 @@ static void section_rela(const char *modname, struct elf_info *elf,
 			    ELF_R_TYPE(r.r_info) == R_RISCV_SUB32)
 				continue;
 			break;
+		case EM_LOONGARCH:
+			if (!strcmp("__ex_table", fromsec) &&
+			    ELF_R_TYPE(r.r_info) == R_LARCH_SUB32)
+				continue;
+			break;
 		}
 		sym = elf->symtab_start + r_sym;
 		/* Skip special sections */
diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index fba40e99f3541aaf4be6acff96809ad91093bf9b..0f2beda80478978d80dacbddd394fad376f0bfb5 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -312,12 +312,12 @@ static int do_file(char const *const fname, void *addr)
 	case EM_PARISC:
 	case EM_PPC:
 	case EM_PPC64:
+	case EM_LOONGARCH:
 		custom_sort = sort_relative_table;
 		break;
 	case EM_ARCOMPACT:
 	case EM_ARCV2:
 	case EM_ARM:
-	case EM_LOONGARCH:
 	case EM_MICROBLAZE:
 	case EM_MIPS:
 	case EM_XTENSA: