summary refs log tree commit diff
path: root/sysdeps/powerpc
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-09-24 23:03:42 +0000
committerUlrich Drepper <drepper@redhat.com>1997-09-24 23:03:42 +0000
commit650425ceb40e840b2123b6c8cc65389589f41218 (patch)
tree70ff83fbe8f34a7829b4a0b511d2cb02ccbcbf2a /sysdeps/powerpc
parent2604afb1b2d9acc3c70b1214285f996200bf0358 (diff)
downloadglibc-650425ceb40e840b2123b6c8cc65389589f41218.tar.gz
glibc-650425ceb40e840b2123b6c8cc65389589f41218.tar.xz
glibc-650425ceb40e840b2123b6c8cc65389589f41218.zip
1997-09-25 00:23  Ulrich Drepper  <drepper@cygnus.com>

	* elf/dl-profile.c: Correct implementation.

	* io/ftwtest-sh: Don't depend on TMPDIR == /tmp.

	* locale/setlocale.c: Rewrite a bit for more clarity.

	* math/Makefile (libm-calls): Add w_exp2.
	* math/math_private.h: Add prototypes for __ieee754_exp2{,f,l}.
	* sysdeps/libm-i387/s_exp2.S: Change name to __ieee754_exp2.
	* sysdeps/libm-i387/s_exp2f.S: Likewise.
	* sysdeps/libm-i387/s_exp2l.S: Likewise.
	* sysdeps/libm-ieee754/k_standard.c: Add error cases for exp2.

	* string/bits/string2.h (__strcpy_small): Optimize.
	(__stpcpy_small): Likewise.
	(strncpy): Use variable for dest argument since it's used more than
	once.
	(strncat): Likewise.
	(strcmp): Add optimization for this function.
	* sysdeps/i386/i486/string.h (strlen): Correctly use __builtin_strlen.
	(__strcpy_small): Optimize.
	(__stpcpy_small): Likewise.
	(__stpcpy_c): Correctly use __mempcpy_* macros.
	(__mempcpy_by2, __mempcpy_by4, __mempcpy_byn): Return pointer to
	byte following last copied.
	(strncat): Use variable for dest argument since it's used more than
	once.
	(strcmp): Add optimization for this function.

	* sysdeps/i386/dl-machine.h (ELF_MACHINE_RUNTIME_TRAMPOLINE): Use
	.text and .previous to select correct section.

