]> git.baikalelectronics.ru Git - kernel.git/commitdiff
s390/vdso: add minimal compat vdso
authorSven Schnelle <svens@linux.ibm.com>
Fri, 25 Jun 2021 12:50:08 +0000 (14:50 +0200)
committerVasily Gorbik <gor@linux.ibm.com>
Thu, 8 Jul 2021 13:37:28 +0000 (15:37 +0200)
Add a small vdso for 31 bit compat application that provides
trampolines for calls to sigreturn,rt_sigreturn,syscall_restart.
This is requird for moving these syscalls away from the signal
frame to the vdso. Note that this patch effectively disables
CONFIG_COMPAT when using clang to compile the kernel. clang
doesn't support 31 bit mode.

We want to redirect sigreturn and restart_syscall to the vdso. However,
the kernel cannot parse the ELF vdso file, so we need to generate header
files which contain the offsets of the syscall instructions in the vdso
page.

Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
16 files changed:
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/elf.h
arch/s390/include/asm/vdso.h
arch/s390/include/asm/vdso/gettimeofday.h
arch/s390/kernel/Makefile
arch/s390/kernel/vdso.c
arch/s390/kernel/vdso32/.gitignore [new file with mode: 0644]
arch/s390/kernel/vdso32/Makefile [new file with mode: 0644]
arch/s390/kernel/vdso32/gen_vdso_offsets.sh [new file with mode: 0755]
arch/s390/kernel/vdso32/note.S [new file with mode: 0644]
arch/s390/kernel/vdso32/vdso32.lds.S [new file with mode: 0644]
arch/s390/kernel/vdso32/vdso32_wrapper.S [new file with mode: 0644]
arch/s390/kernel/vdso32/vdso_user_wrapper.S [new file with mode: 0644]
arch/s390/kernel/vdso64/Makefile
arch/s390/kernel/vdso64/gen_vdso_offsets.sh [new file with mode: 0755]

index ceaa50947d64c9927d149e6801cb687461a61960..a0e2130f0100ca4ad8420d6cfbc826d724716517 100644 (file)
@@ -437,6 +437,7 @@ config COMPAT
        select COMPAT_OLD_SIGACTION
        select HAVE_UID16
        depends on MULTIUSER
+       depends on !CC_IS_CLANG
        help
          Select this option if you want to enable your system kernel to
          handle system-calls from ELF binaries for 31 bit ESA.  This option
index 098abe3a56f37426f02bfd609c222633b8ff2b32..95c75e653e43fc811c476c4b1165fcd965764631 100644 (file)
@@ -166,6 +166,19 @@ archheaders:
 archprepare:
        $(Q)$(MAKE) $(build)=$(syscalls) kapi
        $(Q)$(MAKE) $(build)=$(tools) kapi
+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
+       $(Q)$(MAKE) $(build)=arch/s390/kernel/vdso64 include/generated/vdso64-offsets.h
+       $(if $(CONFIG_COMPAT),$(Q)$(MAKE) \
+               $(build)=arch/s390/kernel/vdso32 include/generated/vdso32-offsets.h)
+endif
 
 # Don't use tabs in echo arguments
 define archhelp
index 6476655d7ce9c6043802ed46d1f62eeabe7e64d1..1376bd2b03926b079cff39cbbe32406b2776fa2c 100644 (file)
@@ -144,8 +144,6 @@ typedef s390_compat_regs compat_elf_gregset_t;
 #include <linux/sched/mm.h>    /* for task_struct */
 #include <asm/mmu_context.h>
 
-#include <asm/vdso.h>
-
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
index 6eaf4a3f227334374916168bebd4305e3406431a..53165aa7813a3b6cc42df0b0eca41667dc8120c4 100644 (file)
@@ -4,18 +4,31 @@
 
 #include <vdso/datapage.h>
 
-/* Default link address for the vDSO */
-#define VDSO_LBASE     0
-
-#define __VVAR_PAGES   2
+#ifndef __ASSEMBLY__
 
-#define VDSO_VERSION_STRING    LINUX_2.6.29
+#include <generated/vdso64-offsets.h>
+#ifdef CONFIG_COMPAT
+#include <generated/vdso32-offsets.h>
+#endif
 
-#ifndef __ASSEMBLY__
+#define VDSO64_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso64_offset_##name))
+#ifdef CONFIG_COMPAT
+#define VDSO32_SYMBOL(tsk, name) ((tsk)->mm->context.vdso_base + (vdso32_offset_##name))
+#else
+#define VDSO32_SYMBOL(tsk, name) (-1UL)
+#endif
 
 extern struct vdso_data *vdso_data;
 
 int vdso_getcpu_init(void);
 
 #endif /* __ASSEMBLY__ */
+
+/* Default link address for the vDSO */
+#define VDSO_LBASE     0
+
+#define __VVAR_PAGES   2
+
+#define VDSO_VERSION_STRING    LINUX_2.6.29
+
 #endif /* __S390_VDSO_H__ */
index 383c53c3dddd5580959af4c9bd8292f97ba7cbd3..d6465b22ffe30deb6ce6a5c1ae78fa7541819709 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <asm/timex.h>
 #include <asm/unistd.h>
-#include <asm/vdso.h>
 #include <linux/compiler.h>
 
 #define vdso_calc_delta __arch_vdso_calc_delta
index 7a77f7f6f9d86511c0a0698df59bf1d912796906..4a44ba5a2d73427eeccc388b64377a2dd1f20ffa 100644 (file)
@@ -77,3 +77,4 @@ obj-$(findstring y, $(CONFIG_PROTECTED_VIRTUALIZATION_GUEST) $(CONFIG_PGSTE)) +=
 
 # vdso
 obj-y                          += vdso64/
+obj-$(CONFIG_COMPAT)           += vdso32/
index f786246e621ae7aa7943d8f0faf26ffb3d0b1023..99694260cac97bc618bd7cce2c2672fdf9053604 100644 (file)
@@ -20,7 +20,7 @@
 #include <asm/vdso.h>
 
 extern char vdso64_start[], vdso64_end[];
-static unsigned int vdso_pages;
+extern char vdso32_start[], vdso32_end[];
 
 static struct vm_special_mapping vvar_mapping;
 
@@ -143,7 +143,12 @@ static struct vm_special_mapping vvar_mapping = {
        .fault = vvar_fault,
 };
 
-static struct vm_special_mapping vdso_mapping = {
+static struct vm_special_mapping vdso64_mapping = {
+       .name = "[vdso]",
+       .mremap = vdso_mremap,
+};
+
+static struct vm_special_mapping vdso32_mapping = {
        .name = "[vdso]",
        .mremap = vdso_mremap,
 };
@@ -159,16 +164,22 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
        unsigned long vdso_text_len, vdso_mapping_len;
        unsigned long vvar_start, vdso_text_start;
+       struct vm_special_mapping *vdso_mapping;
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        int rc;
 
        BUILD_BUG_ON(VVAR_NR_PAGES != __VVAR_PAGES);
-       if (is_compat_task())
-               return 0;
        if (mmap_write_lock_killable(mm))
                return -EINTR;
-       vdso_text_len = vdso_pages << PAGE_SHIFT;
+
+       if (is_compat_task()) {
+               vdso_text_len = vdso32_end - vdso32_start;
+               vdso_mapping = &vdso32_mapping;
+       } else {
+               vdso_text_len = vdso64_end - vdso64_start;
+               vdso_mapping = &vdso64_mapping;
+       }
        vdso_mapping_len = vdso_text_len + VVAR_NR_PAGES * PAGE_SIZE;
        vvar_start = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
        rc = vvar_start;
@@ -186,7 +197,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
        vma = _install_special_mapping(mm, vdso_text_start, vdso_text_len,
                                       VM_READ|VM_EXEC|
                                       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
-                                      &vdso_mapping);
+                                      vdso_mapping);
        if (IS_ERR(vma)) {
                do_munmap(mm, vvar_start, PAGE_SIZE, NULL);
                rc = PTR_ERR(vma);
@@ -199,20 +210,25 @@ out:
        return rc;
 }
 
-static int __init vdso_init(void)
+static struct page ** __init vdso_setup_pages(void *start, void *end)
 {
-       struct page **pages;
+       int pages = (end - start) >> PAGE_SHIFT;
+       struct page **pagelist;
        int i;
 
-       vdso_pages = (vdso64_end - vdso64_start) >> PAGE_SHIFT;
-       pages = kcalloc(vdso_pages + 1, sizeof(struct page *), GFP_KERNEL);
-       if (!pages)
-               panic("failed to allocate VDSO pages");
+       pagelist = kcalloc(pages + 1, sizeof(struct page *), GFP_KERNEL);
+       if (!pagelist)
+               panic("%s: Cannot allocate page list for VDSO", __func__);
+       for (i = 0; i < pages; i++)
+               pagelist[i] = virt_to_page(start + i * PAGE_SIZE);
+       return pagelist;
+}
 
