Skip to contentSkip to conversation

i386 vsyscall DSO implementation, take 2

PATCH In review Roland McGrath 3 participants 4 messages May 2, 2003 – May 4, 2003

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 i386 vsyscall DSO implementation, take 2

There was a small bug in the core dump changes in the patch I posted. I have fixed that. The rest of the patch is unchanged. AFAICT, people like the idea, and this patch works well for me. Can it go in?

Thanks,
Roland

arch/i386/kernel/Makefile +21 -1
@@ -27,9 +27,29 @@ obj-$(CONFIG_SOFTWARE_SUSPEND)	+= suspen
 obj-$(CONFIG_X86_NUMAQ)		+= numaq.o
 obj-$(CONFIG_EDD)             	+= edd.o
 obj-$(CONFIG_MODULES)		+= module.o
-obj-y				+= sysenter.o
+obj-y				+= sysenter.o vsyscall.o
 obj-$(CONFIG_ACPI_SRAT) 	+= srat.o
 
 EXTRA_AFLAGS   := -traditional
 
 obj-$(CONFIG_SCx200)		+= scx200.o
+
+# vsyscall.o contains the vsyscall DSO images as __initdata.
+# We must build both images before we can assemble it.
+$(obj)/vsyscall.o: $(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so
+extra-y += $(foreach F,int80 sysenter,vsyscall-$F.o vsyscall-$F.so)
+
+# The DSO images are built using a special linker script.
+$(obj)/vsyscall-int80.so $(obj)/vsyscall-sysenter.so: \
+$(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o
+	$(CC) -nostdlib -shared -s -Wl,-soname=linux-vsyscall.so.1 \
+	      -o $@ -Wl,-T,$^
+
+# We also create a special relocatable object that should mirror the symbol
+# table and layout of the linked DSO.  With ld -R we can then refer to
+# these symbols in the kernel code rather than hand-coded addresses.
+extra-y += vsyscall-syms.o
+$(obj)/built-in.o: $(obj)/vsyscall-syms.o
+$(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o
+$(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o
+	$(CC) -nostdlib -r -o $@ -Wl,-T,$^
arch/i386/kernel/entry.S +2 -2
@@ -230,8 +230,8 @@ need_resched:
 	jmp need_resched
 #endif
 
-/* Points to after the "sysenter" instruction in the vsyscall page */
-#define SYSENTER_RETURN 0xffffe010
+/* SYSENTER_RETURN points to after the "sysenter" instruction in
+   the vsyscall page.  See vsyscall-sysentry.S, which defines the symbol.  */
 
 	# sysenter call handler stub
 ENTRY(sysenter_entry)
arch/i386/kernel/signal.c +7 -2
@@ -19,6 +19,7 @@
 #include <linux/stddef.h>
 #include <linux/personality.h>
 #include <linux/suspend.h>
+#include <linux/elf.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
@@ -347,6 +348,10 @@ get_sigframe(struct k_sigaction *ka, str
 	return (void __user *)((esp - frame_size) & -8ul);
 }
 
+/* These symbols are defined with the addresses in the vsyscall page.
+   See vsyscall-sigreturn.S.  */
+extern void __kernel_sigreturn, __kernel_rt_sigreturn;
+
 static void setup_frame(int sig, struct k_sigaction *ka,
 			sigset_t *set, struct pt_regs * regs)
 {
@@ -379,7 +384,7 @@ static void setup_frame(int sig, struct 
 	if (err)
 		goto give_sigsegv;
 
-	restorer = (void *) (fix_to_virt(FIX_VSYSCALL) + 32);
+	restorer = &__kernel_sigreturn;
 	if (ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 
@@ -462,7 +467,7 @@ static void setup_rt_frame(int sig, stru
 		goto give_sigsegv;
 
 	/* Set up to return from userspace.  */
-	restorer = (void *) (fix_to_virt(FIX_VSYSCALL) + 64);
+	restorer = &__kernel_rt_sigreturn;
 	if (ka->sa.sa_flags & SA_RESTORER)
 		restorer = ka->sa.sa_restorer;
 	err |= __put_user(restorer, &frame->pretcode);
arch/i386/kernel/sysenter.c +17 -138

168 lines not on this page · raw message

arch/i386/kernel/vsyscall-int80.S +48 -0

48 lines not on this page · raw message

arch/i386/kernel/vsyscall-sysenter.S +97 -0

97 lines not on this page · raw message

arch/i386/kernel/vsyscall-sigreturn.S +38 -0
@@ -0,0 +1,38 @@
+/*
+ * Common code for the sigreturn entry points on the vsyscall page.
+ * So far this code is the same for both int80 and sysenter versions.
+ * This file is #include'd by vsyscall-*.S to define them after the
+ * vsyscall entry point.  The addresses we get for these entry points
+ * by doing ".balign 32" must match in both versions of the page.
+ */
+
+#include <asm/unistd.h>
+
+
+/* XXX
+   Should these be named "_sigtramp" or something?
+*/
+
+	.text
+	.balign 32
+	.globl __kernel_sigreturn
+	.type __kernel_sigreturn,@function
+__kernel_sigreturn:
+.LSTART_kernel_sigreturn:
+	popl %eax		/* XXX does this mean it needs unwind info? */
+	movl $__NR_sigreturn, %eax
+	int $0x80
+.LEND_sigreturn:
+	.size __kernel_sigreturn,.-.LSTART_sigreturn
+
+	.text
+	.balign 32
+	.globl __kernel_rt_sigreturn
+	.type __kernel_rt_sigreturn,@function
+__kernel_rt_sigreturn:
+.LSTART_kernel_rt_sigreturn:
+	movl $__NR_rt_sigreturn, %eax
+	int $0x80
+.LEND_rt_sigreturn:
+	.size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
+	.previous
arch/i386/kernel/vsyscall.lds +67 -0

67 lines not on this page · raw message

fs/binfmt_elf.c +11 -0
@@ -1260,6 +1260,9 @@ static int elf_core_dump(long signr, str
 	elf_core_copy_regs(&prstatus->pr_reg, regs);
 	
 	segs = current->mm->map_count;
+#ifdef ELF_CORE_EXTRA_PHDRS
+	segs += ELF_CORE_EXTRA_PHDRS;
+#endif
 
 	/* Set up header */
 	fill_elf_header(elf, segs+1);	/* including notes section */
@@ -1340,6 +1343,10 @@ static int elf_core_dump(long signr, str
 		DUMP_WRITE(&phdr, sizeof(phdr));
 	}
 
+#ifdef ELF_CORE_WRITE_EXTRA_PHDRS
+	ELF_CORE_WRITE_EXTRA_PHDRS;
+#endif
+
  	/* write out the notes section */
 	for (i = 0; i < numnote; i++)
 		if (!writenote(notes + i, file))
@@ -1385,6 +1392,10 @@ static int elf_core_dump(long signr, str
 		}
 	}
 
+#ifdef ELF_CORE_WRITE_EXTRA_DATA
+	ELF_CORE_WRITE_EXTRA_DATA;
+#endif
+
 	if ((off_t) file->f_pos != offset) {
 		/* Sanity check */
 		printk("elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
include/linux/elf.h +3 -0
@@ -29,8 +29,11 @@ typedef __s64	Elf64_Sxword;
 #define PT_NOTE    4
 #define PT_SHLIB   5
 #define PT_PHDR    6
+#define PT_LOOS	   0x60000000
+#define PT_HIOS	   0x6fffffff
 #define PT_LOPROC  0x70000000
 #define PT_HIPROC  0x7fffffff
+#define PT_GNU_EH_FRAME		0x6474e550
 #define PT_MIPS_REGINFO		0x70000000
 
 /* Flags in the e_flags field of the header */
include/asm-i386/elf.h +48 -7

70 lines not on this page · raw message

#1 lore raw
Quoted 10 lines · Roland McGrath
arch/i386/kernel/vsyscall-sysenter.S +10 -0
+	/* What follows are the instructions for the table generation.
+	   We have to record all changes of the stack pointer.  */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpush_ecx-.LSTART_vsyscall
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x08		/* RA at offset 8 now */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpush_edx-.Lpush_ecx
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x0c		/* RA at offset 12 now */

arch/i386/kernel/vsyscall-sysenter.S line 82

Quoted 10 lines
arch/i386/kernel/vsyscall-sysenter.S +10 -0
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lenter_kernel-.Lpush_edx
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x10		/* RA at offset 16 now */
+	/* Finally the epilogue.  */
+	.byte 0x04		/* DW_CFA_advance_loc4 */
+	.long .Lpop_ebp-.Lenter_kernel
+	.byte 0x0e		/* DW_CFA_def_cfa_offset */
+	.byte 0x12		/* RA at offset 12 now */
+	.byte 0x04		/* DW_CFA_advance_loc4 */

You lost the save/restore notes for ebp.

arch/i386/kernel/vsyscall-sigreturn.S line 22

Quoted 4 lines
arch/i386/kernel/vsyscall-sigreturn.S +4 -0
+	.type __kernel_sigreturn,@function
+__kernel_sigreturn:
+.LSTART_kernel_sigreturn:
+	popl %eax		/* XXX does this mean it needs unwind info? */

Well, yes, but not because of this per-se. The unwind info for sigreturn will be quite complex because it should expose the state of the machine after the return. I.e. it would replace the rather complex code in both gdb and libgcc that fakes some knowledge of the signal stack frame.

I can try to write it for you if you like.

r~

#2 lore raw

PATCH 1/1 fix vsyscall unwind information

Re-adds the %ebp save/restore correction I'd given Uli when the unwind information went into sysenter.c, which somehow got lost with Roland's reorg.

Also adds unwind info for the sigreturn entry points. This can be used instead of special-case hacks currently in libgcc and gdb, and by extension allows the kernel to change these entry points without breaking userland.

Tested with Roland's patch to make the VDSO available in glibc, plus a set of fixes to libgcc, since location expressions hadn't ever been tested before in this context.

Linus, please pull from

	bk://are.twiddle.net/unwind-2.5

r~

 arch/i386/Makefile                    |    9 ++
 arch/i386/kernel/asm-offsets.c        |   31 +++++++++
 arch/i386/kernel/sigframe.h           |   21 ++++++
 arch/i386/kernel/signal.c             |   23 -------
 arch/i386/kernel/vsyscall-sigreturn.S |  110 +++++++++++++++++++++++++++++++++-
 arch/i386/kernel/vsyscall-sysenter.S  |    2 
 6 files changed, 171 insertions(+), 25 deletions(-)

through these ChangeSets:

<[email protected]> (03/05/03 1.1209)
Fix unwind info for sysenter entry point.
Add unwind info for sigreturn entry points.

# This is a BitKeeper generated patch for the following project:
# Project Name: Linux kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas:
# ChangeSet 1.1208 -> 1.1209
# arch/i386/Makefile 1.49 -> 1.50
# arch/i386/kernel/vsyscall-sysenter.S 1.1 -> 1.2
# arch/i386/kernel/signal.c 1.30 -> 1.31
# arch/i386/kernel/vsyscall-sigreturn.S 1.1 -> 1.2

#	               (new)	        -> 1.1     arch/i386/kernel/sigframe.h
#	               (new)	        -> 1.1     arch/i386/kernel/asm-offsets.c

#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 03/05/03 [email protected] 1.1209
# Fix unwind info for sysenter entry point.
# Add unwind info for sigreturn entry points.
# --------------------------------------------
#

arch/i386/Makefile +9 -0
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
@@ -114,6 +114,15 @@
 install fdimage fdimage144 fdimage288: vmlinux
 	$(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
 
+prepare: include/asm-$(ARCH)/asm_offsets.h
+CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h
+
+arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \
+				   include/config/MARKER
+
+include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s
+	$(call filechk,gen-asm-offsets)
+
 archclean:
 	$(Q)$(MAKE) $(clean)=arch/i386/boot
 
arch/i386/kernel/asm-offsets.c new file +31 -0
diff -Nru a/arch/i386/kernel/asm-offsets.c b/arch/i386/kernel/asm-offsets.c
@@ -0,0 +1,31 @@
+/*
+ * Generate definitions needed by assembly language modules.
+ * This code generates raw asm output which is post-processed
+ * to extract and format the required data.
+ */
+
+#include <linux/signal.h>
+#include <asm/ucontext.h>
+#include "sigframe.h"
+
+#define DEFINE(sym, val) \
+        asm volatile("\n->" #sym " %0 " #val : : "i" (val))
+
+#define BLANK() asm volatile("\n->" : : )
+
+void foo(void)
+{
+	DEFINE(SIGCONTEXT_eax, offsetof (struct sigcontext, eax));
+	DEFINE(SIGCONTEXT_ebx, offsetof (struct sigcontext, ebx));
+	DEFINE(SIGCONTEXT_ecx, offsetof (struct sigcontext, ecx));
+	DEFINE(SIGCONTEXT_edx, offsetof (struct sigcontext, edx));
+	DEFINE(SIGCONTEXT_esi, offsetof (struct sigcontext, esi));
+	DEFINE(SIGCONTEXT_edi, offsetof (struct sigcontext, edi));
+	DEFINE(SIGCONTEXT_ebp, offsetof (struct sigcontext, ebp));
+	DEFINE(SIGCONTEXT_esp, offsetof (struct sigcontext, esp));
+	DEFINE(SIGCONTEXT_eip, offsetof (struct sigcontext, eip));
+	BLANK();
+
+	DEFINE(RT_SIGFRAME_sigcontext,
+	       offsetof (struct rt_sigframe, uc.uc_mcontext));
+}
arch/i386/kernel/sigframe.h new file +21 -0
diff -Nru a/arch/i386/kernel/sigframe.h b/arch/i386/kernel/sigframe.h
@@ -0,0 +1,21 @@
+struct sigframe
+{
+	char *pretcode;
+	int sig;
+	struct sigcontext sc;
+	struct _fpstate fpstate;
+	unsigned long extramask[_NSIG_WORDS-1];
+	char retcode[8];
+};
+
+struct rt_sigframe
+{
+	char *pretcode;
+	int sig;
+	struct siginfo *pinfo;
+	void *puc;
+	struct siginfo info;
+	struct ucontext uc;
+	struct _fpstate fpstate;
+	char retcode[8];
+};
arch/i386/kernel/signal.c +1 -22
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
@@ -23,6 +23,7 @@
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 #include <asm/i387.h>
+#include "sigframe.h"
 
 #define DEBUG_SIG 0
 
@@ -125,28 +126,6 @@
 /*
  * Do a signal return; undo the signal stack.
  */
-
-struct sigframe
-{
-	char *pretcode;
-	int sig;
-	struct sigcontext sc;
-	struct _fpstate fpstate;
-	unsigned long extramask[_NSIG_WORDS-1];
-	char retcode[8];
-};
-
-struct rt_sigframe
-{
-	char *pretcode;
-	int sig;
-	struct siginfo *pinfo;
-	void *puc;
-	struct siginfo info;
-	struct ucontext uc;
-	struct _fpstate fpstate;
-	char retcode[8];
-};
 
 static int
 restore_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc, int *peax)
arch/i386/kernel/vsyscall-sigreturn.S +107 -3

134 lines not on this page · raw message

arch/i386/kernel/vsyscall-sysenter.S +2 -0
diff -Nru a/arch/i386/kernel/vsyscall-sysenter.S b/arch/i386/kernel/vsyscall-sysenter.S
@@ -74,11 +74,13 @@
 	.long .Lenter_kernel-.Lpush_edx
 	.byte 0x0e		/* DW_CFA_def_cfa_offset */
 	.byte 0x10		/* RA at offset 16 now */
+	.byte 0x85, 0x04	/* DW_CFA_offset %ebp -16 */
 	/* Finally the epilogue.  */
 	.byte 0x04		/* DW_CFA_advance_loc4 */
 	.long .Lpop_ebp-.Lenter_kernel
 	.byte 0x0e		/* DW_CFA_def_cfa_offset */
 	.byte 0x12		/* RA at offset 12 now */
+	.byte 0xc5		/* DW_CFA_restore %ebp */
 	.byte 0x04		/* DW_CFA_advance_loc4 */
 	.long .Lpop_edx-.Lpop_ebp
 	.byte 0x0e		/* DW_CFA_def_cfa_offset */
#3 lore raw

Re: [PATCH] fix vsyscall unwind information

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 1 line · Richard Henderson

Also adds unwind info for the sigreturn entry points.

Sweet.

Quoted 4 lines

This can
be used instead of special-case hacks currently in libgcc and gdb, and by extension allows the kernel to change these entry points without breaking userland.

Exactly. This means we can get rid of the int $0x80. I.e., move the sigreturn code in the two .S files for sysenter and int80. Reducing the cost of signals is always good.

I'm not sure how this use of sigreturn has to look like. Linus, maybe you should do it yourself.

- --
- --------------. ,-. 444 Castro Street
Ulrich Drepper \ ,-----------------' \ Mountain View, CA 94041 USA
Red Hat --' drepper at redhat.com ---------------------------
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+tMKL2ijCOnn/RHQRAoDbAJ4nnP3Hcb8xAeqjRHxgq0YZZmcs0wCdE4BE Obuu/wRdq70aooscs1JOhto=
=5Sx4
-----END PGP SIGNATURE-----