Add FDPIC dynamic relocations support, similar to what other FDPIC
        targets do.

        Lazy binding is implemented in a folllow-up patch.

        Disable the SEND* macros because they involve relocations to
        access constant strings that are unsupported by the existing
        arm version.

        Define DL_START, START, ARCH_NEEDS_BOOTSTRAP_RELOCS,
        DL_CHECK_LIB_TYPE similarly to what other FDPIC targets do.

        Define raise() because _dl_find_hash references __aeabi_uidivmod,
        which uses __aeabi_idiv0 which in turn references raise.

        * include/elf.h (R_ARM_FUNCDESC): Define.
        (R_ARM_FUNCDESC_VALUE): Define.
        * ldso/include/dl-string.h (SEND_STDERR, SEND_ADDRESS_STDERR)
        (SEND_NUMBER_STDERR): Define empty for __FDPIC__.
        * ldso/ldso/arm/dl-inlines.h: New file.
        * ldso/ldso/arm/dl-startup.h (PERFORM_BOOTSTRAP_RELOC): Fix type
        of load_addr. Fix handling of R_ARM_RELATIVE, add support for
        R_ARM_FUNCDESC_VALUE.
        (DL_START, START): Define for __FDPIC__.
        (raise): Define.
        * ldso/ldso/arm/dl-sysdep.h (ARCH_NEEDS_BOOTSTRAP_RELOCS): Define.
        (DL_CHECK_LIB_TYPE): Define.
        (elf_machine_type_class): Take into account FDPIC related
        relocations.
        (elf_machine_load_address): Support __FDPIC__.
        (elf_machine_relative): Likewise.
        * ldso/ldso/arm/elfinterp.c (_dl_linux_resolver): Dummy support
        for __FDPIC__, implemented in a later patch.
        (_dl_do_reloc): Fix reloc_adr computation for __FDPIC__, fix
        handling of local symbols. Fix handling of R_ARM_RELATIVE, add
        support for R_ARM_FUNCDESC_VALUE, R_ARM_FUNCDESC.
        * ldso/ldso/arm/resolve.S: Make _dl_linux_resolve hidden.
        * ldso/ldso/fdpic/dl-inlines.h (htab_delete): Declare.
        * libc/sysdeps/linux/arm/bits/elf-fdpic.h: New file, similar to bfin's.
        * libc/sysdeps/linux/arm/crtreloc.c: Likewise.
        * libc/sysdeps/linux/arm/find_exidx.c (__dl_addr_in_loadaddr) Define.
        (find_exidx_callback): Support __FDPIC__.

Signed-off-by: Mickaël Guêné <mickael.gu...@st.com>
Signed-off-by: Christophe Lyon <christophe.l...@st.com>

diff --git a/include/elf.h b/include/elf.h
index 2db85c5..6280a56 100644
--- a/include/elf.h
+++ b/include/elf.h
@@ -2696,6 +2696,8 @@ typedef Elf32_Addr Elf32_Conflict;
 #define R_ARM_TLS_LDO12                109
 #define R_ARM_TLS_LE12         110
 #define R_ARM_TLS_IE12GP       111
+#define R_ARM_FUNCDESC         163
+#define R_ARM_FUNCDESC_VALUE   164
 #define R_ARM_RXPC25           249
 #define R_ARM_RSBREL32         250
 #define R_ARM_THM_RPC22                251
diff --git a/ldso/include/dl-string.h b/ldso/include/dl-string.h
index fc1d1fc..bf69971 100644
--- a/ldso/include/dl-string.h
+++ b/ldso/include/dl-string.h
@@ -256,7 +256,8 @@ static __always_inline char * _dl_simple_ltoahex(char 
*local, unsigned long i)
 
 /* On some (wierd) arches, none of this stuff works at all, so
  * disable the whole lot... */
