Date: Thu, 17 Jul 2014 18:17:41 -0600 From: Ian Lepore <ian@FreeBSD.org> To: Konstantin Belousov <kostikbel@gmail.com> Cc: hackers@freebsd.org Subject: Re: [CFR] Adding a function to rtld-elf.so, how to handle Symbol.map? Message-ID: <1405642661.1312.135.camel@revolution.hippie.lan> In-Reply-To: <20140717172910.GH93733@kib.kiev.ua> References: <1405545833.1312.84.camel@revolution.hippie.lan> <20140717004537.GE93733@kib.kiev.ua> <1405616990.1312.111.camel@revolution.hippie.lan> <20140717172910.GH93733@kib.kiev.ua>
next in thread | previous in thread | raw e-mail | index | archive | help
[-- Attachment #1 --]
On Thu, 2014-07-17 at 20:29 +0300, Konstantin Belousov wrote:
> On Thu, Jul 17, 2014 at 11:09:50AM -0600, Ian Lepore wrote:
> > On Thu, 2014-07-17 at 03:45 +0300, Konstantin Belousov wrote:
> > > On Wed, Jul 16, 2014 at 03:23:53PM -0600, Ian Lepore wrote:
> > [snip]
> > I did some looking around and Netbsd, Android, and Risc Os all
> > implemented this in their dynamic loaders, so that seemed like the way
> > to go. Android actually puts a function with this __gnu name in its
> > libc, but all that function does is calls dl_unwind_find_exidx() which
> > is implemented in their loader.
> >
> > I've just discovered that the arm unwind support code that will arrive
> > as part of clang 3.5 appears to assume the Android way of things unless
> > __LINUX__ is defined, so maybe it would be good to follow that model
> > ourselves and add a dl_unwind_find_exidx() stub to libc/gen/dlfcn.c and
> > name the new implementation in ld-elf to match.
> I think that Android/__LINUX__ combination does the right thing, by
> providing the symbol in libc. A libc implementation does not need any
> additional service from rtld, except already existing _rtld_addr_phdr().
>
Android provides a stub of dl_unwind_find_exidx() in libdl and the
shared-object implementation in the dynamic linker. What it puts in
libc is the __gnu_Unwind_Find_exidx() symbol, which just calls through
to the dl_unwind_find_exidx() implementation in the dynamic linker.
That aside, I've reworked my code so it all lives in libc instead of
rtld, as you suggested. It seems to work fine, and I guess I'm agnostic
about whether we're exporting a new function from libc versus rtld. It
seems a bit strange to me to have just one dl_something() function with
its shared/dynamic implementation in libc, while all the other functions
with dl-prefix names are implemented in rtld. But not so weird that
it's a big deal.
-- Ian
[-- Attachment #2 --]
diff -r 63a383d5fd3e lib/libc/arm/Symbol.map
--- lib/libc/arm/Symbol.map Thu May 01 08:14:39 2014 -0600
+++ lib/libc/arm/Symbol.map Thu Jul 17 17:49:52 2014 -0600
@@ -37,6 +37,11 @@ FBSD_1.3 {
__flt_rounds;
};
+FBSD_1.4 {
+ __gnu_Unwind_Find_exidx;
+ dl_unwind_find_exidx;
+};
+
FBSDprivate_1.0 {
/* PSEUDO syscalls */
__sys_getlogin;
diff -r 63a383d5fd3e lib/libc/arm/aeabi/Makefile.inc
--- lib/libc/arm/aeabi/Makefile.inc Thu May 01 08:14:39 2014 -0600
+++ lib/libc/arm/aeabi/Makefile.inc Thu Jul 17 17:49:52 2014 -0600
@@ -3,7 +3,8 @@
.PATH: ${LIBC_SRCTOP}/arm/aeabi
SRCS+= aeabi_atexit.c \
- aeabi_unwind_cpp.c
+ aeabi_unwind_cpp.c \
+ aeabi_unwind_exidx.c
.if ${MACHINE_ARCH} != "armv6hf"
SRCS+= aeabi_double.c \
aeabi_float.c
diff -r 63a383d5fd3e lib/libc/arm/aeabi/aeabi_unwind_exidx.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ lib/libc/arm/aeabi/aeabi_unwind_exidx.c Thu Jul 17 17:49:52 2014 -0600
@@ -0,0 +1,104 @@
+/*-
+ * Copyright (c) 2014 Ian Lepore <ian@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <machine/elf.h>
+#include <link.h>
+#include <stddef.h>
+
+/*
+ * ARM EABI unwind helper.
+ *
+ * This finds the exidx section address and size associated with a given code
+ * address. There are separate implementations for static and dynamic code.
+ *
+ * GCC expects this function to exist as __gnu_Unwind_Find_exidx(), clang and
+ * BSD tools expect it to be dl_unwind_find_exidx(). Both have the same API, so
+ * we set up an alias for GCC.
+ */
+__strong_reference(dl_unwind_find_exidx, __gnu_Unwind_Find_exidx);
+
+/*
+ * Each entry in the exidx section is a pair of 32-bit words. We don't
+ * interpret the contents of the entries here; this typedef is just a local
+ * convenience for using sizeof() and doing pointer math.
+ */
+typedef struct exidx_entry {
+ uint32_t data[2];
+} exidx_entry;
+
+#ifdef __PIC__
+
+/*
+ * Unwind helper for dynamically linked code.
+ *
+ * This finds the shared object that contains the given address, and returns the
+ * address of the exidx section in that shared object along with the number of
+ * entries in that section, or NULL if it wasn't found.
+ */
+void *
+dl_unwind_find_exidx(const void *pc, int *pcount)
+{
+ const Elf_Phdr *hdr;
+ struct dl_phdr_info info;
+ int i;
+
+ if (_rtld_addr_phdr(pc, &info)) {
+ hdr = info.dlpi_phdr;
+ for (i = 0; i < info.dlpi_phnum; i++, hdr++) {
+ if (hdr->p_type == PT_ARM_EXIDX) {
+ *pcount = hdr->p_memsz / (sizeof(exidx_entry));
+ return ((void *)(info.dlpi_addr + hdr->p_vaddr));
+ }
+ }
+ }
+ return (NULL);
+}
+
+#else /* !__PIC__ */
+
+/*
+ * Unwind helper for statically linked code.
+ *
+ * In a statically linked program, the linker populates a pair of symbols with
+ * the addresses of the start and end of the exidx table, so returning the
+ * address and count of elements is pretty straighforward.
+ */
+void *
+dl_unwind_find_exidx(const void *pc, int *pcount)
+{
+ extern struct exidx_entry __exidx_start;
+ extern struct exidx_entry __exidx_end;
+
+ *pcount = (int)(&__exidx_end - &__exidx_start);
+ return (&__exidx_start);
+}
+
+#endif /* __PIC__ */
+
diff -r 63a383d5fd3e sys/arm/include/elf.h
--- sys/arm/include/elf.h Thu May 01 08:14:39 2014 -0600
+++ sys/arm/include/elf.h Thu Jul 17 17:49:52 2014 -0600
@@ -55,6 +55,9 @@ typedef struct { /* Auxiliary vec
#define ELF_MACHINE_OK(x) ((x) == EM_ARM)
+/* Unwind info section type */
+#define PT_ARM_EXIDX (PT_LOPROC + 1)
+
/*
* Relocation types.
*/
diff -r 63a383d5fd3e sys/sys/link_elf.h
--- sys/sys/link_elf.h Thu May 01 08:14:39 2014 -0600
+++ sys/sys/link_elf.h Thu Jul 17 17:49:52 2014 -0600
@@ -95,6 +95,10 @@ extern int dl_iterate_phdr(__dl_iterate_
int _rtld_addr_phdr(const void *, struct dl_phdr_info *);
int _rtld_get_stack_prot(void);
+#ifdef __ARM_EABI__
+void * dl_unwind_find_exidx(const void *, int *);
+#endif
+
__END_DECLS
#endif /* _SYS_LINK_ELF_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1405642661.1312.135.camel>
