[PATCH] vDSO hash-style fix
authorRoland McGrath <roland@redhat.com>
Sun, 30 Jul 2006 10:04:06 +0000 (03:04 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 31 Jul 2006 20:28:43 +0000 (13:28 -0700)
The latest toolchains can produce a new ELF section in DSOs and
dynamically-linked executables.  The new section ".gnu.hash" replaces
".hash", and allows for more efficient runtime symbol lookups by the
dynamic linker.  The new ld option --hash-style={sysv|gnu|both} controls
whether to produce the old ".hash", the new ".gnu.hash", or both.  In some
new systems such as Fedora Core 6, gcc by default passes --hash-style=gnu
to the linker, so that a standard invocation of "gcc -shared" results in
producing a DSO with only ".gnu.hash".  The new ".gnu.hash" sections need
to be dealt with the same way as ".hash" sections in all respects; only the
dynamic linker cares about their contents.  To work with older dynamic
linkers (i.e.  preexisting releases of glibc), a binary must have the old
".hash" section.  The --hash-style=both option produces binaries that a new
dynamic linker can use more efficiently, but an old dynamic linker can
still handle.

The new section runs afoul of the custom linker scripts used to build vDSO
images for the kernel.  On ia64, the failure mode for this is a boot-time
panic because the vDSO's PT_IA_64_UNWIND segment winds up ill-formed.

This patch addresses the problem in two ways.

First, it mentions ".gnu.hash" in all the linker scripts alongside ".hash".
 This produces correct vDSO images with --hash-style=sysv (or old tools),
with --hash-style=gnu, or with --hash-style=both.

Second, it passes the --hash-style=sysv option when building the vDSO
images, so that ".gnu.hash" is not actually produced.  This is the most
conservative choice for compatibility with any old userland.  There is some
concern that some ancient glibc builds (though not any known old production
system) might choke on --hash-style=both binaries.  The optimizations
provided by the new style of hash section do not really matter for a DSO
with a tiny number of symbols, as the vDSO has.  If someone wants to use
=gnu or =both for their vDSO builds and worry less about that
compatibility, just change the option and the linker script changes will
make any choice work fine.

Signed-off-by: Roland McGrath <roland@redhat.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: Kyle McMartin <kyle@mcmartin.ca>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Jeff Dike <jdike@addtoit.com>
Cc: Andi Kleen <ak@muc.de>
Cc: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
15 files changed:
Documentation/kbuild/makefiles.txt
arch/i386/kernel/Makefile
arch/i386/kernel/vsyscall.lds.S
arch/ia64/kernel/Makefile
arch/ia64/kernel/gate.lds.S
arch/parisc/kernel/vmlinux.lds.S
arch/powerpc/kernel/vdso32/Makefile
arch/powerpc/kernel/vdso32/vdso32.lds.S
arch/powerpc/kernel/vdso64/Makefile
arch/powerpc/kernel/vdso64/vdso64.lds.S
arch/ppc/kernel/vmlinux.lds.S
arch/um/kernel/dyn.lds.S
arch/x86_64/ia32/Makefile
arch/x86_64/ia32/vsyscall.lds
scripts/Kbuild.include

index 14ef3868a328d5080b8748507a8e8be576c936cd..0706699c9da91c7814449f41714ee883017e0a66 100644 (file)
@@ -407,6 +407,20 @@ more details, with real examples.
        The second argument is optional, and if supplied will be used
        if first argument is not supported.
 
+    ld-option
+       ld-option is used to check if $(CC) when used to link object files
+       supports the given option.  An optional second option may be
+       specified if first option are not supported.
+
+       Example:
+               #arch/i386/kernel/Makefile
+               vsyscall-flags += $(call ld-option, -Wl$(comma)--hash-style=sysv)
+
+       In the above example vsyscall-flags will be assigned the option
+       -Wl$(comma)--hash-style=sysv if it is supported by $(CC).
+       The second argument is optional, and if supplied will be used
+       if first argument is not supported.
+
     cc-option
        cc-option is used to check if $(CC) support a given option, and not
        supported to use an optional second option.
index 1b452a1665c4ffe92a05f3a5fa80704b4e1738ec..ab98fc21a54105b7d41fed6a5c6861ed44735dad 100644 (file)
@@ -59,7 +59,8 @@ quiet_cmd_syscall = SYSCALL $@
 
 export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH)
 
-vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1
+vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \
+                $(call ld-option, -Wl$(comma)--hash-style=sysv)
 SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags)
 SYSCFLAGS_vsyscall-int80.so    = $(vsyscall-flags)
 
index e26975fc68b650105cbff7b0568ba7b856770085..f66cd11adb7211e211f6d78f2ad063e0701ce832 100644 (file)
@@ -10,6 +10,7 @@ SECTIONS
   . = VDSO_PRELINK + SIZEOF_HEADERS;
 
   .hash           : { *(.hash) }               :text
+  .gnu.hash       : { *(.gnu.hash) }
   .dynsym         : { *(.dynsym) }
   .dynstr         : { *(.dynstr) }
   .gnu.version    : { *(.gnu.version) }
index 0e4553f320bffd4a812401f0cae3836f63d88c7d..ad8215a3c586948f3cf92c2e6c80f31a5ff36aa5 100644 (file)
@@ -45,7 +45,8 @@ CPPFLAGS_gate.lds := -P -C -U$(ARCH)
 quiet_cmd_gate = GATE $@
       cmd_gate = $(CC) -nostdlib $(GATECFLAGS_$(@F)) -Wl,-T,$(filter-out FORCE,$^) -o $@
 
-GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1
+GATECFLAGS_gate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
+                    $(call ld-option, -Wl$(comma)--hash-style=sysv)
 $(obj)/gate.so: $(obj)/gate.lds $(obj)/gate.o FORCE
        $(call if_changed,gate)
 
index cc35cddfd4cfdd8e047ed30b06ef6e87f7f5c7e2..6d198339bf85446d2f47d1bf7a2b5e9731dffbbb 100644 (file)
@@ -12,6 +12,7 @@ SECTIONS
   . = GATE_ADDR + SIZEOF_HEADERS;
 
   .hash                                : { *(.hash) }                          :readable
+  .gnu.hash                    : { *(.gnu.hash) }
   .dynsym                      : { *(.dynsym) }
   .dynstr                      : { *(.dynstr) }
   .gnu.version                 : { *(.gnu.version) }
index 9989495a51dd64e8c026c88c20fec99fc9dc2ae0..b3677fc8eef597fb9f4ebeb6fda0249e4a48f5f2 100644 (file)
@@ -204,6 +204,7 @@ SECTIONS
        *(.dynstr)
        *(.dynamic)
        *(.hash)
+       *(.gnu.hash)
 #endif
        }
 
index 8a3bed5f143a14f4a226a26fbcae4a2ba07e9791..3726358faae88444f8603c7a8cc8f0b394095846 100644 (file)
@@ -14,7 +14,8 @@ obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32))
 
 
 EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin
-EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1
+EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 \
+               $(call ld-option, -Wl$(comma)--hash-style=sysv)
 EXTRA_AFLAGS := -D__VDSO32__ -s
 
 obj-y += vdso32_wrapper.o
index f4bad720cb0a1b7f450260671844261f0ebb634e..6187af2d54c393ea825e523172636ebbcd062427 100644 (file)
@@ -14,6 +14,7 @@ SECTIONS
 {
   . = VDSO32_LBASE + SIZEOF_HEADERS;
   .hash           : { *(.hash) }                       :text
+  .gnu.hash       : { *(.gnu.hash) }
   .dynsym         : { *(.dynsym) }
   .dynstr         : { *(.dynstr) }
   .gnu.version    : { *(.gnu.version) }
index ab39988452ccb8f5ec90fc19c03ecb5be117b0ab..43af9b2a6f3bd21dc8b3d4f86faa7928f041648b 100644 (file)
@@ -8,7 +8,8 @@ targets := $(obj-vdso64) vdso64.so
 obj-vdso64 := $(addprefix $(obj)/, $(obj-vdso64))
 
 EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin
-EXTRA_CFLAGS +=  -nostdlib -Wl,-soname=linux-vdso64.so.1
+EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso64.so.1 \
+               $(call ld-option, -Wl$(comma)--hash-style=sysv)
 EXTRA_AFLAGS := -D__VDSO64__ -s
 
 obj-y += vdso64_wrapper.o
index 4bdf224464abaf2914a2d62bb285f5f3404fe85c..4a2b6dc0960c582b3b0f0f9c8ba73a171195ee0c 100644 (file)
@@ -12,6 +12,7 @@ SECTIONS
 {
   . = VDSO64_LBASE + SIZEOF_HEADERS;
   .hash           : { *(.hash) }               :text
+  .gnu.hash       : { *(.gnu.hash) }
   .dynsym         : { *(.dynsym) }
   .dynstr         : { *(.dynstr) }
   .gnu.version    : { *(.gnu.version) }
index 09c6525cfa6133081b962fdc0257e6189dbe0d67..095fd3323323b077a3acbcdcdf00e91c7bacce02 100644 (file)
@@ -8,6 +8,7 @@ SECTIONS
   . = + SIZEOF_HEADERS;
   .interp : { *(.interp) }
   .hash          : { *(.hash)          }
+  .gnu.hash      : { *(.gnu.hash)      }
   .dynsym        : { *(.dynsym)                }
   .dynstr        : { *(.dynstr)                }
   .rel.text      : { *(.rel.text)              }
index 2517ecb8bf27d07d56fc5903c0cd26052aa7617a..68ed24df5c8fa7f24d5089e305fa91e743c37e5a 100644 (file)
@@ -26,6 +26,7 @@ SECTIONS
 
   /* Read-only sections, merged into text segment: */
   .hash           : { *(.hash) }
+  .gnu.hash       : { *(.gnu.hash) }
   .dynsym         : { *(.dynsym) }
   .dynstr         : { *(.dynstr) }
   .gnu.version    : { *(.gnu.version) }
index 62bc5f56da9e7cf8def1e9749297c6e2b1234cf1..cdae36435e21a308aece3f925cf71e5a5b8a7c8a 100644 (file)
@@ -23,6 +23,7 @@ targets := $(foreach F,sysenter syscall,vsyscall-$F.o vsyscall-$F.so)
 # The DSO images are built using a special linker script
 quiet_cmd_syscall = SYSCALL $@
       cmd_syscall = $(CC) -m32 -nostdlib -shared -s \
+                         $(call ld-option, -Wl$(comma)--hash-style=sysv) \
                           -Wl,-soname=linux-gate.so.1 -o $@ \
                           -Wl,-T,$(filter-out FORCE,$^)
 
index f2e75ed4c6c757caca14fa19cb488e75d97f685e..1dc86ff5bcb9013a3fa404700129ce528ae0061b 100644 (file)
@@ -11,6 +11,7 @@ SECTIONS
   . = VSYSCALL_BASE + SIZEOF_HEADERS;
 
   .hash           : { *(.hash) }               :text
+  .gnu.hash       : { *(.gnu.hash) }
   .dynsym         : { *(.dynsym) }
   .dynstr         : { *(.dynstr) }
   .gnu.version    : { *(.gnu.version) }
index 2180c88cfe89111a79cfb15bb8361aefcd067d59..f01132263535fcfa0a47ecb5ac8cc789ece1c497 100644 (file)
@@ -85,6 +85,13 @@ cc-version = $(shell $(CONFIG_SHELL) $(srctree)/scripts/gcc-version.sh \
 cc-ifversion = $(shell if [ $(call cc-version, $(CC)) $(1) $(2) ]; then \
                        echo $(3); fi;)
 
+# ld-option
+# Usage: ldflags += $(call ld-option, -Wl$(comma)--hash-style=both)
+ld-option = $(shell if $(CC) $(1) \
+                            -nostdlib -o ldtest$$$$.out -xc /dev/null \
+             > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi; \
+            rm -f ldtest$$$$.out)
+
 ###
 # Shorthand for $(Q)$(MAKE) -f scripts/Makefile.build obj=
 # Usage: