Bug 1006 - ld.so does backwards R_SPARC_WDISP30 relocations wrongly
Summary: ld.so does backwards R_SPARC_WDISP30 relocations wrongly
Status: RESOLVED FIXED
Alias: None
Product: glibc
Classification: Unclassified
Component: libc (show other bugs)
Version: 2.3.5
: P2 normal
Target Milestone: ---
Assignee: Jakub Jelinek
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-06-12 00:00 UTC by Peter Hartley
Modified: 2006-09-09 17:24 UTC (History)
1 user (show)

See Also:
Host: sparc64-unknown-linux
Target: sparc64-unknown-linux
Build: sparc64-unknown-linux
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Peter Hartley 2005-06-12 00:00:33 UTC
The code for R_SPARC_WDISP30 relocations at about line 326 of
sysdeps/sparc/sparc64/dl-machine.h doesn't cope with backwards calls: if "value
- reloc_addr" comes out as a negative 64-bit quantity, then bits 31 and 30 of
the result get set, incorrectly.

This causes SIGILL when the resulting code is executed. Modern binutils lays
down such WDISP30 relocations for calls to other routines in the same
translation unit. In particular, this happens when I build zlib and then someone
(e.g. a PNG decoder in the GTK+2 build system) calls zlib's inflateInit, which
has a backwards call to inflateInit2 (just before it in memory) that is laid
down as a R_SPARC_WDISP30 relocation. Applying the patch below fixes the SIGILL
problem.

Sparc64 Linux (64-bit userland), GCC 3.3.5, binutils 2.15.94.0.2.2, problem
observed using glibc 2.3.2 but identical code appears in 2.3.5.

Code before dynamic linking (with stock glibc):

--- glibc-2.3.2/sysdeps/sparc/sparc64/dl-machine.h~     2002-09-28 04:35:31 +0100
+++ glibc-2.3.2/sysdeps/sparc/sparc64/dl-machine.h      2005-06-12 01:03:48 +0100
@@ -322,7 +322,7 @@ elf_machine_rela (struct link_map *map, 
        case R_SPARC_WDISP30:
          *(unsigned int *) reloc_addr =
            ((*(unsigned int *)reloc_addr & 0xc0000000) |
-            ((value - (Elf64_Addr) reloc_addr) >> 2));
+            (((value - (Elf64_Addr) reloc_addr) >> 2) & 0x3fffffff));
          break;
 
        /* MEDLOW code model relocs */
Comment 1 Peter Hartley 2005-07-06 13:57:29 UTC
On looking again, this was sort-of user error. I still reckon the glibc code is
strictly speaking incorrect, but the reason I encountered the bug is that I'd
accidentally not compiled the shared zlib with -fPIC. Adding -fPIC and
recompiling results in no WDISP30 relocations (and so perhaps -fPIC *never*
generates them) and thus the infelicitous code is never reached.
Comment 2 Ulrich Drepper 2006-09-09 17:24:17 UTC
Fixed in cvs.