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