| /* ----------------------------------------------------------------------- |
| hpux32.S - Copyright (c) 2006 Free Software Foundation, Inc. |
| (c) 2008 Red Hat, Inc. |
| (c) 2016 John David Anglin |
| based on src/pa/linux.S |
| |
| HP-UX PA Foreign Function Interface |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| ``Software''), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be included |
| in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR |
| OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, |
| ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| OTHER DEALINGS IN THE SOFTWARE. |
| ----------------------------------------------------------------------- */ |
| |
| #define LIBFFI_ASM |
| #include <fficonfig.h> |
| #include <ffi.h> |
| |
| .LEVEL 1.1 |
| .SPACE $PRIVATE$ |
| .IMPORT $global$,DATA |
| .IMPORT $$dyncall,MILLICODE |
| .SUBSPA $DATA$ |
| .align 4 |
| |
| /* void ffi_call_pa32(void (*)(char *, extended_cif *), |
| extended_cif *ecif, |
| unsigned bytes, |
| unsigned flags, |
| unsigned *rvalue, |
| void (*fn)(void), |
| ffi_go_closure *closure); |
| */ |
| |
| .export ffi_call_pa32,ENTRY,PRIV_LEV=3 |
| .import ffi_prep_args_pa32,CODE |
| |
| .SPACE $TEXT$ |
| .SUBSPA $CODE$ |
| .align 4 |
| |
| L$FB1 |
| ffi_call_pa32 |
| .proc |
| .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4 |
| .entry |
| stw %rp, -20(%sp) |
| copy %r3, %r1 |
| L$CFI11 |
| copy %sp, %r3 |
| L$CFI12 |
| |
| /* Setup the stack for calling prep_args... |
| We want the stack to look like this: |
| |
| [ Previous stack ] <- %r3 |
| |
| [ 64-bytes register save area ] <- %r4 |
| |
| [ Stack space for actual call, passed as ] <- %arg0 |
| [ arg0 to ffi_prep_args_pa32 ] |
| |
| [ Stack for calling prep_args ] <- %sp |
| */ |
| |
| stwm %r1, 64(%sp) |
| stw %r4, 12(%r3) |
| L$CFI13 |
| copy %sp, %r4 |
| |
| addl %arg2, %r4, %arg0 ; arg stack |
| stw %arg3, -48(%r3) ; save flags we need it later |
| |
| /* Call prep_args: |
| %arg0(stack) -- set up above |
| %arg1(ecif) -- same as incoming param |
| %arg2(bytes) -- same as incoming param */ |
| bl ffi_prep_args_pa32,%r2 |
| ldo 64(%arg0), %sp |
| ldo -64(%sp), %sp |
| |
| /* now %sp should point where %arg0 was pointing. */ |
| |
| /* Load the arguments that should be passed in registers |
| The fp args are loaded by the prep_args function. */ |
| ldw -36(%sp), %arg0 |
| ldw -40(%sp), %arg1 |
| ldw -44(%sp), %arg2 |
| ldw -48(%sp), %arg3 |
| |
| /* in case the function is going to return a structure |
| we need to give it a place to put the result. */ |
| ldw -52(%r3), %ret0 ; %ret0 <- rvalue |
| ldw -56(%r3), %r22 ; %r22 <- function to call |
| ldw -60(%r3), %ret1 ; %ret1 <- closure |
| bl $$dyncall, %r31 ; Call the user function |
| copy %r31, %rp |
| |
| /* Prepare to store the result; we need to recover flags and rvalue. */ |
| ldw -48(%r3), %r21 ; r21 <- flags |
| ldw -52(%r3), %r20 ; r20 <- rvalue |
| |
| /* Store the result according to the return type. The most |
| likely types should come first. */ |
| |
| L$checkint |
| comib,<>,n FFI_TYPE_INT, %r21, L$checkint8 |
| b L$done |
| stw %ret0, 0(%r20) |
| |
| L$checkint8 |
| comib,<>,n FFI_TYPE_UINT8, %r21, L$checkint16 |
| b L$done |
| stb %ret0, 0(%r20) |
| |
| L$checkint16 |
| comib,<>,n FFI_TYPE_UINT16, %r21, L$checkdbl |
| b L$done |
| sth %ret0, 0(%r20) |
| |
| L$checkdbl |
| comib,<>,n FFI_TYPE_DOUBLE, %r21, L$checkfloat |
| b L$done |
| fstd %fr4,0(%r20) |
| |
| L$checkfloat |
| comib,<>,n FFI_TYPE_FLOAT, %r21, L$checkll |
| b L$done |
| fstw %fr4L,0(%r20) |
| |
| L$checkll |
| comib,<>,n FFI_TYPE_UINT64, %r21, L$checksmst2 |
| stw %ret0, 0(%r20) |
| b L$done |
| stw %ret1, 4(%r20) |
| |
| L$checksmst2 |
| comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, L$checksmst3 |
| /* 2-byte structs are returned in ret0 as ????xxyy. */ |
| extru %ret0, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| b L$done |
| stb %ret0, 0(%r20) |
| |
| L$checksmst3 |
| comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, L$checksmst4 |
| /* 3-byte structs are returned in ret0 as ??xxyyzz. */ |
| extru %ret0, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret0, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| b L$done |
| stb %ret0, 0(%r20) |
| |
| L$checksmst4 |
| comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, L$checksmst5 |
| /* 4-byte structs are returned in ret0 as wwxxyyzz. */ |
| extru %ret0, 7, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret0, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret0, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| b L$done |
| stb %ret0, 0(%r20) |
| |
| L$checksmst5 |
| comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, L$checksmst6 |
| /* 5 byte values are returned right justified: |
| ret0 ret1 |
| 5: ??????aa bbccddee */ |
| stbs,ma %ret0, 1(%r20) |
| extru %ret1, 7, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| b L$done |
| stb %ret1, 0(%r20) |
| |
| L$checksmst6 |
| comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, L$checksmst7 |
| /* 6 byte values are returned right justified: |
| ret0 ret1 |
| 6: ????aabb ccddeeff */ |
| extru %ret0, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| stbs,ma %ret0, 1(%r20) |
| extru %ret1, 7, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| b L$done |
| stb %ret1, 0(%r20) |
| |
| L$checksmst7 |
| comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, L$checksmst8 |
| /* 7 byte values are returned right justified: |
| ret0 ret1 |
| 7: ??aabbcc ddeeffgg */ |
| extru %ret0, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret0, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| stbs,ma %ret0, 1(%r20) |
| extru %ret1, 7, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| b L$done |
| stb %ret1, 0(%r20) |
| |
| L$checksmst8 |
| comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, L$done |
| /* 8 byte values are returned right justified: |
| ret0 ret1 |
| 8: aabbccdd eeffgghh */ |
| extru %ret0, 7, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret0, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret0, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| stbs,ma %ret0, 1(%r20) |
| extru %ret1, 7, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 15, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| extru %ret1, 23, 8, %r22 |
| stbs,ma %r22, 1(%r20) |
| stb %ret1, 0(%r20) |
| |
| L$done |
| /* all done, return */ |
| copy %r4, %sp ; pop arg stack |
| ldw 12(%r3), %r4 |
| ldwm -64(%sp), %r3 ; .. and pop stack |
| ldw -20(%sp), %rp |
| bv %r0(%rp) |
| nop |
| .exit |
| .procend |
| L$FE1 |
| |
| /* void ffi_closure_pa32(void); |
| Called with closure argument in %r21 */ |
| |
| .SPACE $TEXT$ |
| .SUBSPA $CODE$ |
| .export ffi_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR |
| .import ffi_closure_inner_pa32,CODE |
| .align 4 |
| L$FB2 |
| ffi_closure_pa32 |
| .proc |
| .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 |
| .entry |
| |
| stw %rp, -20(%sp) |
| copy %r3, %r1 |
| L$CFI21 |
| copy %sp, %r3 |
| L$CFI22 |
| stwm %r1, 64(%sp) |
| |
| /* Put arguments onto the stack and call ffi_closure_inner. */ |
| stw %arg0, -36(%r3) |
| stw %arg1, -40(%r3) |
| stw %arg2, -44(%r3) |
| stw %arg3, -48(%r3) |
| |
| /* Closure type 0. */ |
| copy %r21, %arg0 |
| copy %r0, %arg2 |
| bl ffi_closure_inner_pa32, %r2 |
| copy %r3, %arg1 |
| ldwm -64(%sp), %r3 |
| ldw -20(%sp), %rp |
| ldw -36(%sp), %ret0 |
| bv %r0(%rp) |
| ldw -40(%sp), %ret1 |
| .exit |
| .procend |
| L$FE2: |
| |
| /* void ffi_go_closure_pa32(void); |
| Called with closure argument in %ret1 */ |
| |
| .SPACE $TEXT$ |
| .SUBSPA $CODE$ |
| .export ffi_go_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR |
| .import ffi_closure_inner_pa32,CODE |
| .align 4 |
| L$FB3 |
| ffi_go_closure_pa32 |
| .proc |
| .callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3 |
| .entry |
| |
| stw %rp, -20(%sp) |
| copy %r3, %r1 |
| L$CFI31 |
| copy %sp, %r3 |
| L$CFI32 |
| stwm %r1, 64(%sp) |
| |
| /* Put arguments onto the stack and call ffi_closure_inner. */ |
| stw %arg0, -36(%r3) |
| stw %arg1, -40(%r3) |
| stw %arg2, -44(%r3) |
| stw %arg3, -48(%r3) |
| |
| /* Closure type 1. */ |
| copy %ret1, %arg0 |
| ldi 1, %arg2 |
| bl ffi_closure_inner_pa32, %r2 |
| copy %r3, %arg1 |
| ldwm -64(%sp), %r3 |
| ldw -20(%sp), %rp |
| ldw -36(%sp), %ret0 |
| bv %r0(%rp) |
| ldw -40(%sp), %ret1 |
| .exit |
| .procend |
| L$FE3: |
| |
| .SPACE $PRIVATE$ |
| .SUBSPA $DATA$ |
| |
| .align 4 |
| .EXPORT _GLOBAL__F_ffi_call_pa32,DATA |
| _GLOBAL__F_ffi_call_pa32 |
| L$frame1: |
| .word L$ECIE1-L$SCIE1 ;# Length of Common Information Entry |
| L$SCIE1: |
| .word 0x0 ;# CIE Identifier Tag |
| .byte 0x1 ;# CIE Version |
| .ascii "\0" ;# CIE Augmentation |
| .uleb128 0x1 ;# CIE Code Alignment Factor |
| .sleb128 4 ;# CIE Data Alignment Factor |
| .byte 0x2 ;# CIE RA Column |
| .byte 0xc ;# DW_CFA_def_cfa |
| .uleb128 0x1e |
| .uleb128 0x0 |
| .align 4 |
| L$ECIE1: |
| L$SFDE1: |
| .word L$EFDE1-L$ASFDE1 ;# FDE Length |
| L$ASFDE1: |
| .word L$ASFDE1-L$frame1 ;# FDE CIE offset |
| .word L$FB1 ;# FDE initial location |
| .word L$FE1-L$FB1 ;# FDE address range |
| |
| .byte 0x4 ;# DW_CFA_advance_loc4 |
| .word L$CFI11-L$FB1 |
| .byte 0x83 ;# DW_CFA_offset, column 0x3 |
| .uleb128 0x0 |
| .byte 0x11 ;# DW_CFA_offset_extended_sf; save r2 at [r30-20] |
| .uleb128 0x2 |
| .sleb128 -5 |
| |
| .byte 0x4 ;# DW_CFA_advance_loc4 |
| .word L$CFI12-L$CFI11 |
| .byte 0xd ;# DW_CFA_def_cfa_register = r3 |
| .uleb128 0x3 |
| |
| .byte 0x4 ;# DW_CFA_advance_loc4 |
| .word L$CFI13-L$CFI12 |
| .byte 0x84 ;# DW_CFA_offset, column 0x4 |
| .uleb128 0x3 |
| |
| .align 4 |
| L$EFDE1: |
| |
| L$SFDE2: |
| .word L$EFDE2-L$ASFDE2 ;# FDE Length |
| L$ASFDE2: |
| .word L$ASFDE2-L$frame1 ;# FDE CIE offset |
| .word L$FB2 ;# FDE initial location |
| .word L$FE2-L$FB2 ;# FDE address range |
| .byte 0x4 ;# DW_CFA_advance_loc4 |
| .word L$CFI21-L$FB2 |
| .byte 0x83 ;# DW_CFA_offset, column 0x3 |
| .uleb128 0x0 |
| .byte 0x11 ;# DW_CFA_offset_extended_sf |
| .uleb128 0x2 |
| .sleb128 -5 |
| |
| .byte 0x4 ;# DW_CFA_advance_loc4 |
| .word L$CFI22-L$CFI21 |
| .byte 0xd ;# DW_CFA_def_cfa_register = r3 |
| .uleb128 0x3 |
| |
| .align 4 |
| L$EFDE2: |
| |
| L$SFDE3: |
| .word L$EFDE3-L$ASFDE3 ;# FDE Length |
| L$ASFDE3: |
| .word L$ASFDE3-L$frame1 ;# FDE CIE offset |
| .word L$FB3 ;# FDE initial location |
| .word L$FE3-L$FB3 ;# FDE address range |
| .byte 0x4 ;# DW_CFA_advance_loc4 |
| .word L$CFI31-L$FB3 |
| .byte 0x83 ;# DW_CFA_offset, column 0x3 |
| .uleb128 0x0 |
| .byte 0x11 ;# DW_CFA_offset_extended_sf |
| .uleb128 0x2 |
| .sleb128 -5 |
| |
| .byte 0x4 ;# DW_CFA_advance_loc4 |
| .word L$CFI32-L$CFI31 |
| .byte 0xd ;# DW_CFA_def_cfa_register = r3 |
| .uleb128 0x3 |
| |
| .align 4 |
| L$EFDE3: |