about summary refs log tree commit diff
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.gz
glibc-1f205a479b43e5e40672fe5b4ae8f717b28c41b1.tar.xz
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
+
+