archclean:
        $(Q)$(MAKE) $(clean)=$(boot)
 
+ifeq ($(KBUILD_EXTMOD),)
+# We need to generate vdso-offsets.h before compiling certain files in kernel/.
+# In order to do that, we should use the archprepare target, but we can't since
+# asm-offsets.h is included in some files used to generate vdso-offsets.h, and
+# asm-offsets.h is built in prepare0, for which archprepare is a dependency.
+# Therefore we need to generate the header after prepare0 has been made, hence
+# this hack.
+prepare: vdso_prepare
+vdso_prepare: prepare0
+       $(if $(CONFIG_VDSO32),$(Q)$(MAKE) \
+               $(build)=arch/powerpc/kernel/vdso32 include/generated/vdso32-offsets.h)
+       $(if $(CONFIG_PPC64),$(Q)$(MAKE) \
+               $(build)=arch/powerpc/kernel/vdso64 include/generated/vdso64-offsets.h)
+endif
+
 archprepare: checkbin
 
 archheaders:
 
 
 #ifndef __ASSEMBLY__
 
+#ifdef CONFIG_PPC64
+#include <generated/vdso64-offsets.h>
+#endif
+
+#ifdef CONFIG_VDSO32
+#include <generated/vdso32-offsets.h>
+#endif
+
+#define VDSO64_SYMBOL(base, name) ((unsigned long)(base) + (vdso64_offset_##name))
+
+#define VDSO32_SYMBOL(base, name) ((unsigned long)(base) + (vdso32_offset_##name))
+
 /* Offsets relative to thread->vdso_base */
 extern unsigned long vdso64_rt_sigtramp;
 extern unsigned long vdso32_sigtramp;
 
        }
 
        /* Save user registers on the stack */
-       if (vdso32_rt_sigtramp && tsk->mm->context.vdso) {
-               tramp = (unsigned long)tsk->mm->context.vdso + vdso32_rt_sigtramp;
+       if (tsk->mm->context.vdso) {
+               tramp = VDSO32_SYMBOL(tsk->mm->context.vdso, sigtramp_rt32);
        } else {
                tramp = (unsigned long)mctx->mc_pad;
                /* Set up the sigreturn trampoline: li r0,sigret; sc */
        else
                unsafe_save_user_regs(regs, mctx, tm_mctx, 1, failed);
 
-       if (vdso32_sigtramp && tsk->mm->context.vdso) {
-               tramp = (unsigned long)tsk->mm->context.vdso + vdso32_sigtramp;
+       if (tsk->mm->context.vdso) {
+               tramp = VDSO32_SYMBOL(tsk->mm->context.vdso, sigtramp32);
        } else {
                tramp = (unsigned long)mctx->mc_pad;
                /* Set up the sigreturn trampoline: li r0,sigret; sc */
 
        tsk->thread.fp_state.fpscr = 0;
 
        /* Set up to return from userspace. */
-       if (vdso64_rt_sigtramp && tsk->mm->context.vdso) {
-               regs->nip = (unsigned long)tsk->mm->context.vdso + vdso64_rt_sigtramp;
+       if (tsk->mm->context.vdso) {
+               regs->nip = VDSO64_SYMBOL(tsk->mm->context.vdso, sigtramp_rt64);
        } else {
                err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
                if (err)
 
 $(obj)/vgettimeofday.o: %.o: %.c FORCE
        $(call if_changed_dep,vdso32cc)
 
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE
+       $(call if_changed,vdsosym)
+
 # actual build commands
 quiet_cmd_vdso32ld_and_check = VDSO32L $@
       cmd_vdso32ld_and_check = $(VDSOCC) $(c_flags) $(CC32FLAGS) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^) ; $(cmd_vdso_check)
 
--- /dev/null
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Author: Will Deacon <will.deacon@arm.com
+#
+
+LC_ALL=C
+sed -n -e 's/^00*/0/' -e \
+'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso32_offset_\2\t0x\1/p'
 
        local: *;
        };
 }
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp32                = __kernel_sigtramp32;
+VDSO_sigtramp_rt32     = __kernel_sigtramp_rt32;
 
 $(obj)/vdso64.so.dbg: $(src)/vdso64.lds $(obj-vdso64) $(obj)/vgettimeofday.o FORCE
        $(call if_changed,vdso64ld_and_check)
 
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(srctree)/$(src)/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso64-offsets.h: $(obj)/vdso64.so.dbg FORCE
+       $(call if_changed,vdsosym)
+
 # actual build commands
 quiet_cmd_vdso64ld_and_check = VDSO64L $@
       cmd_vdso64ld_and_check = $(CC) $(c_flags) -o $@ -Wl,-T$(filter %.lds,$^) $(filter %.o,$^); $(cmd_vdso_check)
 
--- /dev/null
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+#
+# Match symbols in the DSO that look like VDSO_*; produce a header file
+# of constant offsets into the shared object.
+#
+# Doing this inside the Makefile will break the $(filter-out) function,
+# causing Kbuild to rebuild the vdso-offsets header file every time.
+#
+# Author: Will Deacon <will.deacon@arm.com
+#
+
+LC_ALL=C
+sed -n -e 's/^00*/0/' -e \
+'s/^\([0-9a-fA-F]*\) . VDSO_\([a-zA-Z0-9_]*\)$/\#define vdso64_offset_\2\t0x\1/p'
 
        local: *;
        };
 }
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_sigtramp_rt64     = __kernel_sigtramp_rt64;
 
 {
        if (nip == fp + offsetof(struct signal_frame_32, mctx.mc_pad))
                return 1;
-       if (vdso32_sigtramp && current->mm->context.vdso &&
-           nip == (unsigned long)current->mm->context.vdso + vdso32_sigtramp)
+       if (current->mm->context.vdso &&
+           nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp32))
                return 1;
        return 0;
 }
        if (nip == fp + offsetof(struct rt_signal_frame_32,
                                 uc.uc_mcontext.mc_pad))
                return 1;
-       if (vdso32_rt_sigtramp && current->mm->context.vdso &&
-           nip == (unsigned long)current->mm->context.vdso + vdso32_rt_sigtramp)
+       if (current->mm->context.vdso &&
+           nip == VDSO32_SYMBOL(current->mm->context.vdso, sigtramp_rt32))
                return 1;
        return 0;
 }
 
 {
        if (nip == fp + offsetof(struct signal_frame_64, tramp))
                return 1;
-       if (vdso64_rt_sigtramp && current->mm->context.vdso &&
-           nip == (unsigned long)current->mm->context.vdso + vdso64_rt_sigtramp)
+       if (current->mm->context.vdso &&
+           nip == VDSO64_SYMBOL(current->mm->context.vdso, sigtramp_rt64))
                return 1;
        return 0;
 }