diff options
author | Ulrich Drepper <drepper@redhat.com> | 2003-10-15 05:46:00 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2003-10-15 05:46:00 +0000 |
commit | f19a935e1b4e950cacc0446bb003dd6600864d15 (patch) | |
tree | cf9e3899cf43b7c55a4ef8f36889cbe5b7ee015e /sysdeps/unix/sysv/linux | |
parent | 5420f85dbe86b32d36dbf12e1358551d8de762ee (diff) | |
download | glibc-f19a935e1b4e950cacc0446bb003dd6600864d15.tar glibc-f19a935e1b4e950cacc0446bb003dd6600864d15.tar.gz glibc-f19a935e1b4e950cacc0446bb003dd6600864d15.tar.bz2 glibc-f19a935e1b4e950cacc0446bb003dd6600864d15.zip |
Define PSEUDO_ERRVAL, SYSCALL_ERROR_LABEL under all conditions,
INTERNAL_SYSCALL_DECL, INTERNAL_SYSCALL_ERROR_P,
INTERNAL_SYSCALL_ERRNO, INTERNAL_SYSCALL, and undef
JUMPTARGET before use.
[PIC]: Save pic register around syscall.
Diffstat (limited to 'sysdeps/unix/sysv/linux')
-rw-r--r-- | sysdeps/unix/sysv/linux/hppa/sysdep.h | 276 |
1 files changed, 223 insertions, 53 deletions
diff --git a/sysdeps/unix/sysv/linux/hppa/sysdep.h b/sysdeps/unix/sysv/linux/hppa/sysdep.h index 771c55c400..bb5e31dbb9 100644 --- a/sysdeps/unix/sysv/linux/hppa/sysdep.h +++ b/sysdeps/unix/sysv/linux/hppa/sysdep.h @@ -25,12 +25,26 @@ #include "config.h" #ifndef ASM_LINE_SEP -#define ASM_LINE_SEP ; +# define ASM_LINE_SEP ; #endif #undef SYS_ify #define SYS_ify(syscall_name) (__NR_##syscall_name) +#ifdef PIC +/* WARNING: CANNOT BE USED IN A NOP! */ +# define STW_PIC stw %r19, -32(%sr0, %sp) ASM_LINE_SEP +# define LDW_PIC ldw -32(%sr0, %sp), %r19 ASM_LINE_SEP +# define STW_ASM_PIC " copy %%r19, %%r4\n" +# define LDW_ASM_PIC " copy %%r4, %%r19\n" +# define USING_GR4 "%r4", +#else +# define STW_PIC ASM_LINE_SEP +# define LDW_PIC ASM_LINE_SEP +# define STW_ASM_PIC " \n" +# define LDW_ASM_PIC " \n" +# define USING_GR4 +#endif #ifdef __ASSEMBLER__ @@ -77,20 +91,13 @@ .text ASM_LINE_SEP \ .export C_SYMBOL_NAME(name) ASM_LINE_SEP \ .type C_SYMBOL_NAME(name),@function ASM_LINE_SEP \ - C_LABEL(name) \ - CALL_MCOUNT - -#define ret \ - bv 0(2) ASM_LINE_SEP \ - nop - -#define ret_NOERRNO \ - bv 0(2) ASM_LINE_SEP \ - nop + C_LABEL(name) ASM_LINE_SEP \ + CALL_MCOUNT ASM_LINE_SEP #undef END -#define END(name) \ -1: .size C_SYMBOL_NAME(name),1b-C_SYMBOL_NAME(name) +#define END(name) \ +1: ASM_LINE_SEP \ +.size C_SYMBOL_NAME(name),1b-C_SYMBOL_NAME(name) ASM_LINE_SEP /* If compiled for profiling, call `mcount' at the start of each function. */ /* No, don't bother. gcc will put the call in for us. */ @@ -110,27 +117,83 @@ nop */ -#define PSEUDO(name, syscall_name, args) \ - ENTRY (name) \ - DO_CALL(syscall_name, args) ASM_LINE_SEP \ - nop +#define PSEUDO(name, syscall_name, args) \ + ENTRY (name) \ + DO_CALL(syscall_name, args) ASM_LINE_SEP \ + nop ASM_LINE_SEP + +#define ret \ + /* Return value set by ERRNO code */ ASM_LINE_SEP \ + bv 0(2) ASM_LINE_SEP \ + nop ASM_LINE_SEP #undef PSEUDO_END -#define PSEUDO_END(name) \ +#define PSEUDO_END(name) \ END (name) -#define PSEUDO_NOERRNO(name, syscall_name, args) \ - ENTRY (name) \ - DO_CALL(syscall_name, args) ASM_LINE_SEP \ - nop +/* We don't set the errno on the return from the syscall */ +#define PSEUDO_NOERRNO(name, syscall_name, args) \ + ENTRY (name) \ + DO_CALL_NOERRNO(syscall_name, args) ASM_LINE_SEP \ + nop ASM_LINE_SEP + +#define ret_NOERRNO ret #undef PSEUDO_END_NOERRNO -#define PSEUDO_END_NOERRNO(name) \ +#define PSEUDO_END_NOERRNO(name) \ END (name) +/* This has to return the error value */ +#undef PSEUDO_ERRVAL +#define PSEUDO_ERRVAL(name, syscall_name, args) \ + ENTRY(name) \ + DO_CALL_ERRVAL(syscall_name, args) ASM_LINE_SEP \ + nop ASM_LINE_SEP + +#define ret_ERRVAL ret + +#undef PSEUDO_END_ERRVAL +#define PSEUDO_END_ERRVAL(name) \ + END(name) + +#undef JUMPTARGET #define JUMPTARGET(name) name #define SYSCALL_PIC_SETUP /* Nothing. */ + +/* All the syscall assembly macros rely on finding the approriate + SYSCALL_ERROR_LABEL or rather HANDLER. */ + +/* int * __errno_location(void) so you have to store your value + into the return address! */ +#define DEFAULT_SYSCALL_ERROR_HANDLER \ + .import __errno_location,code ASM_LINE_SEP \ + /* branch to errno handler */ ASM_LINE_SEP \ + bl __errno_location,%rp ASM_LINE_SEP + +/* Here are the myriad of configuration options that the above can + work for... what we've done is provide the framework for future + changes if required to each section */ + +#ifdef PIC +# if RTLD_PRIVATE_ERRNO +# define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER +# else /* !RTLD_PRIVATE_ERRNO */ +# if defined _LIBC_REENTRANT +# define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER +# else /* !_LIBC_REENTRANT */ +# define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER +# endif /* _LIBC_REENTRANT */ +# endif /* RTLD_PRIVATE_ERRNO */ +#else +# ifndef _LIBC_REENTRANT +# define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER +# else +# define SYSCALL_ERROR_HANDLER DEFAULT_SYSCALL_ERROR_HANDLER +# endif +#endif + + /* Linux takes system call arguments in registers: syscall number gr20 arg 1 gr26 @@ -159,25 +222,61 @@ #undef DO_CALL #define DO_CALL(syscall_name, args) \ - DOARGS_##args \ + DOARGS_##args ASM_LINE_SEP \ + STW_PIC ASM_LINE_SEP \ + /* Do syscall, delay loads # */ ASM_LINE_SEP \ ble 0x100(%sr2,%r0) ASM_LINE_SEP \ ldi SYS_ify (syscall_name), %r20 ASM_LINE_SEP \ ldi -0x1000,%r1 ASM_LINE_SEP \ cmpb,>>=,n %r1,%ret0,0f ASM_LINE_SEP \ - stw %rp, -20(%sr0,%r30) ASM_LINE_SEP \ - stw %ret0, -24(%sr0,%r30) ASM_LINE_SEP \ - .import __errno_location,code ASM_LINE_SEP \ - bl __errno_location,%rp ASM_LINE_SEP \ - ldo 64(%r30), %r30 ASM_LINE_SEP \ - ldo -64(%r30), %r30 ASM_LINE_SEP \ - ldw -24(%r30), %r26 ASM_LINE_SEP \ + /* save rp or we get lost */ ASM_LINE_SEP \ + stw %rp, -20(%sr0,%sp) ASM_LINE_SEP \ + /* Restore r19 from frame */ ASM_LINE_SEP \ + LDW_PIC ASM_LINE_SEP \ + stw %ret0, -24(%sr0,%sp) ASM_LINE_SEP \ + SYSCALL_ERROR_HANDLER ASM_LINE_SEP \ + /* create frame */ ASM_LINE_SEP \ + ldo 64(%sp), %sp ASM_LINE_SEP \ + ldo -64(%sp), %sp ASM_LINE_SEP \ + /* OPTIMIZE: Don't reload r19 */ ASM_LINE_SEP \ + /* do a -1*syscall_ret0 */ ASM_LINE_SEP \ + ldw -24(%sr0,%sp), %r26 ASM_LINE_SEP \ sub %r0, %r26, %r26 ASM_LINE_SEP \ + /* Store into errno location */ ASM_LINE_SEP \ stw %r26, 0(%sr0,%ret0) ASM_LINE_SEP \ + /* return -1 as error */ ASM_LINE_SEP \ ldo -1(%r0), %ret0 ASM_LINE_SEP \ - ldw -20(%r30), %rp ASM_LINE_SEP \ + ldw -20(%sr0,%sp), %rp ASM_LINE_SEP \ 0: ASM_LINE_SEP \ + UNDOARGS_##args ASM_LINE_SEP + +/* We do nothing with the return, except hand it back to someone else */ +#undef DO_CALL_NOERRNO +#define DO_CALL_NOERRNO(syscall_name, args) \ + DOARGS_##args \ + /* No need to store r19 */ ASM_LINE_SEP \ + ble 0x100(%sr2,%r0) ASM_LINE_SEP \ + ldi SYS_ify (syscall_name), %r20 ASM_LINE_SEP \ + /* Caller will restore r19 */ ASM_LINE_SEP \ UNDOARGS_##args +/* Here, we return the ERRVAL in assembly, note we don't call the + error handler function, but we do 'negate' the return _IF_ + it's an error. Not sure if this is the right semantic. */ + +#undef DO_CALL_ERRVAL +#define DO_CALL_ERRVAL(syscall_name, args) \ + DOARGS_##args ASM_LINE_SEP \ + /* No need to store r19 */ ASM_LINE_SEP \ + ble 0x100(%sr2,%r0) ASM_LINE_SEP \ + ldi SYS_ify (syscall_name), %r20 ASM_LINE_SEP \ + /* Caller will restore r19 */ ASM_LINE_SEP \ + ldi -0x1000,%r1 ASM_LINE_SEP \ + cmpb,>>=,n %r1,%ret0,0f ASM_LINE_SEP \ + sub %r0, %ret0, %ret0 ASM_LINE_SEP \ +0: ASM_LINE_SEP \ + UNDOARGS_##args ASM_LINE_SEP + #define DOARGS_0 /* nothing */ #define DOARGS_1 /* nothing */ #define DOARGS_2 /* nothing */ @@ -198,53 +297,124 @@ #else +/* GCC has to be warned that a syscall may clobber all the ABI + registers listed as "caller-saves", see page 8, Table 2 + in section 2.2.6 of the PA-RISC RUN-TIME architecture + document. However! r28 is the result and will conflict with + the clobber list so it is left out. Also the input arguments + registers r20 -> r26 will conflict with the list so they + are treated specially. Although r19 is clobbered by the syscall + we cannot say this because it would violate ABI, thus we say + r4 is clobbered and use that register to save/restore r19 + across the syscall. */ + +#define CALL_CLOB_REGS "%r1", "%r2", USING_GR4 \ + "%r20", "%r29", "%r31" + #undef INLINE_SYSCALL -#define INLINE_SYSCALL(name, nr, args...) ({ \ +#define INLINE_SYSCALL(name, nr, args...) ({ \ + long __sys_res; \ + { \ + register unsigned long __res asm("r28"); \ + LOAD_ARGS_##nr(args) \ + /* FIXME: HACK stw/ldw r19 around syscall */ \ + asm volatile( \ + STW_ASM_PIC \ + " ble 0x100(%%sr2, %%r0)\n" \ + " ldi %1, %%r20\n" \ + LDW_ASM_PIC \ + : "=r" (__res) \ + : "i" (SYS_ify(name)) ASM_ARGS_##nr \ + : CALL_CLOB_REGS CLOB_ARGS_##nr \ + ); \ + __sys_res = (long)__res; \ + } \ + if ( (unsigned long)__sys_res >= (unsigned long)-4095 ){ \ + __set_errno(-__sys_res); \ + __sys_res = -1; \ + } \ + __sys_res; \ +}) + +/* INTERNAL_SYSCALL_DECL - Allows us to setup some function static + value to use within the context of the syscall + INTERNAL_SYSCALL_ERROR_P - Returns 0 if it wasn't an error, 1 otherwise + You are allowed to use the syscall result (val) and the DECL error variable + to determine what went wrong. + INTERLAL_SYSCALL_ERRNO - Munges the val/err pair into the error number. + In our case we just flip the sign. */ + +#undef INTERNAL_SYSCALL_DECL +#define INTERNAL_SYSCALL_DECL(err) do { } while (0) + +/* Equivalent to (val < 0)&&(val > -4095) which is what we want */ +#undef INTERNAL_SYSCALL_ERROR_P +#define INTERNAL_SYSCALL_ERROR_P(val, err) \ + ((unsigned long)val >= (unsigned long)-4095) + +#undef INTERNAL_SYSCALL_ERRNO +#define INTERNAL_SYSCALL_ERRNO(val, err) (-(val)) + +/* Similar to INLINE_SYSCALL but we don't set errno */ +#undef INTERNAL_SYSCALL +#define INTERNAL_SYSCALL(name, err, nr, args...) \ +({ \ long __sys_res; \ { \ register unsigned long __res asm("r28"); \ LOAD_ARGS_##nr(args) \ + /* FIXME: HACK stw/ldw r19 around syscall */ \ asm volatile( \ - "ble 0x100(%%sr2, %%r0)\n\t" \ - " ldi %1, %%r20" \ + STW_ASM_PIC \ + " ble 0x100(%%sr2, %%r0)\n" \ + " ldi %1, %%r20\n" \ + LDW_ASM_PIC \ : "=r" (__res) \ : "i" (SYS_ify(name)) ASM_ARGS_##nr \ ); \ - __sys_res = __res; \ - } \ - if ((unsigned long)__sys_res >= (unsigned long)-4095) { \ - __set_errno(-__sys_res); \ - __sys_res = -1; \ + : CALL_CLOB_REGS CLOB_ARGS_##nr \ + ); \ + __sys_res = (long)__res; \ } \ __sys_res; \ -}) + }) #define LOAD_ARGS_0() #define LOAD_ARGS_1(r26) \ - register unsigned long __r26 __asm__("r26") = (unsigned long)r26; \ + register unsigned long __r26 __asm__("r26") = (unsigned long)r26; \ LOAD_ARGS_0() #define LOAD_ARGS_2(r26,r25) \ - register unsigned long __r25 __asm__("r25") = (unsigned long)r25; \ + register unsigned long __r25 __asm__("r25") = (unsigned long)r25; \ LOAD_ARGS_1(r26) #define LOAD_ARGS_3(r26,r25,r24) \ - register unsigned long __r24 __asm__("r24") = (unsigned long)r24; \ + register unsigned long __r24 __asm__("r24") = (unsigned long)r24; \ LOAD_ARGS_2(r26,r25) #define LOAD_ARGS_4(r26,r25,r24,r23) \ - register unsigned long __r23 __asm__("r23") = (unsigned long)r23; \ + register unsigned long __r23 __asm__("r23") = (unsigned long)r23; \ LOAD_ARGS_3(r26,r25,r24) #define LOAD_ARGS_5(r26,r25,r24,r23,r22) \ - register unsigned long __r22 __asm__("r22") = (unsigned long)r22; \ + register unsigned long __r22 __asm__("r22") = (unsigned long)r22; \ LOAD_ARGS_4(r26,r25,r24,r23) #define LOAD_ARGS_6(r26,r25,r24,r23,r22,r21) \ - register unsigned long __r21 __asm__("r21") = (unsigned long)r21; \ + register unsigned long __r21 __asm__("r21") = (unsigned long)r21; \ LOAD_ARGS_5(r26,r25,r24,r23,r22) +/* Even with zero args we use r20 for the syscall number */ #define ASM_ARGS_0 -#define ASM_ARGS_1 , "r" (__r26) -#define ASM_ARGS_2 , "r" (__r26), "r" (__r25) -#define ASM_ARGS_3 , "r" (__r26), "r" (__r25), "r" (__r24) -#define ASM_ARGS_4 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23) -#define ASM_ARGS_5 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23), "r" (__r22) -#define ASM_ARGS_6 , "r" (__r26), "r" (__r25), "r" (__r24), "r" (__r23), "r" (__r22), "r" (__r21) +#define ASM_ARGS_1 ASM_ARGS_0, "r" (__r26) +#define ASM_ARGS_2 ASM_ARGS_1, "r" (__r25) +#define ASM_ARGS_3 ASM_ARGS_2, "r" (__r24) +#define ASM_ARGS_4 ASM_ARGS_3, "r" (__r23) +#define ASM_ARGS_5 ASM_ARGS_4, "r" (__r22) +#define ASM_ARGS_6 ASM_ARGS_5, "r" (__r21) + +/* The registers not listed as inputs but clobbered */ +#define CLOB_ARGS_6 +#define CLOB_ARGS_5 CLOB_ARGS_6, "%r21" +#define CLOB_ARGS_4 CLOB_ARGS_5, "%r22" +#define CLOB_ARGS_3 CLOB_ARGS_4, "%r23" +#define CLOB_ARGS_2 CLOB_ARGS_3, "%r24" +#define CLOB_ARGS_1 CLOB_ARGS_2, "%r25" +#define CLOB_ARGS_0 CLOB_ARGS_1, "%r26" #endif /* __ASSEMBLER__ */ |