1997-09-23 19:56  Philip Blundell  <Philip.Blundell@pobox.com>

	* configure.in: Add `--disable-versioning' option to suppress the
	use of symbol versions even if binutils claims to support it.

1997-09-24 20:10  Philip Blundell  <Philip.Blundell@pobox.com>

	* csu/Makefile (before-compile): Don't try to build abi-tags.h if
	not using ELF.

1997-09-21  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* elf/sofini.c [HAVE_DWARF2_UNWIND_INFO]: Supply termination for
	the frame unwind info section.

	* elf/soinit.c [HAVE_DWARF2_UNWIND_INFO]: Register and unregister
	the frame unwind info.

	* config.h.in (HAVE_DWARF2_UNWIND_INFO): Add #undef.

	* configure.in: Check whether gcc supports DWARF2 unwind info.

	* libc.map: Export frame handling tables.

1997-09-10 06:56  Geoff Keating  <geoffk@ozemail.com.au>

	* sysdeps/unix/sysv/linux/powerpc/bits/kernel_termios.h:
	Use the size of the kernel's termios structure for ioctls.

	* sysdeps/powerpc/dl-machine.h: Prepare for library profiling.

	* sysdeps/powerpc/bits/mathinline.h: Add slightly slower versions
	of the C9X FP comparison macros. Delete 'fabs' and 'sqrt' inline
	routines, because gcc has them as internals.

	* sysdeps/powerpc/Makefile (pic-ccflags): Define this instead of
	CFLAGS-.os.

	* sysdeps/powerpc/bzero.S: New file.
	* sysdeps/powerpc/strcat.c: New file.
	* sysdeps/powerpc/strcpy.S: New file.
	* sysdeps/powerpc/stpcpy.S: New file.

	* math/Makefile: Add atest_exp2, test-reduce.
	* math/atest_exp2.c: New file.
	* math/test-reduce.c: New file.
	* sysdeps/libm-ieee754/Dist: New file.
	* sysdeps/libm-ieee754/s_exp2.c: New file.
	* sysdeps/libm-ieee754/s_exp2f.c: New file.
	* sysdeps/libm-ieee754/t_exp2.h: New file.
	* sysdeps/libm-ieee754/t_exp2f.h: New file.
	* math/libm-test.c (exp2_test): Add some more tests.

	* Rules: Use empty.os instead of empty.o, since it gets linked into
	libc.so...
	* configure.in: Add --disable-static to disable building .a files.
	* config.make.in: Substitute the new variable.
	* Makeconfig: Don't build .o files if not building .a files.

	* elf/dl-runtime.c (fixup): Factor out call to elf_machine_relplt.
	(profile_fixup): Likewise.

1997-09-23  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* posix/globtest.c (main): Change to directory passed as first
	argument.

	* posix/globtest.sh: Don't cd before running the program, instead
	pass testdir as argument, so that $common_objpfx remains valid.

1997-09-23 18:01  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* nis/nis_call.c (__do_niscall2): Fix multiple Server support.

	* nis/nis_findserver.c: Save latest working sockaddr_in.

1997-09-17 22:07  Zack Weinberg  <zack@rabi.phys.columbia.edu>

	* configure.in: Automatically determine whether as and ld are the
	GNU versions.
	(options):  --with-gnu-{as,ld,binutils} replaced by
	single option --with-binutils=PATH specifying a -B option to gcc.
	* aclocal.m4: Two new macros defined, LIBC_PROG_FOO_GNU and
	LIBC_PROG_BINUTILS.

	* configure.in: Allow the user to force configuration for
	unsupported platforms with an undocumented option.

1997-09-22 16:55  Thorsten Kukuk  <kukuk@vt.uni-paderborn.de>

	* sunrpc/get_myaddr.c (get_myaddress): Avoid loopback interfaces,
	return loopback address only if there is no other interface.

	* nis/Makefile: Add nis_callback libnsl-routines.

	* nis/nis_add.c: Use new __do_niscall* interface.
	* nis/nis_cache.c: Likewise.
	* nis/nis_checkpoint.c: Likewise.
	* nis/nis_lookup.c: Likewise.
	* nis/nis_mkdir.c: Likewise.
	* nis/nis_modify.c: Likewise.
	* nis/nis_ping.c: Likewise.
	* nis/nis_remove.c: Likewise.
	* nis/nis_rmdir.c: Likewise.
	* nis/nis_server.c: Likewise.
	* nis/nis_util.c: Likewise.

	* nis/rpcsvc/nis.h: Make C++ safe.

	* nis/nss_nisplus/nisplus-publickey.c (getsecretkey): Fix use
	of variables.

	* nis/nis_findserv.c: Make thread safe.

	* nis/nis_call.c: Add support for callback, Fix use of variables.
	* nis/nis_table.c: Add support for callback, FOLLOW_PATH and
	ALL_RESULTS.
	* nis/nis_callback.c: New, callback functions.
	* nis/nis_intern.h: Add callback declarations.

1997-09-20  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* string/bits/string2.h: Fix logic in preprocessor directive.
	(__strsep_1c, __strsep_g): Don't declare __retval as pointing to
	const, to save a cast and a possible warning.

1997-09-22 04:12  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/i386/i486/atomicity.h (exchange_and_add): Really address
	memory in xadd not %1.

1997-09-21 13:56  Ulrich Drepper  <drepper@cygnus.com>

	* manual/maint.texi (Supported Configurations): Add SPARC64 to
	list of supported platforms.
Diffstat (limited to 'sysdeps/powerpc')
-rw-r--r--sysdeps/powerpc/Makefile6
-rw-r--r--sysdeps/powerpc/bits/mathinline.h44
-rw-r--r--sysdeps/powerpc/bzero.S27
-rw-r--r--sysdeps/powerpc/dl-machine.h71
-rw-r--r--sysdeps/powerpc/machine-gmon.h1
-rw-r--r--sysdeps/powerpc/stpcpy.S100
-rw-r--r--sysdeps/powerpc/strcat.c30
-rw-r--r--sysdeps/powerpc/strcpy.S100
8 files changed, 338 insertions, 41 deletions
diff --git a/sysdeps/powerpc/Makefile b/sysdeps/powerpc/Makefile
index 3e8f22b573..1813c78dd8 100644
--- a/sysdeps/powerpc/Makefile
+++ b/sysdeps/powerpc/Makefile
@@ -21,7 +21,7 @@ endif
 # so that's at least 8192 entries.  Since libc only uses about 1200 entries,
 # we want to use -fpic, because this generates fewer relocs.
 ifeq (yes,$(build-shared))
-CFLAGS-.os = -fpic -fno-common
+pic-ccflag = -fpic
 endif
 
 # The initfini generation code doesn't work in the presence of -fPIC, so
@@ -29,3 +29,7 @@ endif
 ifeq ($(subdir),csu)
 CFLAGS-initfini.s = -g0 -fpic
 endif
+
+ifeq ($(subdir),string)
+CFLAGS-memcmp.c += -Wno-uninitialized
+endif
diff --git a/sysdeps/powerpc/bits/mathinline.h b/sysdeps/powerpc/bits/mathinline.h
index d7f2a3ac0d..d7cabaf28b 100644
--- a/sysdeps/powerpc/bits/mathinline.h
+++ b/sysdeps/powerpc/bits/mathinline.h
@@ -32,34 +32,22 @@ __sgn1 (double __x)
 {
   return __x >= 0.0 ? 1.0 : -1.0;
 }
+#endif /* __NO_MATH_INLINES && __OPTIMZE__ */
 
-/* We'd want to use this if it was implemented in hardware, but
-   how can we tell? */
-#if 0
-__MATH_INLINE double sqrt (double __x);
-__MATH_INLINE double
-sqrt (double __x)
-{
-  register double __value;
-  __asm
-    ("fsqrt %0,%1"
-     : "=f" (__value) : "f" (__x));
-
-  return __value;
-}
-#endif
-
-__MATH_INLINE double fabs (double __x);
-__MATH_INLINE double
-fabs (double __x)
-{
-  register double __value;
-  __asm
-    ("fabs %0,%1"
-     : "=f" (__value) : "f" (__x));
-
-  return __value;
-}
+#if __USE_ISOC9X
+# define __unordered_cmp(x, y) \
+  (__extension__							      \
+   ({ __typeof__(x) __x = (x); __typeof__(y) __y = (y);			      \
+      unsigned __r;							      \
+      __asm__("fcmpu 7,%1,%2 ; mfcr %0" : "=r" (__r) : "f" (__x), "f"(__y));  \
+      __r; }))
+
+# define isgreater(x, y) (__unordered_cmp (x, y) >> 2 & 1)
+# define isgreaterequal(x, y) ((__unordered_cmp (x, y) & 6) != 0)
+# define isless(x, y) (__unordered_cmp (x, y) >> 3 & 1)
+# define islessequal(x, y) ((__unordered_cmp (x, y) & 0xA) != 0)
+# define islessgreater(x, y) ((__unordered_cmp (x, y) & 0xC) != 0)
+# define isunordered(x, y) (__unordered_cmp (x, y) & 1)
+#endif /* __USE_ISOC9X */
 
-#endif /* __NO_MATH_INLINES && __OPTIMZE__ */
 #endif /* __GNUC__  */
diff --git a/sysdeps/powerpc/bzero.S b/sysdeps/powerpc/bzero.S
new file mode 100644
index 0000000000..783a91fdcb
--- /dev/null
+++ b/sysdeps/powerpc/bzero.S
@@ -0,0 +1,27 @@
+/* Optimized bzero `implementation' for PowerPC.
+   Copyright (C) 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   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 Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sysdep.h>
+
+ENTRY(__bzero)
+	mr	%r5,%r4
+	li	%r4,0
+	b	memset@local
+END(__bzero)
+weak_alias (__bzero, bzero)
diff --git a/sysdeps/powerpc/dl-machine.h b/sysdeps/powerpc/dl-machine.h
index 771b711a14..70a3f20b31 100644
--- a/sysdeps/powerpc/dl-machine.h
+++ b/sysdeps/powerpc/dl-machine.h
@@ -199,6 +199,53 @@ _dl_runtime_resolve:
 	bctr
 0:
 	.size	 _dl_runtime_resolve,0b-_dl_runtime_resolve