-#if defined(__mips__)
+/* The same applies for ARM FDPIC at least for the moment.  */
+#if defined(__mips__) || (__FDPIC__)
 
 # define SEND_STDERR(X)
 # define SEND_ADDRESS_STDERR(X, add_a_newline)
diff --git a/ldso/ldso/arm/dl-inlines.h b/ldso/ldso/arm/dl-inlines.h
new file mode 100644
index 0000000..8fdf6eb
--- /dev/null
+++ b/ldso/ldso/arm/dl-inlines.h
@@ -0,0 +1 @@
+#include "../fdpic/dl-inlines.h"
diff --git a/ldso/ldso/arm/dl-startup.h b/ldso/ldso/arm/dl-startup.h
index 371dc22..d15264f 100644
--- a/ldso/ldso/arm/dl-startup.h
+++ b/ldso/ldso/arm/dl-startup.h
@@ -131,7 +131,7 @@ __asm__(
 /* Handle relocation of the symbols in the dynamic loader. */
 static __always_inline
 void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned long *reloc_addr,
-       unsigned long symbol_addr, unsigned long load_addr, Elf32_Sym *symtab)
+       unsigned long symbol_addr, DL_LOADADDR_TYPE load_addr, Elf32_Sym 
*symtab)
 {
        switch (ELF_R_TYPE(rpnt->r_info)) {
                case R_ARM_NONE:
@@ -176,12 +176,53 @@ void PERFORM_BOOTSTRAP_RELOC(ELF_RELOC *rpnt, unsigned 
long *reloc_addr,
                        *reloc_addr = symbol_addr;
                        break;
                case R_ARM_RELATIVE:
-                       *reloc_addr += load_addr;
+                       *reloc_addr = DL_RELOC_ADDR(load_addr, *reloc_addr);
                        break;
                case R_ARM_COPY:
                        break;
+               case R_ARM_FUNCDESC_VALUE:
+                       {
+                               struct funcdesc_value *dst = (struct 
funcdesc_value *) reloc_addr;
+
+                               dst->entry_point += symbol_addr;
+                               dst->got_value = load_addr.got_value;
+                       }
+                       break;
                default:
                        SEND_STDERR("Unsupported relocation type\n");
                        _dl_exit(1);
        }
 }
+
+#ifdef __FDPIC__
+#undef DL_START
+#define DL_START(X)   \
+static void  __attribute__ ((used)) \
+_dl_start (Elf32_Addr dl_boot_got_pointer, \
+          struct elf32_fdpic_loadmap *dl_boot_progmap, \
+          struct elf32_fdpic_loadmap *dl_boot_ldsomap, \
+          Elf32_Dyn *dl_boot_ldso_dyn_pointer, \
+          struct funcdesc_value *dl_main_funcdesc, \
+          X)
+
+/*
+ * Transfer control to the user's application, once the dynamic loader
+ * is done.  We return the address of the function's entry point to
+ * _dl_boot, see boot1_arch.h.
+ */
+#define START()        do {                                                    
\
+  struct elf_resolve *exec_mod = _dl_loaded_modules;                   \
+  dl_main_funcdesc->entry_point = _dl_elf_main;                                
\
+  while (exec_mod->libtype != elf_executable)                          \
+    exec_mod = exec_mod->next;                                         \
+  dl_main_funcdesc->got_value = exec_mod->loadaddr.got_value;          \
+  return;                                                              \
+} while (0)
+
+/* We use __aeabi_idiv0 in _dl_find_hash, so we need to have the raise
+   symbol.  */
+int raise(int sig)
+{
+  _dl_exit(1);
+}
+#endif /* __FDPIC__ */
diff --git a/ldso/ldso/arm/dl-sysdep.h b/ldso/ldso/arm/dl-sysdep.h
index a47a552..2bb0023 100644
--- a/ldso/ldso/arm/dl-sysdep.h
+++ b/ldso/ldso/arm/dl-sysdep.h
@@ -10,6 +10,19 @@
 /* Define this if the system uses RELOCA.  */
 #undef ELF_USES_RELOCA
 #include <elf.h>
