This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch master updated. glibc-2.17-299-g43301bd


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  43301bd3c281036ba97eef384c9340cc7b6130d3 (commit)
      from  85bd816a603a437aedeb688a60a3e0dba4439c50 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sources.redhat.com/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=43301bd3c281036ba97eef384c9340cc7b6130d3

commit 43301bd3c281036ba97eef384c9340cc7b6130d3
Author: Maciej W. Rozycki <macro@codesourcery.com>
Date:   Wed Feb 27 23:45:07 2013 +0000

    Add support for building as MIPS16 code.

diff --git a/ports/ChangeLog.mips b/ports/ChangeLog.mips
index f06c986..2518065 100644
--- a/ports/ChangeLog.mips
+++ b/ports/ChangeLog.mips
@@ -1,3 +1,109 @@
+2013-02-27  Chung-Lin Tang  <cltang@codesourcery.com>
+            Maciej W. Rozycki  <macro@codesourcery.com>
+            Maxim Kuvyrkov  <maxim@codesourcery.com>
+
+	* sysdeps/mips/abort-instr.h (ABORT_INSTRUCTION) [__mips16]:
+	New macro.
+	* sysdeps/mips/dl-machine.h (elf_machine_load_address): Add
+	MIPS16 version of assembly code.
+	(RTLD_START) [__mips16]: New macro.
+	* sysdeps/mips/fpu_control.h (__mips_fpu_getcw): New prototype.
+	(__mips_fpu_setcw): Likewise.
+	(_FPU_GETCW) [__mips16]: New macro.
+	(_FPU_SETCW) [__mips16]: Likewise.
+	* sysdeps/mips/machine-gmon.h (MCOUNT): Add `.set nomips16'.
+	* sysdeps/mips/tls-macros.h (LOAD_GP) [__mips16]: New macro.
+	(TLS_GD, TLS_LD, TLS_IE, TLS_LE) [__mips16]: Likewise.
+	* sysdeps/mips/bits/atomic.h: Also use __atomic_* builtins with
+	GCC 4.7 in MIPS16 code.
+	(atomic_compare_and_exchange_val_acq) [__mips16]: New macro.
+	(atomic_compare_and_exchange_bool_acq) [__mips16]: Likewise.
+	(atomic_exchange_acq) [__mips16]: Likewise.
+	(atomic_exchange_and_add) [__mips16]: Likewise.
+	(atomic_bit_test_set) [__mips16]: Likewise.
+	(atomic_and, atomic_and_val) [__mips16]: Likewise.
+	(atomic_or, atomic_or_val) [__mips16]: Likewise.
+	(atomic_full_barrier) [__mips16]: Likewise.
+	* sysdeps/mips/nptl/tls.h (READ_THREAD_POINTER) [__mips16]:
+	Likewise.
+	* sysdeps/mips/sys/tas.h (_test_and_set): Add `__nomips16__'
+	attribute.
+	* sysdeps/unix/mips/sysdep.h (PSEUDO_NOERRNO): Add
+	`.set nomips16'.
+	(PSEUDO_ERRVAL): Likewise.
+	* sysdeps/unix/mips/mips32/sysdep.h (PSEUDO): Likewise.
+	* sysdeps/unix/mips/mips64/n32/sysdep.h (PSEUDO): Likewise.
+	* sysdeps/unix/mips/mips64/n64/sysdep.h (PSEUDO): Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
+	(INTERNAL_SYSCALL, INTERNAL_SYSCALL_NCS) [__mips16]: New macros.
+	(INTERNAL_SYSCALL_MIPS16) [__mips16]: Likewise.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h (PSEUDO):
+	Add `.set nomips16'.
+	* sysdeps/mips/bsd-_setjmp.S (_setjmp): Likewise.
+	* sysdeps/mips/bsd-setjmp.S (setjmp): Likewise.
+	* sysdeps/mips/memset.S (memset): Likewise.
+	* sysdeps/mips/setjmp.S (__sigsetjmp): Likewise.
+	* sysdeps/mips/start.S (ENTRY_POINT) [__mips16]: New function.
+	* sysdeps/mips/mips32/crti.S: Add `.set nomips16'.
+	* sysdeps/mips/mips32/crtn.S: Likewise.
+	* sysdeps/mips/mips64/n32/crti.S: Likewise.
+	* sysdeps/mips/mips64/n32/crtn.S: Likewise.
+	* sysdeps/mips/mips64/n64/crti.S: Likewise.
+	* sysdeps/mips/mips64/n64/crtn.S: Likewise.
+	* sysdeps/unix/mips/sysdep.S: Likewise.
+	* sysdeps/unix/sysv/linux/mips/clone.S: Likewise.
+	* sysdeps/unix/sysv/linux/mips/getcontext.S: Likewise.
+	* sysdeps/unix/sysv/linux/mips/makecontext.S: Likewise.
+	* sysdeps/unix/sysv/linux/mips/setcontext.S: Likewise.
+	* sysdeps/unix/sysv/linux/mips/swapcontext.S: Likewise.
+	* sysdeps/unix/sysv/linux/mips/vfork.S: Likewise.
+	* sysdeps/mips/__longjmp.c (__longjmp): Rename function to...
+	(____longjmp): ... this.  Make static and add `nomips16'
+	attribute.
+	(__longjmp): New alias.
+	* sysdeps/mips/dl-trampoline.c (_dl_runtime_resolve) [__mips16]:
+	New function.
+	(_dl_runtime_pltresolve): Likewise.
+	* sysdeps/mips/setjmp_aux.c (__sigsetjmp_aux): Add `nomips16'
+	attribute.
+	* sysdeps/mips/fpu/e_sqrt.c (__ieee754_sqrt): Likewise.
+	* sysdeps/mips/fpu/e_sqrtf.c (__ieee754_sqrtf): Likewise.
+	* sysdeps/unix/sysv/linux/mips/brk.c (__brk): Rewrite in terms
+	of INTERNAL_SYSCALL.
+	* sysdeps/mips/mips32/fpu/fpu_control.c: New file.
+	* sysdeps/mips/mips32/mips16/add_n.c: New file.
+	* sysdeps/mips/mips32/mips16/addmul_1.c: New file.
+	* sysdeps/mips/mips32/mips16/lshift.c: New file.
+	* sysdeps/mips/mips32/mips16/mul_1.c: New file.
+	* sysdeps/mips/mips32/mips16/rshift.c: New file.
+	* sysdeps/mips/mips32/mips16/sub_n.c: New file.
+	* sysdeps/mips/mips32/mips16/submul_1.c: New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c:
+	New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c:
+	New file.
+	* sysdeps/mips/mips32/fpu/Versions: New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions: New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist: New
+	file.
+	* sysdeps/mips/mips32/mips16/fpu/Makefile: New file.
+	* sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile: New file.
+	* sysdeps/mips/preconfigure: Handle o32 MIPS16 compilation.
+
 2013-02-20  Thomas Schwinge  <thomas@codesourcery.com>
 
 	* sysdeps/mips/bits/nan.h [!__GNUC__] (__nan_union): Change
diff --git a/ports/sysdeps/mips/__longjmp.c b/ports/sysdeps/mips/__longjmp.c
index a9efb0d..67bdb86 100644
--- a/ports/sysdeps/mips/__longjmp.c
+++ b/ports/sysdeps/mips/__longjmp.c
@@ -23,8 +23,8 @@
   #error This file uses GNU C extensions; you must compile with GCC.
 #endif
 
-void
-__longjmp (env_arg, val_arg)
+static void __attribute__ ((nomips16))
+____longjmp (env_arg, val_arg)
      __jmp_buf env_arg;
      int val_arg;
 {
@@ -86,3 +86,5 @@ __longjmp (env_arg, val_arg)
   /* Avoid `volatile function does return' warnings.  */
   for (;;);
 }
+
+strong_alias (____longjmp, __longjmp);
diff --git a/ports/sysdeps/mips/abort-instr.h b/ports/sysdeps/mips/abort-instr.h
index d7d8d50..7ccae57 100644
--- a/ports/sysdeps/mips/abort-instr.h
+++ b/ports/sysdeps/mips/abort-instr.h
@@ -1,2 +1,6 @@
 /* An instruction which should crash any program is a breakpoint.  */
-#define ABORT_INSTRUCTION asm ("break 255")
+#ifdef __mips16
+# define ABORT_INSTRUCTION asm ("break 63")
+#else
+# define ABORT_INSTRUCTION asm ("break 255")
+#endif
diff --git a/ports/sysdeps/mips/bits/atomic.h b/ports/sysdeps/mips/bits/atomic.h
index 566b3dd..bdc3ace 100644
--- a/ports/sysdeps/mips/bits/atomic.h
+++ b/ports/sysdeps/mips/bits/atomic.h
@@ -78,9 +78,12 @@ typedef uintmax_t uatomic_max_t;
 #define MIPS_SYNC_STR_1(X) MIPS_SYNC_STR_2(X)
 #define MIPS_SYNC_STR MIPS_SYNC_STR_1(MIPS_SYNC)
 