+
+	.align 2
+	.globl _dl_prof_resolve
+	.type _dl_prof_resolve,@function
+_dl_prof_resolve:
+ # We need to save the registers used to pass parameters, and register 0,
+ # which is used by _mcount; the registers are saved in a stack frame.
+	stwu 1,-48(1)
+        stw 0,12(1)
+	stw 3,16(1)
+	stw 4,20(1)
+ # The code that calls this has put parameters for `fixup' in r12 and r11.
+	mr 3,12
+	stw 5,24(1)
+	mr 4,11
+	stw 6,28(1)
+	mflr 5
+ # We also need to save some of the condition register fields.
+	stw 7,32(1)
+	stw 5,52(1)
+	stw 8,36(1)
+	mfcr 0
+	stw 9,40(1)
+	stw 10,44(1)
+	stw 0,8(1)
+	bl profile_fixup@local
+ # 'fixup' returns the address we want to branch to.
+	mtctr 3
+ # Put the registers back...
+	lwz 0,52(1)
+	lwz 10,44(1)
+	lwz 9,40(1)
+	mtlr 0
+	lwz 8,36(1)
+	lwz 0,8(1)
+	lwz 7,32(1)
+	lwz 6,28(1)
+	mtcrf 0xFF,0
+	lwz 5,24(1)
+	lwz 4,20(1)
+	lwz 3,16(1)
+        lwz 0,12(1)
+ # ...unwind the stack frame, and jump to the PLT entry we updated.
+	addi 1,1,48
+	bctr
+0:
+	.size	 _dl_prof_resolve,0b-_dl_prof_resolve
  # Undo '.section text'.
 	.previous
 ");
