public inbox for libc-ports@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/2] MIPS16: MIPS16 support
@ 2013-01-23  4:41 Maciej W. Rozycki
  2013-01-23  4:41 ` [PATCH 1/2] MIPS16: Allocate GLIBC_2.18 Maciej W. Rozycki
  2013-01-23  4:42 ` [PATCH 2/2] MIPS16: MIPS16 support proper Maciej W. Rozycki
  0 siblings, 2 replies; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-23  4:41 UTC (permalink / raw)
  To: libc-alpha, libc-ports; +Cc: Chung-Lin Tang

Hi,

 This patch mini-series adds MIPS16 support to glibc.  It's been split 
into two parts per patch submission guidelines.  The first part applies to 
glibc proper and the second one to the ports add-on.  Full descriptions 
are included with the patches themselves.

  Maciej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 1/2] MIPS16: Allocate GLIBC_2.18
  2013-01-23  4:41 [PATCH 0/2] MIPS16: MIPS16 support Maciej W. Rozycki
@ 2013-01-23  4:41 ` Maciej W. Rozycki
  2013-01-23  4:42 ` [PATCH 2/2] MIPS16: MIPS16 support proper Maciej W. Rozycki
  1 sibling, 0 replies; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-23  4:41 UTC (permalink / raw)
  To: libc-alpha, libc-ports; +Cc: Chung-Lin Tang

Hi,

 This change adds GLIBC_2.18 to the list of defined versions.  It is 
needed for newly-defined functions required for MIPS16 support.

 Please apply.

2013-01-23  Maciej W. Rozycki  <macro@codesourcery.com>

	* Versions.def (libc): Add GLIBC_2.18.

  Maciej

Index: glibc-fsf-trunk-quilt/Versions.def
===================================================================
--- glibc-fsf-trunk-quilt.orig/Versions.def	2012-11-21 23:51:43.000000000 +0000
+++ glibc-fsf-trunk-quilt/Versions.def	2013-01-20 22:12:01.457025518 +0000
@@ -34,6 +34,7 @@ libc {
   GLIBC_2.15
   GLIBC_2.16
   GLIBC_2.17
+  GLIBC_2.18
   HURD_CTHREADS_0.3
 %ifdef EXPORT_UNWIND_FIND_FDE
   GCC_3.0

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-23  4:41 [PATCH 0/2] MIPS16: MIPS16 support Maciej W. Rozycki
  2013-01-23  4:41 ` [PATCH 1/2] MIPS16: Allocate GLIBC_2.18 Maciej W. Rozycki
@ 2013-01-23  4:42 ` Maciej W. Rozycki
  2013-01-23 17:22   ` Joseph S. Myers
  2013-01-24 18:08   ` [PATCH 2/2] MIPS16: MIPS16 support proper Ellcey, Steve
  1 sibling, 2 replies; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-23  4:42 UTC (permalink / raw)
  To: libc-alpha, libc-ports; +Cc: Chung-Lin Tang

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)

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-23  4:42 ` [PATCH 2/2] MIPS16: MIPS16 support proper Maciej W. Rozycki
@ 2013-01-23 17:22   ` Joseph S. Myers
  2013-01-24 10:10     ` Chung-Lin Tang
  2013-02-20 16:19     ` [PATCH v2] MIPS: MIPS16 support Maciej W. Rozycki
  2013-01-24 18:08   ` [PATCH 2/2] MIPS16: MIPS16 support proper Ellcey, Steve
  1 sibling, 2 replies; 26+ messages in thread
From: Joseph S. Myers @ 2013-01-23 17:22 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: libc-ports, Chung-Lin Tang

On Wed, 23 Jan 2013, Maciej W. Rozycki wrote:

> 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);

Why is the renaming / alias needed?

> 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

Indentation inside #if, "# define".

> +/* 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)

glibc requires at least 4.3 to build, so no such condition is needed in an 
internal header.

However, __sync_* are obsolete; the __atomic_* built-in functions 
(supported in 4.7 and later, well-optimized for MIPS in 4.8 and later) are 
preferred because they allow more precise specification of the barrier 
semantics in particular cases.  So if building with 4.8 or later, you 
should use the existing definitions in terms of __atomic_* that are 
already used in those circumstances for MIPS - and probably use them for 
the (4.7 and MIPS16) combination, since they won't be any worse than 
__sync_*.  Fallbacks using __sync_* should only be for the (older GCC, 
MIPS16) combination.  So the logic in the file should be:

#if (4.8 or later, or 4.7 and MIPS16)
existing implementation using __atomic_*
#elif (MIPS16)
implementation using __sync_*, for older GCC and MIPS16
#else
existing implementation using inline asm
#endif

> +#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 (\

Indentation, "# define".  Many further cases in this patch as well, not 
individually pointed out.

>  /* 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

Names __mips_fpu_getcw and __mips_fpu_setcw might reduce any risk of 
conflicts with any future architecture-independent internal function?

> +  _FPU_GETCW(cw);

> +  _FPU_SETCW(cw);

Missing space before '('.

> 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;
> +  }
> +}

The public ABI exported by glibc should not depend on whether glibc itself 
was built as MIPS16; remember that these functions will be needed by 
MIPS16 code linked with a MIPS32 glibc.  So this Versions file should not 
be in a mips16 sysdeps directory.

> 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;

This is an installed header, so you need to use __nomips16__ rather than 
just plain nomips16.

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

We don't put "Contributed by" lines in new files in glibc.

> +   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.  */

All files in glibc should now use a URL instead of an FSF postal address.

These points apply similarly to other new files.

Please send a revised patch for review.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-23 17:22   ` Joseph S. Myers
@ 2013-01-24 10:10     ` Chung-Lin Tang
  2013-01-24 13:13       ` Maciej W. Rozycki
  2013-02-20 16:19     ` [PATCH v2] MIPS: MIPS16 support Maciej W. Rozycki
  1 sibling, 1 reply; 26+ messages in thread
From: Chung-Lin Tang @ 2013-01-24 10:10 UTC (permalink / raw)
  To: Joseph S. Myers; +Cc: Maciej W. Rozycki, libc-ports

On 2013/1/24 01:22 AM, Joseph S. Myers wrote:
>>  
>> > -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);
> Why is the renaming / alias needed?
> 

This was because the declaration of __longjmp() in setjmp.h prohibited
us from tagging it directly with __attribute__ ((nomips16)) locally;
there will be a declaration inconsistent with header error.

Chung-Lin

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-24 10:10     ` Chung-Lin Tang
@ 2013-01-24 13:13       ` Maciej W. Rozycki
  2013-01-24 13:56         ` Richard Sandiford
  0 siblings, 1 reply; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-24 13:13 UTC (permalink / raw)
  To: Richard Sandiford, Chung-Lin Tang; +Cc: Joseph S. Myers, libc-ports

On Thu, 24 Jan 2013, Chung-Lin Tang wrote:

> >> > -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);
> > Why is the renaming / alias needed?
> > 
> 
> This was because the declaration of __longjmp() in setjmp.h prohibited
> us from tagging it directly with __attribute__ ((nomips16)) locally;
> there will be a declaration inconsistent with header error.

 Indeed, GCC goes through a great pain to enforce consistency between a 
function's prototype and the corresponding definition as far as the mips16 
and nomips16 attributes are concerned.  On the other hand it is possible 
to provide a prototype with neither attribute and freely choose the 
instruction encoding used for the definition with either of the -mips16 
and -mno-mips16 command line options applied when building the relevant 
source file.

 I have no idea where this dichotomy comes from -- Richard, do you happen 
to know?  I'd be happy to get enlightened.

  Maciej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-24 13:13       ` Maciej W. Rozycki
@ 2013-01-24 13:56         ` Richard Sandiford
  0 siblings, 0 replies; 26+ messages in thread
From: Richard Sandiford @ 2013-01-24 13:56 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Chung-Lin Tang, Joseph S. Myers, libc-ports

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> On Thu, 24 Jan 2013, Chung-Lin Tang wrote:
>
>> >> > -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);
>> > Why is the renaming / alias needed?
>> > 
>> 
>> This was because the declaration of __longjmp() in setjmp.h prohibited
>> us from tagging it directly with __attribute__ ((nomips16)) locally;
>> there will be a declaration inconsistent with header error.
>
>  Indeed, GCC goes through a great pain to enforce consistency between a 
> function's prototype and the corresponding definition as far as the mips16 
> and nomips16 attributes are concerned.  On the other hand it is possible 
> to provide a prototype with neither attribute and freely choose the 
> instruction encoding used for the definition with either of the -mips16 
> and -mno-mips16 command line options applied when building the relevant 
> source file.
>
>  I have no idea where this dichotomy comes from -- Richard, do you happen 
> to know?  I'd be happy to get enlightened.

As it happens, this very topic was raised on the GCC list recently:

http://gcc.gnu.org/ml/gcc/2013-01/msg00133.html
http://gcc.gnu.org/ml/gcc/2013-01/msg00229.html

Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-23  4:42 ` [PATCH 2/2] MIPS16: MIPS16 support proper Maciej W. Rozycki
  2013-01-23 17:22   ` Joseph S. Myers