-#if __GNUC_PREREQ (4, 8)
+#if __GNUC_PREREQ (4, 8) || (defined __mips16 && __GNUC_PREREQ (4, 7))
 /* The __atomic_* builtins are available in GCC 4.7 and later, but MIPS
-   support for their efficient implementation was added only in GCC 4.8.  */
+   support for their efficient implementation was added only in GCC 4.8.
+   We still want to use them even with GCC 4.7 for MIPS16 code where we
+   have no assembly alternative available and want to avoid the __sync_*
+   if at all possible.  */
 
 /* Compare and exchange.
    For all "bool" routines, we return FALSE if exchange succesful.  */
@@ -200,7 +203,33 @@ typedef uintmax_t uatomic_max_t;
 # define atomic_exchange_and_add_rel(mem, value)			\
   __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,	\
 		       __ATOMIC_RELEASE)
-#else /* !__GNUC_PREREQ (4, 8) */
+
+#elif defined __mips16 /* !__GNUC_PREREQ (4, 7) */
+/* This implementation using __sync* builtins will be removed once glibc
+   requires GCC 4.7 or later to build.  */
+
+# define atomic_compare_and_exchange_val_acq(mem, newval, oldval)	\
+  __sync_val_compare_and_swap ((mem), (oldval), (newval))
+# define atomic_compare_and_exchange_bool_acq(mem, newval, oldval)	\
+  (!__sync_bool_compare_and_swap ((mem), (oldval), (newval)))
+
+# define atomic_exchange_acq(mem, newval)				\
+  __sync_lock_test_and_set ((mem), (newval))
+
+# define atomic_exchange_and_add(mem, val)				\
+  __sync_fetch_and_add ((mem), (val))
+
+# define atomic_bit_test_set(mem, bit)					\
+  ({ __typeof (bit) __bit = (bit);					\
+     (__sync_fetch_and_or ((mem), 1 << (__bit)) & (1 << (__bit))); })
+
+# define atomic_and(mem, mask) (void) __sync_fetch_and_and ((mem), (mask))
+# define atomic_and_val(mem, mask) __sync_fetch_and_and ((mem), (mask))
+
+# define atomic_or(mem, mask) (void) __sync_fetch_and_or ((mem), (mask))
+# define atomic_or_val(mem, mask) __sync_fetch_and_or ((mem), (mask))
+
+#else /* !__mips16 && !__GNUC_PREREQ (4, 8) */
 /* This implementation using inline assembly will be removed once glibc
    requires GCC 4.8 or later to build.  */
 
@@ -443,15 +472,21 @@ typedef uintmax_t uatomic_max_t;
 # define atomic_exchange_and_add_rel(mem, value)			\
   __atomic_val_bysize (__arch_exchange_and_add, int, mem, value,	\
 		       MIPS_SYNC_STR, "")
-#endif /* __GNUC_PREREQ (4, 8) */
+
+#endif /* !__mips16 && !__GNUC_PREREQ (4, 8) */
 
 /* TODO: More atomic operations could be implemented efficiently; only the
    basic requirements are done.  */
 
-#define atomic_full_barrier() \
+#ifdef __mips16
+# define atomic_full_barrier() __sync_synchronize ()
+
+#else /* !__mips16 */
+# define atomic_full_barrier() \
   __asm__ __volatile__ (".set push\n\t"					      \
 			MIPS_PUSH_MIPS2					      \
 			MIPS_SYNC_STR "\n\t"				      \
 			".set pop" : : : "memory")
+#endif /* !__mips16 */
 
 #endif /* bits/atomic.h */
diff --git a/ports/sysdeps/mips/bsd-_setjmp.S b/ports/sysdeps/mips/bsd-_setjmp.S
index 1974e4b..50cce7e 100644
--- a/ports/sysdeps/mips/bsd-_setjmp.S
+++ b/ports/sysdeps/mips/bsd-_setjmp.S
@@ -22,6 +22,8 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
+
 #ifdef __PIC__
 	.option pic2
 #endif
diff --git a/ports/sysdeps/mips/bsd-setjmp.S b/ports/sysdeps/mips/bsd-setjmp.S
index 5eedcdd..18e8b0f 100644
--- a/ports/sysdeps/mips/bsd-setjmp.S
+++ b/ports/sysdeps/mips/bsd-setjmp.S
@@ -22,6 +22,8 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
+
 #ifdef __PIC__
 	.option pic2
 #endif
diff --git a/ports/sysdeps/mips/dl-machine.h b/ports/sysdeps/mips/dl-machine.h
index 91f7a7b..a7c784f 100644
--- a/ports/sysdeps/mips/dl-machine.h
+++ b/ports/sysdeps/mips/dl-machine.h
@@ -119,6 +119,7 @@ static inline ElfW(Addr)
 elf_machine_load_address (void)
 {
   ElfW(Addr) addr;
+#ifndef __mips16
   asm ("	.set noreorder\n"
        "	" STRINGXP (PTR_LA) " %0, 0f\n"
        "	bltzal $0, 0f\n"
@@ -128,6 +129,19 @@ elf_machine_load_address (void)
        :	"=r" (addr)
        :	/* No inputs */
        :	"$31");
+#else
+  ElfW(Addr) tmp;
+  asm ("	.set noreorder\n"
+       "	move %1,$gp\n"
+       "	lw %1,%%got(0f)(%1)\n"
+       "0:	.fill 0\n"		/* Clear the ISA bit on 0:.  */
+       "	la %0,0b\n"
+       "	addiu %1,%%lo(0b)\n"
+       "	subu %0,%1\n"
+       "	.set reorder\n"
+       :	"=d" (addr), "=d" (tmp)
+       :	/* No inputs */);
+#endif
   return addr;
 }
 
@@ -210,7 +224,8 @@ do {									\
    2) That under Unix the entry is named __start
       and not just plain _start.  */
 
-#define RTLD_START asm (\
+#ifndef __mips16
+# define RTLD_START asm (\
 	".text\n\
 	" _RTLD_PROLOGUE(ENTRY_POINT) "\
 	" STRINGXV(SETUP_GPX($25)) "\n\
@@ -283,6 +298,91 @@ do {									\
 	".previous"\
 );
 
+#else /* __mips16 */
+/* MIPS16 version.  We currently only support O32 under MIPS16; the proper
+   assembly preprocessor abstractions will need to be added if other ABIs
+   are to be supported.  */
+
+# define RTLD_START asm (\
+	".text\n\
+	.set mips16\n\
+	" _RTLD_PROLOGUE (ENTRY_POINT) "\
+	# Construct GP value in $3.\n\
+	li $3, %hi(_gp_disp)\n\
+	addiu $4, $pc, %lo(_gp_disp)\n\
+	sll $3, 16\n\
+	addu $3, $4\n\
+	move $28, $3\n\
+	lw $4, %got(_DYNAMIC)($3)\n\
+	sw $4, -0x7ff0($3)\n\
+	move $4, $sp\n\
+	addiu $sp, -16\n\
+	# _dl_start() is sufficiently near to use pc-relative\n\
+	# load address.\n\
+	la $3, _dl_start\n\
+	move $25, $3\n\
+	jalr $3\n\
+	addiu $sp, 16\n\
+	" _RTLD_EPILOGUE (ENTRY_POINT) "\
+	\n\
+	\n\
+	" _RTLD_PROLOGUE (_dl_start_user) "\
+	li $16, %hi(_gp_disp)\n\
+	addiu $4, $pc, %lo(_gp_disp)\n\
+	sll $16, 16\n\
+	addu $16, $4\n\
+	move $17, $2\n\
+	move $28, $16\n\
+	lw $4, %got(_dl_skip_args)($16)\n\
+	lw $4, 0($4)\n\
+	beqz $4, 1f\n\
+	# Load the original argument count.\n\
+	lw $5, 0($sp)\n\
+	# Subtract _dl_skip_args from it.\n\
+	subu $5, $4\n\
+	# Adjust the stack pointer to skip _dl_skip_args words.\n\
+	sll $4, " STRINGXP (PTRLOG) "\n\
+	move $6, $sp\n\
+	addu $6, $4\n\
+	move $sp, $6\n\
+	# Save back the modified argument count.\n\
+	sw $5, 0($sp)\n\
+1:	# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env) \n\
+	lw $4, %got(_rtld_local)($16)\n\
+	lw $4, 0($4)\n\
+	lw $5, 0($sp)\n\
+	addiu $6, $sp, " STRINGXP (PTRSIZE) "\n\
+	sll $7, $5, " STRINGXP (PTRLOG) "\n\
+	addu $7, $6\n\
+	addu $7, " STRINGXP (PTRSIZE) "\n\
+	# Make sure the stack pointer is aligned for _dl_init_internal.\n\
+	li $2, 2 * " STRINGXP (SZREG) "\n\
+	neg $2, $2\n\
+	move $3, $sp\n\
+	and $2, $3\n\
+	sw $3, -" STRINGXP (SZREG) "($2)\n\
+	addiu $2, -32\n\
+	move $sp, $2\n\
+	sw $16, 16($sp)\n\
+	# Call the function to run the initializers.\n\
+	lw $2, %call16(_dl_init_internal)($16)\n\
+	move $25, $2\n\
+	jalr $2\n\
+	# Restore the stack pointer for _start.\n\
+	lw $2, 32-" STRINGXP (SZREG) "($sp)\n\
+	move $sp, $2\n\
+	move $28, $16\n\
+	# Pass our finalizer function to the user in $2 as per ELF ABI.\n\
+	lw $2, %call16(_dl_fini)($16)\n\
+	# Jump to the user entry point.\n\
+	move $25, $17\n\
+	jr $17\n\t"\
+	_RTLD_EPILOGUE (_dl_start_user)\
+	".previous"\
+);
+
+#endif /* __mips16 */
+
 /* Names of the architecture-specific auditing callback functions.  */
 # if _MIPS_SIM == _ABIO32
 #  define ARCH_LA_PLTENTER mips_o32_gnu_pltenter