+
+#ifdef __FDPIC__
+/* Need bootstrap relocations */
+#define ARCH_NEEDS_BOOTSTRAP_RELOCS
+
+#define DL_CHECK_LIB_TYPE(epnt, piclib, _dl_progname, libname) \
+do \
+{ \
+  (piclib) = 2; \
+} \
+while (0)
+#endif /* __FDPIC__ */
+
 /* Initialization sequence for the GOT.  */
 #define INIT_GOT(GOT_BASE,MODULE) \
 {                              \
@@ -62,11 +75,17 @@ unsigned long _dl_linux_resolver(struct elf_resolve * tpnt, 
int reloc_entry);
    define the value.
 
    ELF_RTYPE_CLASS_NOCOPY iff TYPE should not be allowed to resolve to one
-   of the main executable's symbols, as for a COPY reloc.  */
-#define elf_machine_type_class(type)                                           
                        \
-  ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32                 
\
+   of the main executable's symbols, as for a COPY reloc.
+
+   Avoid R_ARM_ABS32 to go through the PLT so that R_ARM_TARGET1
+   translated to R_ARM_ABS32 doesn't use the PLT: otherwise, this
+   breaks init_array because functions are referenced through the
+   PLT.  */
+#define elf_machine_type_class(type)                                   \
+  ((((type) == R_ARM_JUMP_SLOT || (type) == R_ARM_TLS_DTPMOD32         \
+     || (type) == R_ARM_FUNCDESC_VALUE || (type) == R_ARM_FUNCDESC || (type) 
== R_ARM_ABS32 \
      || (type) == R_ARM_TLS_DTPOFF32 || (type) == R_ARM_TLS_TPOFF32)   \
-    * ELF_RTYPE_CLASS_PLT)                                                     
                                        \
+    * ELF_RTYPE_CLASS_PLT)                                             \
    | (((type) == R_ARM_COPY) * ELF_RTYPE_CLASS_COPY))
 
 /* Return the link-time address of _DYNAMIC.  Conveniently, this is the
@@ -106,10 +125,22 @@ elf_machine_dynamic (void)
 
 extern char __dl_start[] __asm__("_dl_start");
 
+/* We must force strings used early in the bootstrap into the data
+   segment.  */
+#undef SEND_EARLY_STDERR
+#define SEND_EARLY_STDERR(S) \
+  do { /* FIXME: implement */; } while (0)
+
+#undef INIT_GOT
+#include "../fdpic/dl-sysdep.h"
+
 /* Return the run-time load address of the shared object.  */
 static __always_inline Elf32_Addr __attribute__ ((unused))
 elf_machine_load_address (void)
 {
+#if defined(__FDPIC__)
+       return 0;
+#else
        Elf32_Addr got_addr = (Elf32_Addr) &__dl_start;
        Elf32_Addr pcrel_addr;
 #if defined __OPTIMIZE__ && !defined __thumb__
@@ -128,19 +159,29 @@ elf_machine_load_address (void)
                 : "=r" (pcrel_addr), "=r" (tmp));
 #endif
        return pcrel_addr - got_addr;
+#endif
 }
 
 static __always_inline void
