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 2/2] MIPS16: MIPS16 support proper


Hi,

 This change adds support for building the MIPS port of glibc as MIPS16 
code, for the o32 ABI.  The MIPS16 instruction set has several limitations 
that required adjustments in the library.  The benefit is a smaller 
footprint of pieces that can actually be compiled to MIPS16 code.

 The execution mode can be freely switched between the standard MIPS and 
the MIPS16 mode by flipping the ISA bit, that is exposed to the programmer 
as bit #0 of the PC and supported by the relevant jump instructions.  
Standard MIPS and MIPS16 code can be mixed in a single program both at the 
static-link and at the dynamic-load time.

 Please note that owing to that property MIPS16 dynamic executables are 
supported by glibc already, barring the issue of _FPU_GETCW and _FPU_SETCW 
described below, simply by linking and loading such programs with 
standard-MIPS glibc binaries; it's just building the library itself that 
is not.

 Here is how individual issues have been addressed by the change proposed:

1. There are no floating-point MIPS16 instructions nor ones to access
   floating-point registers.  That required all the affected functions to 
   be marked with the nomips16 attribute.  This applies to functions like 
   setjmp/longjmp, setcontext/getcontext/etc. that requires access tothe 
   floating-point register stack.

   Further, all the math functions are compiled with the -mno-mips16 
   compiler option, so that they do not have to be individually marked.  
   The overhead to factor out individual low-level floating-point 
   operations, such as addition or multiplication, as standard MIPS code 
   and call the respective functions as appropriate would be prohibitive 
   and no code size gain would result.

   Finally, the _FPU_GETCW and _FPU_SETCW user-accessible macros have been 
   rewritten to refer to new helpers so that they can be called in the 
   MIPS16 mode.

   This code is surrounded by an __mips16 macro check that is only going 
   to work for code built with -mips16 as the preprocessor does not know 
   the actual mode selected by the compiler.  A different solution, such 
   as a __builtin_mips16 compiler function, would be required for the 
   macros to work even for functions marked with the mips16 attribute or 
   compiled to MIPS16 code due to the -mflip-mips16 compiler option.  The 
   solution chosen is I believe the best that we can get and works for the 
   common case.

   I have decided to export prototypes for the new helpers, but I have no 
   strong preference to do that -- we may well keep them as an internal 
   implementation detail instead, i.e.:

#define _FPU_GETCW(cw)							\
  do									\
    {									\
      extern fpu_control_t __fpu_getcw (void) __THROW;			\
      (cw) = __fpu_getcw ();						\
    }									\
  while (0)

   -- and likewise for _FPU_SETCW.  Suggestions?

2. The MIPS16 BREAK instruction has a limited range of its immediate code 
   compared to its standard MIPS counterpart.  Therefore 63, the maximum 
   value supported, has been chosen for ABORT_INSTRUCTION.

3. There are no MIPS16 atomic LL or SC instructions.  GCC has, since 4.1, 
   supported suitable built-ins and this change relies on them.  In 
   practice the built-ins produce small snippets of out-of-line standard 
   MIPS code called from where requested.

4. Several handcoded assembly sequences have been rewritten as 
   corresponding MIPS16 code.  Where there would be no gain from switching 
   to the MIPS16 mode the existing pieces have been marked with the ".set 
   nomips16" GAS directive so that they are built as standard MIPS code.

5. New MIPS16 constructor and destructor prologue and epilogue assembly 
   code has been added.  This code is lumped together with all the 
   individual constructor and destructor call fragments.  This works as 
   long as all the code involved has been built for the same ISA, either 
   the standard MIPS or the MIPS16 one.  This will break if individual 
   pieces have been built for different ISAs.

   To address this properly the MIPS port would have to switch to using
   constructor and destructor arrays rather than lumped code (i.e. 
   DT_INIT_ARRAY and DT_FINI_ARRAY rather than DT_INIT and DT_FINI, 
   respectively).  In this case the ISA bit of the individual array 
   entries would select the execution mode as appropriate for each call.  
   To the best of my knowledge the GNU toolchain has supported these 
   arrays since forever, so this is probably the right moment to switch.  
   NB mixed standard MIPS/microMIPS binaries suffer from the same problem.

   For the time being the change proposed here is the best we can do to 
   support the common case I believe.

