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
--=-9/8rZe+d9rK3teh1VWmm Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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 --=-9/8rZe+d9rK3teh1VWmm Content-Disposition: inline; filename="find_exidx3.diff" Content-Type: text/x-patch; name="find_exidx3.diff"; charset="us-ascii" Content-Transfer-Encoding: 7bit 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_ */ --=-9/8rZe+d9rK3teh1VWmm--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?1405642661.1312.135.camel>