From patchwork Sat Dec 26 19:32:05 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sergei Trofimovich X-Patchwork-Id: 10140 Received: (qmail 111020 invoked by alias); 26 Dec 2015 19:32:24 -0000 Mailing-List: contact libc-alpha-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libc-alpha-owner@sourceware.org Delivered-To: mailing list libc-alpha@sourceware.org Received: (qmail 110989 invoked by uid 89); 26 Dec 2015 19:32:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, RP_MATCHES_RCVD, SPF_PASS autolearn=ham version=3.3.2 spammy=HTo:U*rguenth, H*Ad:U*ebotcazou, gccs, gcc's X-HELO: smtp.gentoo.org From: slyich@gmail.com To: libc-alpha@sourceware.org, Andreas Schwab , Mike Frysinger , Richard Biener Cc: Eric Botcazou , Dennis Schridde , Sergei Trofimovich Subject: [PATCH] elf/get-dynamic-info.h: fix early GNU_HASH processing on ia64 Date: Sat, 26 Dec 2015 19:32:05 +0000 Message-Id: <1451158325-4790-1-git-send-email-slyich@gmail.com> From: Sergei Trofimovich The following code when being called with l = _rtld_local._dl_rtld_map info = l->l_info elf_get_dynamic_info(struct link_map *l,ElfW(Dyn) *dyn) { ... info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn; ... led to generation of the follwoing assembly code: [MMI] ld8 r14=[r32];; # r14 = dyn->d_tag shladd r15=r14,3,r0 # r15 = dyn->d_tag * 8 addl r14=163312,r1;; # r14 = gp + @ltoffx(_rtld_local#+0x380000000) [MMI] ld8 r14=[r14];; adds r14=992,r14 # r14 = [abs_reloc] + 992 nop.i 0x0;; [MMI] nop.m 0x0 sub r14=r14,r15 nop.i 0x0;; [MIB] st8 [r14]=r32 # [[abs_reloc] + 992] = dyn nop.i 0x0 br.ret.sptk.many b0;; This 'abs_reloc' is a relocation of R_IA64_REL64LSB type. objdump -r -R ld.so: DYNAMIC RELOCATION RECORDS OFFSET TYPE VALUE ... 0000000000052910 REL64LSB *ABS*+0x0000000380052a60 After gcc's preprocessor and constant propagation phase the code info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn; became equivalent equivalent to: _rtld_local._dl_rtld_map.l_info[(0x6ffffeff - dyn->d_tag) + 66] (0x6ffffeff + 66) * 8 + 2520 = 0x3800003e0 # 2520 is offset of '_rtld_local._dl_rtld_map.l_info' # 0x3e0 = 992 To workaround generation of that huge offset and relocation I've moved index computation into a separate variable to trick gcc into simpler code. Bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60465#c32 Signed-off-by: Sergei Trofimovich --- elf/get-dynamic-info.h | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/elf/get-dynamic-info.h b/elf/get-dynamic-info.h index dc8359d..45c51aa 100644 --- a/elf/get-dynamic-info.h +++ b/elf/get-dynamic-info.h @@ -66,8 +66,19 @@ elf_get_dynamic_info (struct link_map *l, ElfW(Dyn) *temp) info[DT_VALTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + DT_VERSIONTAGNUM + DT_EXTRANUM] = dyn; else if ((d_tag_utype) DT_ADDRTAGIDX (dyn->d_tag) < DT_ADDRNUM) - info[DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM - + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM] = dyn; + { + /* Use local 'tag_ix' to avoid gcc picking large offset: + DT_ADDRTAGIDX (x) = 0x6ffffeff - x + which leads gcc to use R_IA64_REL64LSB relocation. + We cannot allow it as 'elf_get_dynamic_info' is called + before relocations are processed by 'ld.so'. + https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60465#c32. + */ + d_tag_utype tag_ix = + DT_ADDRTAGIDX (dyn->d_tag) + DT_NUM + DT_THISPROCNUM + + DT_VERSIONTAGNUM + DT_EXTRANUM + DT_VALNUM; + info[tag_ix] = dyn; + } ++dyn; }