@@ -409,8 +456,14 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
       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;
+      extern void _dl_runtime_resolve (void);
+      extern void _dl_prof_resolve (void);
+      Elf32_Word dlrr;
+
+      dlrr = (Elf32_Word)(char *)(profile
+				  ? _dl_prof_resolve
+				  : _dl_runtime_resolve);
 
       if (lazy)
 	for (i = 0; i < num_plt_entries; i++)
@@ -433,8 +486,7 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
       /* 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)
+      if (dlrr <= 0x01fffffc || dlrr >= 0xfe000000)
 	{
 	  /* Load address of link map in r12.  */
 	  plt[2] = OPCODE_LI (12, (Elf32_Word) (char *) map);
@@ -442,15 +494,13 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
 					   + 0x8000) >> 16));
 
 	  /* Call _dl_runtime_resolve.  */
-	  plt[4] = OPCODE_BA ((Elf32_Word) (char *) _dl_runtime_resolve);
+	  plt[4] = OPCODE_BA (dlrr);
 	}
       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[2] = OPCODE_LI (12, dlrr);
+	  plt[3] = OPCODE_ADDIS (12, 12, (dlrr + 0x8000) >> 16);
 	  plt[4] = OPCODE_MTCTR (12);
 
 	  /* Load address of link map in r12.  */
@@ -501,7 +551,6 @@ elf_machine_runtime_setup (struct link_map *map, int lazy, int profile)
 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. */
 }
 
@@ -513,7 +562,7 @@ elf_machine_lazy_rel (struct link_map *map, const Elf32_Rela *reloc)
    LOADADDR is the load address of the object; INFO is an array indexed
    by DT_* of the .dynamic section info.  */
 
