The following allows libgcc to use newer glibc _dl_find_object even
when at compile-time the facility was not available.

Bootstrapped and tested on x86_64-unknown-linux-gnu with new glibc,
on {aarch64,ppc64le,i586,x84_64} SLE15 GA (with old glibc).

We're about to deploy this for SLE15 which builds libgcc_s1 against
GA with glibc 2.26 but customers on SP6 or SP7 benefiting from
glibc 2.38 and possibly faster exception handling with the
_dl_find_object code path.

I think it makes sense to implement a runtime check on such feature
when possible, so I'm proposing the following for trunk.  The actual
dl_find_object layout is unfortunately somewhat of a target specific maze,
I've simplified it to the actually relevant head plus making sure the
overall size is sufficient.  The important part is to guard the
argument passing to find_fde_tail properly:

# if DLFO_STRUCT_HAS_EH_DBASE
                            (_Unwind_Ptr) dlfo.dlfo_eh_dbase,
# else
                            0,
# endif

OK?

Thanks,
Richard.

libgcc/
        * unwind-dw2-fde-dip.c (_Unwind_Find_FDE): When _dl_find_object
        is not available declare it weak and perform a runtime check
        on its presence.
---
 libgcc/unwind-dw2-fde-dip.c | 34 ++++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/libgcc/unwind-dw2-fde-dip.c b/libgcc/unwind-dw2-fde-dip.c
index 5c19838e0a3..74cecfc2c2c 100644
--- a/libgcc/unwind-dw2-fde-dip.c
+++ b/libgcc/unwind-dw2-fde-dip.c
@@ -542,6 +542,40 @@ _Unwind_Find_FDE (void *pc, struct dwarf_eh_bases *bases)
   if (ret != NULL)
     return ret;
 
+/* When the glibc we build against does not have dl_find_object tentatively
+   declare the relevant bits of the structure here and use a weak declaration
+   so we can perform a runtime check on its presence.  */
+#if !defined(DLFO_STRUCT_HAS_EH_DBASE)
+
+#ifdef __i386__
+# define DLFO_STRUCT_HAS_EH_DBASE 1
+#else
+# define DLFO_STRUCT_HAS_EH_DBASE 0
+#endif
+
+/* The following is dl_find_object as in it's maximum size configuration.  */
+struct dl_find_object
+{
+  __extension__ unsigned long long int dlfo_flags;
+  void *dlfo_map_start;         /* Beginning of mapping containing address.  */
+  void *dlfo_map_end;           /* End of mapping.  */
+  struct link_map *dlfo_link_map;
+  void *dlfo_eh_frame;          /* Exception handling data of the object.  */
+# if DLFO_STRUCT_HAS_EH_DBASE
+  void *dlfo_eh_dbase;          /* Base address for DW_EH_PE_datarel.  */
+#  if __WORDSIZE == 32
+  unsigned int __dlfo_eh_dbase_pad;
+#  endif
+# endif
+  /* PAD to an upper bound size.  */
+  __extension__ unsigned long long int __dflo_reserved[8];
+};
+
+  extern int _dl_find_object (void *,
+                             struct dl_find_object *) __attribute__((weak));
+
+  if (_dl_find_object)
+#endif
   /* Use DLFO_STRUCT_HAS_EH_DBASE as a proxy for the existence of a glibc-style
      _dl_find_object function.  */
 #if defined(DLFO_STRUCT_HAS_EH_DBASE)
-- 
2.51.0

Reply via email to