@ 2013-01-24 18:08   ` Ellcey, Steve
  2013-01-25  5:14     ` Maciej W. Rozycki
  1 sibling, 1 reply; 26+ messages in thread
From: Ellcey, Steve @ 2013-01-24 18:08 UTC (permalink / raw)
  To: Maciej W. Rozycki, libc-alpha, libc-ports; +Cc: Chung-Lin Tang

Maciej,

I was able to apply your patches and build a MIPS16 glibc (multiple ones actually for mips32,
mips32r2, big & little endian, soft & hard float), so that was great.  I am having trouble running executables
that I link with those libraries though.  I am using qemu for my testing and the same qemu that runs
mips32r2 binaries just fine won't run something compiled with -mips32r2 -mips16 and linked with the mips16
glibc that I built.

After some poking around I think the problem is not the glibc that I built but with crti.o and crtn.o.  If I use
regular mips32 versions of these crt files and mips16 built versions of everything else (main program, glibc,
libgcc, etc.) then I can run a simple hello world program, if I use the mips16 versions of crti and crtn I get:


mips-mti-linux-gnu-gcc -mips32r2 -mips16 '-Wl,--dynamic-linker=/local/home/sellcey/gcc/mips16/sysroot-mips-mti-linux-gnu/mips16/usr/lib/ld-2.17.90.so' '-Wl,-rpath=/local/home/sellcey/gcc/mips16/sysroot-mips-mti-linux-gnu/mips16/usr/lib:/local/home/sellcey/gcc/mips16/install-mips-mti-linux-gnu/mips-mti-linux-gnu/lib/mips16' hi.c -o x

mips-mti-linux-gnu-qemu -r 2.6.38 ./x
hi
qemu: uncaught target signal 11 (Segmentation fault) - core dumped

Note that it did print 'hi' before getting the signal.

If I try adding '-static' then I get:

mips-mti-linux-gnu-gcc -static -mips32r2 -mips16 hi.c -o x
mips-mti-linux-gnu-qemu -r 2.6.38 ./x
qemu: uncaught target signal 4 (Illegal instruction) - core dumped



I was wondering if you have any idea what could be causing this.  Should the standard qemu be able
to run mips16 executables with no changes?

Steve Ellcey
sellcey@mips.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-24 18:08   ` [PATCH 2/2] MIPS16: MIPS16 support proper Ellcey, Steve
@ 2013-01-25  5:14     ` Maciej W. Rozycki
  2013-01-25 13:59       ` Richard Sandiford
  2013-01-25 22:10       ` Steve Ellcey
  0 siblings, 2 replies; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-25  5:14 UTC (permalink / raw)
  To: Ellcey, Steve; +Cc: libc-alpha, libc-ports, Chung-Lin Tang

Steve,

> After some poking around I think the problem is not the glibc that I built but with crti.o and crtn.o.  If I use
> regular mips32 versions of these crt files and mips16 built versions of everything else (main program, glibc,
> libgcc, etc.) then I can run a simple hello world program, if I use the mips16 versions of crti and crtn I get:
> 
> 
> mips-mti-linux-gnu-gcc -mips32r2 -mips16 '-Wl,--dynamic-linker=/local/home/sellcey/gcc/mips16/sysroot-mips-mti-linux-gnu/mips16/usr/lib/ld-2.17.90.so' '-Wl,-rpath=/local/home/sellcey/gcc/mips16/sysroot-mips-mti-linux-gnu/mips16/usr/lib:/local/home/sellcey/gcc/mips16/install-mips-mti-linux-gnu/mips-mti-linux-gnu/lib/mips16' hi.c -o x
> 
> mips-mti-linux-gnu-qemu -r 2.6.38 ./x
> hi
> qemu: uncaught target signal 11 (Segmentation fault) - core dumped
> 
> Note that it did print 'hi' before getting the signal.
> 
> If I try adding '-static' then I get:
> 
> mips-mti-linux-gnu-gcc -static -mips32r2 -mips16 hi.c -o x
> mips-mti-linux-gnu-qemu -r 2.6.38 ./x
> qemu: uncaught target signal 4 (Illegal instruction) - core dumped
> 
> 
> 
> I was wondering if you have any idea what could be causing this.  Should the standard qemu be able
> to run mips16 executables with no changes?

 I am fairly sure QEMU has issues with MIPS16 code, and I wouldn't be 
surprised if user-mode emulation actually required porting QEMU, rather 
than merely fixing bugs, to support MIPS16 binaries -- it may not be 
prepared to handle the ISA bit at all.

 Have you tried running your code on actual hardware?  This is how we did 
testing of all these changes.

 Please also note that as I mentioned along the patch submission mixing 
execution modes in static constructors or destructors installed as single 
lumps of code (that is with the use of the DT_INIT or DT_FINI dynamic 
tags) cannot be supported.  Can you run `objdump -j .init -j .fini -d' on 
your binary and make sure the disassembly looks right?

 Here's an example of correct MIPS16 code from one of the test cases:

Disassembly of section .init:

00400a2c <_init>:
  400a2c:	f000 6a02 	li	v0,2
  400a30:	f692 0b10 	la	v1,3fa0c0 <_DYNAMIC-0x60dc>
  400a34:	f400 3240 	sll	v0,16
  400a38:	e269      	addu	v0,v1
  400a3a:	64c4      	save	32,ra
  400a3c:	659a      	move	gp,v0
  400a3e:	d204      	sw	v0,16(sp)
  400a40:	f030 9a6c 	lw	v1,-32724(v0)
  400a44:	2304      	beqz	v1,400a4e <_init+0x22>
  400a46:	f030 9a4c 	lw	v0,-32724(v0)
  400a4a:	ea40      	jalr	v0
  400a4c:	653a      	move	t9,v0
  400a4e:	6500      	nop
  400a50:	1a00 036e 	jal	400db8 <frame_dummy>
  400a54:	6500      	nop
  400a56:	1a00 0400 	jal	401000 <__do_global_ctors_aux>
  400a5a:	6500      	nop
  400a5c:	6444      	restore	32,ra
  400a5e:	e8a0      	jrc	ra

Disassembly of section .fini:

00401050 <_fini>:
  401050:	f000 6a02 	li	v0,2
  401054:	f072 0b0c 	la	v1,3fa0c0 <_DYNAMIC-0x60dc>
  401058:	f400 3240 	sll	v0,16
  40105c:	e269      	addu	v0,v1
  40105e:	64c4      	save	32,ra
  401060:	659a      	move	gp,v0
  401062:	d204      	sw	v0,16(sp)
  401064:	1a00 035a 	jal	400d68 <__do_global_dtors_aux>
  401068:	6500      	nop
  40106a:	6444      	restore	32,ra
  40106c:	e8a0      	jrc	ra

  Maciej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-25  5:14     ` Maciej W. Rozycki
@ 2013-01-25 13:59       ` Richard Sandiford
  2013-01-28 22:18         ` Steve Ellcey
  2013-01-25 22:10       ` Steve Ellcey
  1 sibling, 1 reply; 26+ messages in thread
From: Richard Sandiford @ 2013-01-25 13:59 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Ellcey, Steve, libc-alpha, libc-ports, Chung-Lin Tang

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
>> After some poking around I think the problem is not the glibc that I
>> built but with crti.o and crtn.o.  If I use
>> regular mips32 versions of these crt files and mips16 built versions
>> of everything else (main program, glibc,
>> libgcc, etc.) then I can run a simple hello world program, if I use
>> the mips16 versions of crti and crtn I get:
>> 
>> 
>> mips-mti-linux-gnu-gcc -mips32r2 -mips16
>> -Wl,--dynamic-linker=/local/home/sellcey/gcc/mips16/sysroot-mips-mti-linux-gnu/mips16/usr/lib/ld-2.17.90.so'
>> -Wl,-rpath=/local/home/sellcey/gcc/mips16/sysroot-mips-mti-linux-gnu/mips16/usr/lib:/local/home/sellcey/gcc/mips16/install-mips-mti-linux-gnu/mips-mti-linux-gnu/lib/mips16'
>> hi.c -o x
>> 
>> mips-mti-linux-gnu-qemu -r 2.6.38 ./x
>> hi
>> qemu: uncaught target signal 11 (Segmentation fault) - core dumped
>> 
>> Note that it did print 'hi' before getting the signal.
>> 
>> If I try adding '-static' then I get:
>> 
>> mips-mti-linux-gnu-gcc -static -mips32r2 -mips16 hi.c -o x
>> mips-mti-linux-gnu-qemu -r 2.6.38 ./x
>> qemu: uncaught target signal 4 (Illegal instruction) - core dumped
>> 
>> 
>> 
>> I was wondering if you have any idea what could be causing this.
>> Should the standard qemu be able
>> to run mips16 executables with no changes?
>
>  I am fairly sure QEMU has issues with MIPS16 code, and I wouldn't be 
> surprised if user-mode emulation actually required porting QEMU, rather 
> than merely fixing bugs, to support MIPS16 binaries -- it may not be 
> prepared to handle the ISA bit at all.

Never tried user-mode emulation either, but FWIW...

>  Have you tried running your code on actual hardware?  This is how we did 
> testing of all these changes.

...QEMU 1.2 system emulation seems to handle MIPS16 pretty well,
so that might be another alternative.  See:

    http://gcc.gnu.org/ml/gcc-testresults/2013-01/msg02626.html
    http://gcc.gnu.org/ml/gcc-testresults/2013-01/msg02550.html

for some recent results.

Richard

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-25  5:14     ` Maciej W. Rozycki
  2013-01-25 13:59       ` Richard Sandiford
@ 2013-01-25 22:10       ` Steve Ellcey
  2013-01-26  0:32         ` Maciej W. Rozycki
  1 sibling, 1 reply; 26+ messages in thread
From: Steve Ellcey @ 2013-01-25 22:10 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: libc-alpha, libc-ports, Chung-Lin Tang

On Fri, 2013-01-25 at 05:13 +0000, Maciej W. Rozycki wrote:

>  Have you tried running your code on actual hardware?  This is how we did 
> testing of all these changes.

I thought I had a simple program working on my 74K, but I just tried a
test case (hello world compiled statically) and it gave me a bus error.

>  Please also note that as I mentioned along the patch submission mixing 
> execution modes in static constructors or destructors installed as single 
> lumps of code (that is with the use of the DT_INIT or DT_FINI dynamic 
> tags) cannot be supported.  Can you run `objdump -j .init -j .fini -d' on 
> your binary and make sure the disassembly looks right?