-elf_machine_relative (Elf32_Addr load_off, const Elf32_Addr rel_addr,
+elf_machine_relative (DL_LOADADDR_TYPE load_off, const Elf32_Addr rel_addr,
                      Elf32_Word relative_count)
 {
-        Elf32_Rel * rpnt = (void *) rel_addr;
-       --rpnt;
-       do {
-               Elf32_Addr *const reloc_addr = (void *) (load_off + 
(++rpnt)->r_offset);
+#if defined(__FDPIC__)
+    Elf32_Rel *rpnt = (void *) rel_addr;
+
+    do {
+        unsigned long *reloc_addr = (unsigned long *) DL_RELOC_ADDR(load_off, 
rpnt->r_offset);
 
-               *reloc_addr += load_off;
-       } while (--relative_count);
+        *reloc_addr = DL_RELOC_ADDR(load_off, *reloc_addr);
+        rpnt++;
+#else
+    Elf32_Rel * rpnt = (void *) rel_addr;
+    --rpnt;
+    do {
+      Elf32_Addr *const reloc_addr = (void *) (load_off + (++rpnt)->r_offset);
+      *reloc_addr += load_off;
+#endif
+    } while(--relative_count);
 }
 #endif /* !_ARCH_DL_SYSDEP */
 
diff --git a/ldso/ldso/arm/elfinterp.c b/ldso/ldso/arm/elfinterp.c
index 96809a9..1435c2c 100644
--- a/ldso/ldso/arm/elfinterp.c
+++ b/ldso/ldso/arm/elfinterp.c
@@ -36,6 +36,11 @@ extern int _dl_linux_resolve(void);
 
 unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, int reloc_entry)
 {
+#if __FDPIC__
+  /* FIXME: implement.  */
+  while(1) ;
+  return 0;
+#else
        ELF_RELOC *this_reloc;
        char *strtab;
        char *symname;
@@ -88,6 +93,7 @@ unsigned long _dl_linux_resolver(struct elf_resolve *tpnt, 
int reloc_entry)
 #endif
 
        return new_addr;
+#endif
 }
 
 static int
@@ -181,7 +187,7 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct r_scope_elem 
*scope,
        struct elf_resolve *def_mod = 0;
        int goof = 0;
 
-       reloc_addr = (unsigned long *) (tpnt->loadaddr + (unsigned long) 
rpnt->r_offset);
+       reloc_addr = (unsigned long *) DL_RELOC_ADDR(tpnt->loadaddr, 
rpnt->r_offset);
 
        reloc_type = ELF_R_TYPE(rpnt->r_info);
        symtab_index = ELF_R_SYM(rpnt->r_info);
@@ -191,25 +197,30 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct 
r_scope_elem *scope,
        symname = strtab + symtab[symtab_index].st_name;
 
        if (symtab_index) {
-               symbol_addr = (unsigned long)_dl_find_hash(symname, scope, tpnt,
-                                               
elf_machine_type_class(reloc_type), &sym_ref);
-
-               /*
-                * We want to allow undefined references to weak symbols - this 
might
-                * have been intentional.  We should not be linking local 
symbols
-                * here, so all bases should be covered.
-                */
-               if (!symbol_addr && (ELF_ST_TYPE(symtab[symtab_index].st_info) 
!= STT_TLS)
-                       && (ELF_ST_BIND(symtab[symtab_index].st_info) != 
STB_WEAK)) {
-                       /* This may be non-fatal if called from dlopen.  */
-                       return 1;
-
-               }
-               if (_dl_trace_prelink) {
-                       _dl_debug_lookup (symname, tpnt, &symtab[symtab_index],
-                                       &sym_ref, 
elf_machine_type_class(reloc_type));
+               if (ELF_ST_BIND (symtab[symtab_index].st_info) == STB_LOCAL) {
+                       symbol_addr = (unsigned long) 
DL_RELOC_ADDR(tpnt->loadaddr, symtab[symtab_index].st_value);
+                       def_mod = tpnt;
+               } else {
+                       symbol_addr =  (unsigned long)_dl_find_hash(symname, 
scope, tpnt,
+                                                       
elf_machine_type_class(reloc_type), &sym_ref);
+
+                       /*
+                        * We want to allow undefined references to weak 
symbols - this might
+                        * have been intentional.  We should not be linking 
local symbols
+                        * here, so all bases should be covered.
+                        */
+                       if (!symbol_addr && 
(ELF_ST_TYPE(symtab[symtab_index].st_info) != STT_TLS)
+                               && (ELF_ST_BIND(symtab[symtab_index].st_info) 
!= STB_WEAK)) {
+                               /* This may be non-fatal if called from dlopen. 
 */
+                               return 1;
+
+                       }
+                       if (_dl_trace_prelink) {
+                               _dl_debug_lookup (symname, tpnt, 
&symtab[symtab_index],
+                                               &sym_ref, 
elf_machine_type_class(reloc_type));
+                       }
+                       def_mod = sym_ref.tpnt;
                }
-               def_mod = sym_ref.tpnt;
        } else {
                /*
                 * Relocs against STN_UNDEF are usually treated as using a
@@ -267,12 +278,40 @@ _dl_do_reloc (struct elf_resolve *tpnt,struct 
r_scope_elem *scope,
                                *reloc_addr = symbol_addr;
                                break;
                        case R_ARM_RELATIVE:
-                               *reloc_addr += (unsigned long) tpnt->loadaddr;
+                               *reloc_addr = DL_RELOC_ADDR(tpnt->loadaddr, 
*reloc_addr);
                                break;
                        case R_ARM_COPY:
                                _dl_memcpy((void *) reloc_addr,
                                           (void *) symbol_addr, 
symtab[symtab_index].st_size);
                                break;
+                       case R_ARM_FUNCDESC_VALUE:
+                               {
+                                       struct funcdesc_value funcval;
+                                       struct funcdesc_value *dst = (struct 
funcdesc_value *) reloc_addr;
+
+                                       funcval.entry_point = 
(void*)symbol_addr;
+                                       /* Add offset to section address for 
local symbols.  */
+                                       if 
(ELF_ST_BIND(symtab[symtab_index].st_info) == STB_LOCAL)
+                                         funcval.entry_point += *reloc_addr;
+                                       funcval.got_value = 
def_mod->loadaddr.got_value;
+                                       *dst = funcval;
+                               }
+                               break;
+                       case R_ARM_FUNCDESC:
+                               {
+                                 unsigned long reloc_value = *reloc_addr;
+
+                                 if (symbol_addr)
+                                       reloc_value = (unsigned long) 
_dl_funcdesc_for(symbol_addr + reloc_value, sym_ref.tpnt->loadaddr.got_value);
+                                 else
+                                       /* Relocation against an
+                                          undefined weak symbol:
+                                          set funcdesc to zero.  */
+                                       reloc_value = 0;
+
+                                 *reloc_addr = reloc_value;
+                               }
+                               break;
 #if defined USE_TLS && USE_TLS
                        case R_ARM_TLS_DTPMOD32:
                                *reloc_addr = def_mod->l_tls_modid;
@@ -330,7 +369,6 @@ _dl_do_lazy_reloc (struct elf_resolve *tpnt, struct 
r_scope_elem *scope,
 
 #endif
        return 0;
-
 }
 
 void _dl_parse_lazy_relocation_information(struct dyn_elf *rpnt,
@@ -345,3 +383,6 @@ int _dl_parse_relocation_information(struct dyn_elf *rpnt,
        return _dl_parse(rpnt->dyn, scope, rel_addr, rel_size, _dl_do_reloc);
 }
 
+#ifndef IS_IN_libdl
+# include "../../libc/sysdeps/linux/arm/crtreloc.c"
+#endif
diff --git a/ldso/ldso/arm/resolve.S b/ldso/ldso/arm/resolve.S
index 7e0058e..2a51643 100644
--- a/ldso/ldso/arm/resolve.S
+++ b/ldso/ldso/arm/resolve.S
@@ -102,6 +102,7 @@
  .align 4      @ 16 byte boundary and there are 32 bytes below (arm case)
 #if 1 /*(!defined(__thumb__) || defined __THUMB_INTERWORK__) || 
defined(__thumb2__)*/
  .arm
+ .hidden _dl_linux_resolve
  .globl _dl_linux_resolve
  .type _dl_linux_resolve,%function
  .align 4;
diff --git a/ldso/ldso/fdpic/dl-inlines.h b/ldso/ldso/fdpic/dl-inlines.h
index f590875..89e7a9a 100644
--- a/ldso/ldso/fdpic/dl-inlines.h
+++ b/ldso/ldso/fdpic/dl-inlines.h
@@ -7,6 +7,8 @@
 
 #include <inline-hashtab.h>
 
+static __always_inline void htab_delete(struct funcdesc_ht *htab);
+
 /* Initialize a DL_LOADADDR_TYPE given a got pointer and a complete load map. 
*/
 static __always_inline void
 __dl_init_loadaddr_map(struct elf32_fdpic_loadaddr *loadaddr, Elf32_Addr 
dl_boot_got_pointer,
diff --git a/libc/sysdeps/linux/arm/bits/elf-fdpic.h 
b/libc/sysdeps/linux/arm/bits/elf-fdpic.h
new file mode 100644
index 0000000..3d6db54
--- /dev/null
+++ b/libc/sysdeps/linux/arm/bits/elf-fdpic.h
@@ -0,0 +1,114 @@
+/* Copyright 2003, 2004 Free Software Foundation, Inc.
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 2.1 of the
+License, or (at your option) any later version.
+
+In addition to the permissions in the GNU Lesser General Public
+License, the Free Software Foundation gives you unlimited
+permission to link the compiled version of this file with other
+programs, and to distribute those programs without any restriction
+coming from the use of this file.  (The GNU Lesser General Public
+License restrictions do apply in other respects; for example, they
+cover modification of the file, and distribution when not linked
+into another program.)
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _BITS_ELF_FDPIC_H
+#define _BITS_ELF_FDPIC_H
+
+/* These data structures are described in the FDPIC ABI extension.
+   The kernel passes a process a memory map, such that for every LOAD
+   segment there is an elf32_fdpic_loadseg entry.  A pointer to an
+   elf32_fdpic_loadmap is passed in r7 at start-up, and a pointer to
+   an additional such map is passed in r8 for the interpreter, when
+   there is one.  */
+
+#include <elf.h>
+
+/* This data structure represents a PT_LOAD segment.  */
+struct elf32_fdpic_loadseg
+{
+  /* Core address to which the segment is mapped.  */
+  Elf32_Addr addr;
+  /* VMA recorded in the program header.  */
+  Elf32_Addr p_vaddr;
+  /* Size of this segment in memory.  */
+  Elf32_Word p_memsz;
+};
+
+struct elf32_fdpic_loadmap {
+  /* Protocol version number, must be zero.  */
+  Elf32_Half version;
+  /* Number of segments in this map.  */
+  Elf32_Half nsegs;
+  /* The actual memory map.  */
+  struct elf32_fdpic_loadseg segs[/*nsegs*/];
+};
+
+struct elf32_fdpic_loadaddr {
+  struct elf32_fdpic_loadmap *map;
+  void *got_value;
+};
+
+/* Map a pointer's VMA to its corresponding address according to the
+   load map.  */
+static __always_inline void *
+__reloc_pointer (void *p,
+                const struct elf32_fdpic_loadmap *map)
+{
+  int c;
+
+#if 0
+  if (map->version != 0)
+    /* Crash.  */
+    ((void(*)())0)();
+#endif
+
+  /* No special provision is made for NULL.  We don't want NULL
+     addresses to go through relocation, so they shouldn't be in
+     .rofixup sections, and, if they're present in dynamic
+     relocations, they shall be mapped to the NULL address without
+     undergoing relocations.  */
+
+  for (c = 0;
+       /* Take advantage of the fact that the loadmap is ordered by
+         virtual addresses.  In general there will only be 2 entries,
+         so it's not profitable to do a binary search.  */
+       c < map->nsegs && p >= (void*)map->segs[c].p_vaddr;
+       c++)
+    {
+      /* This should be computed as part of the pointer comparison
+        above, but we want to use the carry in the comparison, so we
+        can't convert it to an integer type beforehand.  */
+      unsigned long offset = p - (void*)map->segs[c].p_vaddr;
+      /* We only check for one-past-the-end for the last segment,
+        assumed to be the data segment, because other cases are
+        ambiguous in the absence of padding between segments, and
+        rofixup already serves as padding between text and data.
+        Unfortunately, unless we special-case the last segment, we
+        fail to relocate the _end symbol.  */
+      if (offset < map->segs[c].p_memsz
+         || (offset == map->segs[c].p_memsz && c + 1 == map->nsegs))
+       return (char*)map->segs[c].addr + offset;
+    }
+
+  /* We might want to crash instead.  */
+  return (void*)-1;
+}
+
+# define __RELOC_POINTER(ptr, loadaddr) \
+  (__reloc_pointer ((void*)(ptr), \
+                   (loadaddr).map))
+
+#endif /* _BITS_ELF_FDPIC_H */
diff --git a/libc/sysdeps/linux/arm/crtreloc.c 
b/libc/sysdeps/linux/arm/crtreloc.c
new file mode 100644
index 0000000..560b416
--- /dev/null
+++ b/libc/sysdeps/linux/arm/crtreloc.c
@@ -0,0 +1,144 @@
+/* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+   written by Alexandre Oliva <aol...@redhat.com>
+This file is part of the GNU C Library.
+
+The GNU C Library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public License as
+published by the Free Software Foundation; either version 2.1 of the
+License, or (at your option) any later version.
+
+In addition to the permissions in the GNU Lesser General Public
+License, the Free Software Foundation gives you unlimited
+permission to link the compiled version of this file with other
+programs, and to distribute those programs without any restriction
+coming from the use of this file.  (The GNU Lesser General Public
+License restrictions do apply in other respects; for example, they
+cover modification of the file, and distribution when not linked
+into another program.)
+
+The GNU C Library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+Library General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with the GNU C Library; see the file COPYING.LIB.  If
+not, see <http://www.gnu.org/licenses/>.  */
+
+#ifdef __FDPIC__
+
+#include <sys/types.h>
+#include <link.h>
+
+/* This file is to be compiled into crt object files, to enable
+   executables to easily self-relocate.  */
+
+union word {
+    char c[4];
+    void *v;
+};
+
+/* Compute the runtime address of pointer in the range [p,e), and then
+   map the pointer pointed by it.  */
+static __always_inline void ***
+reloc_range_indirect (void ***p, void ***e,
+                     const struct elf32_fdpic_loadmap *map)
+{
+  while (p < e)
+    {
+      if (*p != (void **)-1)
+       {
+         void *ptr = __reloc_pointer (*p, map);
+         if (ptr != (void *)-1)
+           {
+             void *pt;
+             if ((long)ptr & 3)
+               {
+                 unsigned char *c = ptr;
+                 int i;
+                 unsigned long v = 0;
+                 for (i = 0; i < 4; i++)
+                   v |= c[i] << 8 * i;
+                 pt = (void *)v;
+               }
+             else
+               pt = *(void**)ptr;
+             pt = __reloc_pointer (pt, map);
+             if ((long)ptr & 3)
+               {
+                 unsigned char *c = ptr;
+                 int i;
+                 unsigned long v = (unsigned long)pt;
+                 for (i = 0; i < 4; i++, v >>= 8)
+                   c[i] = v;
+               }
+             else
+               *(void**)ptr = pt;
+           }
+       }
+      p++;
+    }
+  return p;
+}
+
+/* Call __reloc_range_indirect for the given range except for the last
+   entry, whose contents are only relocated.  It's expected to hold
+   the GOT value.  */
+attribute_hidden void*
+__self_reloc (const struct elf32_fdpic_loadmap *map,
+             void ***p, void ***e)
+{
+  p = reloc_range_indirect (p, e-1, map);
+
+  if (p >= e)
+    return (void*)-1;
+
+  return __reloc_pointer (*p, map);
+}
+
+#if 0
+/* These are other functions that might be useful, but that we don't
+   need.  */
+
+/* Remap pointers in [p,e).  */
+static __always_inline void**
+reloc_range (void **p, void **e,
+            const struct elf32_fdpic_loadmap *map)
+{
+  while (p < e)
+    {
+      *p = __reloc_pointer (*p, map);
+      p++;
+    }
+  return p;
+}
+
+/* Remap p, adjust e by the same offset, then map the pointers in the
+   range determined by them.  */
+void attribute_hidden
+__reloc_range (const struct elf32_fdpic_loadmap *map,
+              void **p, void **e)
+{
+  void **old = p;
+
+  p = __reloc_pointer (p, map);
+  e += p - old;
+  reloc_range (p, e, map);
+}
+
+/* Remap p, adjust e by the same offset, then map pointers referenced
+   by the (unadjusted) pointers in the range.  Return the relocated
+   value of the last pointer in the range.  */
+void* attribute_hidden
+__reloc_range_indirect (const struct elf32_fdpic_loadmap *map,
+                       void ***p, void ***e)
+{
+  void ***old = p;
+
+  p = __reloc_pointer (p, map);
+  e += p - old;
+  return reloc_range_indirect (p, e, map);
+}
+#endif
+
+#endif /* __FDPIC__ */
diff --git a/libc/sysdeps/linux/arm/find_exidx.c 
b/libc/sysdeps/linux/arm/find_exidx.c
index 679d90c..cd4d442 100644
--- a/libc/sysdeps/linux/arm/find_exidx.c
+++ b/libc/sysdeps/linux/arm/find_exidx.c
@@ -18,6 +18,23 @@
 #include <link.h>
 #include <unwind.h>
 
+#if __FDPIC__
+#include <bits/elf-fdpic.h>
+static __always_inline int
+__dl_addr_in_loadaddr(void *p, struct elf32_fdpic_loadaddr loadaddr)
+{
+ struct elf32_fdpic_loadmap *map = loadaddr.map;
+ int c;
+
+ for (c = 0; c < map->nsegs; c++)
+   if ((void *)map->segs[c].addr <= p &&
+       (char *)p < (char *)map->segs[c].addr + map->segs[c].p_memsz)
+     return 1;
+
+ return 0;
+}
+#endif
+
 struct unw_eh_callback_data
 {
   _Unwind_Ptr pc;
@@ -32,6 +49,26 @@ struct unw_eh_callback_data
 static int
 find_exidx_callback (struct dl_phdr_info * info, size_t size, void * ptr)
 {
+#if __FDPIC__
+  struct unw_eh_callback_data * data;
+  const ElfW(Phdr) *phdr;
+  int i;
+  int match = 0;
+
+  data = (struct unw_eh_callback_data *) ptr;
+  if (__dl_addr_in_loadaddr((void *) data->pc, info->dlpi_addr)) {
+    match = 1;
+    phdr = info->dlpi_phdr;
+    for (i = info->dlpi_phnum; i > 0; i--, phdr++) {
+      if (phdr->p_type == PT_ARM_EXIDX) {
+        data->exidx_start = (_Unwind_Ptr) __RELOC_POINTER(phdr->p_vaddr, 
info->dlpi_addr);
+        data->exidx_len = phdr->p_memsz;
+      }
+    }
+  }
+
+  return match;
+#else
   struct unw_eh_callback_data * data;
   const ElfW(Phdr) *phdr;
   int i;
@@ -59,6 +96,7 @@ find_exidx_callback (struct dl_phdr_info * info, size_t size, 
void * ptr)
     }
 
   return match;
+#endif
 }
 
 
-- 
2.6.3

_______________________________________________
devel mailing list
devel@uclibc-ng.org
https://mailman.uclibc-ng.org/cgi-bin/mailman/listinfo/devel

Reply via email to