aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/powerpc/dl-machine.h
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-05-21 01:48:59 +0000
committerUlrich Drepper <drepper@redhat.com>1997-05-21 01:48:59 +0000
commit1f205a479b43e5e40672fe5b4ae8f717b28c41b1 (patch)
tree0611b2d3503d81c55b27b235119ae999f1271178 /sysdeps/powerpc/dl-machine.h
parent43b0e40f85770cd1f362c3abbad41e09bd9f0b17 (diff)
downloadglibc-1f205a479b43e5e40672fe5b4ae8f717b28c41b1.tar
glibc-1f205a479b43e5e40672fe5b4ae8f717b28c41b1.tar.gz
glibc-1f205a479b43e5e40672fe5b4ae8f717b28c41b1.tar.bz2
glibc-1f205a479b43e5e40672fe5b4ae8f717b28c41b1.zip
1997-05-21 02:49 Ulrich Drepper <drepper@cygnus.com> * gnu-versions.h (_GNU_OBSTACK_INTERFACE_VERSION): Set to 2 since interface was changed with addition of _obstack_memory_used. Suggested by Ian Taylor <ian@cygnus.com>. * malloc/obstack.c: Include <config.h>. Include <stdlib.h> only if __GNU_LIBRARY__ or HAVE_STDLIB_H is defined. Reported by Ian Taylor <ian@cygnus.com>. * dirent/Makefile (routines): Add versionsort. * dirent/dirent.h: Add prototype for versionsort. * dirent/versionsort.c: New file. * manual/filesys.texi: Add documentation for versionsort. * manual/string.texi: Add documentation for strverscmp. * string/Makefile (routines): Add strverscmp. (tests): Add tst-svc. * string/string.h: Add prototype for strverscmp. * string/strverscmp.c: New file. * string/tst-svc.c: New file. Test for strverscmp. * string/tst-svc.input: New file. Input data for tst-svc. * string/tst-svc.expect: New file. Expected out from tst-svc. * math/Makefile (calls): Add s_signbit. * po/sv.po: Update. * resolv/nss_dns/dns-host.c: Add casts to prevent warnings. * sunrpc/pmap_rmt.c: Likewise. * string/basename.c: Don't use ISO C definition style. Include <config.h> is HAVE_CONFIG_H is defined. * sunrpc/proto.h: Add `const' wherever possible. * sunrpc/rpc_cout.c: Likewise. * sunrpc/rpc_svcout.c: Likewise. * sunrpc/xdr_mem.c: Likewise. * sunrpc/xdr_rec.c: Likewise. * sunrpc/xdr_stdio.c: Likewise. * sunrpc/rpc_parse.c: Delete comma from end of enum definition. * sunrpc/xdr.c: Little code cleanups. * sunrpc/xdr_flaot.c: Likewise. Patches by Matthew Wilcox <matthew.wilcox@chbs.mhs.ciba.com>. * sysdeps/i386/fpu/__math.h (__finite): Fix typo. * sysdeps/unix/sysv/linux/shmdt.c: Add cast to prevent warning. * time/europe: Update from tzdata1997f. * time/zic.c: Update from tzcode1997e. 1997-05-20 19:20 Miguel de Icaza <miguel@athena.nuclecu.unam.mx> * sysdeps/sparc/setjmp.S: Flush windows. Bug found by Richard Henderson. 1997-05-19 12:54 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * misc/efgcvt_r.c (fcvt_r, ecvt_r): Rewritten as to fit the specs. 1997-05-19 18:41 Thorsten Kukuk <kukuk@uni-paderborn.de> * nis/nss_nisplus/nisplus-spwd.c (_nss_nisplus_parse_spent): Use atol instead of atoi. 1997-05-18 00:22 Philip Blundell <pjb27@cam.ac.uk> * inet/Makefile (routines): Add if_index. * sysdeps/unix/sysv/linux/if_index.c: New file. * sysdeps/stub/if_index.c: New file. * sysdeps/unix/sysv/linux/net/if.h: Add prototypes for routines in if_index.c (required by IPv6 basic API). * sysdeps/unix/sysv/linux/netinet/in.h: Add struct ipv6_pktinfo. 1997-05-17 23:29 Philip Blundell <pjb27@cam.ac.uk> * sysdeps/unix/sysv/linux/netinet/in.h: Update IPv6 definitions for new advanced API draft. 1997-05-13 21:33 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * stdio-common/printf_fp.c: Only use the field width for deciding on padding when printing special values. * stdio-common/printf_fphex.c: Likewise. 1997-05-15 13:14 Miles Bader <miles@gnu.ai.mit.edu> Changes by Thomas Bushnell <thomas@gnu.ai.mit.edu>: * hurd/hurdauth.c (_S_msg_add_auth): Implement correctly. 1997-05-12 14:50 Thomas Bushnell, n/BSG <thomas@gnu.ai.mit.edu> * hurd/hurdsig.c (_hurdsig_init): Double size of sigthread stack; msg_add_auth was overflowing it. 1997-05-12 21:20 Richard Henderson <rth@tamu.edu> * elf/dl-lookup.c (_dl_lookup_symbol_skip): Call _dl_signal_error when we can't find the symbol. 1997-05-12 16:54 Ulrich Drepper <drepper@cygnus.com> * posix/regex.c: Fix handling of 32-bit Windog environments. Patch by Arnold Robbins <arnold@skeeve.atl.ga.us>. 1997-05-10 23:26 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * sysdeps/unix/sysv/linux/m68k/syscalls.list: Add cacheflush. 1997-05-10 11:40 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * elf/ldd.bash.in: Remove spurious quote character from version message. 1997-05-10 08:49 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * locale/programs/locale.c (write_charmaps): Don't get stuck in a loop if the file ends in a long line without newline. * locale/programs/charmap.c (charmap_read): Likewise. 1997-05-12 03:47 Ulrich Drepper <drepper@cygnus.com> * sunrpc/rpc/xdr.h: Include more headers to be self-contained. * sunrpc/rpc/svc_auth.h: Likewise. * sunrpc/rpc/svc.h: Likewise. * sunrpc/rpc/rpc_msg.h: Likewise. * sunrpc/rpc/pmap_rmt.h: Likewise. * sunrpc/rpc/pmap_clnt.h: Likewise. * sunrpc/rpc/clnt.h: Likewise. * sunrpc/rpc/auth_unix.h: Likewise. * sysdeps/generic/rpc/auth.h: Likewise. Patches by Michael Deutschmann <ldeutsch@mail.netshop.net>. 1997-05-11 15:29 Philip Blundell <pjb27@cam.ac.uk> * sysdeps/stub/sigaction.c (__sigaction): Correct typo. * sysdeps/standalone/arm/errnos.h: New file. * sysdeps/stub/sys/param.h: Add dummy definition of MAXSYMLINKS. * sysdeps/unix/arm/fork.S: New file. * sysdeps/unix/sysv/linux/arm/sysdep.h: New file. * sysdeps/stub/tempname.c (__stdio_gen_tempname): Add missing `streamptr' argument. * sysdeps/stub/vdprintf.c: Remove second copy of file (!), include <stdarg.h> to get va_list defined, return 0 not NULL. * sysdeps/unix/sysv/linux/statfsbuf.h: Include <gnu/types.h>. * sysdeps/unix/sysv/linux/arm/syscall.S: New file. * sysdeps/stub/direntry.h (struct dirent): Add missing ';'. * sysdeps/stub/seekdir.c (seekdir): Likewise. * sysdeps/stub/dirfd.c (dirfd): Argument dirp is DIR*, not FILE*. * sysdeps/standalone/dirstream.h: Define struct __dirstream not DIR; <dirent.h> provides typedef. * sysdeps/unix/sysv/linux/arm/clone.S: New file. * sysdeps/unix/sysv/linux/arm/socket.S: New file. * sysdeps/stub/sysconf.c (__sysconf): Fix typos. 1997-05-01 06:35 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/powerpc/Dist: New file. * sysdeps/powerpc/Makefile: New file. * sysdeps/powerpc/fclrexcpt.c: New file. * sysdeps/powerpc/fegetenv.c: New file. * sysdeps/powerpc/fegetround.c: New file. * sysdeps/powerpc/feholdexcpt.c: New file. * sysdeps/powerpc/fenvbits.h: New file. * sysdeps/powerpc/fenv_const.c: New file. * sysdeps/powerpc/fenv_libc.h: New file. * sysdeps/powerpc/fesetenv.c: New file. * sysdeps/powerpc/fesetround.c: New file. * sysdeps/powerpc/feupdateenv.c: New file. * sysdeps/powerpc/fgetexcptflg.c: New file. * sysdeps/powerpc/fraiseexcpt.c: New file. * sysdeps/powerpc/fsetexcptflg.c: New file. * sysdeps/powerpc/ftestexcept.c: New file. * sysdeps/powerpc/mathbits.h: New file. * sysdeps/powerpc/dl-machine.h: Wrap in #ifndef dl_machine_h; define elf_machine_lookup_noexec_p, elf_machine_lookup_noplt_p, ELF_MACHINE_RELOC_NOPLT; consequent changes to elf_machine_rela. * sysdeps/powerpc/__math.h: Remove definition for hypot and __sgn. * sysdep/powerpc/fpu_control.h: Correct IEEE default mode. * sysdeps/unix/sysv/linux/powerpc/sysdep.h: Don't use .text, but instead .section ".text". 1997-04-25 05:06 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/powerpc/__longjmp.S: Use symbolic register numbering. * sysdeps/powerpc/bsd-_setjmp.S: Likewise. * sysdeps/powerpc/bsd-setjmp.S: Likewise. * sysdeps/powerpc/setjmp.S: Likewise. * sysdeps/unix/sysv/linux/clone.S: Likewise. * sysdeps/unix/sysv/linux/socket.S: Likewise. * sysdeps/unix/sysv/linux/syscall.S: Likewise. 1997-04-20 04:37 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/powerpc/strchr.s: New file. * sysdeps/powerpc/strcmp.s: New (ugly) file. * sysdeps/powerpc/memset.s: New file. * string/tester.c: Include prototype and _GNU_SOURCE to make standalone compilation possible. Give strcmp a better test. Give memset a better test. 1997-04-05 06:34 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/powerpc/strlen.s: Fixed bugs (how did it ever pass its tests before?). Changed to symbolic register numbering as an experiment. * sysdeps/powerpc/ffs.c: Don't include bstring.h, it doesn't exist. * sysdeps/rs6000/ffs.c: Likewise. 1997-05-12 02:28 Ulrich Drepper <drepper@cygnus.com> * time/sys/time.h: Make second argument of setitimer const. Patch by Michael Deutschmann <ldeutsch@mail.netshop.net>. * sysdeps/stub/setitimer.c: Likewise. * sysdeps/mach/hurd/setitimer.c: Likewise.
Diffstat (limited to 'sysdeps/powerpc/dl-machine.h')
-rw-r--r--sysdeps/powerpc/dl-machine.h638
1 files changed, 329 insertions, 309 deletions
diff --git a/sysdeps/powerpc/dl-machine.h b/sysdeps/powerpc/dl-machine.h
index 3ad5ca89c9..cfada93cd4 100644
--- a/sysdeps/powerpc/dl-machine.h
+++ b/sysdeps/powerpc/dl-machine.h
@@ -17,6 +17,9 @@
write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA. */
+#ifndef dl_machine_h
+#define dl_machine_h
+
#define ELF_MACHINE_NAME "powerpc"
#include <assert.h>
@@ -134,318 +137,13 @@ elf_machine_load_address (void)
/* 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. */
- return (Elf32_Addr)branchaddr - *got +
- (*branchaddr & 0x3fffffc |
- (int)(*branchaddr << 6 & 0x80000000) >> 6);
+ return ((Elf32_Addr)branchaddr - *got
+ + (*branchaddr & 0x3fffffc
+ | (int)(*branchaddr << 6 & 0x80000000) >> 6));
}
#define ELF_MACHINE_BEFORE_RTLD_RELOC(dynamic_info) /* nothing */
-/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
- LOADADDR is the load address of the object; INFO is an array indexed
- by DT_* of the .dynamic section info. */
-
-#ifdef RESOLVE
-
-static inline void
-elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
- const Elf32_Sym *sym, const struct r_found_version *version)
-{
- const Elf32_Sym *const refsym = sym;
- Elf32_Addr *const reloc_addr = (Elf32_Addr *)(map->l_addr + reloc->r_offset);
- Elf32_Word loadbase, finaladdr;
- const int rinfo = ELF32_R_TYPE (reloc->r_info);
-
- if (rinfo == R_PPC_NONE)
- return;
-
- assert (sym != NULL);
- if (ELF32_ST_TYPE (sym->st_info) == STT_SECTION ||
- rinfo == R_PPC_RELATIVE)
- {
- /* Has already been relocated. */
- loadbase = map->l_addr;
- finaladdr = loadbase + reloc->r_addend;
- }
- else
- {
- int flags;
-
- /* We never want to use a PLT entry as the destination of a
- reloc, when what is being relocated is a branch. This is
- partly for efficiency, but mostly so we avoid loops. */
- if (rinfo == R_PPC_REL24 ||
- rinfo == R_PPC_ADDR24 ||
- rinfo == R_PPC_JMP_SLOT)
- flags = DL_LOOKUP_NOPLT;
- else if (rinfo == R_PPC_COPY)
- flags = DL_LOOKUP_NOEXEC;
- else
- flags = 0;
-
- loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version, flags));
- if (sym == NULL)
- {
- /* Weak symbol that wasn't actually defined anywhere. */
- assert(loadbase == 0);
- finaladdr = reloc->r_addend;
- }
- else
- finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
- + reloc->r_addend);
- }
-
- /* This is an if/else if chain because GCC 2.7.2.[012] turns case
- statements into non-PIC table lookups. When a later version
- comes out that fixes this, this should be changed. */
- if (rinfo == R_PPC_UADDR32 ||
- rinfo == R_PPC_GLOB_DAT ||
- rinfo == R_PPC_ADDR32 ||
- rinfo == R_PPC_RELATIVE)
- {
- *reloc_addr = finaladdr;
- }
- else if (rinfo == R_PPC_ADDR16_LO)
- {
- *(Elf32_Half*) reloc_addr = finaladdr;
- }
- else if (rinfo == R_PPC_ADDR16_HI)
- {
- *(Elf32_Half*) reloc_addr = finaladdr >> 16;
- }
- else if (rinfo == R_PPC_ADDR16_HA)
- {
- *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
- }
-#ifndef RTLD_BOOTSTRAP
- else if (rinfo == R_PPC_REL24)
- {
- Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
- if (delta << 6 >> 6 != delta)
- _dl_signal_error (0, map->l_name,
- "R_PPC_REL24 relocation out of range");
- *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc;
- }
- else if (rinfo == R_PPC_ADDR24)
- {
- if (finaladdr << 6 >> 6 != finaladdr)
- _dl_signal_error (0, map->l_name,
- "R_PPC_ADDR24 relocation out of range");
- *reloc_addr = *reloc_addr & 0xfc000003 | finaladdr & 0x3fffffc;
- }
- else if (rinfo == R_PPC_COPY)
- {
- if (sym->st_size != refsym->st_size)
- {
- const char *strtab;
-
- strtab = ((void *) map->l_addr
- + map->l_info[DT_STRTAB]->d_un.d_ptr);
- _dl_sysdep_error ("Symbol `", strtab + refsym->st_name,
- "' has different size in shared object, "
- "consider re-linking\n", NULL);
- }
- memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
- refsym->st_size));
- }
-#endif
- else if (rinfo == R_PPC_REL32)
- {
- *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
- }
- else if (rinfo == R_PPC_JMP_SLOT)
- {
- Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
- if (delta << 6 >> 6 == delta)
- *reloc_addr = OPCODE_B (delta);
- else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
- *reloc_addr = OPCODE_BA (finaladdr);
- else
- {
- Elf32_Word *plt;
- Elf32_Word index;
-
- plt = (Elf32_Word *)((char *)map->l_addr
- + map->l_info[DT_PLTGOT]->d_un.d_val);
- index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
-
- if (index >= PLT_DOUBLE_SIZE)
- {
- /* Slots greater than or equal to 2^13 have 4 words available
- instead of two. */
- reloc_addr[0] = OPCODE_LI (11, finaladdr);
- reloc_addr[1] = OPCODE_ADDIS (11, 11, finaladdr + 0x8000 >> 16);
- reloc_addr[2] = OPCODE_MTCTR (11);
- reloc_addr[3] = OPCODE_BCTR ();
- }
- else
- {
- Elf32_Word num_plt_entries;
-
- num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
- / sizeof(Elf32_Rela));
-
- reloc_addr[0] = OPCODE_LI (11, index*4);
- reloc_addr[1] =
- OPCODE_B (-(4*(index*2
- + 1
- - PLT_LONGBRANCH_ENTRY_WORDS
- + PLT_INITIAL_ENTRY_WORDS)));
- plt[index+PLT_DATA_START_WORDS (num_plt_entries)] = finaladdr;
- }
- }
- MODIFIED_CODE (reloc_addr);
- }
- else
- assert (! "unexpected dynamic reloc type");
-
- if (rinfo == R_PPC_ADDR16_LO ||
- rinfo == R_PPC_ADDR16_HI ||
- rinfo == R_PPC_ADDR16_HA ||
- rinfo == R_PPC_REL24 ||
- rinfo == R_PPC_ADDR24)
- MODIFIED_CODE_NOQUEUE (reloc_addr);
-}
-
-#define ELF_MACHINE_NO_REL 1
-
-#endif
-
-/* Nonzero iff TYPE describes relocation of a PLT entry, so
- PLT entries should not be allowed to define the value. */
-#define elf_machine_pltrel_p(type) ((type) == R_PPC_JMP_SLOT)
-
-/* 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. */
-
-/* A PLT entry does one of three things:
- (i) Jumps to the actual routine. Such entries are set up above, in
- elf_machine_rela.
-
- (ii) Jumps to the actual routine via glue at the start of the PLT.
- We do this by putting the address of the routine in space
- allocated at the end of the PLT, and when the PLT entry is
- called we load the offset of that word (from the start of the
- space) into r11, then call the glue, which loads the word and
- branches to that address. These entries are set up in
- elf_machine_rela, but the glue is set up here.
-
- (iii) Loads the index of this PLT entry (we count the double-size
- entries as one entry for this purpose) into r11, then
- branches to code at the start of the PLT. This code then
- calls `fixup', in dl-runtime.c, via the glue in the macro
- ELF_MACHINE_RUNTIME_TRAMPOLINE, which resets the PLT entry to
- be one of the above two types. These entries are set up here. */
-static inline void
-elf_machine_runtime_setup (struct link_map *map, int lazy)
-{
- if (map->l_info[DT_JMPREL])
- {
- int i;
- /* Fill in the PLT. Its initial contents are directed to a
- function earlier in the PLT which arranges for the dynamic
- linker to be called back. */
- Elf32_Word *plt = (Elf32_Word *) ((char *) map->l_addr
- + map->l_info[DT_PLTGOT]->d_un.d_val);
- Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
- / sizeof (Elf32_Rela));
- Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
- extern void _dl_runtime_resolve (void);
- Elf32_Word size_modified;
-
- if (lazy)
- for (i = 0; i < num_plt_entries; i++)
- {
- Elf32_Word offset = PLT_ENTRY_START_WORDS (i);
-
- if (i >= PLT_DOUBLE_SIZE)
- {
- plt[offset ] = OPCODE_LI (11, i * 4);
- plt[offset+1] = OPCODE_ADDIS (11, 11, (i * 4 + 0x8000) >> 16);
- plt[offset+2] = OPCODE_B (-(4 * (offset + 2)));
- }
- else
- {
- plt[offset ] = OPCODE_LI (11, i * 4);
- plt[offset+1] = OPCODE_B (-(4 * (offset + 1)));
- }
- }
-
- /* Multiply index of entry by 3 (in r11). */
- plt[0] = OPCODE_SLWI (12, 11, 1);
- plt[1] = OPCODE_ADD (11, 12, 11);
- if ((Elf32_Word) (char *) _dl_runtime_resolve <= 0x01fffffc ||
- (Elf32_Word) (char *) _dl_runtime_resolve >= 0xfe000000)
- {
- /* Load address of link map in r12. */
- plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map);
- plt[3] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
- + 0x8000) >> 16));
-
- /* Call _dl_runtime_resolve. */
- plt[4] = OPCODE_BA ((Elf32_Word) (char *) _dl_runtime_resolve);
- }
- else
- {
- /* Get address of _dl_runtime_resolve in CTR. */
- plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) _dl_runtime_resolve);
- plt[3] = OPCODE_ADDIS (12, 12, ((((Elf32_Word) (char *)
- _dl_runtime_resolve)
- + 0x8000) >> 16));
- plt[4] = OPCODE_MTCTR (12);
-
- /* Load address of link map in r12. */
- plt[5] = OPCODE_LI (12, (Elf32_Word) (char *) map);
- plt[6] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
- + 0x8000) >> 16));
-
- /* Call _dl_runtime_resolve. */
- plt[7] = OPCODE_BCTR ();
- }
-
-
- /* Convert the index in r11 into an actual address, and get the
- word at that address. */
- plt[PLT_LONGBRANCH_ENTRY_WORDS] =
- OPCODE_ADDIS (11, 11, (((Elf32_Word) (char*) (plt + rel_offset_words)
- + 0x8000) >> 16));
- plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
- OPCODE_LWZ (11, (Elf32_Word) (char*) (plt+rel_offset_words), 11);
-
- /* Call the procedure at that address. */
- plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR (11);
- plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR ();
-
-
- /* Now, we've modified code (quite a lot of code, possibly). We
- need to write the changes from the data cache to a
- second-level unified cache, then make sure that stale data in
- the instruction cache is removed. (In a multiprocessor
- system, the effect is more complex.)
-
- Assumes the cache line size is at least 32 bytes, or at least
- that dcbst and icbi apply to 32-byte lines. At present, all
- PowerPC processors have line sizes of exactly 32 bytes. */
-
- size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
- for (i = 0; i < size_modified; i+=8)
- PPC_DCBST (plt + i);
- PPC_SYNC;
- for (i = 0; i < size_modified; i+=8)
- PPC_ICBI (plt + i);
- PPC_ISYNC;
- }
-}
-
-static inline void
-elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc)
-{
- assert (ELF32_R_TYPE (reloc->r_info) == R_PPC_JMP_SLOT);
- /* elf_machine_runtime_setup handles this. */
-}
-
/* The PLT uses Elf32_Rela relocs. */
#define elf_machine_relplt elf_machine_rela
@@ -617,7 +315,7 @@ _start:
information here about the way memory is mapped. */
#define ELF_PREFERRED_ADDRESS_DATA \
-static ElfW(Addr) _dl_preferred_address = 1;
+static ElfW(Addr) _dl_preferred_address = 1
#define ELF_PREFERRED_ADDRESS(loader, maplength, mapstartpref) \
( { \
@@ -645,4 +343,326 @@ static ElfW(Addr) _dl_preferred_address = 1;
_dl_preferred_address = mapstart; \
} )
+/* We require the address of the PLT entry returned from fixup, not
+ the first word of the PLT entry. */
#define ELF_FIXUP_RETURNS_ADDRESS 1
+
+/* Nonzero iff TYPE should not be allowed to resolve to one of
+ the main executable's symbols, as for a COPY reloc. */
+#define elf_machine_lookup_noexec_p(type) ((type) == R_PPC_COPY)
+
+/* Nonzero iff TYPE describes relocation of a PLT entry, so
+ PLT entries should not be allowed to define the value. */
+/* We never want to use a PLT entry as the destination of a
+ reloc, when what is being relocated is a branch. This is
+ partly for efficiency, but mostly so we avoid loops. */
+#define elf_machine_lookup_noplt_p(type) ((type) == R_PPC_REL24 || \
+ (type) == R_PPC_ADDR24 || \
+ (type) == R_PPC_JMP_SLOT)
+
+/* A reloc type used for ld.so cmdline arg lookups to reject PLT entries. */
+#define ELF_MACHINE_RELOC_NOPLT R_PPC_JMP_SLOT
+
+/* Nonzero iff TYPE describes relocation of a PLT entry, so
+ PLT entries should not be allowed to define the value. */
+#define elf_machine_pltrel_p(type) ((type) == R_PPC_JMP_SLOT)
+
+/* 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. */
+
+/* A PLT entry does one of three things:
+ (i) Jumps to the actual routine. Such entries are set up above, in
+ elf_machine_rela.
+
+ (ii) Jumps to the actual routine via glue at the start of the PLT.
+ We do this by putting the address of the routine in space
+ allocated at the end of the PLT, and when the PLT entry is
+ called we load the offset of that word (from the start of the
+ space) into r11, then call the glue, which loads the word and
+ branches to that address. These entries are set up in
+ elf_machine_rela, but the glue is set up here.
+
+ (iii) Loads the index of this PLT entry (we count the double-size
+ entries as one entry for this purpose) into r11, then
+ branches to code at the start of the PLT. This code then
+ calls `fixup', in dl-runtime.c, via the glue in the macro
+ ELF_MACHINE_RUNTIME_TRAMPOLINE, which resets the PLT entry to
+ be one of the above two types. These entries are set up here. */
+static inline void
+elf_machine_runtime_setup (struct link_map *map, int lazy)
+{
+ if (map->l_info[DT_JMPREL])
+ {
+ int i;
+ /* Fill in the PLT. Its initial contents are directed to a
+ function earlier in the PLT which arranges for the dynamic
+ linker to be called back. */
+ Elf32_Word *plt = (Elf32_Word *) ((char *) map->l_addr
+ + map->l_info[DT_PLTGOT]->d_un.d_val);
+ Elf32_Word num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
+ / sizeof (Elf32_Rela));
+ Elf32_Word rel_offset_words = PLT_DATA_START_WORDS (num_plt_entries);
+ extern void _dl_runtime_resolve (void);
+ Elf32_Word size_modified;
+
+ if (lazy)
+ for (i = 0; i < num_plt_entries; i++)
+ {
+ Elf32_Word offset = PLT_ENTRY_START_WORDS (i);
+
+ if (i >= PLT_DOUBLE_SIZE)
+ {
+ plt[offset ] = OPCODE_LI (11, i * 4);
+ plt[offset+1] = OPCODE_ADDIS (11, 11, (i * 4 + 0x8000) >> 16);
+ plt[offset+2] = OPCODE_B (-(4 * (offset + 2)));
+ }
+ else
+ {
+ plt[offset ] = OPCODE_LI (11, i * 4);
+ plt[offset+1] = OPCODE_B (-(4 * (offset + 1)));
+ }
+ }
+
+ /* Multiply index of entry by 3 (in r11). */
+ plt[0] = OPCODE_SLWI (12, 11, 1);
+ plt[1] = OPCODE_ADD (11, 12, 11);
+ if ((Elf32_Word) (char *) _dl_runtime_resolve <= 0x01fffffc ||
+ (Elf32_Word) (char *) _dl_runtime_resolve >= 0xfe000000)
+ {
+ /* Load address of link map in r12. */
+ plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map);
+ plt[3] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
+ + 0x8000) >> 16));
+
+ /* Call _dl_runtime_resolve. */
+ plt[4] = OPCODE_BA ((Elf32_Word) (char *) _dl_runtime_resolve);
+ }
+ else
+ {
+ /* Get address of _dl_runtime_resolve in CTR. */
+ plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) _dl_runtime_resolve);
+ plt[3] = OPCODE_ADDIS (12, 12, ((((Elf32_Word) (char *)
+ _dl_runtime_resolve)
+ + 0x8000) >> 16));
+ plt[4] = OPCODE_MTCTR (12);
+
+ /* Load address of link map in r12. */
+ plt[5] = OPCODE_LI (12, (Elf32_Word) (char *) map);
+ plt[6] = OPCODE_ADDIS (12, 12, (((Elf32_Word) (char *) map
+ + 0x8000) >> 16));
+
+ /* Call _dl_runtime_resolve. */
+ plt[7] = OPCODE_BCTR ();
+ }
+
+
+ /* Convert the index in r11 into an actual address, and get the
+ word at that address. */
+ plt[PLT_LONGBRANCH_ENTRY_WORDS] =
+ OPCODE_ADDIS (11, 11, (((Elf32_Word) (char*) (plt + rel_offset_words)
+ + 0x8000) >> 16));
+ plt[PLT_LONGBRANCH_ENTRY_WORDS+1] =
+ OPCODE_LWZ (11, (Elf32_Word) (char*) (plt+rel_offset_words), 11);
+
+ /* Call the procedure at that address. */
+ plt[PLT_LONGBRANCH_ENTRY_WORDS+2] = OPCODE_MTCTR (11);
+ plt[PLT_LONGBRANCH_ENTRY_WORDS+3] = OPCODE_BCTR ();
+
+
+ /* Now, we've modified code (quite a lot of code, possibly). We
+ need to write the changes from the data cache to a
+ second-level unified cache, then make sure that stale data in
+ the instruction cache is removed. (In a multiprocessor
+ system, the effect is more complex.)
+
+ Assumes the cache line size is at least 32 bytes, or at least
+ that dcbst and icbi apply to 32-byte lines. At present, all
+ PowerPC processors have line sizes of exactly 32 bytes. */
+
+ size_modified = lazy ? rel_offset_words : PLT_INITIAL_ENTRY_WORDS;
+ for (i = 0; i < size_modified; i+=8)
+ PPC_DCBST (plt + i);
+ PPC_SYNC;
+ for (i = 0; i < size_modified; i+=8)
+ PPC_ICBI (plt + i);
+ PPC_ISYNC;
+ }
+}
+
+static inline void
+elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc)
+{
+ assert (ELF32_R_TYPE (reloc->r_info) == R_PPC_JMP_SLOT);
+ /* elf_machine_runtime_setup handles this. */
+}
+
+#endif /* dl_machine_h */
+
+#ifdef RESOLVE
+
+/* Perform the relocation specified by RELOC and SYM (which is fully resolved).
+ LOADADDR is the load address of the object; INFO is an array indexed
+ by DT_* of the .dynamic section info. */
+
+static inline void
+elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
+ const Elf32_Sym *sym, const struct r_found_version *version)
+{
+ const Elf32_Sym *const refsym = sym;
+ Elf32_Addr *const reloc_addr = (Elf32_Addr *)(map->l_addr + reloc->r_offset);
+ Elf32_Word loadbase, finaladdr;
+ const int rinfo = ELF32_R_TYPE (reloc->r_info);
+
+ if (rinfo == R_PPC_NONE)
+ return;
+
+ assert (sym != NULL);
+ /* The condition on the next two lines is a hack around a bug in Solaris
+ tools on Sparc. It's not clear whether it should really be here at all,
+ but if not the binutils need to be changed. */
+ if ((sym->st_shndx != SHN_UNDEF
+ && ELF32_ST_BIND (sym->st_info) == STB_LOCAL)
+ || rinfo == R_PPC_RELATIVE)
+ {
+ /* Has already been relocated. */
+ loadbase = map->l_addr;
+ finaladdr = loadbase + reloc->r_addend;
+ }
+ else
+ {
+ loadbase = (Elf32_Word) (char *) (RESOLVE (&sym, version,
+ ELF32_R_TYPE(reloc->r_info)));
+ if (sym == NULL)
+ {
+ /* Weak symbol that wasn't actually defined anywhere. */
+ assert(loadbase == 0);
+ finaladdr = reloc->r_addend;
+ }
+ else
+ finaladdr = (loadbase + (Elf32_Word) (char *) sym->st_value
+ + reloc->r_addend);
+ }
+
+ /* This is an if/else if chain because GCC 2.7.2.[012] turns case
+ statements into non-PIC table lookups. When a later version
+ comes out that fixes this, this should be changed. */
+ if (rinfo == R_PPC_UADDR32 ||
+ rinfo == R_PPC_GLOB_DAT ||
+ rinfo == R_PPC_ADDR32 ||
+ rinfo == R_PPC_RELATIVE)
+ {
+ *reloc_addr = finaladdr;
+ }
+ else if (rinfo == R_PPC_ADDR16_LO)
+ {
+ *(Elf32_Half*) reloc_addr = finaladdr;
+ }
+ else if (rinfo == R_PPC_ADDR16_HI)
+ {
+ *(Elf32_Half*) reloc_addr = finaladdr >> 16;
+ }
+ else if (rinfo == R_PPC_ADDR16_HA)
+ {
+ *(Elf32_Half*) reloc_addr = (finaladdr + 0x8000) >> 16;
+ }
+#ifndef RTLD_BOOTSTRAP
+ else if (rinfo == R_PPC_REL24)
+ {
+ Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
+ if (delta << 6 >> 6 != delta)
+ {
+ _dl_signal_error(0, map->l_name,
+ "R_PPC_REL24 relocation out of range");
+ }
+ *reloc_addr = *reloc_addr & 0xfc000003 | delta & 0x3fffffc;
+ }
+ else if (rinfo == R_PPC_ADDR24)
+ {
+ if (finaladdr << 6 >> 6 != finaladdr)
+ {
+ _dl_signal_error(0, map->l_name,
+ "R_PPC_ADDR24 relocation out of range");
+ }
+ *reloc_addr = *reloc_addr & 0xfc000003 | finaladdr & 0x3fffffc;
+ }
+ else if (rinfo == R_PPC_COPY)
+ {
+ if (sym->st_size != refsym->st_size)
+ {
+ const char *strtab;
+
+ strtab = ((void *) map->l_addr
+ + map->l_info[DT_STRTAB]->d_un.d_ptr);
+ _dl_sysdep_error ("Symbol `", strtab + refsym->st_name,
+ "' has different size in shared object, "
+ "consider re-linking\n", NULL);
+ }
+ memcpy (reloc_addr, (char *) finaladdr, MIN (sym->st_size,
+ refsym->st_size));
+ }
+#endif
+ else if (rinfo == R_PPC_REL32)
+ {
+ *reloc_addr = finaladdr - (Elf32_Word) (char *) reloc_addr;
+ }
+ else if (rinfo == R_PPC_JMP_SLOT)
+ {
+ Elf32_Sword delta = finaladdr - (Elf32_Word) (char *) reloc_addr;
+ if (delta << 6 >> 6 == delta)
+ *reloc_addr = OPCODE_B (delta);
+ else if (finaladdr <= 0x01fffffc || finaladdr >= 0xfe000000)
+ *reloc_addr = OPCODE_BA (finaladdr);
+ else
+ {
+ Elf32_Word *plt;
+ Elf32_Word index;
+
+ plt = (Elf32_Word *)((char *)map->l_addr
+ + map->l_info[DT_PLTGOT]->d_un.d_val);
+ index = (reloc_addr - plt - PLT_INITIAL_ENTRY_WORDS)/2;
+
+ if (index >= PLT_DOUBLE_SIZE)
+ {
+ /* Slots greater than or equal to 2^13 have 4 words available
+ instead of two. */
+ reloc_addr[0] = OPCODE_LI (11, finaladdr);
+ reloc_addr[1] = OPCODE_ADDIS (11, 11, finaladdr + 0x8000 >> 16);
+ reloc_addr[2] = OPCODE_MTCTR (11);
+ reloc_addr[3] = OPCODE_BCTR ();
+ }
+ else
+ {
+ Elf32_Word num_plt_entries;
+
+ num_plt_entries = (map->l_info[DT_PLTRELSZ]->d_un.d_val
+ / sizeof(Elf32_Rela));
+
+ reloc_addr[0] = OPCODE_LI (11, index*4);
+ reloc_addr[1] =
+ OPCODE_B (-(4*(index*2
+ + 1
+ - PLT_LONGBRANCH_ENTRY_WORDS
+ + PLT_INITIAL_ENTRY_WORDS)));
+ plt[index+PLT_DATA_START_WORDS (num_plt_entries)] = finaladdr;
+ }
+ }
+ MODIFIED_CODE (reloc_addr);
+ }
+ else
+ assert (! "unexpected dynamic reloc type");
+
+ if (rinfo == R_PPC_ADDR16_LO ||
+ rinfo == R_PPC_ADDR16_HI ||
+ rinfo == R_PPC_ADDR16_HA ||
+ rinfo == R_PPC_REL24 ||
+ rinfo == R_PPC_ADDR24)
+ MODIFIED_CODE_NOQUEUE (reloc_addr);
+}
+
+#define ELF_MACHINE_NO_REL 1
+
+#endif
+
+