Mine looks a bit different, this is the .init and .fini from a
dynamically linked big endian hello world program, I am not sure where
the addiu instructions are coming from.



x:     file format elf32-tradbigmips


Disassembly of section .init:

004004d0 <_init>:
  4004d0:	f000 6a02 	li	v0,2
  4004d4:	f2f0 0b0c 	la	v1,3f87c0 <_DYNAMIC-0x7a08>
  4004d8:	f400 3240 	sll	v0,16
  4004dc:	e269      	addu	v0,v1
  4004de:	64c4      	save	32,ra
  4004e0:	659a      	move	gp,v0
  4004e2:	d204      	sw	v0,16(sp)
  4004e4:	f030 9a64 	lw	v1,-32732(v0)
  4004e8:	2304      	beqz	v1,4004f2 <_init+0x22>
  4004ea:	f030 9a44 	lw	v0,-32732(v0)
  4004ee:	ea40      	jalr	v0
  4004f0:	653a      	move	t9,v0
  4004f2:	6500      	nop
  4004f4:	0411      	addiu	a0,sp,68
  4004f6:	0001      	addiu	s0,sp,4
  4004f8:	0000      	addiu	s0,sp,0
  4004fa:	0000      	addiu	s0,sp,0
  4004fc:	7410      	cmpi	a0,16
  4004fe:	0196      	addiu	s1,sp,600
  400500:	0000      	addiu	s0,sp,0
  400502:	0000      	addiu	s0,sp,0
  400504:	0411      	addiu	a0,sp,68
  400506:	0001      	addiu	s0,sp,4
  400508:	0000      	addiu	s0,sp,0
  40050a:	0000      	addiu	s0,sp,0
  40050c:	7410      	cmpi	a0,16
  40050e:	01c0      	addiu	s1,sp,768
  400510:	0000      	addiu	s0,sp,0
  400512:	0000      	addiu	s0,sp,0
  400514:	6444      	restore	32,ra
  400516:	e8a0      	jrc	ra

Disassembly of section .fini:

00400730 <_fini>:
  400730:	f000 6a02 	li	v0,2
  400734:	f090 0b0c 	la	v1,3f87c0 <_DYNAMIC-0x7a08>
  400738:	f400 3240 	sll	v0,16
  40073c:	e269      	addu	v0,v1
  40073e:	64c4      	save	32,ra
  400740:	659a      	move	gp,v0
  400742:	d204      	sw	v0,16(sp)
  400744:	0411      	addiu	a0,sp,68
  400746:	0001      	addiu	s0,sp,4
  400748:	0000      	addiu	s0,sp,0
  40074a:	0000      	addiu	s0,sp,0
  40074c:	7410      	cmpi	a0,16
  40074e:	0182      	addiu	s1,sp,520
  400750:	0000      	addiu	s0,sp,0
  400752:	0000      	addiu	s0,sp,0
  400754:	6444      	restore	32,ra
  400756:	e8a0      	jrc	ra


Steve Ellcey
sellcey@mips.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-25 22:10       ` Steve Ellcey
@ 2013-01-26  0:32         ` Maciej W. Rozycki
  2013-01-28 17:36           ` Steve Ellcey
  0 siblings, 1 reply; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-26  0:32 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: libc-alpha, libc-ports, Chung-Lin Tang

On Fri, 25 Jan 2013, Steve Ellcey wrote:

> >  Please also note that as I mentioned along the patch submission mixing 
> > execution modes in static constructors or destructors installed as single 
> > lumps of code (that is with the use of the DT_INIT or DT_FINI dynamic 
> > tags) cannot be supported.  Can you run `objdump -j .init -j .fini -d' on 
> > your binary and make sure the disassembly looks right?
> 
> Mine looks a bit different, this is the .init and .fini from a
> dynamically linked big endian hello world program, I am not sure where
> the addiu instructions are coming from.

 You have some standard MIPS code there, this is not ever going to work 
unless we switch to DT_INIT_ARRAY and DT_FINI_ARRAY 
constructors/destructors.  Until then you need to rebuild the relevant 
sources as MIPS16 code.

> x:     file format elf32-tradbigmips
> 
> 
> Disassembly of section .init:
> 
> 004004d0 <_init>:
>   4004d0:	f000 6a02 	li	v0,2
>   4004d4:	f2f0 0b0c 	la	v1,3f87c0 <_DYNAMIC-0x7a08>
>   4004d8:	f400 3240 	sll	v0,16
>   4004dc:	e269      	addu	v0,v1
>   4004de:	64c4      	save	32,ra
>   4004e0:	659a      	move	gp,v0
>   4004e2:	d204      	sw	v0,16(sp)
>   4004e4:	f030 9a64 	lw	v1,-32732(v0)
>   4004e8:	2304      	beqz	v1,4004f2 <_init+0x22>
>   4004ea:	f030 9a44 	lw	v0,-32732(v0)
>   4004ee:	ea40      	jalr	v0
>   4004f0:	653a      	move	t9,v0
>   4004f2:	6500      	nop
>   4004f4:	0411      	addiu	a0,sp,68
>   4004f6:	0001      	addiu	s0,sp,4
>   4004f8:	0000      	addiu	s0,sp,0
>   4004fa:	0000      	addiu	s0,sp,0
>   4004fc:	7410      	cmpi	a0,16
>   4004fe:	0196      	addiu	s1,sp,600
>   400500:	0000      	addiu	s0,sp,0
>   400502:	0000      	addiu	s0,sp,0
>   400504:	0411      	addiu	a0,sp,68
>   400506:	0001      	addiu	s0,sp,4
>   400508:	0000      	addiu	s0,sp,0
>   40050a:	0000      	addiu	s0,sp,0
>   40050c:	7410      	cmpi	a0,16
>   40050e:	01c0      	addiu	s1,sp,768
>   400510:	0000      	addiu	s0,sp,0
>   400512:	0000      	addiu	s0,sp,0
>   400514:	6444      	restore	32,ra
>   400516:	e8a0      	jrc	ra
> 
> Disassembly of section .fini:
> 
> 00400730 <_fini>:
>   400730:	f000 6a02 	li	v0,2
>   400734:	f090 0b0c 	la	v1,3f87c0 <_DYNAMIC-0x7a08>
>   400738:	f400 3240 	sll	v0,16
>   40073c:	e269      	addu	v0,v1
>   40073e:	64c4      	save	32,ra
>   400740:	659a      	move	gp,v0
>   400742:	d204      	sw	v0,16(sp)
>   400744:	0411      	addiu	a0,sp,68
>   400746:	0001      	addiu	s0,sp,4
>   400748:	0000      	addiu	s0,sp,0
>   40074a:	0000      	addiu	s0,sp,0
>   40074c:	7410      	cmpi	a0,16
>   40074e:	0182      	addiu	s1,sp,520
>   400750:	0000      	addiu	s0,sp,0
>   400752:	0000      	addiu	s0,sp,0
>   400754:	6444      	restore	32,ra
>   400756:	e8a0      	jrc	ra

 The odd instructions disassemble as follows when interpreted as standard 
MIPS code:

   0:	04110001 	bal	8
   4:	00000000 	nop
   8:	74100196 	jalx	400658
   c:	00000000 	nop
  10:	04110001 	bal	18
  14:	00000000 	nop
  18:	741001c0 	jalx	400700
  1c:	00000000 	nop

and:

   0:	04110001 	bal	8
   4:	00000000 	nop
   8:	74100182 	jalx	400608
   c:	00000000 	nop

Make sure that you've got your GCC pieces of the MIPS16 multilib right 
(crtbegin.o and crtend.o files).

  Maciej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-26  0:32         ` Maciej W. Rozycki
@ 2013-01-28 17:36           ` Steve Ellcey
  2013-01-28 17:56             ` Steve Ellcey
  2013-01-28 18:58             ` Richard Henderson
  0 siblings, 2 replies; 26+ messages in thread
From: Steve Ellcey @ 2013-01-28 17:36 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: libc-alpha, libc-ports, Chung-Lin Tang