6. There is no MIPS16 RDHWR instruction.  To implement the 
   READ_THREAD_POINTER macro we use the __builtin_thread_pointer GCC 
   builtin instead.  In practice if called from MIPS16 code, this expands 
   to a call to __mips16_rdhwr that is a small piece of standard MIPS code 
   that executes RDHWR with the right arguments.

7. There is no MIPS16 SYSCALL instruction.  Internal inline syscall 
   wrappers have been rewritten to small snippets of out-of-line standard 
   MIPS code where called from MIPS16 code.  The snippets have been 
   designed such as to avoid unnecessary argument shuffling -- hence the 
   syscall number is passed last.

   Consequently __brk is rewritten in terms of INTERNAL_SYSCALL too.

 The change 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.

 Questions and comments are welcome; otherwise please apply.

2013-01-23  Chung-Lin Tang  <cltang@codesourcery.com>
            Maciej W. Rozycki  <macro@codesourcery.com>
            Maxim Kuvyrkov  <maxim@codesourcery.com>

	ports/
	* 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/unix/mips/sysdep.S: Add ".set nomips16".
	* 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/crti.S: New file.
	* sysdeps/mips/mips32/mips16/crtn.S: 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/mips64/n32/nptl/libc.abilist
        (GLIBC_2.18): New.  Add __fpu_getcw and __fpu_setcw.
	* sysdeps/mips/preconfigure: Handle o32 MIPS16 compilation.

  Maciej

glibc-mips16.diff
Index: ports/sysdeps/mips/__longjmp.c
===================================================================
--- ports/sysdeps/mips/__longjmp.c	2013-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/__longjmp.c	2013-01-20 19:40:57.097753716 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/abort-instr.h	2013-01-20 19:40:57.097753716 +0000
@@ -1,2 +1,6 @@
 /* An instruction which should crash any program is a breakpoint.  */
+#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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/bits/atomic.h	2013-01-20 19:40:57.117793511 +0000
@@ -37,6 +37,40 @@ typedef uintptr_t uatomicptr_t;
 typedef intmax_t atomic_max_t;
 typedef uintmax_t uatomic_max_t;
 
+/* MIPS16 uses GCC __sync_* builtins to implement the required atomic
+   operations, to abstract out the unsupported assembly instructions.
+   ??? Maybe eventually use them for 32-bit MIPS too?  */
+#ifdef __mips16
+# if __GNUC_PREREQ (4, 1)
+
+#  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))
+
+#  define atomic_full_barrier() __sync_synchronize ()
+
+# else
+#  error "MIPS16 requires GCC with __sync_* builtins"
+# endif
+#else /* !__mips16 */
+
 #if _MIPS_SIM == _ABIO32
 #define MIPS_PUSH_MIPS2 ".set	mips2\n\t"
 #else
@@ -454,4 +488,5 @@ typedef uintmax_t uatomic_max_t;
 			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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/bsd-_setjmp.S	2013-01-20 19:40:57.137753861 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/bsd-setjmp.S	2013-01-20 19:40:57.156841347 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/dl-machine.h	2013-01-20 19:40:57.176855918 +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,6 +224,7 @@ do {									\
    2) That under Unix the entry is named __start
       and not just plain _start.  */
 
+#ifndef __mips16
 #define RTLD_START asm (\
 	".text\n\
 	" _RTLD_PROLOGUE(ENTRY_POINT) "\
@@ -283,6 +298,91 @@ do {									\
 	".previous"\
 );
 
+#else
+
+/* 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
+
 /* 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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/dl-trampoline.c	2013-01-20 19:40:57.196878136 +0000
@@ -292,8 +292,11 @@ __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 +353,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 +385,131 @@ _dl_runtime_pltresolve:\n\
 	.previous\n\
 ");
 
+#elif _MIPS_SIM == _ABIO32
+
+/* 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
+#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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/fpu/e_sqrt.c	2013-01-20 19:40:57.216896761 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/fpu/e_sqrtf.c	2013-01-20 19:40:57.236875700 +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-01-16 00:04:04.000000000 +0000
+++ ports/sysdeps/mips/fpu_control.h	2013-01-23 01:25:04.047168836 +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.  */
+extern fpu_control_t __fpu_getcw (void) __THROW;
+extern void __fpu_setcw (fpu_control_t) __THROW;
+#ifdef __mips16
+#define _FPU_GETCW(cw) do { (cw) = __fpu_getcw (); } while (0)
+#define _FPU_SETCW(cw) __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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/machine-gmon.h	2013-01-20 19:40:57.256890706 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/memset.S	2013-01-20 19:40:57.276543548 +0000
@@ -28,6 +28,7 @@
 #endif
 
 ENTRY (memset)