-       for (i = 0; i < vdso_pages; i++)
-               pages[i] = virt_to_page(vdso64_start + i * PAGE_SIZE);
-       pages[vdso_pages] = NULL;
-       vdso_mapping.pages = pages;
+static int __init vdso_init(void)
+{
+       vdso64_mapping.pages = vdso_setup_pages(vdso64_start, vdso64_end);
+       if (IS_ENABLED(CONFIG_COMPAT))
+               vdso32_mapping.pages = vdso_setup_pages(vdso32_start, vdso32_end);
        return 0;
 }
 arch_initcall(vdso_init);
diff --git a/arch/s390/kernel/vdso32/.gitignore b/arch/s390/kernel/vdso32/.gitignore
new file mode 100644 (file)
index 0000000..5167384
--- /dev/null
@@ -0,0 +1,2 @@
+# SPDX-License-Identifier: GPL-2.0-only
+vdso32.lds
diff --git a/arch/s390/kernel/vdso32/Makefile b/arch/s390/kernel/vdso32/Makefile
new file mode 100644 (file)
index 0000000..b2349a3
--- /dev/null
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: GPL-2.0
+# List of files in the vdso
+
+KCOV_INSTRUMENT := n
+ARCH_REL_TYPE_ABS := R_390_COPY|R_390_GLOB_DAT|R_390_JMP_SLOT|R_390_RELATIVE
+ARCH_REL_TYPE_ABS += R_390_GOT|R_390_PLT
+
+include $(srctree)/lib/vdso/Makefile
+obj-vdso32 = vdso_user_wrapper-32.o note-32.o
+
+# Build rules
+
+targets := $(obj-vdso32) vdso32.so vdso32.so.dbg
+obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
+
+KBUILD_AFLAGS += -DBUILD_VDSO
+KBUILD_CFLAGS += -DBUILD_VDSO -DDISABLE_BRANCH_PROFILING
+
+KBUILD_AFLAGS_32 := $(filter-out -m64,$(KBUILD_AFLAGS))
+KBUILD_AFLAGS_32 += -m31 -s
+
+KBUILD_CFLAGS_32 := $(filter-out -m64,$(KBUILD_CFLAGS))
+KBUILD_CFLAGS_32 += -m31 -fPIC -shared -fno-common -fno-builtin
+
+LDFLAGS_vdso32.so.dbg += -fPIC -shared -nostdlib -soname=linux-vdso32.so.1 \
+       --hash-style=both --build-id=sha1 -melf_s390 -T
+
+$(targets:%=$(obj)/%.dbg): KBUILD_CFLAGS = $(KBUILD_CFLAGS_32)
+$(targets:%=$(obj)/%.dbg): KBUILD_AFLAGS = $(KBUILD_AFLAGS_32)
+
+obj-y += vdso32_wrapper.o
+CPPFLAGS_vdso32.lds += -P -C -U$(ARCH)
+
+# Disable gcov profiling, ubsan and kasan for VDSO code
+GCOV_PROFILE := n
+UBSAN_SANITIZE := n
+KASAN_SANITIZE := n
+
+# Force dependency (incbin is bad)
+$(obj)/vdso32_wrapper.o : $(obj)/vdso32.so
+
+$(obj)/vdso32.so.dbg: $(src)/vdso32.lds $(obj-vdso32) FORCE
+       $(call if_changed,ld)
+
+# strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+       $(call if_changed,objcopy)
+
+$(obj-vdso32): %-32.o: %.S FORCE
+       $(call if_changed_dep,vdso32as)
+
+# actual build commands
+quiet_cmd_vdso32as = VDSO32A $@
+      cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $<
+quiet_cmd_vdso32cc = VDSO32C $@
+      cmd_vdso32cc = $(CC) $(c_flags) -c -o $@ $<
+
+# install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+      cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@
+
+vdso32.so: $(obj)/vdso32.so.dbg
+       @mkdir -p $(MODLIB)/vdso
+       $(call cmd,vdso_install)
+
+vdso_install: vdso32.so
+
+# 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)
diff --git a/arch/s390/kernel/vdso32/gen_vdso_offsets.sh b/arch/s390/kernel/vdso32/gen_vdso_offsets.sh
new file mode 100755 (executable)
index 0000000..9c4f951
--- /dev/null
@@ -0,0 +1,15 @@
+#!/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.
+#
+# Inspired by arm64 version.
+#
+
+LC_ALL=C
+sed -n 's/\([0-9a-f]*\) . __kernel_compat_\(.*\)/\#define vdso32_offset_\2\t0x\1/p'
diff --git a/arch/s390/kernel/vdso32/note.S b/arch/s390/kernel/vdso32/note.S
new file mode 100644 (file)
index 0000000..db19d06
--- /dev/null
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
+ * Here we can supply some information useful to userland.
+ */
+
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/elfnote.h>
+
+ELFNOTE_START(Linux, 0, "a")
+       .long LINUX_VERSION_CODE
+ELFNOTE_END
diff --git a/arch/s390/kernel/vdso32/vdso32.lds.S b/arch/s390/kernel/vdso32/vdso32.lds.S
new file mode 100644 (file)
index 0000000..bff50b6
--- /dev/null
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This is the infamous ld script for the 64 bits vdso
+ * library
+ */
+
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-s390", "elf32-s390", "elf32-s390")
+OUTPUT_ARCH(s390:31-bit)
+ENTRY(_start)
+
+SECTIONS
+{
+       PROVIDE(_vdso_data = . - __VVAR_PAGES * PAGE_SIZE);
+#ifdef CONFIG_TIME_NS
+       PROVIDE(_timens_data = _vdso_data + PAGE_SIZE);
+#endif
+       . = VDSO_LBASE + SIZEOF_HEADERS;
+
+       .hash           : { *(.hash) }                  :text
+       .gnu.hash       : { *(.gnu.hash) }
+       .dynsym         : { *(.dynsym) }
+       .dynstr         : { *(.dynstr) }
+       .gnu.version    : { *(.gnu.version) }
+       .gnu.version_d  : { *(.gnu.version_d) }
+       .gnu.version_r  : { *(.gnu.version_r) }
+
+       .note           : { *(.note.*) }                :text   :note
+
+       . = ALIGN(16);
+       .text           : {
+               *(.text .stub .text.* .gnu.linkonce.t.*)
+       } :text
+       PROVIDE(__etext = .);
+       PROVIDE(_etext = .);
+       PROVIDE(etext = .);
+
+       /*
+        * Other stuff is appended to the text segment:
+        */
+       .rodata         : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+       .rodata1        : { *(.rodata1) }
+
+       .dynamic        : { *(.dynamic) }               :text   :dynamic
+
+       .eh_frame_hdr   : { *(.eh_frame_hdr) }          :text   :eh_frame_hdr
+       .eh_frame       : { KEEP (*(.eh_frame)) }       :text
+       .gcc_except_table : { *(.gcc_except_table .gcc_except_table.*) }
+
+       .rela.dyn ALIGN(8) : { *(.rela.dyn) }
+       .got ALIGN(8)   : { *(.got .toc) }
+
+       _end = .;
+       PROVIDE(end = .);
+
+       /*
+        * Stabs debugging sections are here too.
+        */
+       .stab          0 : { *(.stab) }
+       .stabstr       0 : { *(.stabstr) }
+       .stab.excl     0 : { *(.stab.excl) }
+       .stab.exclstr  0 : { *(.stab.exclstr) }
+       .stab.index    0 : { *(.stab.index) }
+       .stab.indexstr 0 : { *(.stab.indexstr) }
+       .comment       0 : { *(.comment) }
+
+       /*
+        * DWARF debug sections.
+        * Symbols in the DWARF debugging sections are relative to the
+        * beginning of the section so we begin them at 0.
+        */
+       /* DWARF 1 */
+       .debug          0 : { *(.debug) }
+       .line           0 : { *(.line) }
+       /* GNU DWARF 1 extensions */
+       .debug_srcinfo  0 : { *(.debug_srcinfo) }
+       .debug_sfnames  0 : { *(.debug_sfnames) }
+       /* DWARF 1.1 and DWARF 2 */
+       .debug_aranges  0 : { *(.debug_aranges) }
+       .debug_pubnames 0 : { *(.debug_pubnames) }
+       /* DWARF 2 */
+       .debug_info     0 : { *(.debug_info .gnu.linkonce.wi.*) }
+       .debug_abbrev   0 : { *(.debug_abbrev) }
+       .debug_line     0 : { *(.debug_line) }
+       .debug_frame    0 : { *(.debug_frame) }
+       .debug_str      0 : { *(.debug_str) }
+       .debug_loc      0 : { *(.debug_loc) }
+       .debug_macinfo  0 : { *(.debug_macinfo) }
+       /* SGI/MIPS DWARF 2 extensions */
+       .debug_weaknames 0 : { *(.debug_weaknames) }
+       .debug_funcnames 0 : { *(.debug_funcnames) }
+       .debug_typenames 0 : { *(.debug_typenames) }
+       .debug_varnames  0 : { *(.debug_varnames) }
+       /* DWARF 3 */
+       .debug_pubtypes 0 : { *(.debug_pubtypes) }
+       .debug_ranges   0 : { *(.debug_ranges) }
+       .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
+
+       /DISCARD/       : {
+               *(.note.GNU-stack)
+               *(.branch_lt)
+               *(.data .data.* .gnu.linkonce.d.* .sdata*)
+               *(.bss .sbss .dynbss .dynsbss)
+       }
+}
+
+/*
+ * Very old versions of ld do not recognize this name token; use the constant.
+ */
+#define PT_GNU_EH_FRAME        0x6474e550
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+       text            PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
+       dynamic         PT_DYNAMIC FLAGS(4);            /* PF_R */
+       note            PT_NOTE FLAGS(4);               /* PF_R */
+       eh_frame_hdr    PT_GNU_EH_FRAME;
+}
+
+/*
+ * This controls what symbols we export from the DSO.
+ */
+VERSION
+{
+       VDSO_VERSION_STRING {
+       global:
+               /*
+                * Has to be there for the kernel to find
+                */
+               __kernel_compat_restart_syscall;
+               __kernel_compat_rt_sigreturn;
+               __kernel_compat_sigreturn;
+       local: *;
+       };
+}
diff --git a/arch/s390/kernel/vdso32/vdso32_wrapper.S b/arch/s390/kernel/vdso32/vdso32_wrapper.S
new file mode 100644 (file)
index 0000000..de2fb93
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/page.h>
+
+       __PAGE_ALIGNED_DATA
+
+       .globl vdso32_start, vdso32_end
+       .balign PAGE_SIZE
+vdso32_start:
+       .incbin "arch/s390/kernel/vdso32/vdso32.so"
+       .balign PAGE_SIZE
+vdso32_end:
+
+       .previous
diff --git a/arch/s390/kernel/vdso32/vdso_user_wrapper.S b/arch/s390/kernel/vdso32/vdso_user_wrapper.S
new file mode 100644 (file)
index 0000000..3f42f27
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <asm/unistd.h>
+#include <asm/dwarf.h>
+
+.macro vdso_syscall func,syscall
+       .globl __kernel_compat_\func
+       .type  __kernel_compat_\func,@function
+       .align 8
+__kernel_compat_\func:
+       CFI_STARTPROC
+       svc     \syscall
+       /* Make sure we notice when a syscall returns, which shouldn't happen */
+       .word   0
+       CFI_ENDPROC
+       .size   __kernel_compat_\func,.-__kernel_compat_\func
+.endm
+
+vdso_syscall restart_syscall,__NR_restart_syscall
+vdso_syscall sigreturn,__NR_sigreturn
+vdso_syscall rt_sigreturn,__NR_rt_sigreturn
index a6e0fb6b91d6c61c08477b345659dcd253ef4d07..2a2092ce19f1b2560ac987d36ae1921c63c57093 100644 (file)
@@ -74,3 +74,11 @@ vdso64.so: $(obj)/vdso64.so.dbg
        $(call cmd,vdso_install)
 
 vdso_install: vdso64.so
+
+# 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)
diff --git a/arch/s390/kernel/vdso64/gen_vdso_offsets.sh b/arch/s390/kernel/vdso64/gen_vdso_offsets.sh
new file mode 100755 (executable)
index 0000000..37f05cb
--- /dev/null
@@ -0,0 +1,15 @@
+#!/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.
+#
+# Inspired by arm64 version.
+#
+
+LC_ALL=C
+sed -n 's/\([0-9a-f]*\) . __kernel_\(.*\)/\#define vdso64_offset_\2\t0x\1/p'