On Sat, 2013-01-26 at 00:31 +0000, Maciej W. Rozycki wrote:
> On Fri, 25 Jan 2013, Steve Ellcey wrote:
> 
> > >  Please also note that as I mentioned along the patch submission mixing 
> > > execution modes in static constructors or destructors installed as single 
> > > lumps of code (that is with the use of the DT_INIT or DT_FINI dynamic 
> > > tags) cannot be supported.  Can you run `objdump -j .init -j .fini -d' on 
> > > your binary and make sure the disassembly looks right?
> > 
> > Mine looks a bit different, this is the .init and .fini from a
> > dynamically linked big endian hello world program, I am not sure where
> > the addiu instructions are coming from.
> 
>  You have some standard MIPS code there, this is not ever going to work 
> unless we switch to DT_INIT_ARRAY and DT_FINI_ARRAY 
> constructors/destructors.  Until then you need to rebuild the relevant 
> sources as MIPS16 code.

OK, I see where this is happening now.  crti (from glibc) is mips16 and
crtbegin (from gcc) is mips32.  crtbegin is mips32 because it uses
CRT_CALL_STATIC_FUNCTION and that has '.nomips16' in it.  I am not sure
how to rewrite CRT_CALL_STATIC_FUNCTION in mips16 to avoid this and it
looks like the codesourcery version of GCC is handling this by making
all .init/.fini code mips32 instead of mips16.  So, should I try to make
crti use a mips32 .init or make crtbegin use a mips16 .init?  I am not
sure which is better.

Steve Ellcey
sellcey@mips.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-28 17:36           ` Steve Ellcey
@ 2013-01-28 17:56             ` Steve Ellcey
  2013-01-28 21:08               ` Maciej W. Rozycki
  2013-01-28 18:58             ` Richard Henderson
  1 sibling, 1 reply; 26+ messages in thread
From: Steve Ellcey @ 2013-01-28 17:56 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: libc-alpha, libc-ports, Chung-Lin Tang

On Mon, 2013-01-28 at 09:35 -0800, Steve Ellcey wrote:

> OK, I see where this is happening now.  crti (from glibc) is mips16 and
> crtbegin (from gcc) is mips32.  crtbegin is mips32 because it uses
> CRT_CALL_STATIC_FUNCTION and that has '.nomips16' in it.  I am not sure
> how to rewrite CRT_CALL_STATIC_FUNCTION in mips16 to avoid this and it
> looks like the codesourcery version of GCC is handling this by making
> all .init/.fini code mips32 instead of mips16.  So, should I try to make
> crti use a mips32 .init or make crtbegin use a mips16 .init?  I am not
> sure which is better.
> 
> Steve Ellcey
> sellcey@mips.com

Following up to my own email, I think I was wrong about codesourcery
using mips32 code in .init/.fini, it looks like they have a GCC patch
to define CRT_CALL_STATIC_FUNCTION differently for mips16/mips32.  I am
going to try and apply that patch to my ToT GCC and see what happens.

Steve Ellcey
sellcey@mips.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-28 17:36           ` Steve Ellcey
  2013-01-28 17:56             ` Steve Ellcey
@ 2013-01-28 18:58             ` Richard Henderson
  2013-01-28 21:06               ` Maciej W. Rozycki
  1 sibling, 1 reply; 26+ messages in thread
From: Richard Henderson @ 2013-01-28 18:58 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: Maciej W. Rozycki, libc-alpha, libc-ports, Chung-Lin Tang

On 01/28/2013 09:35 AM, Steve Ellcey wrote:
> OK, I see where this is happening now.  crti (from glibc) is mips16 and
> crtbegin (from gcc) is mips32.  crtbegin is mips32 because it uses
> CRT_CALL_STATIC_FUNCTION and that has '.nomips16' in it.  I am not sure
> how to rewrite CRT_CALL_STATIC_FUNCTION in mips16 to avoid this and it
> looks like the codesourcery version of GCC is handling this by making
> all .init/.fini code mips32 instead of mips16.  So, should I try to make
> crti use a mips32 .init or make crtbegin use a mips16 .init?  I am not
> sure which is better.

FWIW, I think you're better off considering the .init section to be
mips32 code always, as a part of the ABI.  That way stuff that worked
before continues to work, and no one has to worry about how the
installed toolchain itself is configured.

And of course as you note elsewhere, this is an excellent time to
have new toolchains stop using .init, as DT_INIT_ARRAY has none of
these problems.


r~

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-28 18:58             ` Richard Henderson
@ 2013-01-28 21:06               ` Maciej W. Rozycki
  2013-01-28 21:17                 ` Steve Ellcey
  0 siblings, 1 reply; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-28 21:06 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Steve Ellcey, libc-alpha, libc-ports, Chung-Lin Tang

On Mon, 28 Jan 2013, Richard Henderson wrote:

> > OK, I see where this is happening now.  crti (from glibc) is mips16 and
> > crtbegin (from gcc) is mips32.  crtbegin is mips32 because it uses
> > CRT_CALL_STATIC_FUNCTION and that has '.nomips16' in it.  I am not sure
> > how to rewrite CRT_CALL_STATIC_FUNCTION in mips16 to avoid this and it
> > looks like the codesourcery version of GCC is handling this by making
> > all .init/.fini code mips32 instead of mips16.  So, should I try to make
> > crti use a mips32 .init or make crtbegin use a mips16 .init?  I am not
> > sure which is better.
> 
> FWIW, I think you're better off considering the .init section to be
> mips32 code always, as a part of the ABI.  That way stuff that worked
> before continues to work, and no one has to worry about how the
> installed toolchain itself is configured.

 That may work as a temporary measure for MIPS16 code only, as any 
processor that supports MIPS16 execution must also support standard MIPS 
execution.

 However we have the very same problem with microMIPS code -- that glibc 
supports out of the box thanks to the high level of source compatibility 
the ISA provides and GCC support for which is currently under review.  
There we cannot agree upon using standard MIPS code in .init/.fini because 
we have conflicting objectives to choose from:

1. We want to support mixing standard MIPS and microMIPS code, so we 
   cannot assume all binary modules in a static link will use the same 
   encoding.

2. We want to support processors that only support either instruction 
   encoding, so the encoding of .init/.fini code has to match the encoding 
   of the remaining parts of the module concerned.

And regardless of the scenario chosen we want to keep the same binary 
modules built for either ISA without the need to rebuild any parts of 
them.

> And of course as you note elsewhere, this is an excellent time to
> have new toolchains stop using .init, as DT_INIT_ARRAY has none of
> these problems.

 Given the above I think we need it sooner rather than later.  Who's got 
the power to make it happen?

  Maciej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* RE: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-28 17:56             ` Steve Ellcey
@ 2013-01-28 21:08               ` Maciej W. Rozycki
  0 siblings, 0 replies; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-01-28 21:08 UTC (permalink / raw)
  To: Steve Ellcey; +Cc: libc-alpha, libc-ports, Chung-Lin Tang

On Mon, 28 Jan 2013, Steve Ellcey wrote:

> Following up to my own email, I think I was wrong about codesourcery
> using mips32 code in .init/.fini, it looks like they have a GCC patch
> to define CRT_CALL_STATIC_FUNCTION differently for mips16/mips32.  I am
> going to try and apply that patch to my ToT GCC and see what happens.

 Indeed, I wasn't aware there was an outstanding change there.  Sorry 
about that.  I think for now our best option is to follow Richard's 
suggestion.  I'll take it into account with the upcoming patch update.

  Maciej

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-28 21:06               ` Maciej W. Rozycki
@ 2013-01-28 21:17                 ` Steve Ellcey
  2013-01-29 16:24                   ` Richard Henderson
  0 siblings, 1 reply; 26+ messages in thread
From: Steve Ellcey @ 2013-01-28 21:17 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: Richard Henderson, libc-alpha, libc-ports, Chung-Lin Tang, rdsandiford

On Mon, 2013-01-28 at 21:06 +0000, Maciej W. Rozycki wrote:
> On Mon, 28 Jan 2013, Richard Henderson wrote:
> 
> > And of course as you note elsewhere, this is an excellent time to
> > have new toolchains stop using .init, as DT_INIT_ARRAY has none of
> > these problems.
> 
>  Given the above I think we need it sooner rather than later.  Who's got 
> the power to make it happen?
> 
>   Maciej

Would switching from .init to DT_INIT_ARRAY be an incompatible ABI
change?  I think I remember the GNU linker can handle mixing both types
of sections in one executable but I am not sure if that is right.

I added Richard Sandiford to this email in case he hasn't seen it on the
libc mailing lists.

Steve Ellcey
sellcey@mips.com


^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-25 13:59       ` Richard Sandiford
@ 2013-01-28 22:18         ` Steve Ellcey
  0 siblings, 0 replies; 26+ messages in thread
From: Steve Ellcey @ 2013-01-28 22:18 UTC (permalink / raw)
  To: Richard Sandiford
  Cc: Maciej W. Rozycki, libc-alpha, libc-ports, Chung-Lin Tang

On Fri, 2013-01-25 at 13:59 +0000, Richard Sandiford wrote:
> "Maciej W. Rozycki" <macro@codesourcery.com> writes:
>
> Never tried user-mode emulation either, but FWIW...
> 
> >  Have you tried running your code on actual hardware?  This is how we did 
> > testing of all these changes.
> 
> ...QEMU 1.2 system emulation seems to handle MIPS16 pretty well,
> so that might be another alternative.  See:
> 
>     http://gcc.gnu.org/ml/gcc-testresults/2013-01/msg02626.html
>     http://gcc.gnu.org/ml/gcc-testresults/2013-01/msg02550.html
> 
> for some recent results.
> 
> Richard

FYI: Now that I got my .init section straightened out with a patch to
GCC I was able to use qemu to test mips16.  I ran the entire GCC
testsuite with -mips16 and the only failure I saw that didn't look
familiar to me was:

FAIL: gcc.c-torture/execute/ieee/compare-fp-1.c compilation,  -O2 -flto
-fuse-linker-plugin -fno-fat-lto-objects

This is a segfault coming from the linker, I haven't investigated it
anymore then that yet, but in general the testing looks very good now.

Steve Ellcey
sellcey@mips.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-28 21:17                 ` Steve Ellcey
@ 2013-01-29 16:24                   ` Richard Henderson
  2013-01-29 19:27                     ` Joseph S. Myers
  0 siblings, 1 reply; 26+ messages in thread