+	.set	nomips16
 	.set	noreorder
 
 	slti	t1, a2, 8		# Less than 8?
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-01-20 23:16:11.026712794 +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
+__fpu_getcw (void)
+{
+  fpu_control_t cw;
+
+  _FPU_GETCW(cw);
+  return cw;
+}
+
+void
+__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-01-20 19:40:57.296892628 +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-01-20 19:40:57.296892628 +0000
@@ -0,0 +1 @@
+#include <stdlib/addmul_1.c>
Index: ports/sysdeps/mips/mips32/mips16/crti.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/crti.S	2013-01-20 20:05:43.816556531 +0000
@@ -0,0 +1,111 @@
+/* Special .init and .fini section support for MIPS16 (o32).
+   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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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/>.  */
+
+/* crti.S puts a function prologue at the beginning of the .init and
+   .fini sections and defines global symbols for those addresses, so
+   they can be called as functions.  The symbols _init and _fini are
+   magic and cause the linker to emit DT_INIT and DT_FINI.  */
+
+#include <libc-symbols.h>
+
+#ifndef PREINIT_FUNCTION
+# define PREINIT_FUNCTION __gmon_start__
+#endif
+
+#ifndef PREINIT_FUNCTION_WEAK
+# define PREINIT_FUNCTION_WEAK 1
+#endif
+
+#if PREINIT_FUNCTION_WEAK
+	weak_extern (PREINIT_FUNCTION)
+#else
+	.hidden	PREINIT_FUNCTION
+#endif
+
+	.section .init, "ax", @progbits
+	.p2align 2
+	.globl	_init
+	.type	_init, @function
+_init:
+	li	$2, %hi(_gp_disp)
+	addiu	$3, $pc, %lo(_gp_disp)
+	sll	$2, 16
+	addu	$2, $3
+#if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	save	32, $31
+#else
+	addiu	$sp, -32
+	sw	$31, 28($sp)
+#endif
+	move	$28, $2
+	sw	$2, 16($sp)
+#if PREINIT_FUNCTION_WEAK
+	lw	$3, %got(PREINIT_FUNCTION)($2)
+	beqz	$3, .Lno_weak_fn
+	lw	$2, %call16(PREINIT_FUNCTION)($2)
+	.set	noreorder
+	.set	nomacro
+	jalr	$2
+	 move	$25, $2
+	.set	macro
+	.set	reorder
+.Lno_weak_fn:
+#else
+	lw	$2, %got(PREINIT_FUNCTION)($2)
+	.set	noreorder
+	.set	nomacro
+	jalr	$2
+	 move	$25, $2
+	.set	macro
+	.set	reorder
+#endif
+
+	.section .fini, "ax", @progbits
+	.p2align 2
+	.globl	_fini
+	.type	_fini, @function
+_fini:
+	li	$2, %hi(_gp_disp)
+	addiu	$3, $pc, %lo(_gp_disp)
+	sll	$2, 16
+	addu	$2, $3
+#if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	save	32, $31
+#else
+	addiu	$sp, -32
+	sw	$31, 28($sp)
+#endif
+	move	$28, $2
+	sw	$2, 16($sp)
Index: ports/sysdeps/mips/mips32/mips16/crtn.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/crtn.S	2013-01-20 20:00:38.716871098 +0000
@@ -0,0 +1,57 @@
+/* Special .init and .fini section support for MIPS16 (o32).
+   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.
+
+   In addition to the permissions in the GNU Lesser General Public
+   License, the Free Software Foundation gives you unlimited
+   permission to link the compiled version of this file with other
+   programs, and to distribute those programs without any restriction
+   coming from the use of this file. (The GNU Lesser General Public
+   License restrictions do apply in other respects; for example, they
+   cover modification of the file, and distribution when not linked
+   into another program.)
+
+   Note that people who make modified versions of this file are not
+   obligated to grant this special exception for their modified
+   versions; it is their choice whether to do so. The GNU Lesser
+   General Public License gives permission to release a modified
+   version without this exception; this exception also makes it
+   possible to release a modified version which carries forward this
+   exception.
+
+   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/>.  */
+
+/* crtn.S puts function epilogues in the .init and .fini sections
+   corresponding to the prologues in crti.S. */
+
+	.section .init, "ax", @progbits
+#if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	restore	32, $31
+	j	$31
+#else
+	lw	$7, 28($sp)
+	addiu	$sp, 32
+	j	$7
+#endif
+
+	.section .fini, "ax", @progbits
+#if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	restore	32, $31
+	j	$31
+#else
+	lw	$7, 28($sp)
+	addiu	$sp, 32
+	j	$7
+#endif
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-01-20 19:40:57.296892628 +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/fpu/Versions
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ ports/sysdeps/mips/mips32/mips16/fpu/Versions	2013-01-20 22:11:01.057025227 +0000
@@ -0,0 +1,5 @@
+libc {
+  GLIBC_2.18 {
+    __fpu_getcw; __fpu_getcw;
+  }
+}
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-01-20 19:40:57.296892628 +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-01-20 19:40:57.296892628 +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-01-20 19:40:57.296892628 +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-01-20 19:40:57.296892628 +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-01-20 19:40:57.296892628 +0000
@@ -0,0 +1 @@
+#include <stdlib/submul_1.c>
Index: ports/sysdeps/mips/nptl/tls.h
===================================================================
--- ports/sysdeps/mips/nptl/tls.h	2013-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/nptl/tls.h	2013-01-20 19:40:57.296892628 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/preconfigure	2013-01-20 19:40:57.306553118 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/setjmp.S	2013-01-20 19:40:57.326814470 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/setjmp_aux.c	2013-01-20 19:40:57.346890569 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/start.S	2013-01-20 19:40:57.366883392 +0000
@@ -74,6 +74,7 @@
 	.text
 	.globl ENTRY_POINT
 	.type ENTRY_POINT,@function
