This is the mail archive of the libc-ports@sources.redhat.com mailing list for the libc-ports 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]

[PATCH v2] MIPS: MIPS16 support


Joseph,

 Here's an updated version of the change to add MIPS16 support to GNU 
libc.  I hope I have addressed all your concerns to your satisfaction.  

 MIPS16 CRT files have now been dropped and likewise the GCC change I used 
for MIPS16 support there and I have bootstrapped the whole toolchain to 
make sure the new arrangement still works as expected.

 Also GLIBC_2.18 has been defined meanwhile, so I dropped the Versions.def 
change, and consequently the patch does not require any attention at the 
libc-alpha list anymore.

 Like the original the update was regression-tested successfully for the 
following configurations (compiler flag/multilib options), for both 
endiannesses each (the -EB and -EL compiler option, respectively):

* standard MIPS ISA, o32 (-mabi=32),

* standard MIPS ISA, n64 (-mabi=64),

* standard MIPS ISA, n32 (-mabi=n32),

* standard MIPS ISA, o32, soft-float (-mabi=32 -msoft-float),

* standard MIPS ISA, n64, soft-float (-mabi=64 -msoft-float),

* standard MIPS ISA, n32, soft-float (-mabi=n32 -msoft-float),

* microMIPS ISA, o32 (-mmicromips -mabi=32),

* microMIPS ISA, o32, soft-float (-mmicromips -mabi=32 -msoft-float),

with the MIPS32r2 or MIPS64r2 ISA level selected as applicable.  Likewise
new functionality has been tested for:

* MIPS16 ISA, o32 (-mips16 -mabi=32),

* MIPS16 ISA, o32, soft-float (-mips16 -mabi=32 -msoft-float),

producing no failures other to ones already present for the standard MIPS
and microMIPS ISAs.

 OK to apply?