From: Richard Henderson @ 2013-01-29 16:24 UTC (permalink / raw)
  To: Steve Ellcey
  Cc: Maciej W. Rozycki, libc-alpha, libc-ports, Chung-Lin Tang, rdsandiford

On 01/28/2013 01:17 PM, Steve Ellcey wrote:
> On Mon, 2013-01-28 at 21:06 +0000, Maciej W. Rozycki wrote:
>> On Mon, 28 Jan 2013, Richard Henderson wrote:
>>
>>> And of course as you note elsewhere, this is an excellent time to
>>> have new toolchains stop using .init, as DT_INIT_ARRAY has none of
>>> these problems.
>>
>>   Given the above I think we need it sooner rather than later.  Who's got
>> the power to make it happen?
>>
>>    Maciej
>
> Would switching from .init to DT_INIT_ARRAY be an incompatible ABI
> change?  I think I remember the GNU linker can handle mixing both types
> of sections in one executable but I am not sure if that is right.
>
> I added Richard Sandiford to this email in case he hasn't seen it on the
> libc mailing lists.

Both gcc and ld have an --enable-initfini-array configuration switch.

Both programs can autodetect the current host setting during native 
builds to preserve the system setting.

I don't believe there's currently a way to force the setting on based on 
a configuration triple, but it ought not be hard to add.


r~

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH 2/2] MIPS16: MIPS16 support proper
  2013-01-29 16:24                   ` Richard Henderson
@ 2013-01-29 19:27                     ` Joseph S. Myers
  0 siblings, 0 replies; 26+ messages in thread
From: Joseph S. Myers @ 2013-01-29 19:27 UTC (permalink / raw)
  To: Richard Henderson
  Cc: Steve Ellcey, Maciej W. Rozycki, libc-alpha, libc-ports,
	Chung-Lin Tang, rdsandiford

On Tue, 29 Jan 2013, Richard Henderson wrote:

> Both gcc and ld have an --enable-initfini-array configuration switch.
> 
> Both programs can autodetect the current host setting during native builds to
> preserve the system setting.
> 
> I don't believe there's currently a way to force the setting on based on a
> configuration triple, but it ought not be hard to add.

FWIW, ARM EABI has used init_array/fini_array for a long time (probably 
since before this configure option existed, and maybe not using the same 
mechanism as the configure option), following an EABI requirement (which 
might have been motivated by Thumb causing the same issues for .init/.fini 
as MIPS16 and microMIPS).

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v2] MIPS: MIPS16 support
  2013-01-23 17:22   ` Joseph S. Myers
  2013-01-24 10:10     ` Chung-Lin Tang
@ 2013-02-20 16:19     ` Maciej W. Rozycki
  2013-02-20 16:29       ` Joseph S. Myers
  1 sibling, 1 reply; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-02-20 16:19 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: libc-ports, Chung-Lin Tang, Steve Ellcey, Richard Sandiford

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)

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v2] MIPS: MIPS16 support
  2013-02-20 16:19     ` [PATCH v2] MIPS: MIPS16 support Maciej W. Rozycki
@ 2013-02-20 16:29       ` Joseph S. Myers
  2013-02-27  1:38         ` [PATCH v3] " Maciej W. Rozycki
  0 siblings, 1 reply; 26+ messages in thread
From: Joseph S. Myers @ 2013-02-20 16:29 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: libc-ports, Chung-Lin Tang, Steve Ellcey, Richard Sandiford

On Wed, 20 Feb 2013, Maciej W. Rozycki wrote:

> 	* sysdeps/mips/fpu_control.h (__fpu_getcw) [__mips16]: New
> 	prototype.
> 	(__fpu_setcw) [__mips16]: Likewise.

Since you've renamed the functions to __mips_fpu_getcw and 
__mips_fpu_setcw, you need to update the ChangeLog entry accordingly.  
The ChangeLog entries may also need updates for other changes in this 
patch version.

> 	* sysdeps/mips/mips32/mips16/fpu/Versions: New file.

Actually you moved the Versions file to the correct place for the symbol 
versions not to depend on whether glibc itself is built as MIPS16.  But 
the contents of the file - and of the libc.abilist changes - need updating 
for the new symbol names.

(Given these inconsistencies, I haven't fully reviewed the rest of the 
patch contents.)

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [PATCH v3] MIPS: MIPS16 support
  2013-02-20 16:29       ` Joseph S. Myers
@ 2013-02-27  1:38         ` Maciej W. Rozycki
  2013-02-27 17:50           ` Joseph S. Myers
  0 siblings, 1 reply; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-02-27  1:38 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: libc-ports, Chung-Lin Tang, Steve Ellcey, Richard Sandiford

On Wed, 20 Feb 2013, Joseph S. Myers wrote:

> (Given these inconsistencies, I haven't fully reviewed the rest of the 
> patch contents.)

 I apologise about the inconsistencies you found, I missed them somehow 
even though I thought I had adjusted all the ChangeLog entries as I had 
been making the respective source changes.

 I have therefore went over the whole change again and verified all 
ChangeLog data is accurate.  And while doing that I actually discovered 
some issues with the getcw/setcw symbols themselves, so I have corrected 
them.

 I have also decided to put as much consistency as possible among all the 