+#ifndef __mips16
 ENTRY_POINT:
 #ifdef __PIC__
 	SETUP_GPX($0)
@@ -108,6 +109,68 @@
 	jal __libc_start_main
 hlt:	b hlt			/* Crash if somehow it does return.  */
 
+#elif _MIPS_SIM == _ABIO32
+	/* 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
+#error "MIPS16 support for N32/N64 not implemented"
+#endif
+
 /* 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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/sys/tas.h	2013-01-20 19:40:57.376549265 +0000
@@ -24,7 +24,7 @@
 
 __BEGIN_DECLS
 
-extern int _test_and_set (int *__p, int __v) __THROW;
+extern int __attribute__((nomips16)) test_and_set (int *__p, int __v) __THROW;
 
 #ifdef __USE_EXTERN_INLINES
 
@@ -32,7 +32,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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/mips/tls-macros.h	2013-01-20 19:40:57.406635785 +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,46 @@
 	  ADDU " %0,%0,$3"				\
 	  : "+r" (__result) : : "$3");			\
      __result; })
+
+#else
+
+/* 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
Index: ports/sysdeps/unix/mips/mips32/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/mips32/sysdep.h	2013-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/mips/mips32/sysdep.h	2013-01-20 19:40:57.406635785 +0000
@@ -23,6 +23,7 @@
    backwards into the previous fn.  */
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .align 2;								      \
   99: la t9,__syscall_error;						      \
   jr t9;								      \
@@ -36,6 +37,7 @@
 L(syse1):
 #else
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .set noreorder;							      \
   .align 2;								      \
   99: j __syscall_error;						      \
Index: ports/sysdeps/unix/mips/mips64/n32/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/mips64/n32/sysdep.h	2013-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/mips/mips64/n32/sysdep.h	2013-01-20 19:40:57.426877081 +0000
@@ -25,6 +25,7 @@
    backwards into the previous fn.  */
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .align 2;								      \
   99:;									      \
   .set noat;								      \
