summaryrefslogtreecommitdiff
path: root/sysdeps/powerpc/powerpc32/dl-machine.h
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/powerpc/powerpc32/dl-machine.h')
-rw-r--r--sysdeps/powerpc/powerpc32/dl-machine.h305
1 files changed, 190 insertions, 115 deletions
diff --git a/sysdeps/powerpc/powerpc32/dl-machine.h b/sysdeps/powerpc/powerpc32/dl-machine.h
index 496fa71ecc..a8c1e3e490 100644
--- a/sysdeps/powerpc/powerpc32/dl-machine.h
+++ b/sysdeps/powerpc/powerpc32/dl-machine.h
@@ -1,5 +1,5 @@
/* Machine-dependent ELF dynamic relocation inline functions. PowerPC version.
- Copyright (C) 1995-2002, 2003, 2005 Free Software Foundation, Inc.
+ Copyright (C) 1995-2002, 2003 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
@@ -25,10 +25,6 @@
#include <assert.h>
#include <dl-tls.h>
-/* Translate a processor specific dynamic tag to the index
- in l_info array. */
-#define DT_PPC(x) (DT_PPC_##x - DT_LOPROC + DT_NUM)
-
/* Return nonzero iff ELF header is compatible with the running host. */
static inline int
elf_machine_matches_host (const Elf32_Ehdr *ehdr)
@@ -36,38 +32,24 @@ elf_machine_matches_host (const Elf32_Ehdr *ehdr)
return ehdr->e_machine == EM_PPC;
}
-/* Return the value of the GOT pointer. */
-static inline Elf32_Addr * __attribute__ ((const))
-ppc_got (void)
-{
- Elf32_Addr *got;
-#ifdef HAVE_ASM_PPC_REL16
- asm ("bcl 20,31,1f\n"
- "1: mflr %0\n"
- " addis %0,%0,_GLOBAL_OFFSET_TABLE_-1b@ha\n"
- " addi %0,%0,_GLOBAL_OFFSET_TABLE_-1b@l\n"
- : "=b" (got) : : "lr");
-#else
- asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
- : "=l" (got));
-#endif
- return got;
-}
/* Return the link-time address of _DYNAMIC, stored as
the first value in the GOT. */
-static inline Elf32_Addr __attribute__ ((const))
+static inline Elf32_Addr
elf_machine_dynamic (void)
{
- return *ppc_got ();
+ Elf32_Addr *got;
+ asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
+ : "=l"(got));
+ return *got;
}
/* Return the run-time load address of the shared object. */
-static inline Elf32_Addr __attribute__ ((const))
+static inline Elf32_Addr
elf_machine_load_address (void)
{
- Elf32_Addr *branchaddr;
- Elf32_Addr runtime_dynamic;
+ unsigned int *got;
+ unsigned int *branchaddr;
/* This is much harder than you'd expect. Possibly I'm missing something.
The 'obvious' way:
@@ -98,17 +80,19 @@ elf_machine_load_address (void)
the address ourselves. That gives us the following code: */
/* Get address of the 'b _DYNAMIC@local'... */
- asm ("bcl 20,31,0f;"
+ asm ("bl 0f ;"
"b _DYNAMIC@local;"
"0:"
- : "=l" (branchaddr));
+ : "=l"(branchaddr));
+
+ /* ... and the address of the GOT. */
+ asm (" bl _GLOBAL_OFFSET_TABLE_-4@local"
+ : "=l"(got));
/* So now work out the difference between where the branch actually points,
and the offset of that location in memory from the start of the file. */
- runtime_dynamic = ((Elf32_Addr) branchaddr
- + ((Elf32_Sword) (*branchaddr << 6 & 0xffffff00) >> 6));
-
- return runtime_dynamic - elf_machine_dynamic ();
+ return ((Elf32_Addr)branchaddr - *got
+ + ((int)(*branchaddr << 6 & 0xffffff00) >> 6));
}
#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
@@ -116,6 +100,160 @@ elf_machine_load_address (void)
/* The PLT uses Elf32_Rela relocs. */
#define elf_machine_relplt elf_machine_rela
+/* This code is used in dl-runtime.c to call the `fixup' function
+ and then redirect to the address it returns. It is called
+ from code built in the PLT by elf_machine_runtime_setup. */
+#if !defined PROF
+#define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
+ .section \".text\" \n\
+ .align 2 \n\
+ .globl _dl_runtime_resolve \n\
+ .type _dl_runtime_resolve,@function \n\
+_dl_runtime_resolve: \n\
+ # We need to save the registers used to pass parameters, and register 0,\n\
+ # which is used by _mcount; the registers are saved in a stack frame.\n\
+ stwu 1,-64(1) \n\
+ stw 0,12(1) \n\
+ stw 3,16(1) \n\
+ stw 4,20(1) \n\
+ # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
+ mr 3,12 \n\
+ stw 5,24(1) \n\
+ mr 4,11 \n\
+ stw 6,28(1) \n\
+ mflr 0 \n\
+ # We also need to save some of the condition register fields.\n\
+ stw 7,32(1) \n\
+ stw 0,48(1) \n\
+ stw 8,36(1) \n\
+ mfcr 0 \n\
+ stw 9,40(1) \n\
+ stw 10,44(1) \n\
+ stw 0,8(1) \n\
+ bl fixup@local \n\
+ # 'fixup' returns the address we want to branch to.\n\
+ mtctr 3 \n\
+ # Put the registers back...\n\
+ lwz 0,48(1) \n\
+ lwz 10,44(1) \n\
+ lwz 9,40(1) \n\
+ mtlr 0 \n\
+ lwz 8,36(1) \n\
+ lwz 0,8(1) \n\
+ lwz 7,32(1) \n\
+ lwz 6,28(1) \n\
+ mtcrf 0xFF,0 \n\
+ lwz 5,24(1) \n\
+ lwz 4,20(1) \n\
+ lwz 3,16(1) \n\
+ lwz 0,12(1) \n\
+ # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
+ addi 1,1,64 \n\
+ bctr \n\
+ .size _dl_runtime_resolve,.-_dl_runtime_resolve \n\
+ \n\
+ .align 2 \n\
+ .globl _dl_prof_resolve \n\
+ .type _dl_prof_resolve,@function \n\
+_dl_prof_resolve: \n\
+ # We need to save the registers used to pass parameters, and register 0,\n\
+ # which is used by _mcount; the registers are saved in a stack frame.\n\
+ stwu 1,-64(1) \n\
+ stw 0,12(1) \n\
+ stw 3,16(1) \n\
+ stw 4,20(1) \n\
+ # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
+ mr 3,12 \n\
+ stw 5,24(1) \n\
+ mr 4,11 \n\
+ stw 6,28(1) \n\
+ mflr 5 \n\
+ # We also need to save some of the condition register fields.\n\
+ stw 7,32(1) \n\
+ stw 5,48(1) \n\
+ stw 8,36(1) \n\
+ mfcr 0 \n\
+ stw 9,40(1) \n\
+ stw 10,44(1) \n\
+ stw 0,8(1) \n\
+ bl profile_fixup@local \n\
+ # 'fixup' returns the address we want to branch to.\n\
+ mtctr 3 \n\
+ # Put the registers back...\n\
+ lwz 0,48(1) \n\
+ lwz 10,44(1) \n\
+ lwz 9,40(1) \n\
+ mtlr 0 \n\
+ lwz 8,36(1) \n\
+ lwz 0,8(1) \n\
+ lwz 7,32(1) \n\
+ lwz 6,28(1) \n\
+ mtcrf 0xFF,0 \n\
+ lwz 5,24(1) \n\
+ lwz 4,20(1) \n\
+ lwz 3,16(1) \n\
+ lwz 0,12(1) \n\
+ # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
+ addi 1,1,64 \n\
+ bctr \n\
+ .size _dl_prof_resolve,.-_dl_prof_resolve \n\
+ # Undo '.section text'.\n\
+ .previous \n\
+");
+#else
+# define ELF_MACHINE_RUNTIME_TRAMPOLINE asm ("\n\
+ .section \".text\" \n\
+ .align 2 \n\
+ .globl _dl_runtime_resolve \n\
+ .globl _dl_prof_resolve \n\
+ .type _dl_runtime_resolve,@function \n\
+ .type _dl_prof_resolve,@function \n\
+_dl_runtime_resolve: \n\
+_dl_prof_resolve: \n\
+ # We need to save the registers used to pass parameters, and register 0,\n\
+ # which is used by _mcount; the registers are saved in a stack frame.\n\
+ stwu 1,-64(1) \n\
+ stw 0,12(1) \n\
+ stw 3,16(1) \n\
+ stw 4,20(1) \n\
+ # The code that calls this has put parameters for `fixup' in r12 and r11.\n\
+ mr 3,12 \n\
+ stw 5,24(1) \n\
+ mr 4,11 \n\
+ stw 6,28(1) \n\
+ mflr 0 \n\
+ # We also need to save some of the condition register fields.\n\
+ stw 7,32(1) \n\
+ stw 0,48(1) \n\
+ stw 8,36(1) \n\
+ mfcr 0 \n\
+ stw 9,40(1) \n\
+ stw 10,44(1) \n\
+ stw 0,8(1) \n\
+ bl fixup@local \n\
+ # 'fixup' returns the address we want to branch to.\n\
+ mtctr 3 \n\
+ # Put the registers back...\n\
+ lwz 0,48(1) \n\
+ lwz 10,44(1) \n\
+ lwz 9,40(1) \n\
+ mtlr 0 \n\
+ lwz 8,36(1) \n\
+ lwz 0,8(1) \n\
+ lwz 7,32(1) \n\
+ lwz 6,28(1) \n\
+ mtcrf 0xFF,0 \n\
+ lwz 5,24(1) \n\
+ lwz 4,20(1) \n\
+ lwz 3,16(1) \n\
+ lwz 0,12(1) \n\
+ # ...unwind the stack frame, and jump to the PLT entry we updated.\n\
+ addi 1,1,64 \n\
+ bctr \n\
+ .size _dl_runtime_resolve,.-_dl_runtime_resolve \n\
+");
+#endif
+
/* Mask identifying addresses reserved for the user program,
where the dynamic linker should not map anything. */
#define ELF_MACHINE_USER_ADDRESS_MASK 0xf0000000UL
@@ -160,69 +298,13 @@ __elf_preferred_address(struct link_map *loader, size_t maplength,
/* The PowerPC never uses REL relocations. */
#define ELF_MACHINE_NO_REL 1
-/* Set up the loaded object described by MAP so its unrelocated PLT
+/* Set up the loaded object described by L so its unrelocated PLT
entries will jump to the on-demand fixup code in dl-runtime.c.
Also install a small trampoline to be used by entries that have
been relocated to an address too far away for a single branch. */
extern int __elf_machine_runtime_setup (struct link_map *map,
int lazy, int profile);
-
-static inline int
-elf_machine_runtime_setup (struct link_map *map,
- int lazy, int profile)
-{
- if (map->l_info[DT_JMPREL] == 0)
- return lazy;
-
- if (map->l_info[DT_PPC(GOT)] == 0)
- /* Handle old style PLT. */
- return __elf_machine_runtime_setup (map, lazy, profile);
-
- /* New style non-exec PLT consisting of an array of addresses. */
- map->l_info[DT_PPC(GOT)]->d_un.d_ptr += map->l_addr;
- if (lazy)
- {
- Elf32_Addr *plt, *got, glink;
- Elf32_Word num_plt_entries;
- void (*dlrr) (void);
- extern void _dl_runtime_resolve (void);
- extern void _dl_prof_resolve (void);
-
- if (__builtin_expect (!profile, 1))
- dlrr = _dl_runtime_resolve;
- else
- {
- if (GLRO(dl_profile) != NULL
- &&_dl_name_match_p (GLRO(dl_profile), map))
- GL(dl_profile_map) = map;
- dlrr = _dl_prof_resolve;
- }
- got = (Elf32_Addr *) map->l_info[DT_PPC(GOT)]->d_un.d_ptr;
- glink = got[1];
- got[1] = (Elf32_Addr) dlrr;
- got[2] = (Elf32_Addr) map;
-
- /* Relocate everything in .plt by the load address offset. */
- plt = (Elf32_Addr *) D_PTR (map, l_info[DT_PLTGOT]);
- num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
- / sizeof (Elf32_Rela));
-
- /* If a library is prelinked but we have to relocate anyway,
- we have to be able to undo the prelinking of .plt section.
- The prelinker saved us at got[1] address of .glink
- section's start. */
- if (glink)
- {
- glink += map->l_addr;
- while (num_plt_entries-- != 0)
- *plt++ = glink, glink += 4;
- }
- else
- while (num_plt_entries-- != 0)
- *plt++ += map->l_addr;
- }
- return lazy;
-}
+#define elf_machine_runtime_setup __elf_machine_runtime_setup
/* Change the PLT entry whose reloc is 'reloc' to call the actual routine. */
extern Elf32_Addr __elf_machine_fixup_plt (struct link_map *map,
@@ -235,12 +317,7 @@ elf_machine_fixup_plt (struct link_map *map, lookup_t t,
const Elf32_Rela *reloc,
Elf32_Addr *reloc_addr, Elf64_Addr finaladdr)
{
- if (map->l_info[DT_PPC(GOT)] == 0)
- /* Handle old style PLT. */
- return __elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
-
- *reloc_addr = finaladdr;
- return finaladdr;
+ return __elf_machine_fixup_plt (map, reloc, reloc_addr, finaladdr);
}
/* Return the final value of a plt relocation. */
@@ -251,14 +328,9 @@ elf_machine_plt_value (struct link_map *map, const Elf32_Rela *reloc,
return value + reloc->r_addend;
}
-
-/* Names of the architecture-specific auditing callback functions. */
-#define ARCH_LA_PLTENTER ppc32_gnu_pltenter
-#define ARCH_LA_PLTEXIT ppc32_gnu_pltexit
-
#endif /* dl_machine_h */
-#ifdef RESOLVE_MAP
+#ifdef RESOLVE
/* Do the actual processing of a reloc, once its target address
has been determined. */
@@ -281,7 +353,7 @@ extern void _dl_reloc_overflow (struct link_map *map,
LOADADDR is the load address of the object; INFO is an array indexed
by DT_* of the .dynamic section info. */
-auto inline void __attribute__ ((always_inline))
+inline void
elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
const Elf32_Sym *sym, const struct r_found_version *version,
void *const reloc_addr_arg)
@@ -309,8 +381,16 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
value = map->l_addr;
else
{
+# if defined USE_TLS && !defined RTLD_BOOTSTRAP
sym_map = RESOLVE_MAP (&sym, version, r_type);
- value = sym_map == NULL ? 0 : sym_map->l_addr + sym->st_value;
+ value = sym == NULL ? 0 : sym_map->l_addr + sym->st_value;
+# else
+ value = RESOLVE (&sym, version, r_type);
+# ifndef RTLD_BOOTSTRAP
+ if (sym != NULL)
+# endif
+ value += sym->st_value;
+# endif
}
value += reloc->r_addend;
#else
@@ -363,16 +443,11 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
break;
#endif /* USE_TLS etc. */
- case R_PPC_JMP_SLOT:
#ifdef RESOLVE_CONFLICT_FIND_MAP
+ case R_PPC_JMP_SLOT:
RESOLVE_CONFLICT_FIND_MAP (map, reloc_addr);
-#endif
- if (map->l_info[DT_PPC(GOT)] != 0)
- {
- *reloc_addr = value;
- break;
- }
/* FALLTHROUGH */
+#endif
default:
__process_machine_rela (map, reloc, sym_map, sym, refsym,
@@ -380,7 +455,7 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
}
}
-auto inline void __attribute__ ((always_inline))
+static inline void
elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
void *const reloc_addr_arg)
{
@@ -388,7 +463,7 @@ elf_machine_rela_relative (Elf32_Addr l_addr, const Elf32_Rela *reloc,
*reloc_addr = l_addr + reloc->r_addend;
}
-auto inline void __attribute__ ((always_inline))
+static inline void
elf_machine_lazy_rel (struct link_map *map,
Elf32_Addr l_addr, const Elf32_Rela *reloc)
{
@@ -399,4 +474,4 @@ elf_machine_lazy_rel (struct link_map *map,
DT_RELA table. */
#define ELF_MACHINE_PLTREL_OVERLAP 1
-#endif /* RESOLVE_MAP */
+#endif /* RESOLVE */