.set nomips16 pseudo-ops added.  Their exact placement has a marginal 
significance as any .align pseudo-op following that actually emits padding 
will use the NOP encoding correct for the newly-selected ISA mode.  
However the absence of any symbol between .set and .align will cause 
`objdump' to decode that instruction stream according to the old mode, 
producing garbled output.  On the other hand for assembly sources where 
.set nomips16 applies throughout I think it's most readable if the 
pseudo-op is located at the top rather than being buried somewhere within 
the first function defined.

 Unfortunately our assembly sources lack formatting consistency, but I 
tried my best.

 Given I made changes I pushed this new version, as the original, through 
a full regression test cycle across the following multilibs (both 
endiannesses each):

* 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),

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

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

 OK to apply?

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

	* sysdeps/mips/abort-instr.h (ABORT_INSTRUCTION) [__mips16]:
	New macro.
	* sysdeps/mips/dl-machine.h (elf_machine_load_address): Add
	MIPS16 version of assembly code.
	(RTLD_START) [__mips16]: New macro.
	* sysdeps/mips/fpu_control.h (__mips_fpu_getcw): New prototype.
	(__mips_fpu_setcw): Likewise.
	(_FPU_GETCW) [__mips16]: New macro.
	(_FPU_SETCW) [__mips16]: Likewise.
	* sysdeps/mips/machine-gmon.h (MCOUNT): Add `.set nomips16'.
	* sysdeps/mips/tls-macros.h (LOAD_GP) [__mips16]: New macro.
	(TLS_GD, TLS_LD, TLS_IE, TLS_LE) [__mips16]: Likewise.
	* sysdeps/mips/bits/atomic.h: Also use __atomic_* builtins with
	GCC 4.7 in MIPS16 code.
	(atomic_compare_and_exchange_val_acq) [__mips16]: New macro.
	(atomic_compare_and_exchange_bool_acq) [__mips16]: Likewise.
	(atomic_exchange_acq) [__mips16]: Likewise.
	(atomic_exchange_and_add) [__mips16]: Likewise.
	(atomic_bit_test_set) [__mips16]: Likewise.
	(atomic_and, atomic_and_val) [__mips16]: Likewise.
	(atomic_or, atomic_or_val) [__mips16]: Likewise.
	(atomic_full_barrier) [__mips16]: Likewise.
	* sysdeps/mips/nptl/tls.h (READ_THREAD_POINTER) [__mips16]:
	Likewise.
	* sysdeps/mips/sys/tas.h (_test_and_set): Add `__nomips16__'
	attribute.
	* sysdeps/unix/mips/sysdep.h (PSEUDO_NOERRNO): Add
	`.set nomips16'.
	(PSEUDO_ERRVAL): Likewise.
	* sysdeps/unix/mips/mips32/sysdep.h (PSEUDO): Likewise.
	* sysdeps/unix/mips/mips64/n32/sysdep.h (PSEUDO): Likewise.
	* sysdeps/unix/mips/mips64/n64/sysdep.h (PSEUDO): Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
	(INTERNAL_SYSCALL, INTERNAL_SYSCALL_NCS) [__mips16]: New macros.
	(INTERNAL_SYSCALL_MIPS16) [__mips16]: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h:
	New file.
	* sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h (PSEUDO):
	Add `.set nomips16'.
	* sysdeps/mips/bsd-_setjmp.S (_setjmp): Likewise.
	* sysdeps/mips/bsd-setjmp.S (setjmp): Likewise.
	* sysdeps/mips/memset.S (memset): Likewise.
	* sysdeps/mips/setjmp.S (__sigsetjmp): Likewise.
	* sysdeps/mips/start.S (ENTRY_POINT) [__mips16]: New function.
	* sysdeps/mips/mips32/crti.S: Add `.set nomips16'.
	* sysdeps/mips/mips32/crtn.S: Likewise.
	* sysdeps/mips/mips64/n32/crti.S: Likewise.
	* sysdeps/mips/mips64/n32/crtn.S: Likewise.
	* sysdeps/mips/mips64/n64/crti.S: Likewise.
	* sysdeps/mips/mips64/n64/crtn.S: Likewise.
	* sysdeps/unix/mips/sysdep.S: Likewise.
	* sysdeps/unix/sysv/linux/mips/clone.S: Likewise.
	* sysdeps/unix/sysv/linux/mips/getcontext.S: Likewise.
	* sysdeps/unix/sysv/linux/mips/makecontext.S: Likewise.
	* sysdeps/unix/sysv/linux/mips/setcontext.S: Likewise.
	* sysdeps/unix/sysv/linux/mips/swapcontext.S: Likewise.
	* sysdeps/unix/sysv/linux/mips/vfork.S: Likewise.
	* sysdeps/mips/__longjmp.c (__longjmp): Rename function to...
	(____longjmp): ... this.  Make static and add `nomips16'
	attribute.
	(__longjmp): New alias.
	* sysdeps/mips/dl-trampoline.c (_dl_runtime_resolve) [__mips16]:
	New function.
	(_dl_runtime_pltresolve): Likewise.
	* sysdeps/mips/setjmp_aux.c (__sigsetjmp_aux): Add `nomips16'
	attribute.
	* sysdeps/mips/fpu/e_sqrt.c (__ieee754_sqrt): Likewise.
	* sysdeps/mips/fpu/e_sqrtf.c (__ieee754_sqrtf): Likewise.
	* sysdeps/unix/sysv/linux/mips/brk.c (__brk): Rewrite in terms
	of INTERNAL_SYSCALL.
	* sysdeps/mips/mips32/fpu/fpu_control.c: New file.
	* sysdeps/mips/mips32/mips16/add_n.c: New file.
	* sysdeps/mips/mips32/mips16/addmul_1.c: New file.
	* sysdeps/mips/mips32/mips16/lshift.c: New file.
	* sysdeps/mips/mips32/mips16/mul_1.c: New file.
	* sysdeps/mips/mips32/mips16/rshift.c: New file.
	* sysdeps/mips/mips32/mips16/sub_n.c: New file.
	* sysdeps/mips/mips32/mips16/submul_1.c: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c:
	New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c:
	New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c:
	New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c:
	New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c:
	New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c:
	New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c:
	New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c:
	New file.
	* sysdeps/mips/mips32/fpu/Versions: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist: New
	file.
	* sysdeps/mips/mips32/mips16/fpu/Makefile: New file.
	* sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile: New file.
	* sysdeps/mips/preconfigure: Handle o32 MIPS16 compilation.

  Maciej