-static inline void
+static void
 elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 		  const Elf32_Sym *sym, const struct r_found_version *version,
 		  Elf32_Addr *const reloc_addr)
@@ -709,4 +758,4 @@ elf_machine_rela (struct link_map *map, const Elf32_Rela *reloc,
 
 #define ELF_MACHINE_NO_REL 1
 
-#endif
+#endif /* RESOLVE */
diff --git a/sysdeps/powerpc/machine-gmon.h b/sysdeps/powerpc/machine-gmon.h
index ba53807308..b890dd5c53 100644
--- a/sysdeps/powerpc/machine-gmon.h
+++ b/sysdeps/powerpc/machine-gmon.h
@@ -1,7 +1,6 @@
 /* PowerPC-specific implementation of profiling support.
    Copyright (C) 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public License as
diff --git a/sysdeps/powerpc/stpcpy.S b/sysdeps/powerpc/stpcpy.S
new file mode 100644
index 0000000000..58ad5b12b6
--- /dev/null
+++ b/sysdeps/powerpc/stpcpy.S
@@ -0,0 +1,100 @@
+/* Optimized stpcpy implementation for PowerPC.
+   Copyright (C) 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   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 Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sysdep.h>
+
+/* See strlen.s for comments on how the end-of-string testing works.  */
+
+EALIGN(__stpcpy,4,0)
+/* char * [r3] stpcpy (char *dest [r3], const char *src [r4])  */
+
+/* General register assignments:
+   r0:	temporary
+   r3:	pointer to previous word in dest
+   r4:	pointer to previous word in src
+   r6:	current word from src
+   r7:	0xfefefeff
+   r8:	0x7f7f7f7f
+   r9:	~(word in src | 0x7f7f7f7f)
+   r10:	alternate word from src.  */
+
+	or    %r0,%r4,%r3
+	clrlwi. %r0,%r0,30
+	addi  %r3,%r3,-4
+	bne   L(unaligned)
+
+	lis   %r7,0xfeff
+	lis   %r8,0x7f7f
+	lwz   %r6,0(%r4)
+	addi  %r7,%r7,-0x101
+	addi  %r8,%r8,0x7f7f
+	b     2f
+
+0:	lwzu  %r10,4(%r4)
+	stwu  %r6,4(%r3)
+	add   %r0,%r7,%r10
+	nor   %r9,%r8,%r10
+	and.  %r0,%r0,%r9
+	bne-  1f
+	lwzu  %r6,4(%r4)
+	stwu  %r10,4(%r3)
+2:	add   %r0,%r7,%r6
+	nor   %r9,%r8,%r6
+	and.  %r0,%r0,%r9
+	beq+  0b
+
+	mr    %r10,%r6
+/* We've hit the end of the string.  Do the rest byte-by-byte.  */
+1:	rlwinm. %r0,%r10,8,24,31
+	stbu  %r0,4(%r3)
+	beqlr-
+	rlwinm. %r0,%r10,16,24,31
+	stbu  %r0,1(%r3)
+	beqlr-
+	rlwinm. %r0,%r10,24,24,31
+	stbu  %r0,1(%r3)
+	beqlr-
+	stbu  %r10,1(%r3)
+	blr
+
+/* Oh well.  In this case, we just do a byte-by-byte copy.  */
+	.align 4
+	nop
+L(unaligned):
+	lbz   %r6,0(%r4)
+	addi  %r3,%r3,3
+	cmpwi %r6,0
+	beq-  2f
+
+0:	lbzu  %r10,1(%r4)
+	stbu  %r6,1(%r3)
+	cmpwi %r10,0
+	beq-  1f
+	nop		/* Let 601 load start of loop.  */
+	lbzu  %r6,1(%r4)
+	stbu  %r10,1(%r3)
+	cmpwi %r6,0
+	bne+  0b
+2:	stbu  %r6,1(%r3)
+	blr
+1:	stbu  %r10,1(%r3)
+	blr
+END(__stpcpy)
+
+weak_alias (__stpcpy, stpcpy)
diff --git a/sysdeps/powerpc/strcat.c b/sysdeps/powerpc/strcat.c
new file mode 100644
index 0000000000..9d9ab6549a
--- /dev/null
+++ b/sysdeps/powerpc/strcat.c
@@ -0,0 +1,30 @@
+/* strcat version that uses fast strcpy/strlen.
+   Copyright (C) 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   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 Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <string.h>
+
+#undef strcat
+
+/* Append SRC on the end of DEST.  */
+char *
+strcat (char *dest, const char *src)
+{
+  strcpy (dest + strlen (dest), src);
+  return dest;
+}
diff --git a/sysdeps/powerpc/strcpy.S b/sysdeps/powerpc/strcpy.S
new file mode 100644
index 0000000000..3c0cce7844
--- /dev/null
+++ b/sysdeps/powerpc/strcpy.S
@@ -0,0 +1,100 @@
+/* Optimized strcpy implementation for PowerPC.
+   Copyright (C) 1997 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 Library General Public License as
+   published by the Free Software Foundation; either version 2 of the
+   License, or (at your option) any later version.
+
+   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 Library General Public
+   License along with the GNU C Library; see the file COPYING.LIB.  If not,
+   write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA.  */
+
+#include <sysdep.h>
+
+/* See strlen.s for comments on how the end-of-string testing works.  */
+
+EALIGN(strcpy,4,0)
+/* char * [r3] strcpy (char *dest [r3], const char *src [r4])  */
+
+/* General register assignments:
+   r0:	temporary
+   r3:	saved `dest'
+   r4:	pointer to previous word in src
+   r5:	pointer to previous word in dest
+   r6:	current word from src
+   r7:	0xfefefeff
+   r8:	0x7f7f7f7f
+   r9:	~(word in src | 0x7f7f7f7f)
+   r10:	alternate word from src.  */
+
+	or    %r0,%r4,%r3
+	clrlwi. %r0,%r0,30
+	addi  %r5,%r3,-4
+	bne   L(unaligned)
+
+	lis   %r7,0xfeff
+	lis   %r8,0x7f7f
+	lwz   %r6,0(%r4)
+	addi  %r7,%r7,-0x101
+	addi  %r8,%r8,0x7f7f
+	b     2f
+
+0:	lwzu  %r10,4(%r4)
+	stwu  %r6,4(%r5)
+	add   %r0,%r7,%r10
+	nor   %r9,%r8,%r10
+	and.  %r0,%r0,%r9
+	bne-  1f
+	lwzu  %r6,4(%r4)
+	stwu  %r10,4(%r5)
+2:	add   %r0,%r7,%r6
+	nor   %r9,%r8,%r6
+	and.  %r0,%r0,%r9
+	beq+  0b
+
+	mr    %r10,%r6
+/* We've hit the end of the string.  Do the rest byte-by-byte.  */
+1:	rlwinm. %r0,%r10,8,24,31
+	stb   %r0,4(%r5)
+	beqlr-
+	rlwinm. %r0,%r10,16,24,31
+	stb   %r0,5(%r5)
+	beqlr-
+	rlwinm. %r0,%r10,24,24,31
+	stb   %r0,6(%r5)
+	beqlr-
+	stb   %r10,7(%r5)
+	blr
+
+/* Oh well.  In this case, we just do a byte-by-byte copy.  */
+	.align 4
+	nop
+L(unaligned):
+	lbz   %r6,0(%r4)
+	addi  %r5,%r3,-1
+	cmpwi %r6,0
+	beq-  2f
+
+0:	lbzu  %r10,1(%r4)
+	stbu  %r6,1(%r5)
+	cmpwi %r10,0
+	beq-  1f
+	nop		/* Let 601 load start of loop.  */
+	lbzu  %r6,1(%r4)
+	stbu  %r10,1(%r5)
+	cmpwi %r6,0
+	bne+  0b
+2:	stb   %r6,1(%r5)
+	blr
+1:	stb   %r10,1(%r5)
+	blr
+
+END(strcpy)