add     \addr, \addr, \post_inc;
                alternative_endif
 
-               .section __ex_table,"a";
-               .align  3;
-               .quad   8888b,\l;
-               .quad   8889b,\l;
-               .previous;
+               _asm_extable    8888b,\l;
+               _asm_extable    8889b,\l;
        .endm
 
        .macro uao_stp l, reg1, reg2, addr, post_inc
                        add     \addr, \addr, \post_inc;
                alternative_endif
 
-               .section __ex_table,"a";
-               .align  3;
-               .quad   8888b,\l;
-               .quad   8889b,\l;
-               .previous
+               _asm_extable    8888b,\l;
+               _asm_extable    8889b,\l;
        .endm
 
        .macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
                        add             \addr, \addr, \post_inc;
                alternative_endif
 
-               .section __ex_table,"a";
-               .align  3;
-               .quad   8888b,\l;
-               .previous
+               _asm_extable    8888b,\l;
        .endm
 #else
        .macro uao_ldp l, reg1, reg2, addr, post_inc
 
        dmb     \opt
        .endm
 
+/*
+ * Emit an entry into the exception table
+ */
+       .macro          _asm_extable, from, to
+       .pushsection    __ex_table, "a"
+       .align          3
+       .long           (\from - .), (\to - .)
+       .popsection
+       .endm
+
 #define USER(l, x...)                          \
 9999:  x;                                      \
-       .section __ex_table,"a";                \
-       .align  3;                              \
-       .quad   9999b,l;                        \
-       .previous
+       _asm_extable    9999b, l
 
 /*
  * Register aliases.
 
 "4:    mov     %w0, %w5\n"                                             \
 "      b       3b\n"                                                   \
 "      .popsection\n"                                                  \
-"      .pushsection __ex_table,\"a\"\n"                                \
-"      .align  3\n"                                                    \
-"      .quad   1b, 4b, 2b, 4b\n"                                       \
-"      .popsection\n"                                                  \
+       _ASM_EXTABLE(1b, 4b)                                            \
+       _ASM_EXTABLE(2b, 4b)                                            \
        ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,            \
                    CONFIG_ARM64_PAN)                                   \
        : "=&r" (ret), "=&r" (oldval), "+Q" (*uaddr), "=&r" (tmp)       \
 "4:    mov     %w0, %w6\n"
 "      b       3b\n"
 "      .popsection\n"
-"      .pushsection __ex_table,\"a\"\n"
-"      .align  3\n"
-"      .quad   1b, 4b, 2b, 4b\n"
-"      .popsection\n"
+       _ASM_EXTABLE(1b, 4b)
+       _ASM_EXTABLE(2b, 4b)
 ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN, CONFIG_ARM64_PAN)
        : "+r" (ret), "=&r" (val), "+Q" (*uaddr), "=&r" (tmp)
        : "r" (oldval), "r" (newval), "Ir" (-EFAULT)
 
 #define VERIFY_WRITE 1
 
 /*
- * The exception table consists of pairs of addresses: the first is the
- * address of an instruction that is allowed to fault, and the second is
- * the address 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.
+ * 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,
 
 struct exception_table_entry
 {
-       unsigned long insn, fixup;
+       int insn, fixup;
 };
 
+#define ARCH_HAS_RELATIVE_EXTABLE
+
 extern int fixup_exception(struct pt_regs *regs);
 
 #define KERNEL_DS      (-1UL)
 #define access_ok(type, addr, size)    __range_ok(addr, size)
 #define user_addr_max                  get_fs
 
+#define _ASM_EXTABLE(from, to)                                         \
+       "       .pushsection    __ex_table, \"a\"\n"                    \
+       "       .align          3\n"                                    \
+       "       .long           (" #from " - .), (" #to " - .)\n"       \
+       "       .popsection\n"
+
 /*
  * The "__xxx" versions of the user access functions do not verify the address
  * space - it must have been done previously with a separate "access_ok()"
        "       mov     %1, #0\n"                                       \
        "       b       2b\n"                                           \
        "       .previous\n"                                            \
-       "       .section __ex_table,\"a\"\n"                            \
-       "       .align  3\n"                                            \
-       "       .quad   1b, 3b\n"                                       \
-       "       .previous"                                              \
+       _ASM_EXTABLE(1b, 3b)                                            \
        : "+r" (err), "=&r" (x)                                         \
        : "r" (addr), "i" (-EFAULT))
 
        "3:     mov     %w0, %3\n"                                      \
        "       b       2b\n"                                           \
        "       .previous\n"                                            \
-       "       .section __ex_table,\"a\"\n"                            \
-       "       .align  3\n"                                            \
-       "       .quad   1b, 3b\n"                                       \
-       "       .previous"                                              \
+       _ASM_EXTABLE(1b, 3b)                                            \
        : "+r" (err)                                                    \
        : "r" (x), "r" (addr), "i" (-EFAULT))
 
 
 #ifndef __ASM_WORD_AT_A_TIME_H
 #define __ASM_WORD_AT_A_TIME_H
 
+#include <asm/uaccess.h>
+
 #ifndef __AARCH64EB__
 
 #include <linux/kernel.h>
 #endif
        "       b       2b\n"
        "       .popsection\n"
-       "       .pushsection __ex_table,\"a\"\n"
-       "       .align  3\n"
-       "       .quad   1b, 3b\n"
-       "       .popsection"
+       _ASM_EXTABLE(1b, 3b)
        : "=&r" (ret), "=&r" (offset)
        : "r" (addr), "Q" (*(unsigned long *)addr));
 
 
        "4:     mov             %w0, %w5\n"                     \
        "       b               3b\n"                           \
        "       .popsection"                                    \
-       "       .pushsection     __ex_table,\"a\"\n"            \
-       "       .align          3\n"                            \
-       "       .quad           0b, 4b\n"                       \
-       "       .quad           1b, 4b\n"                       \
-       "       .popsection\n"                                  \
+       _ASM_EXTABLE(0b, 4b)                                    \
+       _ASM_EXTABLE(1b, 4b)                                    \
        ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_HAS_PAN,    \
                CONFIG_ARM64_PAN)                               \
        : "=&r" (res), "+r" (data), "=&r" (temp)                \
 
 
        fixup = search_exception_tables(instruction_pointer(regs));
        if (fixup)
-               regs->pc = fixup->fixup;
+               regs->pc = (unsigned long)&fixup->fixup + fixup->fixup;
 
        return fixup != NULL;
 }
 
        case EM_386:
        case EM_X86_64:
        case EM_S390:
+       case EM_AARCH64:
                custom_sort = sort_relative_table;
                break;
        case EM_ARCOMPACT:
        case EM_ARCV2:
        case EM_ARM:
-       case EM_AARCH64:
        case EM_MICROBLAZE:
        case EM_MIPS:
        case EM_XTENSA: