This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug dynamic-link/17868] New: powerpc: ifuncmain6pie failure with GCC 4.9
- From: "azanella at linux dot vnet.ibm.com" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sourceware dot org
- Date: Fri, 23 Jan 2015 16:03:15 +0000
- Subject: [Bug dynamic-link/17868] New: powerpc: ifuncmain6pie failure with GCC 4.9
- Auto-submitted: auto-generated
https://sourceware.org/bugzilla/show_bug.cgi?id=17868
Bug ID: 17868
Summary: powerpc: ifuncmain6pie failure with GCC 4.9
Product: glibc
Version: 2.20
Status: NEW
Severity: normal
Priority: P2
Component: dynamic-link
Assignee: unassigned at sourceware dot org
Reporter: azanella at linux dot vnet.ibm.com
Since GLIBC release 2.20, the testcase elf/ifuncmain6pie fails when building
with GCC 4.9+. e.
The which basically check if some IFUNC is being relocated correctly in a
shared library. The failures is:
$ ./testrun.sh elf/ifuncmain6pie
Illegal instruction (core dumped)
And debugging it I found that the issue seems to be the value used in IFUNC
relocation address at:
* sysdeps/powerpc/powerpc64/dl-machine.h:
606 /* Call function at address VALUE (an OPD entry) to resolve ifunc relocs.
*/
607 auto inline Elf64_Addr __attribute__ ((always_inline))
608 resolve_ifunc (Elf64_Addr value,
609 const struct link_map *map, const struct link_map *sym_map)
610 {
611 #if _CALL_ELF != 2
612 #ifndef RESOLVE_CONFLICT_FIND_MAP
613 /* The function we are calling may not yet have its opd entry relocated.
*/
614 Elf64_FuncDesc opd;
615 if (map != sym_map
616 # if !defined RTLD_BOOTSTRAP && defined SHARED
617 /* Bootstrap map doesn't have l_relocated set for it. */
618 && sym_map != &GL(dl_rtld_map)
619 # endif
620 && !sym_map->l_relocated)
621 {
622 Elf64_FuncDesc *func = (Elf64_FuncDesc *) value;
623 opd.fd_func = func->fd_func + sym_map->l_addr;
624 opd.fd_toc = func->fd_toc + sym_map->l_addr;
625 opd.fd_aux = func->fd_aux;
626 value = (Elf64_Addr) &opd;
627 }
628 #endif
629 #endif
630 return ((Elf64_Addr (*) (unsigned long int)) value) (GLRO(dl_hwcap));
631 }
The function is a always inline one and GLIBC can not be built without
optimization, so took me some time to figure out where exactly it was being
called and the issues.
On GCC 4.9 the problems is on line 630. the 'value' is a bogus one, leading to
a memory area that contains no code and thus issuing an invalid instruction.
At first I though it would be a GLIBC or a linker issue, but debugging it does
not seem so. The 'resolve_ifunc' is being called at:
* sysdeps/powerpc/powerpc64/dl-machine.h:
633 /* Perform the relocation specified by RELOC and SYM (which is fully
634 resolved). MAP is the object containing the reloc. */
635 auto inline void __attribute__ ((always_inline))
636 elf_machine_rela (struct link_map *map,
637 const Elf64_Rela *reloc,
638 const Elf64_Sym *sym,
639 const struct r_found_version *version,
640 void *const reloc_addr_arg,
641 int skip_ifunc)
642 {
643 Elf64_Addr *const reloc_addr = reloc_addr_arg;
644 const int r_type = ELF64_R_TYPE (reloc->r_info);
645 const Elf64_Sym *const refsym = sym;
646 union unaligned
647 {
648 uint16_t u2;
649 uint32_t u4;
650 uint64_t u8;
651 } __attribute__ ((__packed__));
652
653 if (r_type == R_PPC64_RELATIVE)
654 {
655 *reloc_addr = map->l_addr + reloc->r_addend;
656 return;
657 }
658
659 if (__glibc_unlikely (r_type == R_PPC64_NONE))
660 return;
661
662 /* We need SYM_MAP even in the absence of TLS, for elf_machine_fixup_plt
663 and STT_GNU_IFUNC. */
664 struct link_map *sym_map = RESOLVE_MAP (&sym, version, r_type);
665 Elf64_Addr value = ((sym_map == NULL ? 0 : sym_map->l_addr +
sym->st_value)
666 + reloc->r_addend);
And I identified the assembly generated and registers being used. Below, both
assembly starts at the 'resolve_ifunc' tests:
615 if (map != sym_map
616 # if !defined RTLD_BOOTSTRAP && defined SHARED
617 /* Bootstrap map doesn't have l_relocated set for it. */
618 && sym_map != &GL(dl_rtld_map)
619 # endif
620 && !sym_map->l_relocated)
GCC 4.8:
(gdb) x/28i $pc-48
0x2f30180c <_dl_relocate_object+8956>: cmpwi cr7,r9,0
0x2f301810 <_dl_relocate_object+8960>: beq- cr7,0x2f2ff87c
<_dl_relocate_object+876>
0x2f301814 <_dl_relocate_object+8964>: bne- cr3,0x2f2ff87c
<_dl_relocate_object+876>
0x2f301818 <_dl_relocate_object+8968>: cmpld cr7,r29,r23
0x2f30181c <_dl_relocate_object+8972>: beq cr7,0x2f301864
<_dl_relocate_object+9044>
0x2f301820 <_dl_relocate_object+8976>: nop
0x2f301824 <_dl_relocate_object+8980>: ld r8,-32624(r2)
0x2f301828 <_dl_relocate_object+8984>: cmpd cr7,r23,r8
0x2f30182c <_dl_relocate_object+8988>: beq cr7,0x2f301864
<_dl_relocate_object+9044>
0x2f301830 <_dl_relocate_object+8992>: ld r9,816(r23)
0x2f301834 <_dl_relocate_object+8996>: rldicl. r7,r9,35,63
0x2f301838 <_dl_relocate_object+9000>: bne 0x2f301864
<_dl_relocate_object+9044>
=> 0x2f30183c <_dl_relocate_object+9004>: ld r9,0(r23)
0x2f301840 <_dl_relocate_object+9008>: ld r8,0(r10)
0x2f301844 <_dl_relocate_object+9012>: ld r7,8(r10)
0x2f301848 <_dl_relocate_object+9016>: ld r10,16(r10)
0x2f30184c <_dl_relocate_object+9020>: add r8,r9,r8
0x2f301850 <_dl_relocate_object+9024>: add r9,r7,r9
0x2f301854 <_dl_relocate_object+9028>: std r8,176(r31)
0x2f301858 <_dl_relocate_object+9032>: std r9,184(r31)
0x2f30185c <_dl_relocate_object+9036>: std r10,192(r31)
0x2f301860 <_dl_relocate_object+9040>: addi r10,r31,176
0x2f301864 <_dl_relocate_object+9044>: std r2,40(r1)
0x2f301868 <_dl_relocate_object+9048>: addis r8,r2,-1
0x2f30186c <_dl_relocate_object+9052>: ld r3,26616(r8)
0x2f301870 <_dl_relocate_object+9056>: ld r9,0(r10)
0x2f301874 <_dl_relocate_object+9060>: ld r11,16(r10)
0x2f301878 <_dl_relocate_object+9064>: mtctr r9
GCC 4.9:
(gdb) x/28i $pc-40
0x495a0b40 <_dl_relocate_object+4608>: cmpld cr7,r29,r8
0x495a0b44 <_dl_relocate_object+4612>: beq cr7,0x495a0b68
<_dl_relocate_object+4648>
0x495a0b48 <_dl_relocate_object+4616>: nop
0x495a0b4c <_dl_relocate_object+4620>: ld r6,-32624(r2)
0x495a0b50 <_dl_relocate_object+4624>: cmpd cr7,r8,r6
0x495a0b54 <_dl_relocate_object+4628>: beq cr7,0x495a0b68
<_dl_relocate_object+4648>
0x495a0b58 <_dl_relocate_object+4632>: ld r10,816(r8)
0x495a0b5c <_dl_relocate_object+4636>: rldicl. r7,r10,35,63
0x495a0b60 <_dl_relocate_object+4640>: bne 0x495a0b68
<_dl_relocate_object+4648>
0x495a0b64 <_dl_relocate_object+4644>: addi r9,r31,176
=> 0x495a0b68 <_dl_relocate_object+4648>: std r2,40(r1)
0x495a0b6c <_dl_relocate_object+4652>: addis r10,r2,-1
0x495a0b70 <_dl_relocate_object+4656>: ld r3,26616(r10)
0x495a0b74 <_dl_relocate_object+4660>: ld r10,0(r9)
0x495a0b78 <_dl_relocate_object+4664>: ld r11,16(r9)
0x495a0b7c <_dl_relocate_object+4668>: std r8,272(r31)
0x495a0b80 <_dl_relocate_object+4672>: mtctr r10
0x495a0b84 <_dl_relocate_object+4676>: ld r2,8(r9)
0x495a0b88 <_dl_relocate_object+4680>: bctrl
The GCC 4.8 does have the branch taken code
621 {
622 Elf64_FuncDesc *func = (Elf64_FuncDesc *) value;
623 opd.fd_func = func->fd_func + sym_map->l_addr;
624 opd.fd_toc = func->fd_toc + sym_map->l_addr;
625 opd.fd_aux = func->fd_aux;
626 value = (Elf64_Addr) &opd;
627 }
Correctly set:
=> 0x2f30183c <_dl_relocate_object+9004>: ld r9,0(r23)
0x2f301840 <_dl_relocate_object+9008>: ld r8,0(r10)
0x2f301844 <_dl_relocate_object+9012>: ld r7,8(r10)
0x2f301848 <_dl_relocate_object+9016>: ld r10,16(r10)
0x2f30184c <_dl_relocate_object+9020>: add r8,r9,r8
0x2f301850 <_dl_relocate_object+9024>: add r9,r7,r9
0x2f301854 <_dl_relocate_object+9028>: std r8,176(r31)
0x2f301858 <_dl_relocate_object+9032>: std r9,184(r31)
0x2f30185c <_dl_relocate_object+9036>: std r10,192(r31)
0x2f301860 <_dl_relocate_object+9040>: addi r10,r31,176
0x2f301864 <_dl_relocate_object+9044>: std r2,40(r1)
0x2f301868 <_dl_relocate_object+9048>: addis r8,r2,-1
0x2f30186c <_dl_relocate_object+9052>: ld r3,26616(r8)
0x2f301870 <_dl_relocate_object+9056>: ld r9,0(r10)
0x2f301874 <_dl_relocate_object+9060>: ld r11,16(r10)
0x2f301878 <_dl_relocate_object+9064>: mtctr r9
GCC 4.9 seems to just omit it for some reason. Also, if I calculate the
'opd.fd_func = func->fd_func + sym_map->l_addr;' using GCC 4.9 register state
I correctly the expected 'value' to call the IFUNC resolver function.
I was suggested to add an explicit dependency o value and opd variable to avoid
the code elimination from GCC:
diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h
b/sysdeps/powerpc/powerpc64/dl-machine.h
index 9448712..3b2746f 100644
--- a/sysdeps/powerpc/powerpc64/dl-machine.h
+++ b/sysdeps/powerpc/powerpc64/dl-machine.h
@@ -623,7 +623,7 @@ resolve_ifunc (Elf64_Addr value,
opd.fd_func = func->fd_func + sym_map->l_addr;
opd.fd_toc = func->fd_toc + sym_map->l_addr;
opd.fd_aux = func->fd_aux;
- value = (Elf64_Addr) &opd;
+ asm ("" : "=r" (value) : "0" (&opd), "X" (opd));
}
#endif
#endif
The testcase passes with the fix.
--
You are receiving this mail because:
You are on the CC list for the bug.