diff --git a/ports/sysdeps/mips/dl-trampoline.c b/ports/sysdeps/mips/dl-trampoline.c
index 57fb05b..605e44e 100644
--- a/ports/sysdeps/mips/dl-trampoline.c
+++ b/ports/sysdeps/mips/dl-trampoline.c
@@ -292,9 +292,11 @@ __dl_runtime_resolve (ElfW(Word) sym_index,
 
 #endif
 
+#ifndef __mips16
 asm ("\n\
 	.text\n\
 	.align	2\n\
+	.set	nomips16\n\
 	.globl	_dl_runtime_resolve\n\
 	.type	_dl_runtime_resolve,@function\n\
 	.ent	_dl_runtime_resolve\n\
@@ -351,6 +353,7 @@ _dl_runtime_resolve:\n\
 asm ("\n\
 	.text\n\
 	.align	2\n\
+	.set	nomips16\n\
 	.globl	_dl_runtime_pltresolve\n\
 	.type	_dl_runtime_pltresolve,@function\n\
 	.ent	_dl_runtime_pltresolve\n\
@@ -381,3 +384,130 @@ _dl_runtime_pltresolve:\n\
 	.previous\n\
 ");
 
+#elif _MIPS_SIM == _ABIO32 /* __mips16 */
+/* MIPS16 version, O32 only.  */
+asm ("\n\
+	.text\n\
+	.align	2\n\
+	.set	mips16\n\
+	.globl	_dl_runtime_resolve\n\
+	.type	_dl_runtime_resolve,@function\n\
+	.ent	_dl_runtime_resolve\n\
+_dl_runtime_resolve:\n\
+	.frame	$29, " STRINGXP (ELF_DL_FRAME_SIZE) ", $31\n\
+	# Save arguments and sp value in stack.\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"save	" STRINGXP (ELF_DL_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"addiu	$sp, -" STRINGXP (ELF_DL_FRAME_SIZE) "\n\
+	sw	$7, 32($sp)\n\
+	sw	$6, 28($sp)\n\
+	sw	$5, 24($sp)\n\
+	sw	$4, 20($sp)\n\t"
+# endif
+	"# Preserve caller's $ra, for RESTORE instruction below.\n\
+	move	$5, $15\n\
+	sw	$5, 36($sp)\n\
+	# Compute GP into $2.\n\
+	li	$2, %hi(_gp_disp)\n\
+	addiu	$3, $pc, %lo(_gp_disp)\n\
+	sll	$2, 16\n\
+	addu	$2, $3\n\
+	lw	$3, %got(__dl_runtime_resolve)($2)\n\
+	move	$4, $24\n\
+	addiu	$3, %lo(__dl_runtime_resolve)\n\
+	move	$7, $ra\n\
+	move	$6, $28\n\
+	move	$25, $3\n\
+	jalr	$3\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"restore " STRINGXP(ELF_DL_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"# Restore $ra, move placed further down to hide latency.\n\
+	lw	$4, 36($sp)\n\
+	lw	$5, 24($sp)\n\
+	lw	$6, 28($sp)\n\
+	lw	$7, 32($sp)\n\
+	move	$ra, $4\n\
+	lw	$4, 20($sp)\n\
+	addiu	$sp, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\t"
+# endif
+	"move	$25, $2\n\
+	jr	$2\n\
+	.end	_dl_runtime_resolve\n\
+	.previous\n\
+");
+
+asm ("\n\
+	.text\n\
+	.align	2\n\
+	.set	mips16\n\
+	.globl	_dl_runtime_pltresolve\n\
+	.type	_dl_runtime_pltresolve,@function\n\
+	.ent	_dl_runtime_pltresolve\n\
+_dl_runtime_pltresolve:\n\
+	.frame	$29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $31\n\
+	# Save arguments and sp value in stack.\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"save	" STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"addiu	$sp, -" STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
+	sw	$7, 40($sp)\n\
+	sw	$6, 36($sp)\n\
+	sw	$5, 32($sp)\n\
+	sw	$4, 28($sp)\n\t"
+# endif
+	"# Preserve MIPS16 stub function arguments.\n\
+	sw	$3, 20($sp)\n\
+	sw	$2, 16($sp)\n\
+	# Preserve caller's $ra, for RESTORE instruction below.\n\
+	move	$3, $15\n\
+	sw	$3, 44($sp)\n\
+	# Compute GP into $2.\n\
+	li	$2, %hi(_gp_disp)\n\
+	addiu	$3, $pc, %lo(_gp_disp)\n\
+	sll	$2, 16\n\
+	addu	$2, $3\n\
+	# Save GP value in slot.\n\
+	sw	$2, 24($sp)\n\
+	# Load _dl_fixup address.\n\
+	lw	$6, %call16(_dl_fixup)($2)\n\
+	# Load link map address.\n\
+	move	$3, $28\n\
+	lw	$4, " STRINGXP (PTRSIZE) "($3)\n\
+	move	$5, $24\n\
+	sll	$5, " STRINGXP (PTRLOG) " + 1\n\
+	# Call _dl_fixup.\n\
+	move	$25, $6\n\
+	jalr	$6\n\
+	move	$25, $2\n\
+	# Reload GP value into $28.\n\
+	lw	$3, 24($sp)\n\
+	move	$28, $3\n\
+	lw	$3, 16($sp)\n\
+	move	$15, $3\n\
+	lw	$3, 20($sp)\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"restore " STRINGXP (ELF_DL_PLT_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"# Restore $ra, move placed further down to hide latency.\n\
+	lw	$4, 44($sp)\n\
+	lw	$5, 32($sp)\n\
+	lw	$6, 36($sp)\n\
+	lw	$7, 40($sp)\n\
+	move	$ra, $4\n\
+	lw	$4, 28($sp)\n\
+	addiu	$sp, " STRINGXP (ELF_DL_PLT_FRAME_SIZE) "\n\t"
+# endif
+	".set	noreorder\n\
+	jr	$2\n\
+	 move	$2, $15\n\
+	.set	reorder\n\
+	.end	_dl_runtime_pltresolve\n\
+	.previous\n\
+");
+
+#else /* __mips16 && _MIPS_SIM != _ABIO32 */
+# error "MIPS16 support for N32/N64 not implemented"
+
+#endif /* __mips16 */
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/mips/fpu/e_sqrt.c
index cff9cec..26314b0 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/mips/fpu/e_sqrt.c
@@ -22,7 +22,7 @@
 
 #if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
 
-double
+double __attribute__ ((nomips16))
 __ieee754_sqrt (double x)
 {
   double z;
diff --git a/ports/sysdeps/mips/fpu/e_sqrtf.c b/ports/sysdeps/mips/fpu/e_sqrtf.c
index 87d242d..0f7bfd9 100644
--- a/ports/sysdeps/mips/fpu/e_sqrtf.c
+++ b/ports/sysdeps/mips/fpu/e_sqrtf.c
@@ -22,7 +22,7 @@
 
 #if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
 
-float
+float __attribute__ ((nomips16))
 __ieee754_sqrtf (float x)
 {
   float z;
diff --git a/ports/sysdeps/mips/fpu_control.h b/ports/sysdeps/mips/fpu_control.h
index 30e54f9..6aecb3b 100644
--- a/ports/sysdeps/mips/fpu_control.h
+++ b/ports/sysdeps/mips/fpu_control.h
@@ -99,8 +99,15 @@ extern fpu_control_t __fpu_control;
 typedef unsigned int fpu_control_t __attribute__ ((__mode__ (__SI__)));
 
 /* Macros for accessing the hardware control word.  */
-#define _FPU_GETCW(cw) __asm__ volatile ("cfc1 %0,$31" : "=r" (cw))
-#define _FPU_SETCW(cw) __asm__ volatile ("ctc1 %0,$31" : : "r" (cw))
+extern fpu_control_t __mips_fpu_getcw (void) __THROW;
+extern void __mips_fpu_setcw (fpu_control_t) __THROW;
+#ifdef __mips16
+# define _FPU_GETCW(cw) do { (cw) = __mips_fpu_getcw (); } while (0)
+# define _FPU_SETCW(cw) __mips_fpu_setcw (cw)
+#else
+# define _FPU_GETCW(cw) __asm__ volatile ("cfc1 %0,$31" : "=r" (cw))
+# define _FPU_SETCW(cw) __asm__ volatile ("ctc1 %0,$31" : : "r" (cw))
+#endif
 
 /* Default control word set at startup.  */
 extern fpu_control_t __fpu_control;
diff --git a/ports/sysdeps/mips/machine-gmon.h b/ports/sysdeps/mips/machine-gmon.h
index 8c62d84..144c044 100644
--- a/ports/sysdeps/mips/machine-gmon.h
+++ b/ports/sysdeps/mips/machine-gmon.h
@@ -37,6 +37,8 @@ static void __attribute_used__ __mcount (u_long frompc, u_long selfpc)
 #define MCOUNT asm(\
 	".globl _mcount;\n\t" \
 	".align 2;\n\t" \
+	".set push;\n\t" \
+	".set nomips16;\n\t" \
 	".type _mcount,@function;\n\t" \
 	".ent _mcount\n\t" \
         "_mcount:\n\t" \
@@ -67,9 +69,8 @@ static void __attribute_used__ __mcount (u_long frompc, u_long selfpc)
         "addu $29,$29,56;\n\t" \
         "j $31;\n\t" \
         "move $31,$1;\n\t" \
-        ".set reorder;\n\t" \
-        ".set at\n\t" \
-        ".end _mcount");
+	".end _mcount;\n\t" \
+	".set pop");
 
 #else
 
@@ -94,6 +95,8 @@ static void __attribute_used__ __mcount (u_long frompc, u_long selfpc)
 #define MCOUNT asm(\
 	".globl _mcount;\n\t" \
 	".align 3;\n\t" \
+	".set push;\n\t" \
+	".set nomips16;\n\t" \
 	".type _mcount,@function;\n\t" \
 	".ent _mcount\n\t" \
         "_mcount:\n\t" \
@@ -132,8 +135,7 @@ static void __attribute_used__ __mcount (u_long frompc, u_long selfpc)
         PTR_ADDU_STRING " $29,$29,96;\n\t" \
         "j $31;\n\t" \
         "move $31,$1;\n\t" \
-        ".set reorder;\n\t" \
-        ".set at\n\t" \
-        ".end _mcount");
+	".end _mcount;\n\t" \
+	".set pop");
 
 #endif
