/* Assembler macros with cancellation support, Nios II version. Copyright (C) 2003-2016 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 . */ #include #include #ifndef __ASSEMBLER__ # include #endif #if IS_IN (libc) || IS_IN (libpthread) || IS_IN (librt) # undef PSEUDO # define PSEUDO(name, syscall_name, args) \ .type __##syscall_name##_nocancel, @function; \ .globl __##syscall_name##_nocancel; \ __##syscall_name##_nocancel: \ cfi_startproc; \ DO_CALL (syscall_name, args); \ bne r7, zero, SYSCALL_ERROR_LABEL; \ ret; \ cfi_endproc; \ .size __##syscall_name##_nocancel,.-__##syscall_name##_nocancel; \ ENTRY (name) \ SINGLE_THREAD_P(r2); \ bne r2, zero, pseudo_cancel; \ DO_CALL (syscall_name, args); \ bne r7, zero, SYSCALL_ERROR_LABEL; \ ret; \ pseudo_cancel: \ SAVESTK_##args; /* save syscall args and adjust stack */ \ SAVEREG(ra, 0); /* save return address */ \ SAVEREG(r22, 4); /* save GOT pointer */ \ nextpc r22; \ 1: movhi r2, %hiadj(_gp_got - 1b); \ addi r2, r2, %lo(_gp_got - 1b); \ add r22, r22, r2; \ CENABLE; \ callr r3; \ stw r2, 8(sp); /* save mask */ \ LOADARGS_##args; \ movi r2, SYS_ify(syscall_name); \ trap; \ stw r2, 12(sp); /* save syscall result */ \ stw r7, 16(sp); /* save syscall error flag */ \ ldw r4, 8(sp); /* pass mask as argument 1 */ \ CDISABLE; \ callr r3; \ ldw r7, 16(sp); /* restore syscall error flag */ \ ldw r2, 12(sp); /* restore syscall result */ \ ldw ra, 0(sp); /* restore return address */ \ ldw r22, 4(sp); /* restore GOT pointer */ \ RESTORESTK_##args; \ bne r7, zero, SYSCALL_ERROR_LABEL; # undef PSEUDO_END # define PSEUDO_END(sym) \ SYSCALL_ERROR_HANDLER \ END (sym) #define SAVEREG(REG, LOC) stw REG, LOC(sp); cfi_rel_offset (REG, LOC) #define SAVESTK(X) subi sp, sp, X; cfi_adjust_cfa_offset(X) #define SAVESTK_0 SAVESTK(20) #define SAVEARG_1 SAVEREG(r4, 20) #define SAVESTK_1 SAVESTK(24); SAVEARG_1 #define SAVEARG_2 SAVEREG(r5, 24); SAVEARG_1 #define SAVESTK_2 SAVESTK(28); SAVEARG_2 #define SAVEARG_3 SAVEREG(r6, 28); SAVEARG_2 #define SAVESTK_3 SAVESTK(32); SAVEARG_3 #define SAVEARG_4 SAVEREG(r7, 32); SAVEARG_3 #define SAVESTK_4 SAVESTK(36); SAVEARG_4 #define SAVESTK_5 SAVESTK_4 #define SAVESTK_6 SAVESTK_5 #define LOADARGS_0 #define LOADARGS_1 ldw r4, 20(sp) #define LOADARGS_2 LOADARGS_1; ldw r5, 24(sp) #define LOADARGS_3 LOADARGS_2; ldw r6, 28(sp) #define LOADARGS_4 LOADARGS_3; ldw r7, 32(sp) #define LOADARGS_5 LOADARGS_4; ldw r8, 36(sp) #define LOADARGS_6 LOADARGS_5; ldw r9, 40(sp) #define RESTORESTK(X) addi sp, sp, X; cfi_adjust_cfa_offset(-X) #define RESTORESTK_0 RESTORESTK(20) #define RESTORESTK_1 RESTORESTK(24) #define RESTORESTK_2 RESTORESTK(28) #define RESTORESTK_3 RESTORESTK(32) #define RESTORESTK_4 RESTORESTK(36) #define RESTORESTK_5 RESTORESTK(36) #define RESTORESTK_6 RESTORESTK(36) # if IS_IN (libpthread) # define CENABLE ldw r3, %call(__pthread_enable_asynccancel)(r22) # define CDISABLE ldw r3, %call(__pthread_disable_asynccancel)(r22) # elif IS_IN (librt) # define CENABLE ldw r3, %call(__librt_enable_asynccancel)(r22) # define CDISABLE ldw r3, %call(__librt_disable_asynccancel)(r22) # elif IS_IN (libc) # define CENABLE ldw r3, %call(__libc_enable_asynccancel)(r22) # define CDISABLE ldw r3, %call(__libc_disable_asynccancel)(r22) # else # error Unsupported library # endif # ifndef __ASSEMBLER__ # define SINGLE_THREAD_P \ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ header.multiple_threads) \ == 0, 1) # else # define SINGLE_THREAD_P(reg) \ ldw reg, MULTIPLE_THREADS_OFFSET(r23) #endif #elif !defined __ASSEMBLER__ # define SINGLE_THREAD_P 1 # define NO_CANCELLATION 1 #endif #ifndef __ASSEMBLER__ # define RTLD_SINGLE_THREAD_P \ __builtin_expect (THREAD_GETMEM (THREAD_SELF, \ header.multiple_threads) == 0, 1) #endif