glibc-mips16.diff
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/__longjmp.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/__longjmp.c	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/__longjmp.c	2013-02-26 22:32:04.447786638 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/abort-instr.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/abort-instr.h	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/abort-instr.h	2013-02-26 22:32:04.447786638 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/bits/atomic.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/bits/atomic.h	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/bits/atomic.h	2013-02-26 22:32:04.447786638 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/bsd-_setjmp.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/bsd-_setjmp.S	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/bsd-_setjmp.S	2013-02-26 22:32:04.457754330 +0000
@@ -22,6 +22,8 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
+
 #ifdef __PIC__
 	.option pic2
 #endif
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/bsd-setjmp.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/bsd-setjmp.S	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/bsd-setjmp.S	2013-02-26 22:32:04.457754330 +0000
@@ -22,6 +22,8 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
+
 #ifdef __PIC__
 	.option pic2
 #endif
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/dl-machine.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/dl-machine.h	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/dl-machine.h	2013-02-26 22:32:04.457754330 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/dl-trampoline.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/dl-trampoline.c	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/dl-trampoline.c	2013-02-26 22:32:04.457754330 +0000
@@ -292,9 +292,11 @@ __dl_runtime_resolve (ElfW(Word) sym_ind
 
 #endif
 
+#ifndef __mips16
 asm ("\n\
 	.text\n\
 	.align	2\n\
+	.set	nomips16\n\
 	.globl	_dl_runtime_resolve\n\
 	.type	_dl_runtime_resolve,@function\n\
 	.ent	_dl_runtime_resolve\n\
@@ -351,6 +353,7 @@ _dl_runtime_resolve:\n\
 asm ("\n\
 	.text\n\
 	.align	2\n\
+	.set	nomips16\n\
 	.globl	_dl_runtime_pltresolve\n\
 	.type	_dl_runtime_pltresolve,@function\n\
 	.ent	_dl_runtime_pltresolve\n\
@@ -381,3 +384,130 @@ _dl_runtime_pltresolve:\n\
 	.previous\n\
 ");
 
+#elif _MIPS_SIM == _ABIO32 /* __mips16 */
+/* MIPS16 version, O32 only.  */
+asm ("\n\
+	.text\n\
+	.align	2\n\
+	.set	mips16\n\
+	.globl	_dl_runtime_resolve\n\
+	.type	_dl_runtime_resolve,@function\n\
+	.ent	_dl_runtime_resolve\n\
+_dl_runtime_resolve:\n\
+	.frame	$29, " STRINGXP (ELF_DL_FRAME_SIZE) ", $31\n\
+	# Save arguments and sp value in stack.\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"save	" STRINGXP (ELF_DL_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"addiu	$sp, -" STRINGXP (ELF_DL_FRAME_SIZE) "\n\
+	sw	$7, 32($sp)\n\
+	sw	$6, 28($sp)\n\
+	sw	$5, 24($sp)\n\
+	sw	$4, 20($sp)\n\t"
+# endif
+	"# Preserve caller's $ra, for RESTORE instruction below.\n\
+	move	$5, $15\n\
+	sw	$5, 36($sp)\n\
+	# Compute GP into $2.\n\
+	li	$2, %hi(_gp_disp)\n\
+	addiu	$3, $pc, %lo(_gp_disp)\n\
+	sll	$2, 16\n\
+	addu	$2, $3\n\
+	lw	$3, %got(__dl_runtime_resolve)($2)\n\
+	move	$4, $24\n\
+	addiu	$3, %lo(__dl_runtime_resolve)\n\
+	move	$7, $ra\n\
+	move	$6, $28\n\
+	move	$25, $3\n\
+	jalr	$3\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"restore " STRINGXP(ELF_DL_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"# Restore $ra, move placed further down to hide latency.\n\
+	lw	$4, 36($sp)\n\
+	lw	$5, 24($sp)\n\
+	lw	$6, 28($sp)\n\
+	lw	$7, 32($sp)\n\
+	move	$ra, $4\n\
+	lw	$4, 20($sp)\n\
+	addiu	$sp, " STRINGXP(ELF_DL_FRAME_SIZE) "\n\t"
+# endif
+	"move	$25, $2\n\
+	jr	$2\n\
+	.end	_dl_runtime_resolve\n\
+	.previous\n\
+");
+
+asm ("\n\
+	.text\n\
+	.align	2\n\
+	.set	mips16\n\
+	.globl	_dl_runtime_pltresolve\n\
+	.type	_dl_runtime_pltresolve,@function\n\
+	.ent	_dl_runtime_pltresolve\n\
+_dl_runtime_pltresolve:\n\
+	.frame	$29, " STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $31\n\
+	# Save arguments and sp value in stack.\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"save	" STRINGXP(ELF_DL_PLT_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"addiu	$sp, -" STRINGXP(ELF_DL_PLT_FRAME_SIZE) "\n\
+	sw	$7, 40($sp)\n\
+	sw	$6, 36($sp)\n\
+	sw	$5, 32($sp)\n\
+	sw	$4, 28($sp)\n\t"
+# endif
+	"# Preserve MIPS16 stub function arguments.\n\
+	sw	$3, 20($sp)\n\
+	sw	$2, 16($sp)\n\
+	# Preserve caller's $ra, for RESTORE instruction below.\n\
+	move	$3, $15\n\
+	sw	$3, 44($sp)\n\
+	# Compute GP into $2.\n\
+	li	$2, %hi(_gp_disp)\n\
+	addiu	$3, $pc, %lo(_gp_disp)\n\
+	sll	$2, 16\n\
+	addu	$2, $3\n\
+	# Save GP value in slot.\n\
+	sw	$2, 24($sp)\n\
+	# Load _dl_fixup address.\n\
+	lw	$6, %call16(_dl_fixup)($2)\n\
+	# Load link map address.\n\
+	move	$3, $28\n\
+	lw	$4, " STRINGXP (PTRSIZE) "($3)\n\
+	move	$5, $24\n\
+	sll	$5, " STRINGXP (PTRLOG) " + 1\n\
+	# Call _dl_fixup.\n\
+	move	$25, $6\n\
+	jalr	$6\n\
+	move	$25, $2\n\
+	# Reload GP value into $28.\n\
+	lw	$3, 24($sp)\n\
+	move	$28, $3\n\
+	lw	$3, 16($sp)\n\
+	move	$15, $3\n\
+	lw	$3, 20($sp)\n\t"
+# if _MIPS_ISA >= _MIPS_ISA_MIPS32
+	"restore " STRINGXP (ELF_DL_PLT_FRAME_SIZE) ", $4-$7, $ra\n\t"
+# else
+	"# Restore $ra, move placed further down to hide latency.\n\
+	lw	$4, 44($sp)\n\
+	lw	$5, 32($sp)\n\
+	lw	$6, 36($sp)\n\
+	lw	$7, 40($sp)\n\
+	move	$ra, $4\n\
+	lw	$4, 28($sp)\n\
+	addiu	$sp, " STRINGXP (ELF_DL_PLT_FRAME_SIZE) "\n\t"
+# endif
+	".set	noreorder\n\
+	jr	$2\n\
+	 move	$2, $15\n\
+	.set	reorder\n\
+	.end	_dl_runtime_pltresolve\n\
+	.previous\n\
+");
+
+#else /* __mips16 && _MIPS_SIM != _ABIO32 */
+# error "MIPS16 support for N32/N64 not implemented"
+
+#endif /* __mips16 */
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu/e_sqrt.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/fpu/e_sqrt.c	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu/e_sqrt.c	2013-02-26 22:32:04.457754330 +0000
@@ -22,7 +22,7 @@
 
 #if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
 
-double
+double __attribute__ ((nomips16))
 __ieee754_sqrt (double x)
 {
   double z;
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu/e_sqrtf.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/fpu/e_sqrtf.c	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu/e_sqrtf.c	2013-02-26 22:32:04.457754330 +0000
@@ -22,7 +22,7 @@
 
 #if (_MIPS_ISA >= _MIPS_ISA_MIPS2)
 
-float
+float __attribute__ ((nomips16))
 __ieee754_sqrtf (float x)
 {
   float z;
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu_control.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/fpu_control.h	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/fpu_control.h	2013-02-26 22:32:04.457754330 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/machine-gmon.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/machine-gmon.h	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/machine-gmon.h	2013-02-26 22:32:04.457754330 +0000
@@ -37,6 +37,8 @@ static void __attribute_used__ __mcount 
 #define MCOUNT asm(\
 	".globl _mcount;\n\t" \
 	".align 2;\n\t" \
+	".set push;\n\t" \
+	".set nomips16;\n\t" \
 	".type _mcount,@function;\n\t" \
 	".ent _mcount\n\t" \
         "_mcount:\n\t" \
@@ -67,9 +69,8 @@ static void __attribute_used__ __mcount 
         "addu $29,$29,56;\n\t" \
         "j $31;\n\t" \
         "move $31,$1;\n\t" \
-        ".set reorder;\n\t" \
-        ".set at\n\t" \
-        ".end _mcount");
+	".end _mcount;\n\t" \
+	".set pop");
 
 #else
 
@@ -94,6 +95,8 @@ static void __attribute_used__ __mcount 
 #define MCOUNT asm(\
 	".globl _mcount;\n\t" \
 	".align 3;\n\t" \
+	".set push;\n\t" \
+	".set nomips16;\n\t" \
 	".type _mcount,@function;\n\t" \
 	".ent _mcount\n\t" \
         "_mcount:\n\t" \
@@ -132,8 +135,7 @@ static void __attribute_used__ __mcount 
         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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/memset.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/memset.S	2013-02-26 21:08:22.197807296 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/memset.S	2013-02-26 22:32:04.457754330 +0000
@@ -18,6 +18,7 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
 
 /* void *memset(void *s, int c, size_t n).  */
 
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/crti.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips32/crti.S	2013-02-26 21:08:22.206574592 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/crti.S	2013-02-26 22:32:04.457754330 +0000
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/crtn.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips32/crtn.S	2013-02-26 21:08:22.206574592 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/crtn.S	2013-02-26 22:32:04.457754330 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/fpu/Versions
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/fpu/Versions	2013-02-26 22:32:04.457754330 +0000
@@ -0,0 +1,5 @@
+libc {
+  GLIBC_2.18 {
+    __mips_fpu_getcw; __mips_fpu_setcw;
+  }
+}
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/fpu/fpu_control.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/fpu/fpu_control.c	2013-02-26 22:32:04.457754330 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/add_n.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/add_n.c	2013-02-26 22:32:04.457754330 +0000
@@ -0,0 +1 @@
+#include <stdlib/add_n.c>
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/addmul_1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/addmul_1.c	2013-02-26 22:32:04.467753501 +0000
@@ -0,0 +1 @@
+#include <stdlib/addmul_1.c>
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/fpu/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/fpu/Makefile	2013-02-26 22:32:04.467753501 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/lshift.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/lshift.c	2013-02-26 22:32:04.467753501 +0000
@@ -0,0 +1 @@
+#include <stdlib/lshift.c>
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/mul_1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/mul_1.c	2013-02-26 22:32:04.467753501 +0000
@@ -0,0 +1 @@
+#include <stdlib/mul_1.c>
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/rshift.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/rshift.c	2013-02-26 22:32:04.467753501 +0000
@@ -0,0 +1 @@
+#include <stdlib/rshift.c>
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/sub_n.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/sub_n.c	2013-02-26 22:32:04.467753501 +0000
@@ -0,0 +1 @@
+#include <stdlib/sub_n.c>
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/submul_1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips32/mips16/submul_1.c	2013-02-26 22:32:04.467753501 +0000
@@ -0,0 +1 @@
+#include <stdlib/submul_1.c>
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n32/crti.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips64/n32/crti.S	2013-02-26 21:08:22.206574592 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n32/crti.S	2013-02-26 22:32:04.467753501 +0000
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n32/crtn.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips64/n32/crtn.S	2013-02-26 21:08:22.206574592 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n32/crtn.S	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n64/crti.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips64/n64/crti.S	2013-02-26 21:08:22.206574592 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n64/crti.S	2013-02-26 22:32:04.477753462 +0000
@@ -54,6 +54,8 @@
 	.hidden PREINIT_FUNCTION
 #endif
 
+	.set nomips16
+
 	.section .init,"ax",@progbits
 	.p2align 2
 	.globl _init
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n64/crtn.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/mips64/n64/crtn.S	2013-02-26 21:08:22.206574592 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/mips64/n64/crtn.S	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/nptl/tls.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/nptl/tls.h	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/nptl/tls.h	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/preconfigure
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/preconfigure	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/preconfigure	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/setjmp.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/setjmp.S	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/setjmp.S	2013-02-26 22:32:04.477753462 +0000
@@ -17,6 +17,8 @@
 
 #include <sysdep.h>
 
+	.set	nomips16
+
 /* The function __sigsetjmp_aux saves all the registers, but it can't
    reliably access the stack or frame pointers, so we pass them in as
    extra arguments.  */
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/setjmp_aux.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/setjmp_aux.c	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/setjmp_aux.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/start.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/start.S	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/start.S	2013-02-26 22:32:04.477753462 +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.  */
+	.set	mips16
+ENTRY_POINT:
+# ifdef __PIC__
+	li	$3, %hi(_gp_disp)
+	addiu	$4, $pc, %lo(_gp_disp)
+	sll	$3, 16
+	addu	$3, $4
+	move	$gp, $3
+# else
+	li	$3, %hi(_gp)
+	sll	$3, 16
+	addiu	$3, %lo(_gp)
+	move	$gp, $3
+# endif
+	/* Tie end of stack frames.  */
+	li	$4, 0
+	move	$31, $4
+	/* Create new SP value in $7, including alignment.  */
+	li	$4, 2 * SZREG
+	neg	$4, $4
+	move	$7, $sp
+	and	$7, $4
+	addiu	$7, -32
+	/* Load arguments with original SP.  */
+	lw	$5, 0($sp)
+	addiu	$6, $sp, PTRSIZE
+	/* Update SP.  */
+	move	$sp, $7
+	/* Lay out last arguments, and call __libc_start_main().  */
+# ifdef __PIC__
+	sw	$7, 24($sp)			/* stack_end */
+	lw	$4, %got(__libc_csu_fini)($3)
+	lw	$7, %got(__libc_csu_init)($3)	/* init */
+	sw	$4, 16($sp)			/* fini */
+	lw	$4, %got(main)($3)		/* main */
+	lw	$3, %call16(__libc_start_main)($3)
+	sw	$2, 20($sp)			/* rtld_fini */
+	move	$25, $3
+	jalr	$3
+# else
+	lw	$4, 1f
+	sw	$7, 24($sp)			/* stack_end */
+	lw	$7, 2f				/* init */
+	sw	$4, 16($sp)			/* fini */
+	lw	$4, 3f				/* main */
+	sw	$2, 20($sp)			/* rtld_fini */
+	jal	__libc_start_main
+# endif
+hlt:	b	hlt		/* Crash if somehow it does return.  */
+# ifndef __PIC__
+	.align	2
+1:	.word	__libc_csu_fini
+2:	.word	__libc_csu_init
+3:	.word	main
+# endif
+
+#else /* __mips16 && _MIPS_SIM != _ABIO32 */
+# error "MIPS16 support for N32/N64 not implemented"
+
+#endif /* __mips16 */
+
 /* Define a symbol for the first piece of initialized data.  */
 	.data
 	.globl __data_start
Index: glibc-fsf-trunk-quilt/ports/sysdeps/mips/sys/tas.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/sys/tas.h	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/sys/tas.h	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/mips/tls-macros.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/mips/tls-macros.h	2013-02-26 21:08:22.186821407 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/mips/tls-macros.h	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/mips32/sysdep.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/mips/mips32/sysdep.h	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/mips32/sysdep.h	2013-02-26 22:32:04.477753462 +0000
@@ -24,6 +24,7 @@
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99: la t9,__syscall_error;						      \
   jr t9;								      \
@@ -39,6 +40,7 @@
 #else
 #define PSEUDO(name, syscall_name, args) \
   .set noreorder;							      \
+  .set nomips16;							      \
   .align 2;								      \
   cfi_startproc;							      \
   99: j __syscall_error;						      \
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/mips64/n32/sysdep.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/mips/mips64/n32/sysdep.h	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/mips64/n32/sysdep.h	2013-02-26 22:32:04.477753462 +0000
@@ -26,6 +26,7 @@
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99:;									      \
   .set noat;								      \
@@ -46,6 +47,7 @@
 #define PSEUDO(name, syscall_name, args) \
   .set noreorder;							      \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99: j __syscall_error;						      \
   nop;                                                                        \
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/mips64/n64/sysdep.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/mips/mips64/n64/sysdep.h	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/mips64/n64/sysdep.h	2013-02-26 22:32:04.477753462 +0000
@@ -26,6 +26,7 @@
 #ifdef __PIC__
 #define PSEUDO(name, syscall_name, args) \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99:;									      \
   .set noat;								      \
@@ -46,6 +47,7 @@
 #define PSEUDO(name, syscall_name, args) \
   .set noreorder;							      \
   .align 2;								      \
+  .set nomips16;							      \
   cfi_startproc;							      \
   99: j __syscall_error;						      \
   nop;                                                                        \
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/sysdep.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/mips/sysdep.S	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/sysdep.S	2013-02-26 22:32:04.477753462 +0000
@@ -21,6 +21,8 @@
 #include <bits/errno.h>
 #include <sys/asm.h>
 
+	.set	nomips16
+
 #ifdef _LIBC_REENTRANT
 
 LOCALSZ= 3
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/sysdep.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/mips/sysdep.h	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/mips/sysdep.h	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/brk.c
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/brk.c	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/brk.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/clone.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/clone.S	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/clone.S	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/getcontext.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/getcontext.S	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/getcontext.S	2013-02-26 22:32:04.477753462 +0000
@@ -27,6 +27,7 @@
 /* int getcontext (ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 MASK = 0x00000000
 #ifdef __PIC__
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/makecontext.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/makecontext.S	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/makecontext.S	2013-02-26 22:32:04.477753462 +0000
@@ -27,6 +27,7 @@
 /* int makecontext (ucontext_t *ucp, (void *func) (), int argc, ...) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Makefile	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/Versions	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall.h	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall0.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall1.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall2.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall3.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall4.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall5.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall6.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/mips16/mips16-syscall7.c	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/nptl/libc.abilist	2013-02-26 22:32:04.477753462 +0000
@@ -1401,6 +1401,8 @@ GLIBC_2.17
 GLIBC_2.18
  GLIBC_2.18 A
  __cxa_thread_atexit_impl F
+ __mips_fpu_getcw F
+ __mips_fpu_setcw F
 GLIBC_2.2
  GLIBC_2.2 A
  _Exit F
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/mips32/sysdep.h	2013-02-26 22:32:04.477753462 +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: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h	2013-02-26 21:08:22.397776709 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/nptl/sysdep-cancel.h	2013-02-26 22:32:04.477753462 +0000
@@ -39,6 +39,7 @@
 # undef PSEUDO
 # define PSEUDO(name, syscall_name, args)				      \
       .align 2;								      \
+      .set nomips16;							      \
   L(pseudo_start):							      \
       cfi_startproc;							      \
   99: PSEUDO_ERRJMP							      \
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/setcontext.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/setcontext.S	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/setcontext.S	2013-02-26 22:32:04.477753462 +0000
@@ -27,6 +27,7 @@
 /* int setcontext (const ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/swapcontext.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/swapcontext.S	2013-02-26 21:08:22.176752232 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/swapcontext.S	2013-02-26 22:32:04.487753065 +0000
@@ -27,6 +27,7 @@
 /* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
 
 	.text
+	.set	nomips16
 LOCALSZ = 0
 ARGSZ = 0
 MASK = 0x00000000
Index: glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/vfork.S
===================================================================
--- glibc-fsf-trunk-quilt.orig/ports/sysdeps/unix/sysv/linux/mips/vfork.S	2013-02-26 21:08:22.166795198 +0000
+++ glibc-fsf-trunk-quilt/ports/sysdeps/unix/sysv/linux/mips/vfork.S	2013-02-26 22:32:04.497752188 +0000
@@ -34,6 +34,7 @@
 /* int vfork() */
 
 	.text
+	.set		nomips16
 LOCALSZ= 1
 FRAMESZ= (((NARGSAVE+LOCALSZ)*SZREG)+ALSZ)&ALMASK
 GPOFF= FRAMESZ-(1*SZREG)

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] MIPS: MIPS16 support
  2013-02-27  1:38         ` [PATCH v3] " Maciej W. Rozycki
@ 2013-02-27 17:50           ` Joseph S. Myers
  2013-02-27 23:54             ` Maciej W. Rozycki
  0 siblings, 1 reply; 26+ messages in thread
From: Joseph S. Myers @ 2013-02-27 17:50 UTC (permalink / raw)
  To: Maciej W. Rozycki
  Cc: libc-ports, Chung-Lin Tang, Steve Ellcey, Richard Sandiford

On Wed, 27 Feb 2013, Maciej W. Rozycki wrote:

>  OK to apply?

This patch version is OK.

-- 
Joseph S. Myers
joseph@codesourcery.com

^ permalink raw reply	[flat|nested] 26+ messages in thread

* Re: [PATCH v3] MIPS: MIPS16 support
  2013-02-27 17:50           ` Joseph S. Myers
@ 2013-02-27 23:54             ` Maciej W. Rozycki
  0 siblings, 0 replies; 26+ messages in thread
From: Maciej W. Rozycki @ 2013-02-27 23:54 UTC (permalink / raw)
  To: Joseph S. Myers
  Cc: libc-ports, Chung-Lin Tang, Steve Ellcey, Richard Sandiford

On Wed, 27 Feb 2013, Joseph S. Myers wrote:

> >  OK to apply?
> 
> This patch version is OK.

 Applied now, thanks for going through this review.

  Maciej

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2013-02-27 23:54 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-01-23  4:41 [PATCH 0/2] MIPS16: MIPS16 support Maciej W. Rozycki
2013-01-23  4:41 ` [PATCH 1/2] MIPS16: Allocate GLIBC_2.18 Maciej W. Rozycki
2013-01-23  4:42 ` [PATCH 2/2] MIPS16: MIPS16 support proper Maciej W. Rozycki
2013-01-23 17:22   ` Joseph S. Myers
2013-01-24 10:10     ` Chung-Lin Tang
2013-01-24 13:13       ` Maciej W. Rozycki
2013-01-24 13:56         ` Richard Sandiford
2013-02-20 16:19     ` [PATCH v2] MIPS: MIPS16 support Maciej W. Rozycki
2013-02-20 16:29       ` Joseph S. Myers
2013-02-27  1:38         ` [PATCH v3] " Maciej W. Rozycki
2013-02-27 17:50           ` Joseph S. Myers
2013-02-27 23:54             ` Maciej W. Rozycki
2013-01-24 18:08   ` [PATCH 2/2] MIPS16: MIPS16 support proper Ellcey, Steve
2013-01-25  5:14     ` Maciej W. Rozycki
2013-01-25 13:59       ` Richard Sandiford
2013-01-28 22:18         ` Steve Ellcey
2013-01-25 22:10       ` Steve Ellcey
2013-01-26  0:32         ` Maciej W. Rozycki
2013-01-28 17:36           ` Steve Ellcey
2013-01-28 17:56             ` Steve Ellcey
2013-01-28 21:08               ` Maciej W. Rozycki
2013-01-28 18:58             ` Richard Henderson
2013-01-28 21:06               ` Maciej W. Rozycki
2013-01-28 21:17                 ` Steve Ellcey
2013-01-29 16:24                   ` Richard Henderson
2013-01-29 19:27                     ` Joseph S. Myers

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).