diff --git a/ports/sysdeps/mips/memset.S b/ports/sysdeps/mips/memset.S
index 8c8606c..78dab48 100644
--- a/ports/sysdeps/mips/memset.S
+++ b/ports/sysdeps/mips/memset.S
@@ -18,6 +18,7 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
 
 /* void *memset(void *s, int c, size_t n).  */
 
diff --git a/ports/sysdeps/mips/mips32/crti.S b/ports/sysdeps/mips/mips32/crti.S
index 5b46279..5f3e9ba 100644
--- a/ports/sysdeps/mips/mips32/crti.S
+++ b/ports/sysdeps/mips/mips32/crti.S
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
diff --git a/ports/sysdeps/mips/mips32/crtn.S b/ports/sysdeps/mips/mips32/crtn.S
index 44cdff0..42381c5 100644
--- a/ports/sysdeps/mips/mips32/crtn.S
+++ b/ports/sysdeps/mips/mips32/crtn.S
@@ -36,6 +36,8 @@
 /* crtn.S puts function epilogues in the .init and .fini sections
    corresponding to the prologues in crti.S. */
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	lw $31,28($sp)
 	.set noreorder
diff --git a/ports/sysdeps/mips/mips32/fpu/Versions b/ports/sysdeps/mips/mips32/fpu/Versions
new file mode 100644
index 0000000..91bbf56
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/fpu/Versions
@@ -0,0 +1,5 @@
+libc {
+  GLIBC_2.18 {
+    __mips_fpu_getcw; __mips_fpu_setcw;
+  }
+}
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/mips/mips32/fpu/fpu_control.c
similarity index 60%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/mips/mips32/fpu/fpu_control.c
index cff9cec..cd107c5 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/mips/mips32/fpu/fpu_control.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* FPU control word handling, MIPS version, needed by MIPS16 callers.
+   Copyright (C) 1996-2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,22 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <math/fpu_control.c>
 
-#include <sgidefs.h>
-
+fpu_control_t
+__mips_fpu_getcw (void)
+{
+  fpu_control_t cw;
 
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
+  _FPU_GETCW (cw);
+  return cw;
+}
 
-double
-__ieee754_sqrt (double x)
+void
+__mips_fpu_setcw (fpu_control_t cw)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  _FPU_SETCW (cw);
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/mips32/mips16/add_n.c b/ports/sysdeps/mips/mips32/mips16/add_n.c
new file mode 100644
index 0000000..fbb4120
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/add_n.c
@@ -0,0 +1 @@
+#include <stdlib/add_n.c>
diff --git a/ports/sysdeps/mips/mips32/mips16/addmul_1.c b/ports/sysdeps/mips/mips32/mips16/addmul_1.c
new file mode 100644
index 0000000..c0e4a0b
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/addmul_1.c
@@ -0,0 +1 @@
+#include <stdlib/addmul_1.c>
diff --git a/ports/sysdeps/mips/mips32/mips16/fpu/Makefile b/ports/sysdeps/mips/mips32/mips16/fpu/Makefile
new file mode 100644
index 0000000..b58c4ee
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/fpu/Makefile
@@ -0,0 +1,5 @@
+# Building hard-float libm as MIPS16 actually produces larger code size,
+# so avoid doing so.
+ifeq ($(subdir),math)
+sysdep-CFLAGS += -mno-mips16
+endif
diff --git a/ports/sysdeps/mips/mips32/mips16/lshift.c b/ports/sysdeps/mips/mips32/mips16/lshift.c
new file mode 100644
index 0000000..2f945d2
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/lshift.c
@@ -0,0 +1 @@
+#include <stdlib/lshift.c>
diff --git a/ports/sysdeps/mips/mips32/mips16/mul_1.c b/ports/sysdeps/mips/mips32/mips16/mul_1.c
new file mode 100644
index 0000000..8e758d6
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/mul_1.c
@@ -0,0 +1 @@
+#include <stdlib/mul_1.c>
diff --git a/ports/sysdeps/mips/mips32/mips16/rshift.c b/ports/sysdeps/mips/mips32/mips16/rshift.c
new file mode 100644
index 0000000..4e350a0
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/rshift.c
@@ -0,0 +1 @@
+#include <stdlib/rshift.c>
diff --git a/ports/sysdeps/mips/mips32/mips16/sub_n.c b/ports/sysdeps/mips/mips32/mips16/sub_n.c
new file mode 100644
index 0000000..d8b5492
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/sub_n.c
@@ -0,0 +1 @@
+#include <stdlib/sub_n.c>
diff --git a/ports/sysdeps/mips/mips32/mips16/submul_1.c b/ports/sysdeps/mips/mips32/mips16/submul_1.c
new file mode 100644
index 0000000..44cadf5
--- /dev/null
+++ b/ports/sysdeps/mips/mips32/mips16/submul_1.c
@@ -0,0 +1 @@
+#include <stdlib/submul_1.c>
diff --git a/ports/sysdeps/mips/mips64/n32/crti.S b/ports/sysdeps/mips/mips64/n32/crti.S
index d9066b2..ddcc9cc 100644
--- a/ports/sysdeps/mips/mips64/n32/crti.S
+++ b/ports/sysdeps/mips/mips64/n32/crti.S
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
diff --git a/ports/sysdeps/mips/mips64/n32/crtn.S b/ports/sysdeps/mips/mips64/n32/crtn.S
index daf7d42..5eb2b4f 100644
--- a/ports/sysdeps/mips/mips64/n32/crtn.S
+++ b/ports/sysdeps/mips/mips64/n32/crtn.S
@@ -36,6 +36,8 @@
 /* crtn.S puts function epilogues in the .init and .fini sections
    corresponding to the prologues in crti.S. */
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	ld $31,8($sp)
 	ld $28,0($sp)
diff --git a/ports/sysdeps/mips/mips64/n64/crti.S b/ports/sysdeps/mips/mips64/n64/crti.S
index 2111ba5..0c66d0d 100644
--- a/ports/sysdeps/mips/mips64/n64/crti.S
+++ b/ports/sysdeps/mips/mips64/n64/crti.S
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
diff --git a/ports/sysdeps/mips/mips64/n64/crtn.S b/ports/sysdeps/mips/mips64/n64/crtn.S
index c66a2e5..4c014b7 100644
--- a/ports/sysdeps/mips/mips64/n64/crtn.S
+++ b/ports/sysdeps/mips/mips64/n64/crtn.S
@@ -36,6 +36,8 @@
 /* crtn.S puts function epilogues in the .init and .fini sections
    corresponding to the prologues in crti.S. */
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	ld $31,8($sp)
 	ld $28,0($sp)
diff --git a/ports/sysdeps/mips/nptl/tls.h b/ports/sysdeps/mips/nptl/tls.h
index 0c91995..2529408 100644
--- a/ports/sysdeps/mips/nptl/tls.h
+++ b/ports/sysdeps/mips/nptl/tls.h
@@ -37,12 +37,17 @@ typedef union dtv
   } pointer;
 } dtv_t;
 
+#ifdef __mips16
+/* MIPS16 uses GCC builtin to access the TP.  */
+# define READ_THREAD_POINTER() (__builtin_thread_pointer ())
+#else
 /* Note: rd must be $v1 to be ABI-conformant.  */
 # define READ_THREAD_POINTER() \
     ({ void *__result;							      \
        asm volatile (".set\tpush\n\t.set\tmips32r2\n\t"			      \
 		     "rdhwr\t%0, $29\n\t.set\tpop" : "=v" (__result));	      \
        __result; })
+#endif
 
 #else /* __ASSEMBLER__ */
 # include <tcb-offsets.h>
diff --git a/ports/sysdeps/mips/preconfigure b/ports/sysdeps/mips/preconfigure
index 9190eee..b215eb2 100644
--- a/ports/sysdeps/mips/preconfigure
+++ b/ports/sysdeps/mips/preconfigure
@@ -25,5 +25,10 @@ mips64*)	base_machine=mips64
 		  CPPFLAGS="$CPPFLAGS -mabi=$mips_config_abi"
 		fi
 		;;
-mips*)		base_machine=mips machine=mips/mips32/$machine ;;
+mips*)		base_machine=mips
+		case "$CC $CFLAGS $CPPFLAGS " in
+		*" -mips16 "*) machine=mips/mips32/mips16/$machine ;;
+		*) machine=mips/mips32/$machine ;;
+		esac
+		;;
 esac
diff --git a/ports/sysdeps/mips/setjmp.S b/ports/sysdeps/mips/setjmp.S
index 3f923fb..f014b73 100644
--- a/ports/sysdeps/mips/setjmp.S
+++ b/ports/sysdeps/mips/setjmp.S
@@ -17,6 +17,8 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
+
 /* The function __sigsetjmp_aux saves all the registers, but it can't
    reliably access the stack or frame pointers, so we pass them in as
    extra arguments.  */
diff --git a/ports/sysdeps/mips/setjmp_aux.c b/ports/sysdeps/mips/setjmp_aux.c
index a955a4f..cb9ea24 100644
--- a/ports/sysdeps/mips/setjmp_aux.c
+++ b/ports/sysdeps/mips/setjmp_aux.c
@@ -23,7 +23,7 @@
    pointer.  We do things this way because it's difficult to reliably
    access them in C.  */
 