2013-02-20  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.
	(RTLD_START): Likewise.
	* sysdeps/mips/fpu_control.h (__fpu_getcw) [__mips16]: New
	prototype.
	(__fpu_setcw) [__mips16]: 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.
	* sysdeps/mips/bits/atomic.h
	(atomic_compare_and_exchange_val_acq) [__mips16]: Likewise.
	(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.
	(TLS_GD, TLS_LD, TLS_IE, TLS_LE) [__mips16]: Likewise.
	* sysdeps/mips/sys/tas.h (_test_and_set): Add `.set nomips16'.
	* sysdeps/unix/mips/sysdep.h (PSEUDO_NOERRNO): Likewise.
	(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/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): Add MIPS16 version.
	* 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 nomips16.
	(__longjmp): New alias.
	* sysdeps/mips/dl-trampoline.c (_dl_runtime_resolve): Add MIPS16
	version.
	(_dl_runtime_pltresolve): Likewise.
	* sysdeps/mips/setjmp_aux.c (__sigsetjmp_aux): Add nomips16
	attribute.
	* sysdeps/mips/fpu/e_sqrt.c (__ieee754_sqrt): Add nomips16
	attribute.
	* sysdeps/mips/fpu/e_sqrtf.c (__ieee754_sqrtf): Likewise.
	* sysdeps/unix/sysv/linux/mips/brk.c (__brk): Replace inline asm
	with INTERNAL_SYSCALL.
	* sysdeps/mips/mips32/fpu/Implies: New file.
	* 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/mips/mips32/mips16/Makefile: New file.
	* sysdeps/mips/mips32/mips16/fpu/Makefile: New file.
	* sysdeps/mips/mips32/mips16/fpu/Versions: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h:
	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/unix/sysv/linux/mips/mips32/mips16/Makefile: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
        (GLIBC_2.18): Add __fpu_getcw and __fpu_setcw.
	* sysdeps/mips/preconfigure: Handle o32 MIPS16 compilation.

  Maciej

glibc-mips16-upstream.diff
Index: ports/sysdeps/mips/__longjmp.c
===================================================================
--- ports/sysdeps/mips/__longjmp.c	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/__longjmp.c	2013-02-19 22:23:55.317751073 +0000
@@ -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);
Index: ports/sysdeps/mips/abort-instr.h
===================================================================
--- ports/sysdeps/mips/abort-instr.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/abort-instr.h	2013-02-19 22:23:55.317751073 +0000
@@ -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
Index: ports/sysdeps/mips/bits/atomic.h
===================================================================
--- ports/sysdeps/mips/bits/atomic.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/bits/atomic.h	2013-02-19 22:23:55.317751073 +0000
@@ -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 */
Index: ports/sysdeps/mips/bsd-_setjmp.S
===================================================================
--- ports/sysdeps/mips/bsd-_setjmp.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/bsd-_setjmp.S	2013-02-19 22:23:55.317751073 +0000
@@ -26,6 +26,7 @@
 	.option pic2
 #endif
 ENTRY (_setjmp)
+	.set	nomips16
 #ifdef __PIC__
 	.set	noreorder
 	.cpload t9
Index: ports/sysdeps/mips/bsd-setjmp.S
===================================================================
--- ports/sysdeps/mips/bsd-setjmp.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/bsd-setjmp.S	2013-02-19 22:23:55.317751073 +0000
@@ -26,6 +26,7 @@
 	.option pic2
 #endif
 ENTRY (setjmp)
+	.set	nomips16
 	.set	noreorder
 #ifdef __PIC__
 	.cpload t9
Index: ports/sysdeps/mips/dl-machine.h
===================================================================
--- ports/sysdeps/mips/dl-machine.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/dl-machine.h	2013-02-19 22:23:55.317751073 +0000
@@ -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
Index: ports/sysdeps/mips/dl-trampoline.c
===================================================================
--- ports/sysdeps/mips/dl-trampoline.c	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/dl-trampoline.c	2013-02-19 22:23:55.317751073 +0000
@@ -292,8 +292,10 @@ __dl_runtime_resolve (ElfW(Word) sym_ind
 
 #endif
 
+#ifndef __mips16
 asm ("\n\
 	.text\n\
+	.set nomips16\n\
 	.align	2\n\
 	.globl	_dl_runtime_resolve\n\
 	.type	_dl_runtime_resolve,@function\n\
@@ -350,6 +352,7 @@ _dl_runtime_resolve:\n\
 
 asm ("\n\
 	.text\n\
+	.set nomips16\n\
 	.align	2\n\
 	.globl	_dl_runtime_pltresolve\n\
 	.type	_dl_runtime_pltresolve,@function\n\
@@ -381,3 +384,130 @@ _dl_runtime_pltresolve:\n\
 	.previous\n\
 ");
 
+#elif _MIPS_SIM == _ABIO32 /* __mips16 */
+/* MIPS16 version, O32 only.  */
+asm ("\n\
+	.text\n\
+	.set	mips16\n\
+	.align	2\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\
+	.set	mips16\n\
+	.align	2\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 */
Index: ports/sysdeps/mips/fpu/e_sqrt.c
===================================================================
--- ports/sysdeps/mips/fpu/e_sqrt.c	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/fpu/e_sqrt.c	2013-02-19 22:23:55.317751073 +0000
@@ -22,7 +22,7 @@
 
 #if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
 
-double
+double __attribute__ ((nomips16))
 __ieee754_sqrt (double x)
 {
   double z;
Index: ports/sysdeps/mips/fpu/e_sqrtf.c
===================================================================
--- ports/sysdeps/mips/fpu/e_sqrtf.c	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/fpu/e_sqrtf.c	2013-02-19 22:23:55.317751073 +0000
@@ -22,7 +22,7 @@
 
 #if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
 
-float
+float __attribute__ ((nomips16))
 __ieee754_sqrtf (float x)
 {
   float z;
Index: ports/sysdeps/mips/fpu_control.h
===================================================================
--- ports/sysdeps/mips/fpu_control.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/fpu_control.h	2013-02-19 22:23:55.317751073 +0000
@@ -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;
Index: ports/sysdeps/mips/machine-gmon.h
===================================================================
--- ports/sysdeps/mips/machine-gmon.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/machine-gmon.h	2013-02-19 22:23:55.317751073 +0000
@@ -35,6 +35,8 @@ static void __attribute_used__ __mcount 
 #endif
 
 #define MCOUNT asm(\
+	".set push;\n\t" \
+	".set nomips16;\n\t" \
 	".globl _mcount;\n\t" \
 	".align 2;\n\t" \
 	".type _mcount,@function;\n\t" \
@@ -67,9 +69,8 @@ static void __attribute_used__ __mcount 
         "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
 
@@ -92,6 +93,8 @@ static void __attribute_used__ __mcount 
 #endif
 
 #define MCOUNT asm(\
+	".set push;\n\t" \
+	".set nomips16;\n\t" \
 	".globl _mcount;\n\t" \
 	".align 3;\n\t" \
 	".type _mcount,@function;\n\t" \
@@ -132,8 +135,7 @@ static void __attribute_used__ __mcount 
         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
Index: ports/sysdeps/mips/memset.S
===================================================================
--- ports/sysdeps/mips/memset.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/memset.S	2013-02-19 22:23:55.317751073 +0000
@@ -28,6 +28,7 @@
 #endif
 
 ENTRY (memset)
+	.set	nomips16
 	.set	noreorder
 
 	slti	t1, a2, 8		# Less than 8?
Index: ports/sysdeps/mips/mips32/crti.S
===================================================================
--- ports/sysdeps/mips/mips32/crti.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/mips32/crti.S	2013-02-19 22:23:55.317751073 +0000
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
Index: ports/sysdeps/mips/mips32/crtn.S
===================================================================
--- ports/sysdeps/mips/mips32/crtn.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/mips32/crtn.S	2013-02-19 22:23:55.317751073 +0000
@@ -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
Index: ports/sysdeps/mips/mips32/fpu/Versions
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/fpu/Versions	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1,5 @@
+libc {
+  GLIBC_2.18 {
+    __fpu_getcw; __fpu_getcw;
+  }
+}
Index: ports/sysdeps/mips/mips32/fpu/fpu_control.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/fpu/fpu_control.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1,34 @@
+/* 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.
+
+   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/>.  */
+
+#include <math/fpu_control.c>
+
+fpu_control_t
+__mips_fpu_getcw (void)
+{
+  fpu_control_t cw;
+
+  _FPU_GETCW (cw);
+  return cw;
+}
+
+void
+__mips_fpu_setcw (fpu_control_t cw)
+{
+  _FPU_SETCW (cw);
+}
Index: ports/sysdeps/mips/mips32/mips16/add_n.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/add_n.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1 @@
+#include <stdlib/add_n.c>
Index: ports/sysdeps/mips/mips32/mips16/addmul_1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/addmul_1.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1 @@
+#include <stdlib/addmul_1.c>
Index: ports/sysdeps/mips/mips32/mips16/fpu/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/fpu/Makefile	2013-02-19 22:23:55.317751073 +0000
@@ -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
Index: ports/sysdeps/mips/mips32/mips16/lshift.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/lshift.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1 @@
+#include <stdlib/lshift.c>
Index: ports/sysdeps/mips/mips32/mips16/mul_1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/mul_1.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1 @@
+#include <stdlib/mul_1.c>
Index: ports/sysdeps/mips/mips32/mips16/rshift.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/rshift.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1 @@
+#include <stdlib/rshift.c>
Index: ports/sysdeps/mips/mips32/mips16/sub_n.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/sub_n.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1 @@
+#include <stdlib/sub_n.c>
Index: ports/sysdeps/mips/mips32/mips16/submul_1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/submul_1.c	2013-02-19 22:23:55.317751073 +0000
@@ -0,0 +1 @@
+#include <stdlib/submul_1.c>
Index: ports/sysdeps/mips/mips64/n32/crti.S
===================================================================
--- ports/sysdeps/mips/mips64/n32/crti.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/mips64/n32/crti.S	2013-02-19 22:23:55.317751073 +0000
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
Index: ports/sysdeps/mips/mips64/n32/crtn.S
===================================================================
--- ports/sysdeps/mips/mips64/n32/crtn.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/mips64/n32/crtn.S	2013-02-19 22:23:55.317751073 +0000
@@ -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)
Index: ports/sysdeps/mips/mips64/n64/crti.S
===================================================================
--- ports/sysdeps/mips/mips64/n64/crti.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/mips64/n64/crti.S	2013-02-19 22:23:55.317751073 +0000
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
Index: ports/sysdeps/mips/mips64/n64/crtn.S
===================================================================
--- ports/sysdeps/mips/mips64/n64/crtn.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/mips64/n64/crtn.S	2013-02-19 22:23:55.317751073 +0000
@@ -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)
Index: ports/sysdeps/mips/nptl/tls.h
===================================================================
--- ports/sysdeps/mips/nptl/tls.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/nptl/tls.h	2013-02-19 22:23:55.317751073 +0000
@@ -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>
Index: ports/sysdeps/mips/preconfigure
===================================================================
--- ports/sysdeps/mips/preconfigure	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/preconfigure	2013-02-19 22:23:55.317751073 +0000
@@ -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
Index: ports/sysdeps/mips/setjmp.S
===================================================================
--- ports/sysdeps/mips/setjmp.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/setjmp.S	2013-02-19 22:23:55.317751073 +0000
@@ -24,6 +24,7 @@
 	.option pic2
 #endif
 ENTRY (__sigsetjmp)
+	.set 	nomips16
 #ifdef __PIC__
 	.set	noreorder
 	.cpload	t9
Index: ports/sysdeps/mips/setjmp_aux.c
===================================================================
--- ports/sysdeps/mips/setjmp_aux.c	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/setjmp_aux.c	2013-02-19 22:23:55.317751073 +0000
@@ -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
Index: ports/sysdeps/mips/start.S
===================================================================
--- ports/sysdeps/mips/start.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/start.S	2013-02-19 22:23:55.327333248 +0000
@@ -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 @@
 	   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.  */
+ENTRY_POINT:
+	.set mips16
+# 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
Index: ports/sysdeps/mips/sys/tas.h
===================================================================
--- ports/sysdeps/mips/sys/tas.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/sys/tas.h	2013-02-19 22:23:55.327333248 +0000
@@ -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 
 #  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;
Index: ports/sysdeps/mips/tls-macros.h
===================================================================
--- ports/sysdeps/mips/tls-macros.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/mips/tls-macros.h	2013-02-19 22:23:55.327333248 +0000
@@ -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 */
Index: ports/sysdeps/unix/mips/mips32/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/mips32/sysdep.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/mips/mips32/sysdep.h	2013-02-19 22:23:55.327333248 +0000
@@ -23,6 +23,7 @@
    backwards into the previous fn.  */
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .align 2;								      \
   cfi_startproc;							      \
   99: la t9,__syscall_error;						      \
@@ -38,6 +39,7 @@
 L(syse1):
 #else
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .set noreorder;							      \
   .align 2;								      \
   cfi_startproc;							      \
Index: ports/sysdeps/unix/mips/mips64/n32/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/mips64/n32/sysdep.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/mips/mips64/n32/sysdep.h	2013-02-19 22:23:55.327333248 +0000
@@ -25,6 +25,7 @@
    backwards into the previous fn.  */
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .align 2;								      \
   cfi_startproc;							      \
   99:;									      \
@@ -44,6 +45,7 @@
 L(syse1):
 #else
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .set noreorder;							      \
   .align 2;								      \
   cfi_startproc;							      \
Index: ports/sysdeps/unix/mips/mips64/n64/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/mips64/n64/sysdep.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/mips/mips64/n64/sysdep.h	2013-02-19 22:23:55.327333248 +0000
@@ -25,6 +25,7 @@
    backwards into the previous fn.  */
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .align 2;								      \
   cfi_startproc;							      \
   99:;									      \
@@ -44,6 +45,7 @@
 L(syse1):
 #else
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .set noreorder;							      \
   .align 2;								      \
   cfi_startproc;							      \
Index: ports/sysdeps/unix/mips/sysdep.S
===================================================================
--- ports/sysdeps/unix/mips/sysdep.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/mips/sysdep.S	2013-02-19 22:23:55.327333248 +0000
@@ -21,6 +21,8 @@
 #include <bits/errno.h>
 #include <sys/asm.h>
 
+	.set nomips16
+
 #ifdef _LIBC_REENTRANT
 
 LOCALSZ= 3
Index: ports/sysdeps/unix/mips/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/sysdep.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/mips/sysdep.h	2013-02-19 22:23:55.327333248 +0000
@@ -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
Index: ports/sysdeps/unix/sysv/linux/mips/brk.c
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/brk.c	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/brk.c	2013-02-19 22:23:55.327333248 +0000
@@ -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)
Index: ports/sysdeps/unix/sysv/linux/mips/clone.S
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/clone.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/clone.S	2013-02-19 22:23:55.327333248 +0000
@@ -34,6 +34,7 @@
 	     void *parent_tidptr, void *tls, void *child_tidptr) */
 
 	.text
+	.set		nomips16
 #if _MIPS_SIM == _ABIO32
 # define EXTRA_LOCALS 1
 #else
Index: ports/sysdeps/unix/sysv/linux/mips/getcontext.S
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/getcontext.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/getcontext.S	2013-02-19 22:23:55.327333248 +0000
@@ -27,6 +27,7 @@
 /* int getcontext (ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 MASK = 0x00000000
 #ifdef __PIC__
Index: ports/sysdeps/unix/sysv/linux/mips/makecontext.S
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/makecontext.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/makecontext.S	2013-02-19 22:23:55.327333248 +0000
@@ -27,6 +27,7 @@
 /* int makecontext (ucontext_t *ucp, (void *func) (), int argc, ...) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile	2013-02-19 22:23:55.327333248 +0000
@@ -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
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,6 @@
+libc {
+  GLIBC_PRIVATE {
+    __mips16_syscall0; __mips16_syscall1; __mips16_syscall2; __mips16_syscall3;
+    __mips16_syscall4; __mips16_syscall5; __mips16_syscall6; __mips16_syscall7;
+  }
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h	2013-02-19 22:23:55.327333248 +0000
@@ -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
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,30 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall0
+
+long long __nomips16
+__mips16_syscall0 (long number)
+{
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 0);
+  return ret.val;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,32 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall1
+
+long long __nomips16
+__mips16_syscall1 (long a0,
+		   long number)
+{
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 1,
+					a0);
+  return ret.val;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,32 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall2
+
+long long __nomips16
+__mips16_syscall2 (long a0, long a1,
+		   long number)
+{
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 2,
+					a0, a1);
+  return ret.val;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,32 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall3
+
+long long __nomips16
+__mips16_syscall3 (long a0, long a1, long a2,
+		   long number)
+{
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 3,
+					a0, a1, a2);
+  return ret.val;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,32 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall4
+
+long long __nomips16
+__mips16_syscall4 (long a0, long a1, long a2, long a3,
+		   long number)
+{
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 4,
+					a0, a1, a2, a3);
+  return ret.val;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,33 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall5
+
+long long __nomips16
+__mips16_syscall5 (long a0, long a1, long a2, long a3,
+		   long a4,
+		   long number)
+{
+  union __mips16_syscall_return ret;
+  ret.reg.v0 = INTERNAL_SYSCALL_MIPS16 (number, ret.reg.v1, 5,
+					a0, a1, a2, a3, a4);
+  return ret.val;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,33 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall6
+
+long long __nomips16
+__mips16_syscall6 (long a0, long a1, long a2, long a3,
+		   long a4, long a5,
+		   long number)
+{
+  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;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c	2013-02-19 22:23:55.327333248 +0000
@@ -0,0 +1,33 @@
+/* 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/>.  */
+
+#include <sysdep.h>
+#include <mips16-syscall.h>
+
+#undef __mips16_syscall7
+
+long long __nomips16
+__mips16_syscall7 (long a0, long a1, long a2, long a3,
+		   long a4, long a5, long a6,
+		   long number)
+{
+  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;
+}
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist	2013-02-19 22:23:55.327333248 +0000
@@ -2253,3 +2253,5 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+ __fpu_getcw F
+ __fpu_setcw F
Index: ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	2013-02-19 22:23:55.327333248 +0000
@@ -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;						\
Index: ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h	2013-02-19 22:23:55.327333248 +0000
@@ -45,6 +45,7 @@
 # undef PSEUDO
 # define PSEUDO(name, syscall_name, args)				      \
       .align 2;								      \
+      .set nomips16;							      \
   L(pseudo_start):							      \
       cfi_startproc;							      \
   99: PSEUDO_ERRJMP							      \
Index: ports/sysdeps/unix/sysv/linux/mips/setcontext.S
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/setcontext.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/setcontext.S	2013-02-19 22:23:55.327333248 +0000
@@ -27,6 +27,7 @@
 /* int setcontext (const ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
Index: ports/sysdeps/unix/sysv/linux/mips/swapcontext.S
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/swapcontext.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/swapcontext.S	2013-02-19 22:23:55.327333248 +0000
@@ -27,6 +27,7 @@
 /* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
Index: ports/sysdeps/unix/sysv/linux/mips/vfork.S
===================================================================
--- ports/sysdeps/unix/sysv/linux/mips/vfork.S	2013-02-19 22:23:49.556613890 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/vfork.S	2013-02-19 22:23:55.327333248 +0000
@@ -34,6 +34,7 @@
 /* int vfork() */
 
 	.text
+	.set		nomips16
 LOCALSZ= 1
 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
 GPOFF= FRAMESZ-(1*SZREG)


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