@@ -40,6 +41,7 @@
 L(syse1):
 #else
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .set noreorder;							      \
   .align 2;								      \
   99: j __syscall_error;						      \
Index: ports/sysdeps/unix/mips/mips64/n64/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/mips64/n64/sysdep.h	2013-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/mips/mips64/n64/sysdep.h	2013-01-20 19:40:57.446887899 +0000
@@ -25,6 +25,7 @@
    backwards into the previous fn.  */
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .align 2;								      \
   99:;									      \
   .set noat;								      \
@@ -40,6 +41,7 @@
 L(syse1):
 #else
 #define PSEUDO(name, syscall_name, args) \
+  .set nomips16;							      \
   .set noreorder;							      \
   .align 2;								      \
   99: j __syscall_error;						      \
Index: ports/sysdeps/unix/mips/sysdep.S
===================================================================
--- ports/sysdeps/unix/mips/sysdep.S	2013-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/mips/sysdep.S	2013-01-20 19:40:57.466877139 +0000
@@ -21,6 +21,9 @@
 #include <bits/errno.h>
 #include <sys/asm.h>
 
+	/* Not MIPS16 code.  */
+	.set nomips16
+
 #ifdef _LIBC_REENTRANT
 
 LOCALSZ= 3
Index: ports/sysdeps/unix/mips/sysdep.h
===================================================================
--- ports/sysdeps/unix/mips/sysdep.h	2013-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/mips/sysdep.h	2013-01-20 19:40:57.486831430 +0000
@@ -42,6 +42,7 @@
 #define PSEUDO_NOERRNO(name, syscall_name, args)	\
   .align 2;						\
   ENTRY(name)						\
+  .set nomips16;					\
   .set noreorder;					\
   li v0, SYS_ify(syscall_name);				\
   syscall
@@ -54,6 +55,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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/brk.c	2013-01-20 19:40:57.506879197 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/clone.S	2013-01-20 19:40:57.526854098 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/getcontext.S	2013-01-20 19:40:57.546859991 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/makecontext.S	2013-01-20 19:40:57.546859991 +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-01-20 19:40:57.546859991 +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-01-20 19:40:57.546859991 +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-01-20 19:40:57.546859991 +0000
@@ -0,0 +1,91 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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-01-20 19:40:57.546859991 +0000
@@ -0,0 +1,32 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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-01-20 19:40:57.546859991 +0000
@@ -0,0 +1,34 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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-01-20 19:40:57.546859991 +0000
@@ -0,0 +1,35 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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;
+}
+//libc_hidden_def (__mips16_syscall2)
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-01-20 19:40:57.546859991 +0000
@@ -0,0 +1,34 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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-01-20 19:40:57.546859991 +0000
@@ -0,0 +1,34 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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-01-20 19:40:57.556541697 +0000
@@ -0,0 +1,35 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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-01-20 19:40:57.556541697 +0000
@@ -0,0 +1,35 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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-01-20 19:40:57.556541697 +0000
@@ -0,0 +1,35 @@
+/* MIPS16 syscall wrappers.
+   Copyright (C) 2013 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+   Contributed by Maciej W. Rozycki <macro@codesourcery.com>.
+
+   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, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#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	2012-11-21 23:51:44.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist	2013-01-20 23:50:55.947782276 +0000
@@ -2250,3 +2250,7 @@ GLIBC_2.17
  clock_nanosleep F
  clock_settime F
  secure_getenv F
+GLIBC_2.18
+ GLIBC_2.18 A
+ __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-01-19 19:25:30.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	2013-01-20 19:40:57.556541697 +0000
@@ -84,17 +84,47 @@
 #endif
 
 #undef INTERNAL_SYSCALL
+#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...)			\
 	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-01-17 01:18:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h	2013-01-20 19:40:57.576858974 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/setcontext.S	2013-01-20 19:40:57.596908144 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/swapcontext.S	2013-01-20 19:40:57.616906450 +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-01-17 00:55:17.000000000 +0000
+++ ports/sysdeps/unix/sysv/linux/mips/vfork.S	2013-01-20 19:40:57.646908672 +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]