-int
+int __attribute__ ((nomips16))
 __sigsetjmp_aux (jmp_buf env, int savemask, int sp, int fp)
 {
 #ifdef __mips_hard_float
diff --git a/ports/sysdeps/mips/start.S b/ports/sysdeps/mips/start.S
index 82b7a22..83a6895 100644
--- a/ports/sysdeps/mips/start.S
+++ b/ports/sysdeps/mips/start.S
@@ -74,14 +74,15 @@
 	.text
 	.globl ENTRY_POINT
 	.type ENTRY_POINT,@function
+#ifndef __mips16
 ENTRY_POINT:
-#ifdef __PIC__
+# ifdef __PIC__
 	SETUP_GPX($0)
 	SETUP_GPX64($25,$0)
-#else
+# else
 	PTR_LA $28, _gp		/* Setup GP correctly if we're non-PIC.  */
 	move $31, $0
-#endif
+# endif
 
 	PTR_LA $4, main		/* main */
 	PTR_L $5, 0($29)		/* argc */
@@ -92,22 +93,85 @@ ENTRY_POINT:
 	   on o32 and quad words (16 bytes) on n32 and n64.  */
 	
 	and $29, -2 * SZREG
-#if _MIPS_SIM == _ABIO32
+# if _MIPS_SIM == _ABIO32
 	PTR_SUBIU $29, 32
-#endif
+# endif
 	PTR_LA $7, __libc_csu_init		/* init */
 	PTR_LA $8, __libc_csu_fini
-#if _MIPS_SIM == _ABIO32
+# if _MIPS_SIM == _ABIO32
 	PTR_S $8, 16($29)		/* fini */
 	PTR_S $2, 20($29)		/* rtld_fini */
 	PTR_S $29, 24($29)		/* stack_end */
-#else
+# else
 	move $9, $2		/* rtld_fini */
 	move $10, $29		/* stack_end */
-#endif
+# endif
 	jal __libc_start_main
 hlt:	b hlt			/* Crash if somehow it does return.  */
 
+#elif _MIPS_SIM == _ABIO32 /* __mips16 */
+	/* MIPS16 entry point.  */
+	.set	mips16
+ENTRY_POINT:
+# ifdef __PIC__
+	li	$3, %hi(_gp_disp)
+	addiu	$4, $pc, %lo(_gp_disp)
+	sll	$3, 16
+	addu	$3, $4
+	move	$gp, $3
+# else
+	li	$3, %hi(_gp)
+	sll	$3, 16
+	addiu	$3, %lo(_gp)
+	move	$gp, $3
+# endif
+	/* Tie end of stack frames.  */
+	li	$4, 0
+	move	$31, $4
+	/* Create new SP value in $7, including alignment.  */
+	li	$4, 2 * SZREG
+	neg	$4, $4
+	move	$7, $sp
+	and	$7, $4
+	addiu	$7, -32
+	/* Load arguments with original SP.  */
+	lw	$5, 0($sp)
+	addiu	$6, $sp, PTRSIZE
+	/* Update SP.  */
+	move	$sp, $7
+	/* Lay out last arguments, and call __libc_start_main().  */
+# ifdef __PIC__
+	sw	$7, 24($sp)			/* stack_end */
+	lw	$4, %got(__libc_csu_fini)($3)
+	lw	$7, %got(__libc_csu_init)($3)	/* init */
+	sw	$4, 16($sp)			/* fini */
+	lw	$4, %got(main)($3)		/* main */
+	lw	$3, %call16(__libc_start_main)($3)
+	sw	$2, 20($sp)			/* rtld_fini */
+	move	$25, $3
+	jalr	$3
+# else
+	lw	$4, 1f
+	sw	$7, 24($sp)			/* stack_end */
+	lw	$7, 2f				/* init */
+	sw	$4, 16($sp)			/* fini */
+	lw	$4, 3f				/* main */
+	sw	$2, 20($sp)			/* rtld_fini */
+	jal	__libc_start_main
+# endif
+hlt:	b	hlt		/* Crash if somehow it does return.  */
+# ifndef __PIC__
+	.align	2
+1:	.word	__libc_csu_fini
+2:	.word	__libc_csu_init
+3:	.word	main
+# endif
+
+#else /* __mips16 && _MIPS_SIM != _ABIO32 */
+# error "MIPS16 support for N32/N64 not implemented"
+
+#endif /* __mips16 */
+
 /* Define a symbol for the first piece of initialized data.  */
 	.data
 	.globl __data_start
diff --git a/ports/sysdeps/mips/sys/tas.h b/ports/sysdeps/mips/sys/tas.h
index 603346a..8718185 100644
--- a/ports/sysdeps/mips/sys/tas.h
+++ b/ports/sysdeps/mips/sys/tas.h
@@ -24,7 +24,8 @@
 
 __BEGIN_DECLS
 
-extern int _test_and_set (int *__p, int __v) __THROW;
+extern int _test_and_set (int *__p, int __v)
+     __THROW __attribute__ ((__nomips16__));
 
 #ifdef __USE_EXTERN_INLINES
 
@@ -32,7 +33,7 @@ extern int _test_and_set (int *__p, int __v) __THROW;
 #  define _EXTERN_INLINE __extern_inline
 # endif
 
-_EXTERN_INLINE int
+_EXTERN_INLINE int __attribute__ ((__nomips16__))
 __NTH (_test_and_set (int *__p, int __v))
 {
   int __r, __t;
diff --git a/ports/sysdeps/mips/tls-macros.h b/ports/sysdeps/mips/tls-macros.h
index 8fe2e4a..3e87e42 100644
--- a/ports/sysdeps/mips/tls-macros.h
+++ b/ports/sysdeps/mips/tls-macros.h
@@ -12,16 +12,33 @@
    (abicalls pic0) function.  */
 #ifndef __PIC__
 # if _MIPS_SIM != _ABI64
-#  define LOAD_GP "move %[tmp], $28\n\tla $28, __gnu_local_gp\n\t"
+#  ifndef __mips16
+#   define LOAD_GP "move %[tmp], $28\n\tla $28, __gnu_local_gp\n\t"
+#  else
+#   define LOAD_GP					\
+           "li %[tmp], %%hi(__gnu_local_gp)\n\t"	\
+           "sll %[tmp], 16\n\t"				\
+           "addiu %[tmp], %%lo(__gnu_local_gp)\n\t"
+#  endif
 # else
 #  define LOAD_GP "move %[tmp], $28\n\tdla $28, __gnu_local_gp\n\t"
 # endif
 # define UNLOAD_GP "\n\tmove $28, %[tmp]"
 #else
-# define LOAD_GP
+/* MIPS16 (re)creates the GP value using PC-relative instructions.  */
+# ifdef __mips16
+#  define LOAD_GP					\
+           "li %[tmp], %%hi(_gp_disp)\n\t"		\
+           "addiu %0, $pc, %%lo(_gp_disp)\n\t"		\
+           "sll %[tmp], 16\n\t"				\
+           "addu %[tmp], %0\n\t"
+# else
+#  define LOAD_GP
+# endif
 # define UNLOAD_GP
 #endif
 
+#ifndef __mips16
 # define TLS_GD(x)					\
   ({ void *__result, *__tmp;				\
      extern void *__tls_get_addr (void *);		\
@@ -62,3 +79,45 @@
 	  ADDU " %0,%0,$3"				\
 	  : "+r" (__result) : : "$3");			\
      __result; })
+
+#else /* __mips16 */
+/* MIPS16 version.  */
+# define TLS_GD(x)					\
+  ({ void *__result, *__tmp;				\
+     extern void *__tls_get_addr (void *);		\
+     asm (LOAD_GP ADDIU " %1, %%tlsgd(" #x ")"		\
+	  "\n\tmove %0, %1"				\
+	  : "=d" (__result), [tmp] "=&d" (__tmp));	\
+     (int *) __tls_get_addr (__result); })
+# define TLS_LD(x)					\
+  ({ void *__result, *__tmp;				\
+     extern void *__tls_get_addr (void *);		\
+     asm (LOAD_GP ADDIU " %1, %%tlsldm(" #x ")"		\
+	  "\n\tmove %0, %1"				\
+	  : "=d" (__result), [tmp] "=&d" (__tmp));	\
+     __result = __tls_get_addr (__result);		\
+     asm ("li $3,%%dtprel_hi(" #x ")\n\t"		\
+	  "sll $3,16\n\t"				\
+	  "addiu $3,%%dtprel_lo(" #x ")\n\t"		\
+	  ADDU " %0,%0,$3"				\
+	  : "+d" (__result) : : "$3");			\
+     __result; })
+# define TLS_IE(x)					\
+  ({ void *__result, *__tmp, *__tp;			\
+     __tp = __builtin_thread_pointer ();		\
+     asm (LOAD_GP LW " $3,%%gottprel(" #x ")(%1)\n\t"	\
+	  ADDU " %0,%[tp],$3"				\
+	  : "=&d" (__result), [tmp] "=&d" (__tmp)	\
+	  : [tp] "d" (__tp) : "$3");			\
+     __result; })
+# define TLS_LE(x)					\
+  ({ void *__result, *__tp;				\
+     __tp = __builtin_thread_pointer ();		\
+     asm ("li $3,%%tprel_hi(" #x ")\n\t"		\
+	  "sll $3,16\n\t"				\
+	  "addiu $3,%%tprel_lo(" #x ")\n\t"		\
+	  ADDU " %0,%[tp],$3"				\
+	  : "=d" (__result) : [tp] "d" (__tp) : "$3");	\
+     __result; })
+
+#endif /* __mips16 */
diff --git a/ports/sysdeps/unix/mips/mips32/sysdep.h b/ports/sysdeps/unix/mips/mips32/sysdep.h
index 5c5d769..5d96d05 100644
--- a/ports/sysdeps/unix/mips/mips32/sysdep.h
+++ b/ports/sysdeps/unix/mips/mips32/sysdep.h
@@ -24,6 +24,7 @@
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99: la t9,__syscall_error;						      \
   jr t9;								      \
@@ -39,6 +40,7 @@ L(syse1):
 #else
 #define PSEUDO(name, syscall_name, args) \
   .set noreorder;							      \
+  .set nomips16;							      \
   .align 2;								      \
   cfi_startproc;							      \
   99: j __syscall_error;						      \
diff --git a/ports/sysdeps/unix/mips/mips64/n32/sysdep.h b/ports/sysdeps/unix/mips/mips64/n32/sysdep.h
index 49ae769..c55b95c 100644
--- a/ports/sysdeps/unix/mips/mips64/n32/sysdep.h
+++ b/ports/sysdeps/unix/mips/mips64/n32/sysdep.h
@@ -26,6 +26,7 @@
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99:;									      \
   .set noat;								      \
@@ -46,6 +47,7 @@ L(syse1):
 #define PSEUDO(name, syscall_name, args) \
   .set noreorder;							      \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99: j __syscall_error;						      \
   nop;                                                                        \
diff --git a/ports/sysdeps/unix/mips/mips64/n64/sysdep.h b/ports/sysdeps/unix/mips/mips64/n64/sysdep.h
index 2670c68..445e6ff 100644
--- a/ports/sysdeps/unix/mips/mips64/n64/sysdep.h
+++ b/ports/sysdeps/unix/mips/mips64/n64/sysdep.h
@@ -26,6 +26,7 @@
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99:;									      \
   .set noat;								      \
@@ -46,6 +47,7 @@ L(syse1):
 #define PSEUDO(name, syscall_name, args) \
   .set noreorder;							      \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99: j __syscall_error;						      \
   nop;                                                                        \
diff --git a/ports/sysdeps/unix/mips/sysdep.S b/ports/sysdeps/unix/mips/sysdep.S
index e778918..e27aada 100644
--- a/ports/sysdeps/unix/mips/sysdep.S
+++ b/ports/sysdeps/unix/mips/sysdep.S
@@ -21,6 +21,8 @@
 #include <bits/errno.h>
 #include <sys/asm.h>
 
+	.set	nomips16
+
 #ifdef _LIBC_REENTRANT
 
 LOCALSZ= 3
diff --git a/ports/sysdeps/unix/mips/sysdep.h b/ports/sysdeps/unix/mips/sysdep.h
index ef5c089..4d7667e 100644
--- a/ports/sysdeps/unix/mips/sysdep.h
+++ b/ports/sysdeps/unix/mips/sysdep.h
@@ -44,6 +44,7 @@
 #define PSEUDO_NOERRNO(name, syscall_name, args)	\
   .align 2;						\
   ENTRY(name)						\
+  .set nomips16;					\
   .set noreorder;					\
   li v0, SYS_ify(syscall_name);				\
   syscall
@@ -56,6 +57,7 @@
 #define PSEUDO_ERRVAL(name, syscall_name, args)	\
   .align 2;						\
   ENTRY(name)						\
+  .set nomips16;					\
   .set noreorder;					\
   li v0, SYS_ify(syscall_name);				\
   syscall
diff --git a/ports/sysdeps/unix/sysv/linux/mips/brk.c b/ports/sysdeps/unix/sysv/linux/mips/brk.c
index 9bd6d94..07c8a96 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/brk.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/brk.c
@@ -30,19 +30,10 @@ weak_alias (__curbrk, ___brk_addr)
 int
 __brk (void *addr)
 {
+  INTERNAL_SYSCALL_DECL (err);
   void *newbrk;
 
-  {
-    register long int res __asm__ ("$2");
-
-    asm ("move\t$4,%2\n\t"
-	 "li\t%0,%1\n\t"
-	 "syscall"		/* Perform the system call.  */
-	 : "=r" (res)
-	 : "I" (SYS_ify (brk)), "r" (addr)
-	 : "$4", "$7", __SYSCALL_CLOBBERS);
-    newbrk = (void *) res;
-  }
+  newbrk = (void *) INTERNAL_SYSCALL (brk, err, 1, addr);
   __curbrk = newbrk;
 
   if (newbrk < addr)
diff --git a/ports/sysdeps/unix/sysv/linux/mips/clone.S b/ports/sysdeps/unix/sysv/linux/mips/clone.S
index ef80188..f6f2f05 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/clone.S
+++ b/ports/sysdeps/unix/sysv/linux/mips/clone.S
@@ -34,6 +34,7 @@
 	     void *parent_tidptr, void *tls, void *child_tidptr) */
 
 	.text
+	.set		nomips16
 #if _MIPS_SIM == _ABIO32
 # define EXTRA_LOCALS 1
 #else
diff --git a/ports/sysdeps/unix/sysv/linux/mips/getcontext.S b/ports/sysdeps/unix/sysv/linux/mips/getcontext.S
index 7af6825..268098c 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/getcontext.S
+++ b/ports/sysdeps/unix/sysv/linux/mips/getcontext.S
@@ -27,6 +27,7 @@
 /* int getcontext (ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 MASK = 0x00000000
 #ifdef __PIC__
diff --git a/ports/sysdeps/unix/sysv/linux/mips/makecontext.S b/ports/sysdeps/unix/sysv/linux/mips/makecontext.S
index d89db01..a8bbebb 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/makecontext.S
+++ b/ports/sysdeps/unix/sysv/linux/mips/makecontext.S
@@ -27,6 +27,7 @@
 /* int makecontext (ucontext_t *ucp, (void *func) (), int argc, ...) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile
new file mode 100644
index 0000000..fa9fcb7
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile
@@ -0,0 +1,13 @@
+ifeq ($(subdir),misc)
+sysdep_routines += mips16-syscall0 mips16-syscall1 mips16-syscall2
+sysdep_routines += mips16-syscall3 mips16-syscall4 mips16-syscall5
+sysdep_routines += mips16-syscall6 mips16-syscall7
+CFLAGS-mips16-syscall0.c += -fexceptions
+CFLAGS-mips16-syscall1.c += -fexceptions
+CFLAGS-mips16-syscall2.c += -fexceptions
+CFLAGS-mips16-syscall3.c += -fexceptions
+CFLAGS-mips16-syscall4.c += -fexceptions
+CFLAGS-mips16-syscall5.c += -fexceptions
+CFLAGS-mips16-syscall6.c += -fexceptions
+CFLAGS-mips16-syscall7.c += -fexceptions
+endif
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions
new file mode 100644
index 0000000..73bcfb5
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions
@@ -0,0 +1,6 @@
+libc {
+  GLIBC_PRIVATE {
+    __mips16_syscall0; __mips16_syscall1; __mips16_syscall2; __mips16_syscall3;
+    __mips16_syscall4; __mips16_syscall5; __mips16_syscall6; __mips16_syscall7;
+  }
+}
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h
new file mode 100644
index 0000000..8449836
--- /dev/null
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h
@@ -0,0 +1,89 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef MIPS16_SYSCALL_H
+#define MIPS16_SYSCALL_H 1
+
+#define __nomips16 __attribute__ ((nomips16))
+
+union __mips16_syscall_return
+  {
+    long long val;
+    struct
+      {
+	long v0;
+	long v1;
+      }
+    reg;
+  };
+
+long long __nomips16 __mips16_syscall0 (long number);
+#define __mips16_syscall0(dummy, number)				\
+	__mips16_syscall0 ((long) (number))
+
+long long __nomips16 __mips16_syscall1 (long a0,
+					long number);
+#define __mips16_syscall1(a0, number)					\
+	__mips16_syscall1 ((long) (a0),					\
+			   (long) (number))
+
+long long __nomips16 __mips16_syscall2 (long a0, long a1,
+					long number);
+#define __mips16_syscall2(a0, a1, number)				\
+	__mips16_syscall2 ((long) (a0), (long) (a1),			\
+			   (long) (number))
+
+long long __nomips16 __mips16_syscall3 (long a0, long a1, long a2,
+					long number);
+#define __mips16_syscall3(a0, a1, a2, number)				\
+	__mips16_syscall3 ((long) (a0), (long) (a1), (long) (a2),	\
+			   (long) (number))
+
+long long __nomips16 __mips16_syscall4 (long a0, long a1, long a2, long a3,
+					long number);
+#define __mips16_syscall4(a0, a1, a2, a3, number)			\
+	__mips16_syscall4 ((long) (a0), (long) (a1), (long) (a2),	\
+			   (long) (a3),					\
+			   (long) (number))
+
+long long __nomips16 __mips16_syscall5 (long a0, long a1, long a2, long a3,
+					long a4,
+					long number);
+#define __mips16_syscall5(a0, a1, a2, a3, a4, number)			\
+	__mips16_syscall5 ((long) (a0), (long) (a1), (long) (a2),	\
+			   (long) (a3), (long) (a4),			\
+			   (long) (number))
+
+long long __nomips16 __mips16_syscall6 (long a0, long a1, long a2, long a3,
+					long a4, long a5,
+					long number);
+#define __mips16_syscall6(a0, a1, a2, a3, a4, a5, number)		\
+	__mips16_syscall6 ((long) (a0), (long) (a1), (long) (a2),	\
+			   (long) (a3), (long) (a4), (long) (a5),	\
+			   (long) (number))
+
+long long __nomips16 __mips16_syscall7 (long a0, long a1, long a2, long a3,
+					long a4, long a5, long a6,
+					long number);
+#define __mips16_syscall7(a0, a1, a2, a3, a4, a5, a6, number)		\
+	__mips16_syscall7 ((long) (a0), (long) (a1), (long) (a2),	\
+			   (long) (a3), (long) (a4), (long) (a5),	\
+			   (long) (a6),					\
+			   (long) (number))
+
+#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
similarity index 60%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
index cff9cec..0cdf94c 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,18 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall0
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall0 (long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 0);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
similarity index 60%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
index cff9cec..5e60a59 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,20 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall1
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall1 (long a0,
+		   long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 1,
+					a0);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
similarity index 60%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
index cff9cec..7750c51 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,20 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall2
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall2 (long a0, long a1,
+		   long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 2,
+					a0, a1);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
similarity index 60%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
index cff9cec..7fc1c4e 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,20 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall3
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall3 (long a0, long a1, long a2,
+		   long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 3,
+					a0, a1, a2);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
similarity index 60%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
index cff9cec..b8b4198 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,20 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall4
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall4 (long a0, long a1, long a2, long a3,
+		   long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 4,
+					a0, a1, a2, a3);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
similarity index 59%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
index cff9cec..e1322d1 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,21 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall5
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall5 (long a0, long a1, long a2, long a3,
+		   long a4,
+		   long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 5,
+					a0, a1, a2, a3, a4);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
similarity index 59%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
index cff9cec..a9e5cd9 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,21 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall6
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall6 (long a0, long a1, long a2, long a3,
+		   long a4, long a5,
+		   long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 6,
+					a0, a1, a2, a3, a4, a5);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/mips/fpu/e_sqrt.c b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c
similarity index 58%
copy from ports/sysdeps/mips/fpu/e_sqrt.c
copy to ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c
index cff9cec..d87b5ba 100644
--- a/ports/sysdeps/mips/fpu/e_sqrt.c
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c
@@ -1,6 +1,6 @@
-/* Copyright (C) 2002-2013 Free Software Foundation, Inc.
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
-   Contributed by Hartvig Ekner <hartvige@mips.com>, 2002.
 
    The GNU C Library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
@@ -13,26 +13,21 @@
    Lesser General Public License for more details.
 
    You should have received a copy of the GNU Lesser General Public
-   License along with the GNU C Library.  If not, see
+   License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
+#include <sysdep.h>
+#include <mips16-syscall.h>
 
-#include <sgidefs.h>
+#undef __mips16_syscall7
 
-
-#if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
-
-double
-__ieee754_sqrt (double x)
+long long __nomips16
+__mips16_syscall7 (long a0, long a1, long a2, long a3,
+		   long a4, long a5, long a6,
+		   long number)
 {
-  double z;
-  __asm__ ("sqrt.d %0,%1" : "=f" (z) : "f" (x));
-  return z;
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 7,
+					a0, a1, a2, a3, a4, a5, a6);
+  return ret.val;
 }
-strong_alias (__ieee754_sqrt, __sqrt_finite)
-
-#else
-
-#include <sysdeps/ieee754/dbl-64/e_sqrt.c>
-
-#endif
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist b/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
index 2c2cd54..f01278e 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
@@ -1401,6 +1401,8 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+ __mips_fpu_getcw F
+ __mips_fpu_setcw F
 GLIBC_2.2
  GLIBC_2.2 A
  _Exit F
diff --git a/ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h b/ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
index c8bfe5d..0faf68c 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
+++ b/ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
@@ -95,17 +95,46 @@
 #endif
 
 #undef INTERNAL_SYSCALL
-#define INTERNAL_SYSCALL(name, err, nr, args...)			\
+#undef INTERNAL_SYSCALL_NCS
+
+#ifdef __mips16
+/* There's no MIPS16 syscall instruction, so we go through out-of-line
+   standard MIPS wrappers.  These do use inline snippets below though,
+   through INTERNAL_SYSCALL_MIPS16.  Spilling the syscall number to
+   memory gives the best code in that case, avoiding the need to save
+   and restore a static register.  */
+
+# include <mips16-syscall.h>
+
+# define INTERNAL_SYSCALL(name, err, nr, args...)			\
+	INTERNAL_SYSCALL_NCS (SYS_ify (name), err, nr, args)
+
+# define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
+({									\
+	union __mips16_syscall_return ret;				\
+	ret.val = __mips16_syscall##nr (args, number);			\
+	err = ret.reg.v1;						\
+	ret.reg.v0;							\
+})
+
+# define INTERNAL_SYSCALL_MIPS16(number, err, nr, args...)		\
+	internal_syscall##nr ("lw\t%0, %2\n\t",				\
+			      "R" (number),				\
+			      0, err, args)
+
+#else /* !__mips16 */
+# define INTERNAL_SYSCALL(name, err, nr, args...)			\
 	internal_syscall##nr ("li\t%0, %2\t\t\t# " #name "\n\t",	\
 			      "IK" (SYS_ify (name)),			\
 			      0, err, args)
 
