summaryrefslogtreecommitdiff
path: root/sysdeps/hppa
diff options
context:
space:
mode:
authorJohn David Anglin <danglin@gcc.gnu.org>2017-12-02 14:43:28 -0500
committerJohn David Anglin <danglin@gcc.gnu.org>2017-12-02 14:43:28 -0500
commitb3f7fb12f5c490787d548ecc479920e608f6f904 (patch)
tree15f8efbcb6b8c29510e265cc0c1ef7f5904b3094 /sysdeps/hppa
parent800a496acbb8c43036b3832460220d4ecbbc22a4 (diff)
Handle __gmon_start__ as undefined weak on hppa.
[BZ libc/19170] * sysdeps/hppa/crti.S: Declare PREINIT_FUNCTION weak_extern when PREINIT_FUNCTION_WEAK is nonzero. (gmon_initializer): New function. Put procedure label for it in .init_array section. (_init): Don't call PREINIT_FUNCTION. * sysdeps/hppa/crtn.S (__gmon_start__): Remove. * sysdeps/hppa/dl-lookupcfg.h (DL_FIXUP_MAKE_VALUE): Create null fixup value when map argument is null.
Diffstat (limited to 'sysdeps/hppa')
-rw-r--r--sysdeps/hppa/crti.S97
-rw-r--r--sysdeps/hppa/crtn.S21
-rw-r--r--sysdeps/hppa/dl-lookupcfg.h3
3 files changed, 91 insertions, 30 deletions
diff --git a/sysdeps/hppa/crti.S b/sysdeps/hppa/crti.S
index 7c1470ddf8..0f9bb7b013 100644
--- a/sysdeps/hppa/crti.S
+++ b/sysdeps/hppa/crti.S
@@ -49,6 +49,95 @@
# define PREINIT_FUNCTION_WEAK 1
#endif
+#if PREINIT_FUNCTION_WEAK
+ weak_extern (PREINIT_FUNCTION)
+#else
+ .hidden PREINIT_FUNCTION
+#endif
+
+
+/* If we have working .init_array support, we want to keep the .init
+ section empty (apart from the mandatory prologue/epilogue. This
+ ensures that the default unwind conventions (return-pointer in b0,
+ frame state in ar.pfs, etc.) will do the Right Thing. To ensure
+ an empty .init section, we register gmon_initializer() via the
+ .init_array.
+
+ --davidm 02/10/29 */
+
+#if PREINIT_FUNCTION_WEAK
+/* This blob of assembly code is one simple C function:
+
+static void
+__attribute__ ((used))
+gmon_initializer (void)
+{
+ extern void weak_function __gmon_start__ (void);
+
+ if (__gmon_start__)
+ (*__gmon_start__)();
+}
+
+In a final executable, PLABEL32 relocations for function pointers are
+resolved at link time. Typically, binutils/ld resolves __gmon_start__
+using an external shared library. __gmon_start__ is always called if
+it is found at link time. If __gmon_start__ is not found at runtime
+due to a library update, then the function pointer will point at a null
+function descriptor and calling it will cause a segmentation fault.
+So, we call __canonicalize_funcptr_for_compare to obtain the canonicalized
+address of __gmon_start__ and skip calling __gmon_start__ if it is zero.
+
+ */
+ .type __canonicalize_funcptr_for_compare,@function
+ .type $$dyncall,@function
+
+ .section .data.rel.ro,"aw",@progbits
+ .align 4
+.LC0:
+ .type __gmon_start__,@function
+ .word P%__gmon_start__
+
+ .text
+ .align 4
+ .type gmon_initializer,@function
+gmon_initializer:
+ .PROC
+ .CALLINFO FRAME=64,CALLS,SAVE_RP,ENTRY_GR=4
+ .ENTRY
+ stw %r2,-20(%r30)
+ stwm %r4,64(%r30)
+ stw %r3,-60(%r30)
+ addil LT'.LC0,%r19
+ ldw RT'.LC0(%r1),%r28
+ ldw 0(%r28),%r3
+ comib,= 0,%r3,1f
+ copy %r19,%r4
+ stw %r19,-32(%r30)
+ bl __canonicalize_funcptr_for_compare,%r2
+ copy %r3,%r26
+ comib,= 0,%r28,1f
+ copy %r4,%r19
+ copy %r3,%r22
+ .CALL ARGW0=GR
+ bl $$dyncall,%r31
+ copy %r31,%r2
+1:
+ ldw -84(%r30),%r2
+ ldw -60(%r30),%r3
+ bv %r0(%r2)
+ ldwm -64(%r30),%r4
+ .EXIT
+ .PROCEND
+ .size gmon_initializer, .-gmon_initializer
+
+# undef PREINIT_FUNCTION
+# define PREINIT_FUNCTION gmon_initializer
+#endif
+
+ .section .init_array, "aw"
+ .word P% PREINIT_FUNCTION
+
+
/* _init prologue. */
.section .init, "ax", %progbits
.align 4
@@ -58,14 +147,6 @@ _init:
stw %rp,-20(%sp)
stwm %r4,64(%sp)
stw %r19,-32(%sp)
-#if PREINIT_FUNCTION_WEAK
- bl PREINIT_FUNCTION,%rp
- copy %r19,%r4 /* delay slot */
-#else
- bl PREINIT_FUNCTION,%rp
- copy %r19,%r4 /* delay slot */
-#endif
- copy %r4,%r19
/* _fini prologue. */
.section .fini,"ax",%progbits
diff --git a/sysdeps/hppa/crtn.S b/sysdeps/hppa/crtn.S
index 42f310d217..49666b81f9 100644
--- a/sysdeps/hppa/crtn.S
+++ b/sysdeps/hppa/crtn.S
@@ -38,27 +38,6 @@
/* crtn.S puts function epilogues in the .init and .fini sections
corresponding to the prologues in crti.S. */
-/* Note that we cannot have a weak undefined __gmon_start__, because
- that would require this to be PIC, and the linker is currently not
- able to generate a proper procedure descriptor for _init. Sad but
- true. Anyway, HPPA is one of those horrible architectures where
- making the comparison and indirect call is quite expensive (see the
- comment in sysdeps/generic/initfini.c). */
- .text
- .align 4
- .weak __gmon_start__
- .type __gmon_start__,@function
-__gmon_start__:
- .proc
- .callinfo
- .entry
- bv,n %r0(%r2)
- .exit
- .procend
-
-/* Here is the tail end of _init. We put __gmon_start before this so
- that the assembler creates the .PARISC.unwind section for us, ie.
- with the right attributes. */
.section .init, "ax", @progbits
ldw -84(%sp),%rp
copy %r4,%r19
diff --git a/sysdeps/hppa/dl-lookupcfg.h b/sysdeps/hppa/dl-lookupcfg.h
index 0b0ae85b5d..0b8f031823 100644
--- a/sysdeps/hppa/dl-lookupcfg.h
+++ b/sysdeps/hppa/dl-lookupcfg.h
@@ -73,7 +73,8 @@ void attribute_hidden _dl_unmap (struct link_map *map);
/* Construct a fixup value from the address and linkmap */
#define DL_FIXUP_MAKE_VALUE(map, addr) \
- ((struct fdesc) { (addr), (map)->l_info[DT_PLTGOT]->d_un.d_ptr })
+ (map) ? ((struct fdesc) { (addr), (map)->l_info[DT_PLTGOT]->d_un.d_ptr }) \
+ : ((struct fdesc) { 0, 0 })
/* Extract the code address from a fixup value */
#define DL_FIXUP_VALUE_CODE_ADDR(value) ((value).ip)