-#undef INTERNAL_SYSCALL_NCS
-#define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
+# define INTERNAL_SYSCALL_NCS(number, err, nr, args...)			\
 	internal_syscall##nr (MOVE32 "\t%0, %2\n\t",			\
 			      "r" (__s0),				\
 			      number, err, args)
 
+#endif /* !__mips16 */
+
 #define internal_syscall0(v0_init, input, number, err, dummy...)	\
 ({									\
 	long _sys_result;						\
diff --git a/ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h b/ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h
index 1e0bfed..3b0eccc 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h
+++ b/ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h
@@ -39,6 +39,7 @@
 # undef PSEUDO
 # define PSEUDO(name, syscall_name, args)				      \
       .align 2;								      \
+      .set nomips16;							      \
   L(pseudo_start):							      \
       cfi_startproc;							      \
   99: PSEUDO_ERRJMP							      \
diff --git a/ports/sysdeps/unix/sysv/linux/mips/setcontext.S b/ports/sysdeps/unix/sysv/linux/mips/setcontext.S
index 6ed355c..2d5aee0 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/setcontext.S
+++ b/ports/sysdeps/unix/sysv/linux/mips/setcontext.S
@@ -27,6 +27,7 @@
 /* int setcontext (const ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
diff --git a/ports/sysdeps/unix/sysv/linux/mips/swapcontext.S b/ports/sysdeps/unix/sysv/linux/mips/swapcontext.S
index ddd3b28..ec271b0 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/swapcontext.S
+++ b/ports/sysdeps/unix/sysv/linux/mips/swapcontext.S
@@ -27,6 +27,7 @@
 /* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
diff --git a/ports/sysdeps/unix/sysv/linux/mips/vfork.S b/ports/sysdeps/unix/sysv/linux/mips/vfork.S
index d627923..ae76a91 100644
--- a/ports/sysdeps/unix/sysv/linux/mips/vfork.S
+++ b/ports/sysdeps/unix/sysv/linux/mips/vfork.S
@@ -34,6 +34,7 @@
 /* int vfork() */
 
 	.text
+	.set		nomips16
 LOCALSZ= 1
 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
 GPOFF= FRAMESZ-(1*SZREG)

-----------------------------------------------------------------------

Summary of changes:
 ports/ChangeLog.mips                               |  106 ++++++++++++++++
 ports/sysdeps/mips/__longjmp.c                     |    6 +-
 ports/sysdeps/mips/abort-instr.h                   |    6 +-
 ports/sysdeps/mips/bits/atomic.h                   |   45 ++++++-
 ports/sysdeps/mips/bsd-_setjmp.S                   |    2 +
 ports/sysdeps/mips/bsd-setjmp.S                    |    2 +
 ports/sysdeps/mips/dl-machine.h                    |  102 +++++++++++++++-
 ports/sysdeps/mips/dl-trampoline.c                 |  130 ++++++++++++++++++++
 ports/sysdeps/mips/fpu/e_sqrt.c                    |    2 +-
 ports/sysdeps/mips/fpu/e_sqrtf.c                   |    2 +-
 ports/sysdeps/mips/fpu_control.h                   |   11 ++-
 ports/sysdeps/mips/machine-gmon.h                  |   14 ++-
 ports/sysdeps/mips/memset.S                        |    1 +
 ports/sysdeps/mips/mips32/crti.S                   |    2 +
 ports/sysdeps/mips/mips32/crtn.S                   |    2 +
 ports/sysdeps/mips/mips32/fpu/Versions             |    5 +
 ports/sysdeps/mips/mips32/fpu/fpu_control.c        |   34 +++++
 ports/sysdeps/mips/mips32/mips16/add_n.c           |    1 +
 ports/sysdeps/mips/mips32/mips16/addmul_1.c        |    1 +
 ports/sysdeps/mips/mips32/mips16/fpu/Makefile      |    5 +
 ports/sysdeps/mips/mips32/mips16/lshift.c          |    1 +
 ports/sysdeps/mips/mips32/mips16/mul_1.c           |    1 +
 ports/sysdeps/mips/mips32/mips16/rshift.c          |    1 +
 ports/sysdeps/mips/mips32/mips16/sub_n.c           |    1 +
 ports/sysdeps/mips/mips32/mips16/submul_1.c        |    1 +
 ports/sysdeps/mips/mips64/n32/crti.S               |    2 +
 ports/sysdeps/mips/mips64/n32/crtn.S               |    2 +
 ports/sysdeps/mips/mips64/n64/crti.S               |    2 +
 ports/sysdeps/mips/mips64/n64/crtn.S               |    2 +
 ports/sysdeps/mips/nptl/tls.h                      |    5 +
 ports/sysdeps/mips/preconfigure                    |    7 +-
 ports/sysdeps/mips/setjmp.S                        |    2 +
 ports/sysdeps/mips/setjmp_aux.c                    |    2 +-
 ports/sysdeps/mips/start.S                         |   80 +++++++++++--
 ports/sysdeps/mips/sys/tas.h                       |    5 +-
 ports/sysdeps/mips/tls-macros.h                    |   63 +++++++++-
 ports/sysdeps/unix/mips/mips32/sysdep.h            |    2 +
 ports/sysdeps/unix/mips/mips64/n32/sysdep.h        |    2 +
 ports/sysdeps/unix/mips/mips64/n64/sysdep.h        |    2 +
 ports/sysdeps/unix/mips/sysdep.S                   |    2 +
 ports/sysdeps/unix/mips/sysdep.h                   |    2 +
 ports/sysdeps/unix/sysv/linux/mips/brk.c           |   13 +--
 ports/sysdeps/unix/sysv/linux/mips/clone.S         |    1 +
 ports/sysdeps/unix/sysv/linux/mips/getcontext.S    |    1 +
 ports/sysdeps/unix/sysv/linux/mips/makecontext.S   |    1 +
 .../unix/sysv/linux/mips/mips32/mips16/Makefile    |   13 ++
 .../unix/sysv/linux/mips/mips32/mips16/Versions    |    6 +
 .../sysv/linux/mips/mips32/mips16/mips16-syscall.h |   89 +++++++++++++
 .../linux/mips/mips32/mips16/mips16-syscall0.c     |   30 +++++
 .../linux/mips/mips32/mips16/mips16-syscall1.c     |   32 +++++
 .../linux/mips/mips32/mips16/mips16-syscall2.c     |   32 +++++
 .../linux/mips/mips32/mips16/mips16-syscall3.c     |   32 +++++
 .../linux/mips/mips32/mips16/mips16-syscall4.c     |   32 +++++
 .../linux/mips/mips32/mips16/mips16-syscall5.c     |   33 +++++
 .../linux/mips/mips32/mips16/mips16-syscall6.c     |   33 +++++
 .../linux/mips/mips32/mips16/mips16-syscall7.c     |   33 +++++
 .../unix/sysv/linux/mips/mips32/nptl/libc.abilist  |    2 +
 ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h |   35 +++++-
 .../unix/sysv/linux/mips/nptl/sysdep-cancel.h      |    1 +
 ports/sysdeps/unix/sysv/linux/mips/setcontext.S    |    1 +
 ports/sysdeps/unix/sysv/linux/mips/swapcontext.S   |    1 +
 ports/sysdeps/unix/sysv/linux/mips/vfork.S         |    1 +
 62 files changed, 1041 insertions(+), 47 deletions(-)
 create mode 100644 ports/sysdeps/mips/mips32/fpu/Versions
 create mode 100644 ports/sysdeps/mips/mips32/fpu/fpu_control.c
 create mode 100644 ports/sysdeps/mips/mips32/mips16/add_n.c
 create mode 100644 ports/sysdeps/mips/mips32/mips16/addmul_1.c
 create mode 100644 ports/sysdeps/mips/mips32/mips16/fpu/Makefile
 create mode 100644 ports/sysdeps/mips/mips32/mips16/lshift.c
 create mode 100644 ports/sysdeps/mips/mips32/mips16/mul_1.c
 create mode 100644 ports/sysdeps/mips/mips32/mips16/rshift.c
 create mode 100644 ports/sysdeps/mips/mips32/mips16/sub_n.c
 create mode 100644 ports/sysdeps/mips/mips32/mips16/submul_1.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
 create mode 100644 ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]