ctypes-commit Mailing List for ctypes (Page 17)
Brought to you by:
theller
You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
(8) |
May
(90) |
Jun
(143) |
Jul
(106) |
Aug
(94) |
Sep
(84) |
Oct
(163) |
Nov
(60) |
Dec
(58) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(128) |
Feb
(79) |
Mar
(227) |
Apr
(192) |
May
(179) |
Jun
(41) |
Jul
(53) |
Aug
(103) |
Sep
(28) |
Oct
(38) |
Nov
(81) |
Dec
(17) |
2006 |
Jan
(184) |
Feb
(111) |
Mar
(188) |
Apr
(67) |
May
(58) |
Jun
(123) |
Jul
(73) |
Aug
|
Sep
|
Oct
(1) |
Nov
|
Dec
|
From: Thomas H. <th...@us...> - 2006-03-03 20:25:24
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/mips In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16345 Added Files: o32.S n32.S ffitarget.h ffi.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: n32.S --- /* ----------------------------------------------------------------------- n32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc. MIPS 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 CYGNUS SOLUTIONS 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> /* Only build this code if we are compiling for n32 */ #if defined(FFI_MIPS_N32) #define callback a0 #define bytes a2 #define flags a3 #define raddr a4 #define fn a5 #define SIZEOF_FRAME ( 8 * FFI_SIZEOF_ARG ) .abicalls .text .align 2 .globl ffi_call_N32 .ent ffi_call_N32 ffi_call_N32: # Prologue SUBU $sp, SIZEOF_FRAME # Frame size REG_S $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Save frame pointer REG_S ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Save return address move $fp, $sp move t9, callback # callback function pointer REG_S bytes, 2*FFI_SIZEOF_ARG($fp) # bytes REG_S flags, 3*FFI_SIZEOF_ARG($fp) # flags REG_S raddr, 4*FFI_SIZEOF_ARG($fp) # raddr REG_S fn, 5*FFI_SIZEOF_ARG($fp) # fn # Allocate at least 4 words in the argstack move v0, bytes bge bytes, 4 * FFI_SIZEOF_ARG, bigger LI v0, 4 * FFI_SIZEOF_ARG b sixteen bigger: ADDU t4, v0, 2 * FFI_SIZEOF_ARG -1 # make sure it is aligned and v0, t4, -2 * FFI_SIZEOF_ARG # to a proper boundry. sixteen: SUBU $sp, $sp, v0 # move the stack pointer to reflect the # arg space ADDU a0, $sp, 0 # 4 * FFI_SIZEOF_ARG ADDU a3, $fp, 3 * FFI_SIZEOF_ARG # Call ffi_prep_args jal t9 # ADDU $sp, $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args # Copy the stack pointer to t9 move t9, $sp # Fix the stack if there are more than 8 64bit slots worth # of arguments. # Load the number of bytes REG_L t6, 2*FFI_SIZEOF_ARG($fp) # Is it bigger than 8 * FFI_SIZEOF_ARG? dadd t7, $0, 8 * FFI_SIZEOF_ARG dsub t8, t6, t7 bltz t8, loadregs add t9, t9, t8 loadregs: REG_L t4, 3*FFI_SIZEOF_ARG($fp) # load the flags word add t6, t4, 0 # and copy it into t6 and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg1_floatp REG_L a0, 0*FFI_SIZEOF_ARG(t9) b arg1_next arg1_floatp: bne t4, FFI_TYPE_FLOAT, arg1_doublep l.s $f12, 0*FFI_SIZEOF_ARG(t9) b arg1_next arg1_doublep: l.d $f12, 0*FFI_SIZEOF_ARG(t9) arg1_next: add t4, t6, 0 SRL t4, 1*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg2_floatp REG_L a1, 1*FFI_SIZEOF_ARG(t9) b arg2_next arg2_floatp: bne t4, FFI_TYPE_FLOAT, arg2_doublep l.s $f13, 1*FFI_SIZEOF_ARG(t9) b arg2_next arg2_doublep: l.d $f13, 1*FFI_SIZEOF_ARG(t9) arg2_next: add t4, t6, 0 SRL t4, 2*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg3_floatp REG_L a2, 2*FFI_SIZEOF_ARG(t9) b arg3_next arg3_floatp: bne t4, FFI_TYPE_FLOAT, arg3_doublep l.s $f14, 2*FFI_SIZEOF_ARG(t9) b arg3_next arg3_doublep: l.d $f14, 2*FFI_SIZEOF_ARG(t9) arg3_next: add t4, t6, 0 SRL t4, 3*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg4_floatp REG_L a3, 3*FFI_SIZEOF_ARG(t9) b arg4_next arg4_floatp: bne t4, FFI_TYPE_FLOAT, arg4_doublep l.s $f15, 3*FFI_SIZEOF_ARG(t9) b arg4_next arg4_doublep: l.d $f15, 3*FFI_SIZEOF_ARG(t9) arg4_next: add t4, t6, 0 SRL t4, 4*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg5_floatp REG_L a4, 4*FFI_SIZEOF_ARG(t9) b arg5_next arg5_floatp: bne t4, FFI_TYPE_FLOAT, arg5_doublep l.s $f16, 4*FFI_SIZEOF_ARG(t9) b arg5_next arg5_doublep: l.d $f16, 4*FFI_SIZEOF_ARG(t9) arg5_next: add t4, t6, 0 SRL t4, 5*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg6_floatp REG_L a5, 5*FFI_SIZEOF_ARG(t9) b arg6_next arg6_floatp: bne t4, FFI_TYPE_FLOAT, arg6_doublep l.s $f17, 5*FFI_SIZEOF_ARG(t9) b arg6_next arg6_doublep: l.d $f17, 5*FFI_SIZEOF_ARG(t9) arg6_next: add t4, t6, 0 SRL t4, 6*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg7_floatp REG_L a6, 6*FFI_SIZEOF_ARG(t9) b arg7_next arg7_floatp: bne t4, FFI_TYPE_FLOAT, arg7_doublep l.s $f18, 6*FFI_SIZEOF_ARG(t9) b arg7_next arg7_doublep: l.d $f18, 6*FFI_SIZEOF_ARG(t9) arg7_next: add t4, t6, 0 SRL t4, 7*FFI_FLAG_BITS and t4, ((1<<FFI_FLAG_BITS)-1) bnez t4, arg8_floatp REG_L a7, 7*FFI_SIZEOF_ARG(t9) b arg8_next arg8_floatp: bne t4, FFI_TYPE_FLOAT, arg8_doublep l.s $f19, 7*FFI_SIZEOF_ARG(t9) b arg8_next arg8_doublep: l.d $f19, 7*FFI_SIZEOF_ARG(t9) arg8_next: callit: # Load the function pointer REG_L t9, 5*FFI_SIZEOF_ARG($fp) # If the return value pointer is NULL, assume no return value. REG_L t5, 4*FFI_SIZEOF_ARG($fp) beqz t5, noretval # Shift the return type flag over SRL t6, 8*FFI_FLAG_BITS bne t6, FFI_TYPE_INT, retfloat jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) REG_S v0, 0(t4) b epilogue retfloat: bne t6, FFI_TYPE_FLOAT, retdouble jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.s $f0, 0(t4) b epilogue retdouble: bne t6, FFI_TYPE_DOUBLE, retstruct_d jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.d $f0, 0(t4) b epilogue retstruct_d: bne t6, FFI_TYPE_STRUCT_D, retstruct_f jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.d $f0, 0(t4) b epilogue retstruct_f: bne t6, FFI_TYPE_STRUCT_F, retstruct_d_d jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.s $f0, 0(t4) b epilogue retstruct_d_d: bne t6, FFI_TYPE_STRUCT_DD, retstruct_f_f jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.d $f0, 0(t4) s.d $f2, 8(t4) b epilogue retstruct_f_f: bne t6, FFI_TYPE_STRUCT_FF, retstruct_d_f jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.s $f0, 0(t4) s.s $f2, 4(t4) b epilogue retstruct_d_f: bne t6, FFI_TYPE_STRUCT_DF, retstruct_f_d jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.d $f0, 0(t4) s.s $f2, 8(t4) b epilogue retstruct_f_d: bne t6, FFI_TYPE_STRUCT_FD, retstruct_small jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) s.s $f0, 0(t4) s.d $f2, 8(t4) b epilogue retstruct_small: bne t6, FFI_TYPE_STRUCT_SMALL, retstruct_small2 jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) REG_S v0, 0(t4) b epilogue retstruct_small2: bne t6, FFI_TYPE_STRUCT_SMALL2, retstruct jal t9 REG_L t4, 4*FFI_SIZEOF_ARG($fp) REG_S v0, 0(t4) REG_S v1, 8(t4) b epilogue retstruct: noretval: jal t9 # Epilogue epilogue: move $sp, $fp REG_L $fp, SIZEOF_FRAME - 2*FFI_SIZEOF_ARG($sp) # Restore frame pointer REG_L ra, SIZEOF_FRAME - 1*FFI_SIZEOF_ARG($sp) # Restore return address ADDU $sp, SIZEOF_FRAME # Fix stack pointer j ra .end ffi_call_N32 #endif --- NEW FILE: o32.S --- /* ----------------------------------------------------------------------- o32.S - Copyright (c) 1996, 1998, 2005 Red Hat, Inc. MIPS 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 CYGNUS SOLUTIONS 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> /* Only build this code if we are compiling for o32 */ #if defined(FFI_MIPS_O32) #define callback a0 #define bytes a2 #define flags a3 #define SIZEOF_FRAME (4 * FFI_SIZEOF_ARG + 2 * FFI_SIZEOF_ARG) #define A3_OFF (SIZEOF_FRAME + 3 * FFI_SIZEOF_ARG) #define FP_OFF (SIZEOF_FRAME - 2 * FFI_SIZEOF_ARG) #define RA_OFF (SIZEOF_FRAME - 1 * FFI_SIZEOF_ARG) .abicalls .text .align 2 .globl ffi_call_O32 .ent ffi_call_O32 ffi_call_O32: $LFB0: # Prologue SUBU $sp, SIZEOF_FRAME # Frame size $LCFI0: REG_S $fp, FP_OFF($sp) # Save frame pointer $LCFI1: REG_S ra, RA_OFF($sp) # Save return address $LCFI2: move $fp, $sp $LCFI3: move t9, callback # callback function pointer REG_S flags, A3_OFF($fp) # flags # Allocate at least 4 words in the argstack LI v0, 4 * FFI_SIZEOF_ARG blt bytes, v0, sixteen ADDU v0, bytes, 7 # make sure it is aligned and v0, -8 # to an 8 byte boundry sixteen: SUBU $sp, v0 # move the stack pointer to reflect the # arg space ADDU a0, $sp, 4 * FFI_SIZEOF_ARG jalr t9 REG_L t0, A3_OFF($fp) # load the flags word SRL t2, t0, 4 # shift our arg info and t0, ((1<<4)-1) # mask out the return type ADDU $sp, 4 * FFI_SIZEOF_ARG # adjust $sp to new args bnez t0, pass_d # make it quick for int REG_L a0, 0*FFI_SIZEOF_ARG($sp) # just go ahead and load the REG_L a1, 1*FFI_SIZEOF_ARG($sp) # four regs. REG_L a2, 2*FFI_SIZEOF_ARG($sp) REG_L a3, 3*FFI_SIZEOF_ARG($sp) b call_it pass_d: bne t0, FFI_ARGS_D, pass_f l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args REG_L a2, 2*FFI_SIZEOF_ARG($sp) # passing a double REG_L a3, 3*FFI_SIZEOF_ARG($sp) b call_it pass_f: bne t0, FFI_ARGS_F, pass_d_d l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args REG_L a1, 1*FFI_SIZEOF_ARG($sp) # passing a float REG_L a2, 2*FFI_SIZEOF_ARG($sp) REG_L a3, 3*FFI_SIZEOF_ARG($sp) b call_it pass_d_d: bne t0, FFI_ARGS_DD, pass_f_f l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing two doubles b call_it pass_f_f: bne t0, FFI_ARGS_FF, pass_d_f l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args l.s $f14, 1*FFI_SIZEOF_ARG($sp) # passing two floats REG_L a2, 2*FFI_SIZEOF_ARG($sp) REG_L a3, 3*FFI_SIZEOF_ARG($sp) b call_it pass_d_f: bne t0, FFI_ARGS_DF, pass_f_d l.d $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args l.s $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float REG_L a3, 3*FFI_SIZEOF_ARG($sp) b call_it pass_f_d: # assume that the only other combination must be float then double # bne t0, FFI_ARGS_F_D, call_it l.s $f12, 0*FFI_SIZEOF_ARG($sp) # load $fp regs from args l.d $f14, 2*FFI_SIZEOF_ARG($sp) # passing double and float call_it: # Load the function pointer REG_L t9, SIZEOF_FRAME + 5*FFI_SIZEOF_ARG($fp) # If the return value pointer is NULL, assume no return value. REG_L t1, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) beqz t1, noretval bne t2, FFI_TYPE_INT, retlonglong jalr t9 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) REG_S v0, 0(t0) b epilogue retlonglong: # Really any 64-bit int, signed or not. bne t2, FFI_TYPE_UINT64, retfloat jalr t9 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) REG_S v1, 4(t0) REG_S v0, 0(t0) b epilogue retfloat: bne t2, FFI_TYPE_FLOAT, retdouble jalr t9 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) s.s $f0, 0(t0) b epilogue retdouble: bne t2, FFI_TYPE_DOUBLE, noretval jalr t9 REG_L t0, SIZEOF_FRAME + 4*FFI_SIZEOF_ARG($fp) s.d $f0, 0(t0) b epilogue noretval: jalr t9 # Epilogue epilogue: move $sp, $fp REG_L $fp, FP_OFF($sp) # Restore frame pointer REG_L ra, RA_OFF($sp) # Restore return address ADDU $sp, SIZEOF_FRAME # Fix stack pointer j ra $LFE0: .end ffi_call_O32 /* ffi_closure_O32. Expects address of the passed-in ffi_closure in t0. Stores any arguments passed in registers onto the stack, then calls ffi_closure_mips_inner_O32, which then decodes them. Stack layout: 14 - Start of parameters, original sp 13 - ra save 12 - fp save 11 - $16 (s0) save 10 - cprestore 9 - return value high (v1) 8 - return value low (v0) 7 - f14 (le high, be low) 6 - f14 (le low, be high) 5 - f12 (le high, be low) 4 - f12 (le low, be high) 3 - Called function a3 save 2 - Called function a2 save 1 - Called function a1 save 0 - Called function a0 save our sp, fp point here */ #define SIZEOF_FRAME2 (14 * FFI_SIZEOF_ARG) #define A3_OFF2 (SIZEOF_FRAME2 + 3 * FFI_SIZEOF_ARG) #define A2_OFF2 (SIZEOF_FRAME2 + 2 * FFI_SIZEOF_ARG) #define A1_OFF2 (SIZEOF_FRAME2 + 1 * FFI_SIZEOF_ARG) #define A0_OFF2 (SIZEOF_FRAME2 + 0 * FFI_SIZEOF_ARG) #define RA_OFF2 (SIZEOF_FRAME2 - 1 * FFI_SIZEOF_ARG) #define FP_OFF2 (SIZEOF_FRAME2 - 2 * FFI_SIZEOF_ARG) #define S0_OFF2 (SIZEOF_FRAME2 - 3 * FFI_SIZEOF_ARG) #define GP_OFF2 (SIZEOF_FRAME2 - 4 * FFI_SIZEOF_ARG) #define V1_OFF2 (SIZEOF_FRAME2 - 5 * FFI_SIZEOF_ARG) #define V0_OFF2 (SIZEOF_FRAME2 - 6 * FFI_SIZEOF_ARG) #define FA_1_1_OFF2 (SIZEOF_FRAME2 - 7 * FFI_SIZEOF_ARG) #define FA_1_0_OFF2 (SIZEOF_FRAME2 - 8 * FFI_SIZEOF_ARG) #define FA_0_1_OFF2 (SIZEOF_FRAME2 - 9 * FFI_SIZEOF_ARG) #define FA_0_0_OFF2 (SIZEOF_FRAME2 - 10 * FFI_SIZEOF_ARG) .text .align 2 .globl ffi_closure_O32 .ent ffi_closure_O32 ffi_closure_O32: $LFB1: # Prologue .frame $fp, SIZEOF_FRAME2, ra .set noreorder .cpload t9 .set reorder SUBU $sp, SIZEOF_FRAME2 .cprestore GP_OFF2 $LCFI4: REG_S $16, S0_OFF2($sp) # Save s0 REG_S $fp, FP_OFF2($sp) # Save frame pointer REG_S ra, RA_OFF2($sp) # Save return address $LCFI6: move $fp, $sp $LCFI7: # Store all possible argument registers. If there are more than # four arguments, then they are stored above where we put a3. REG_S a0, A0_OFF2($fp) REG_S a1, A1_OFF2($fp) REG_S a2, A2_OFF2($fp) REG_S a3, A3_OFF2($fp) # Load ABI enum to s0 REG_L $16, 20($8) # cif pointer follows tramp. REG_L $16, 0($16) # abi is first member. li $13, 1 # FFI_O32 bne $16, $13, 1f # Skip fp save if FFI_O32_SOFT_FLOAT # Store all possible float/double registers. s.d $f12, FA_0_0_OFF2($fp) s.d $f14, FA_1_0_OFF2($fp) 1: # Call ffi_closure_mips_inner_O32 to do the work. la t9, ffi_closure_mips_inner_O32 move a0, $8 # Pointer to the ffi_closure addu a1, $fp, V0_OFF2 addu a2, $fp, A0_OFF2 addu a3, $fp, FA_0_0_OFF2 jalr t9 # Load the return value into the appropriate register. move $8, $2 li $9, FFI_TYPE_VOID beq $8, $9, closure_done li $13, 1 # FFI_O32 bne $16, $13, 1f # Skip fp restore if FFI_O32_SOFT_FLOAT li $9, FFI_TYPE_FLOAT l.s $f0, V0_OFF2($fp) beq $8, $9, closure_done li $9, FFI_TYPE_DOUBLE l.d $f0, V0_OFF2($fp) beq $8, $9, closure_done 1: REG_L $3, V1_OFF2($fp) REG_L $2, V0_OFF2($fp) closure_done: # Epilogue move $sp, $fp REG_L $16, S0_OFF2($sp) # Restore s0 REG_L $fp, FP_OFF2($sp) # Restore frame pointer REG_L ra, RA_OFF2($sp) # Restore return address ADDU $sp, SIZEOF_FRAME2 j ra $LFE1: .end ffi_closure_O32 /* DWARF-2 unwind info. */ .section .eh_frame,"a",@progbits $Lframe0: .4byte $LECIE0-$LSCIE0 # Length of Common Information Entry $LSCIE0: .4byte 0x0 # CIE Identifier Tag .byte 0x1 # CIE Version .ascii "zR\0" # CIE Augmentation .uleb128 0x1 # CIE Code Alignment Factor .sleb128 4 # CIE Data Alignment Factor .byte 0x1f # CIE RA Column .uleb128 0x1 # Augmentation size .byte 0x00 # FDE Encoding (absptr) .byte 0xc # DW_CFA_def_cfa .uleb128 0x1d .uleb128 0x0 .align 2 $LECIE0: $LSFDE0: .4byte $LEFDE0-$LASFDE0 # FDE Length $LASFDE0: .4byte $LASFDE0-$Lframe0 # FDE CIE offset .4byte $LFB0 # FDE initial location .4byte $LFE0-$LFB0 # FDE address range .uleb128 0x0 # Augmentation size .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI0-$LFB0 .byte 0xe # DW_CFA_def_cfa_offset .uleb128 0x18 .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI2-$LCFI0 .byte 0x11 # DW_CFA_offset_extended_sf .uleb128 0x1e # $fp .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) .byte 0x11 # DW_CFA_offset_extended_sf .uleb128 0x1f # $ra .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI3-$LCFI2 .byte 0xc # DW_CFA_def_cfa .uleb128 0x1e .uleb128 0x18 .align 2 $LEFDE0: $LSFDE1: .4byte $LEFDE1-$LASFDE1 # FDE Length $LASFDE1: .4byte $LASFDE1-$Lframe0 # FDE CIE offset .4byte $LFB1 # FDE initial location .4byte $LFE1-$LFB1 # FDE address range .uleb128 0x0 # Augmentation size .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI4-$LFB1 .byte 0xe # DW_CFA_def_cfa_offset .uleb128 0x38 .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI6-$LCFI4 .byte 0x11 # DW_CFA_offset_extended_sf .uleb128 0x10 # $16 .sleb128 -3 # SIZEOF_FRAME2 - 3*FFI_SIZEOF_ARG($sp) .byte 0x11 # DW_CFA_offset_extended_sf .uleb128 0x1e # $fp .sleb128 -2 # SIZEOF_FRAME2 - 2*FFI_SIZEOF_ARG($sp) .byte 0x11 # DW_CFA_offset_extended_sf .uleb128 0x1f # $ra .sleb128 -1 # SIZEOF_FRAME2 - 1*FFI_SIZEOF_ARG($sp) .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI7-$LCFI6 .byte 0xc # DW_CFA_def_cfa .uleb128 0x1e .uleb128 0x38 .align 2 $LEFDE1: #endif --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1996 Red Hat, Inc. MIPS 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> #include <sys/cachectl.h> #if _MIPS_SIM == _ABIN32 #define FIX_ARGP \ FFI_ASSERT(argp <= &stack[bytes]); \ if (argp == &stack[bytes]) \ { \ argp = stack; \ ffi_stop_here(); \ } #else #define FIX_ARGP #endif /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ static void ffi_prep_args(char *stack, extended_cif *ecif, int bytes, int flags) { int i; void **p_argv; char *argp; ffi_type **p_arg; #if _MIPS_SIM == _ABIN32 /* If more than 8 double words are used, the remainder go on the stack. We reorder stuff on the stack here to support this easily. */ if (bytes > 8 * sizeof(ffi_arg)) argp = &stack[bytes - (8 * sizeof(ffi_arg))]; else argp = stack; #else argp = stack; #endif memset(stack, 0, bytes); #if _MIPS_SIM == _ABIN32 if ( ecif->cif->rstruct_flag != 0 ) #else if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) #endif { *(ffi_arg *) argp = (ffi_arg) ecif->rvalue; argp += sizeof(ffi_arg); FIX_ARGP; } p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++) { size_t z; unsigned int a; /* Align if necessary. */ a = (*p_arg)->alignment; if (a < sizeof(ffi_arg)) a = sizeof(ffi_arg); if ((a - 1) & (unsigned int) argp) { argp = (char *) ALIGN(argp, a); FIX_ARGP; } z = (*p_arg)->size; if (z <= sizeof(ffi_arg)) { z = sizeof(ffi_arg); switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(ffi_arg *)argp = *(SINT8 *)(* p_argv); break; case FFI_TYPE_UINT8: *(ffi_arg *)argp = *(UINT8 *)(* p_argv); break; case FFI_TYPE_SINT16: *(ffi_arg *)argp = *(SINT16 *)(* p_argv); break; case FFI_TYPE_UINT16: *(ffi_arg *)argp = *(UINT16 *)(* p_argv); break; case FFI_TYPE_SINT32: *(ffi_arg *)argp = *(SINT32 *)(* p_argv); break; case FFI_TYPE_UINT32: case FFI_TYPE_POINTER: *(ffi_arg *)argp = *(UINT32 *)(* p_argv); break; /* This can only happen with 64bit slots. */ case FFI_TYPE_FLOAT: *(float *) argp = *(float *)(* p_argv); break; /* Handle small structures. */ case FFI_TYPE_STRUCT: default: memcpy(argp, *p_argv, (*p_arg)->size); break; } } else { #if _MIPS_SIM == _ABIO32 memcpy(argp, *p_argv, z); #else { unsigned end = (unsigned) argp+z; unsigned cap = (unsigned) stack+bytes; /* Check if the data will fit within the register space. Handle it if it doesn't. */ if (end <= cap) memcpy(argp, *p_argv, z); else { unsigned portion = end - cap; memcpy(argp, *p_argv, portion); argp = stack; memcpy(argp, (void*)((unsigned)(*p_argv)+portion), z - portion); } } #endif } p_argv++; argp += z; FIX_ARGP; } } #if _MIPS_SIM == _ABIN32 /* The n32 spec says that if "a chunk consists solely of a double float field (but not a double, which is part of a union), it is passed in a floating point register. Any other chunk is passed in an integer register". This code traverses structure definitions and generates the appropriate flags. */ unsigned calc_n32_struct_flags(ffi_type *arg, unsigned *shift) { unsigned flags = 0; unsigned index = 0; ffi_type *e; while (e = arg->elements[index]) { if (e->type == FFI_TYPE_DOUBLE) { flags += (FFI_TYPE_DOUBLE << *shift); *shift += FFI_FLAG_BITS; } else if (e->type == FFI_TYPE_STRUCT) flags += calc_n32_struct_flags(e, shift); else *shift += FFI_FLAG_BITS; index++; } return flags; } unsigned calc_n32_return_struct_flags(ffi_type *arg) { unsigned flags = 0; unsigned index = 0; unsigned small = FFI_TYPE_SMALLSTRUCT; ffi_type *e; /* Returning structures under n32 is a tricky thing. A struct with only one or two floating point fields is returned in $f0 (and $f2 if necessary). Any other struct results at most 128 bits are returned in $2 (the first 64 bits) and $3 (remainder, if necessary). Larger structs are handled normally. */ if (arg->size > 16) return 0; if (arg->size > 8) small = FFI_TYPE_SMALLSTRUCT2; e = arg->elements[0]; if (e->type == FFI_TYPE_DOUBLE) flags = FFI_TYPE_DOUBLE << FFI_FLAG_BITS; else if (e->type == FFI_TYPE_FLOAT) flags = FFI_TYPE_FLOAT << FFI_FLAG_BITS; if (flags && (e = arg->elements[1])) { if (e->type == FFI_TYPE_DOUBLE) flags += FFI_TYPE_DOUBLE; else if (e->type == FFI_TYPE_FLOAT) flags += FFI_TYPE_FLOAT; else return small; if (flags && (arg->elements[2])) { /* There are three arguments and the first two are floats! This must be passed the old way. */ return small; } } else if (!flags) return small; return flags; } #endif /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { cif->flags = 0; #if _MIPS_SIM == _ABIO32 /* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT * does not have special handling for floating point args. */ if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32) { if (cif->nargs > 0) { switch ((cif->arg_types)[0]->type) { case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags += (cif->arg_types)[0]->type; break; default: break; } if (cif->nargs > 1) { /* Only handle the second argument if the first is a float or double. */ if (cif->flags) { switch ((cif->arg_types)[1]->type) { case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS; break; default: break; } } } } } /* Set the return type flag */ if (cif->abi == FFI_O32_SOFT_FLOAT) { switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_DOUBLE: cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); break; case FFI_TYPE_FLOAT: default: cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); break; } } else { /* FFI_O32 */ switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); break; default: cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); break; } } #endif #if _MIPS_SIM == _ABIN32 /* Set the flags necessary for N32 processing */ { unsigned shift = 0; unsigned count = (cif->nargs < 8) ? cif->nargs : 8; unsigned index = 0; unsigned struct_flags = 0; if (cif->rtype->type == FFI_TYPE_STRUCT) { struct_flags = calc_n32_return_struct_flags(cif->rtype); if (struct_flags == 0) { /* This means that the structure is being passed as a hidden argument */ shift = FFI_FLAG_BITS; count = (cif->nargs < 7) ? cif->nargs : 7; cif->rstruct_flag = !0; } else cif->rstruct_flag = 0; } else cif->rstruct_flag = 0; while (count-- > 0) { switch ((cif->arg_types)[index]->type) { case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags += ((cif->arg_types)[index]->type << shift); shift += FFI_FLAG_BITS; break; case FFI_TYPE_STRUCT: cif->flags += calc_n32_struct_flags((cif->arg_types)[index], &shift); break; default: shift += FFI_FLAG_BITS; } index++; } /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_STRUCT: { if (struct_flags == 0) { /* The structure is returned through a hidden first argument. Do nothing, 'cause FFI_TYPE_VOID is 0 */ } else { /* The structure is returned via some tricky mechanism */ cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8)); } break; } case FFI_TYPE_VOID: /* Do nothing, 'cause FFI_TYPE_VOID is 0 */ break; case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8); break; default: cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); break; } } #endif return FFI_OK; } /* Low level routine for calling O32 functions */ extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), extended_cif *, unsigned, unsigned, unsigned *, void (*)()); /* Low level routine for calling N32 functions */ extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), extended_cif *, unsigned, unsigned, unsigned *, void (*)()); void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) ecif.rvalue = alloca(cif->rtype->size); else ecif.rvalue = rvalue; switch (cif->abi) { #if _MIPS_SIM == _ABIO32 case FFI_O32: case FFI_O32_SOFT_FLOAT: ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif #if _MIPS_SIM == _ABIN32 case FFI_N32: ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; #endif default: FFI_ASSERT(0); break; } } #if FFI_CLOSURES /* N32 not implemented yet, FFI_CLOSURES not defined */ #if defined(FFI_MIPS_O32) extern void ffi_closure_O32(void); #endif /* FFI_MIPS_O32 */ ffi_status ffi_prep_closure (ffi_closure *closure, ffi_cif *cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) { unsigned int *tramp = (unsigned int *) &closure->tramp[0]; unsigned int fn; unsigned int ctx = (unsigned int) closure; #if defined(FFI_MIPS_O32) FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT); fn = (unsigned int) ffi_closure_O32; #else /* FFI_MIPS_N32 */ FFI_ASSERT(cif->abi == FFI_N32); FFI_ASSERT(!"not implemented"); #endif /* FFI_MIPS_O32 */ tramp[0] = 0x3c190000 | (fn >> 16); /* lui $25,high(fn) */ tramp[1] = 0x37390000 | (fn & 0xffff); /* ori $25,low(fn) */ tramp[2] = 0x3c080000 | (ctx >> 16); /* lui $8,high(ctx) */ tramp[3] = 0x03200008; /* jr $25 */ tramp[4] = 0x35080000 | (ctx & 0xffff); /* ori $8,low(ctx) */ closure->cif = cif; closure->fun = fun; closure->user_data = user_data; /* XXX this is available on Linux, but anything else? */ cacheflush (tramp, FFI_TRAMPOLINE_SIZE, ICACHE); return FFI_OK; } /* * Decodes the arguments to a function, which will be stored on the * stack. AR is the pointer to the beginning of the integer arguments * (and, depending upon the arguments, some floating-point arguments * as well). FPR is a pointer to the area where floating point * registers have been saved, if any. * * RVALUE is the location where the function return value will be * stored. CLOSURE is the prepared closure to invoke. * * This function should only be called from assembly, which is in * turn called from a trampoline. * * Returns the function return type. * * Based on the similar routine for sparc. */ int ffi_closure_mips_inner_O32 (ffi_closure *closure, void *rvalue, ffi_arg *ar, double *fpr) { ffi_cif *cif; void **avaluep; ffi_arg *avalue; ffi_type **arg_types; int i, avn, argn, seen_int; cif = closure->cif; avalue = alloca (cif->nargs * sizeof (ffi_arg)); avaluep = alloca (cif->nargs * sizeof (ffi_arg)); seen_int = (cif->abi == FFI_O32_SOFT_FLOAT); argn = 0; if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT) { rvalue = (void *) ar[0]; argn = 1; } i = 0; avn = cif->nargs; arg_types = cif->arg_types; while (i < avn) { if (i < 2 && !seen_int && (arg_types[i]->type == FFI_TYPE_FLOAT || arg_types[i]->type == FFI_TYPE_DOUBLE)) { #ifdef __MIPSEB__ if (arg_types[i]->type == FFI_TYPE_FLOAT) avaluep[i] = ((char *) &fpr[i]) + sizeof (float); else #endif avaluep[i] = (char *) &fpr[i]; } else { if (arg_types[i]->alignment == 8 && (argn & 0x1)) argn++; switch (arg_types[i]->type) { case FFI_TYPE_SINT8: avaluep[i] = &avalue[i]; *(SINT8 *) &avalue[i] = (SINT8) ar[argn]; break; case FFI_TYPE_UINT8: avaluep[i] = &avalue[i]; *(UINT8 *) &avalue[i] = (UINT8) ar[argn]; break; case FFI_TYPE_SINT16: avaluep[i] = &avalue[i]; *(SINT16 *) &avalue[i] = (SINT16) ar[argn]; break; case FFI_TYPE_UINT16: avaluep[i] = &avalue[i]; *(UINT16 *) &avalue[i] = (UINT16) ar[argn]; break; default: avaluep[i] = (char *) &ar[argn]; break; } seen_int = 1; } argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; i++; } /* Invoke the closure. */ (closure->fun) (cif, rvalue, avaluep, closure->user_data); if (cif->abi == FFI_O32_SOFT_FLOAT) { switch (cif->rtype->type) { case FFI_TYPE_FLOAT: return FFI_TYPE_INT; case FFI_TYPE_DOUBLE: return FFI_TYPE_UINT64; default: return cif->rtype->type; } } else { return cif->rtype->type; } } #endif /* FFI_CLOSURES */ --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for MIPS. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #if !defined(_MIPS_SIM) -- something is very wrong -- #else # if (_MIPS_SIM==_ABIN32 && defined(_ABIN32)) || (_MIPS_SIM==_ABI64 && defined(_ABI64)) # define FFI_MIPS_N32 # else # if (_MIPS_SIM==_ABIO32 && defined(_ABIO32)) # define FFI_MIPS_O32 # else -- this is an unsupported platform -- # endif # endif #endif #ifdef FFI_MIPS_O32 /* O32 stack frames have 32bit integer args */ #define FFI_SIZEOF_ARG 4 #else /* N32 and N64 frames have 64bit integer args */ #define FFI_SIZEOF_ARG 8 #endif #define FFI_FLAG_BITS 2 /* SGI's strange assembler requires that we multiply by 4 rather than shift left by FFI_FLAG_BITS */ #define FFI_ARGS_D FFI_TYPE_DOUBLE #define FFI_ARGS_F FFI_TYPE_FLOAT #define FFI_ARGS_DD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_DOUBLE #define FFI_ARGS_FF FFI_TYPE_FLOAT * 4 + FFI_TYPE_FLOAT #define FFI_ARGS_FD FFI_TYPE_DOUBLE * 4 + FFI_TYPE_FLOAT #define FFI_ARGS_DF FFI_TYPE_FLOAT * 4 + FFI_TYPE_DOUBLE /* Needed for N32 structure returns */ #define FFI_TYPE_SMALLSTRUCT FFI_TYPE_UINT8 #define FFI_TYPE_SMALLSTRUCT2 FFI_TYPE_SINT8 #if 0 /* The SGI assembler can't handle this.. */ #define FFI_TYPE_STRUCT_DD (( FFI_ARGS_DD ) << 4) + FFI_TYPE_STRUCT /* (and so on) */ #else /* ...so we calculate these by hand! */ #define FFI_TYPE_STRUCT_D 61 #define FFI_TYPE_STRUCT_F 45 #define FFI_TYPE_STRUCT_DD 253 #define FFI_TYPE_STRUCT_FF 173 #define FFI_TYPE_STRUCT_FD 237 #define FFI_TYPE_STRUCT_DF 189 #define FFI_TYPE_STRUCT_SMALL 93 #define FFI_TYPE_STRUCT_SMALL2 109 #endif #ifdef LIBFFI_ASM #define v0 $2 #define v1 $3 #define a0 $4 #define a1 $5 #define a2 $6 #define a3 $7 #define a4 $8 #define a5 $9 #define a6 $10 #define a7 $11 #define t0 $8 #define t1 $9 #define t2 $10 #define t3 $11 #define t4 $12 #define t5 $13 #define t6 $14 #define t7 $15 #define t8 $24 #define t9 $25 #define ra $31 #ifdef FFI_MIPS_O32 #define REG_L lw #define REG_S sw #define SUBU subu #define ADDU addu #define SRL srl #define LI li #else /* !FFI_MIPS_O32 */ #define REG_L ld #define REG_S sd #define SUBU dsubu #define ADDU daddu #define SRL dsrl #define LI dli #endif /* !FFI_MIPS_O32 */ #else /* !LIBFFI_ASM */ #ifdef FFI_MIPS_O32 /* O32 stack frames have 32bit integer args */ typedef unsigned int ffi_arg __attribute__((__mode__(__SI__))); typedef signed int ffi_sarg __attribute__((__mode__(__SI__))); #else /* N32 and N64 frames have 64bit integer args */ typedef unsigned int ffi_arg __attribute__((__mode__(__DI__))); typedef signed int ffi_sarg __attribute__((__mode__(__DI__))); #endif typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_O32, FFI_N32, FFI_N64, FFI_O32_SOFT_FLOAT, #ifdef FFI_MIPS_O32 #ifdef __mips_soft_float FFI_DEFAULT_ABI = FFI_O32_SOFT_FLOAT, #else FFI_DEFAULT_ABI = FFI_O32, #endif #else FFI_DEFAULT_ABI = FFI_N32, #endif FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #define FFI_EXTRA_CIF_FIELDS unsigned rstruct_flag #endif /* !LIBFFI_ASM */ /* ---- Definitions for closures ----------------------------------------- */ #if defined(FFI_MIPS_O32) #define FFI_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 20 #else /* N32/N64 not implemented yet. */ #define FFI_CLOSURES 0 #endif /* FFI_MIPS_O32 */ #define FFI_NATIVE_RAW_API 0 #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:25:13
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/m68k In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv16107 Added Files: sysv.S ffitarget.h ffi.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: sysv.S --- /* ----------------------------------------------------------------------- sysv.S m68k Foreign Function Interface ----------------------------------------------------------------------- */ #define LIBFFI_ASM #include <fficonfig.h> #include <ffi.h> .text .globl ffi_call_SYSV .type ffi_call_SYSV,@function ffi_call_SYSV: link %fp,#0 move.l %d2,-(%sp) | Make room for all of the new args. sub.l 16(%fp),%sp | Call ffi_prep_args move.l 12(%fp),-(%sp) pea 4(%sp) move.l 8(%fp),%a0 jsr (%a0) addq.l #8,%sp | Pass pointer to struct value, if any move.l %a0,%a1 | Call the function move.l 32(%fp),%a0 jsr (%a0) | Remove the space we pushed for the args add.l 16(%fp),%sp | Load the pointer to storage for the return value move.l 28(%fp),%a1 | Load the return type code move.l 20(%fp),%d2 | If the return value pointer is NULL, assume no return value. tst.l %a1 jbeq noretval btst #0,%d2 jbeq retlongint move.l %d0,(%a1) jbra epilogue retlongint: btst #1,%d2 jbeq retfloat move.l %d0,(%a1) move.l %d1,4(%a1) jbra epilogue retfloat: btst #2,%d2 jbeq retdouble fmove.s %fp0,(%a1) jbra epilogue retdouble: btst #3,%d2 jbeq retlongdouble fmove.d %fp0,(%a1) jbra epilogue retlongdouble: btst #4,%d2 jbeq retpointer fmove.x %fp0,(%a1) jbra epilogue retpointer: btst #5,%d2 jbeq retstruct move.l %a0,(%a1) jbra epilogue retstruct: btst #6,%d2 jbeq noretval move.l 24(%fp),%d2 bfins %d0,(%a1){#0,%d2} noretval: epilogue: move.l (%sp)+,%d2 unlk %a6 rts .size ffi_call_SYSV,.-ffi_call_SYSV --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c m68k Foreign Function Interface ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments. */ static void * ffi_prep_args (void *stack, extended_cif *ecif) { unsigned int i; void **p_argv; char *argp; ffi_type **p_arg; void *struct_value_ptr; argp = stack; if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8) struct_value_ptr = ecif->rvalue; else struct_value_ptr = NULL; p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i != 0; i--, p_arg++) { size_t z; /* Align if necessary. */ if (((*p_arg)->alignment - 1) & (unsigned) argp) argp = (char *) ALIGN (argp, (*p_arg)->alignment); z = (*p_arg)->size; if (z < sizeof (int)) { switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; break; case FFI_TYPE_UINT8: *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; break; case FFI_TYPE_SINT16: *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; break; case FFI_TYPE_UINT16: *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; break; case FFI_TYPE_STRUCT: memcpy (argp + sizeof (int) - z, *p_argv, z); break; default: FFI_ASSERT (0); } z = sizeof (int); } else memcpy (argp, *p_argv, z); p_argv++; argp += z; } return struct_value_ptr; } #define CIF_FLAGS_INT 1 #define CIF_FLAGS_DINT 2 #define CIF_FLAGS_FLOAT 4 #define CIF_FLAGS_DOUBLE 8 #define CIF_FLAGS_LDOUBLE 16 #define CIF_FLAGS_POINTER 32 #define CIF_FLAGS_STRUCT 64 /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep (ffi_cif *cif) { /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: cif->flags = 0; break; case FFI_TYPE_STRUCT: if (cif->rtype->size > 4 && cif->rtype->size <= 8) cif->flags = CIF_FLAGS_DINT; else if (cif->rtype->size <= 4) cif->flags = CIF_FLAGS_STRUCT; else cif->flags = 0; break; case FFI_TYPE_FLOAT: cif->flags = CIF_FLAGS_FLOAT; break; case FFI_TYPE_DOUBLE: cif->flags = CIF_FLAGS_DOUBLE; break; case FFI_TYPE_LONGDOUBLE: cif->flags = CIF_FLAGS_LDOUBLE; break; case FFI_TYPE_POINTER: cif->flags = CIF_FLAGS_POINTER; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: cif->flags = CIF_FLAGS_DINT; break; default: cif->flags = CIF_FLAGS_INT; break; } return FFI_OK; } extern void ffi_call_SYSV (void *(*) (void *, extended_cif *), extended_cif *, unsigned, unsigned, unsigned, void *, void (*fn) ()); void ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return value address then we need to make one. */ if (rvalue == NULL && cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size > 8) ecif.rvalue = alloca (cif->rtype->size); else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->rtype->size * 8, ecif.rvalue, fn); break; default: FFI_ASSERT (0); break; } } --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for Motorola 68K. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_DEFAULT_ABI = FFI_SYSV, FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 0 #define FFI_NATIVE_RAW_API 0 #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:25:04
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/m32r In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15972 Added Files: sysv.S ffitarget.h ffi.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: sysv.S --- /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 2004 Renesas Technology M32R 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 RENESAS TECHNOLOGY 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> #ifdef HAVE_MACHINE_ASM_H #include <machine/asm.h> #else /* XXX these lose for some platforms, I'm sure. */ #define CNAME(x) x #define ENTRY(x) .globl CNAME(x)! .type CNAME(x),%function! CNAME(x): #endif .text /* R0: ffi_prep_args */ /* R1: &ecif */ /* R2: cif->bytes */ /* R3: fig->flags */ /* sp+0: ecif.rvalue */ /* sp+4: fn */ /* This assumes we are using gas. */ ENTRY(ffi_call_SYSV) /* Save registers. */ push fp push lr push r3 push r2 push r1 push r0 mv fp, sp /* Make room for all of the new args. */ sub sp, r2 /* Place all of the ffi_prep_args in position. */ mv lr, r0 mv r0, sp /* R1 already set. */ /* And call. */ jl lr /* Move first 4 parameters in registers... */ ld r0, @(0,sp) ld r1, @(4,sp) ld r2, @(8,sp) ld r3, @(12,sp) /* ...and adjust the stack. */ ld lr, @(8,fp) cmpi lr, #16 bc adjust_stack ldi lr, #16 adjust_stack: add sp, lr /* Call the function. */ ld lr, @(28,fp) jl lr /* Remove the space we pushed for the args. */ mv sp, fp /* Load R2 with the pointer to storage for the return value. */ ld r2, @(24,sp) /* Load R3 with the return type code. */ ld r3, @(12,sp) /* If the return value pointer is NULL, assume no return value. */ beqz r2, epilogue /* Return INT. */ ldi r4, #FFI_TYPE_INT bne r3, r4, return_double st r0, @r2 bra epilogue return_double: /* Return DOUBLE or LONGDOUBLE. */ ldi r4, #FFI_TYPE_DOUBLE bne r3, r4, epilogue st r0, @r2 st r1, @(4,r2) epilogue: pop r0 pop r1 pop r2 pop r3 pop lr pop fp jmp lr .ffi_call_SYSV_end: .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2004 Renesas Technology M32R 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 RENESAS TECHNOLOGY 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments. */ /*@-exportheader@*/ void ffi_prep_args(char *stack, extended_cif *ecif) /*@=exportheader@*/ { unsigned int i; int tmp; unsigned int avn; void **p_argv; char *argp; ffi_type **p_arg; tmp = 0; argp = stack; if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 8) { *(void **) argp = ecif->rvalue; argp += 4; } avn = ecif->cif->nargs; p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0) && (avn != 0); i--, p_arg++) { size_t z; /* Align if necessary. */ if (((*p_arg)->alignment - 1) & (unsigned) argp) argp = (char *) ALIGN (argp, (*p_arg)->alignment); if (avn != 0) { avn--; z = (*p_arg)->size; if (z < sizeof (int)) { z = sizeof (int); switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); break; case FFI_TYPE_UINT8: *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); break; case FFI_TYPE_SINT16: *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); break; case FFI_TYPE_UINT16: *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); break; case FFI_TYPE_STRUCT: z = (*p_arg)->size; if ((*p_arg)->alignment != 1) memcpy (argp, *p_argv, z); else memcpy (argp + 4 - z, *p_argv, z); z = sizeof (int); break; default: FFI_ASSERT(0); } } else if (z == sizeof (int)) { *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); } else { if ((*p_arg)->type == FFI_TYPE_STRUCT) { if (z > 8) { *(unsigned int *) argp = (unsigned int)(void *)(* p_argv); z = sizeof(void *); } else { memcpy(argp, *p_argv, z); z = 8; } } else { /* Double or long long 64bit. */ memcpy (argp, *p_argv, z); } } p_argv++; argp += z; } } return; } /* Perform machine dependent cif processing. */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { /* Set the return type flag. */ switch (cif->rtype->type) { case FFI_TYPE_VOID: cif->flags = (unsigned) cif->rtype->type; break; case FFI_TYPE_STRUCT: if (cif->rtype->size <= 4) cif->flags = FFI_TYPE_INT; else if (cif->rtype->size <= 8) cif->flags = FFI_TYPE_DOUBLE; else cif->flags = (unsigned) cif->rtype->type; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_DOUBLE: cif->flags = FFI_TYPE_DOUBLE; break; case FFI_TYPE_FLOAT: default: cif->flags = FFI_TYPE_INT; break; } return FFI_OK; } /*@-declundef@*/ /*@-exportheader@*/ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); /*@=declundef@*/ /*@=exportheader@*/ void ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return value address then we need to make one. */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca (cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); if (cif->rtype->type == FFI_TYPE_STRUCT) { int size = cif->rtype->size; int align = cif->rtype->alignment; if (size < 4) { if (align == 1) *(unsigned long *)(ecif.rvalue) <<= (4 - size) * 8; } else if (4 < size && size < 8) { if (align == 1) { memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); } else if (align == 2) { if (size & 1) size += 1; if (size != 8) memcpy (ecif.rvalue, ecif.rvalue + 8-size, size); } } } /*@=usedef@*/ break; default: FFI_ASSERT(0); break; } } --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 2004 Renesas Technology. Target configuration macros for M32R. 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 RENESAS TECHNOLOGY 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_DEFAULT_ABI = FFI_SYSV, FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif #define FFI_CLOSURES 0 #define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:24:57
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/ia64 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15913 Added Files: unix.S ia64_flags.h ffitarget.h ffi.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: unix.S --- /* ----------------------------------------------------------------------- unix.S - Copyright (c) 1998 Red Hat, Inc. Copyright (c) 2000 Hewlett Packard Company IA64/unix Foreign Function Interface Primary author: Hans Boehm, HP Labs Loosely modeled on Cygnus code for other platforms. 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 CYGNUS SOLUTIONS 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> #include "ia64_flags.h" .pred.safe_across_calls p1-p5,p16-p63 .text /* int ffi_call_unix (struct ia64_args *stack, PTR64 rvalue, void (*fn)(), int flags); */ .align 16 .global ffi_call_unix .proc ffi_call_unix ffi_call_unix: .prologue /* Bit o trickiness. We actually share a stack frame with ffi_call. Rely on the fact that ffi_call uses a vframe and don't bother tracking one here at all. */ .fframe 0 .save ar.pfs, r36 // loc0 alloc loc0 = ar.pfs, 4, 3, 8, 0 .save rp, loc1 mov loc1 = b0 .body add r16 = 16, in0 mov loc2 = gp mov r8 = in1 ;; /* Load up all of the argument registers. */ ldf.fill f8 = [in0], 32 ldf.fill f9 = [r16], 32 ;; ldf.fill f10 = [in0], 32 ldf.fill f11 = [r16], 32 ;; ldf.fill f12 = [in0], 32 ldf.fill f13 = [r16], 32 ;; ldf.fill f14 = [in0], 32 ldf.fill f15 = [r16], 24 ;; ld8 out0 = [in0], 16 ld8 out1 = [r16], 16 ;; ld8 out2 = [in0], 16 ld8 out3 = [r16], 16 ;; ld8 out4 = [in0], 16 ld8 out5 = [r16], 16 ;; ld8 out6 = [in0] ld8 out7 = [r16] ;; /* Deallocate the register save area from the stack frame. */ mov sp = in0 /* Call the target function. */ ld8 r16 = [in2], 8 ;; ld8 gp = [in2] mov b6 = r16 br.call.sptk.many b0 = b6 ;; /* Dispatch to handle return value. */ mov gp = loc2 zxt1 r16 = in3 ;; mov ar.pfs = loc0 addl r18 = @ltoffx(.Lst_table), gp ;; ld8.mov r18 = [r18], .Lst_table mov b0 = loc1 ;; shladd r18 = r16, 3, r18 ;; ld8 r17 = [r18] shr in3 = in3, 8 ;; add r17 = r17, r18 ;; mov b6 = r17 br b6 ;; .Lst_void: br.ret.sptk.many b0 ;; .Lst_uint8: zxt1 r8 = r8 ;; st8 [in1] = r8 br.ret.sptk.many b0 ;; .Lst_sint8: sxt1 r8 = r8 ;; st8 [in1] = r8 br.ret.sptk.many b0 ;; .Lst_uint16: zxt2 r8 = r8 ;; st8 [in1] = r8 br.ret.sptk.many b0 ;; .Lst_sint16: sxt2 r8 = r8 ;; st8 [in1] = r8 br.ret.sptk.many b0 ;; .Lst_uint32: zxt4 r8 = r8 ;; st8 [in1] = r8 br.ret.sptk.many b0 ;; .Lst_sint32: sxt4 r8 = r8 ;; st8 [in1] = r8 br.ret.sptk.many b0 ;; .Lst_int64: st8 [in1] = r8 br.ret.sptk.many b0 ;; .Lst_float: stfs [in1] = f8 br.ret.sptk.many b0 ;; .Lst_double: stfd [in1] = f8 br.ret.sptk.many b0 ;; .Lst_ldouble: stfe [in1] = f8 br.ret.sptk.many b0 ;; .Lst_small_struct: add sp = -16, sp cmp.lt p6, p0 = 8, in3 cmp.lt p7, p0 = 16, in3 cmp.lt p8, p0 = 24, in3 ;; add r16 = 8, sp add r17 = 16, sp add r18 = 24, sp ;; st8 [sp] = r8 (p6) st8 [r16] = r9 mov out0 = in1 (p7) st8 [r17] = r10 (p8) st8 [r18] = r11 mov out1 = sp mov out2 = in3 br.call.sptk.many b0 = memcpy# ;; mov ar.pfs = loc0 mov b0 = loc1 mov gp = loc2 br.ret.sptk.many b0 .Lst_hfa_float: add r16 = 4, in1 cmp.lt p6, p0 = 4, in3 ;; stfs [in1] = f8, 8 (p6) stfs [r16] = f9, 8 cmp.lt p7, p0 = 8, in3 cmp.lt p8, p0 = 12, in3 ;; (p7) stfs [in1] = f10, 8 (p8) stfs [r16] = f11, 8 cmp.lt p9, p0 = 16, in3 cmp.lt p10, p0 = 20, in3 ;; (p9) stfs [in1] = f12, 8 (p10) stfs [r16] = f13, 8 cmp.lt p6, p0 = 24, in3 cmp.lt p7, p0 = 28, in3 ;; (p6) stfs [in1] = f14 (p7) stfs [r16] = f15 br.ret.sptk.many b0 ;; .Lst_hfa_double: add r16 = 8, in1 cmp.lt p6, p0 = 8, in3 ;; stfd [in1] = f8, 16 (p6) stfd [r16] = f9, 16 cmp.lt p7, p0 = 16, in3 cmp.lt p8, p0 = 24, in3 ;; (p7) stfd [in1] = f10, 16 (p8) stfd [r16] = f11, 16 cmp.lt p9, p0 = 32, in3 cmp.lt p10, p0 = 40, in3 ;; (p9) stfd [in1] = f12, 16 (p10) stfd [r16] = f13, 16 cmp.lt p6, p0 = 48, in3 cmp.lt p7, p0 = 56, in3 ;; (p6) stfd [in1] = f14 (p7) stfd [r16] = f15 br.ret.sptk.many b0 ;; .Lst_hfa_ldouble: add r16 = 16, in1 cmp.lt p6, p0 = 16, in3 ;; stfe [in1] = f8, 32 (p6) stfe [r16] = f9, 32 cmp.lt p7, p0 = 32, in3 cmp.lt p8, p0 = 48, in3 ;; (p7) stfe [in1] = f10, 32 (p8) stfe [r16] = f11, 32 cmp.lt p9, p0 = 64, in3 cmp.lt p10, p0 = 80, in3 ;; (p9) stfe [in1] = f12, 32 (p10) stfe [r16] = f13, 32 cmp.lt p6, p0 = 96, in3 cmp.lt p7, p0 = 112, in3 ;; (p6) stfe [in1] = f14 (p7) stfe [r16] = f15 br.ret.sptk.many b0 ;; .endp ffi_call_unix .align 16 .global ffi_closure_unix .proc ffi_closure_unix #define FRAME_SIZE (8*16 + 8*8 + 8*16) ffi_closure_unix: .prologue .save ar.pfs, r40 // loc0 alloc loc0 = ar.pfs, 8, 4, 4, 0 .fframe FRAME_SIZE add r12 = -FRAME_SIZE, r12 .save rp, loc1 mov loc1 = b0 .save ar.unat, loc2 mov loc2 = ar.unat .body /* Retrieve closure pointer and real gp. */ #ifdef _ILP32 addp4 out0 = 0, gp addp4 gp = 16, gp #else mov out0 = gp add gp = 16, gp #endif ;; ld8 gp = [gp] /* Spill all of the possible argument registers. */ add r16 = 16 + 8*16, sp add r17 = 16 + 8*16 + 16, sp ;; stf.spill [r16] = f8, 32 stf.spill [r17] = f9, 32 mov loc3 = gp ;; stf.spill [r16] = f10, 32 stf.spill [r17] = f11, 32 ;; stf.spill [r16] = f12, 32 stf.spill [r17] = f13, 32 ;; stf.spill [r16] = f14, 32 stf.spill [r17] = f15, 24 ;; .mem.offset 0, 0 st8.spill [r16] = in0, 16 .mem.offset 8, 0 st8.spill [r17] = in1, 16 add out1 = 16 + 8*16, sp ;; .mem.offset 0, 0 st8.spill [r16] = in2, 16 .mem.offset 8, 0 st8.spill [r17] = in3, 16 add out2 = 16, sp ;; .mem.offset 0, 0 st8.spill [r16] = in4, 16 .mem.offset 8, 0 st8.spill [r17] = in5, 16 mov out3 = r8 ;; .mem.offset 0, 0 st8.spill [r16] = in6 .mem.offset 8, 0 st8.spill [r17] = in7 /* Invoke ffi_closure_unix_inner for the hard work. */ br.call.sptk.many b0 = ffi_closure_unix_inner ;; /* Dispatch to handle return value. */ mov gp = loc3 zxt1 r16 = r8 ;; addl r18 = @ltoffx(.Lld_table), gp mov ar.pfs = loc0 ;; ld8.mov r18 = [r18], .Lld_table mov b0 = loc1 ;; shladd r18 = r16, 3, r18 mov ar.unat = loc2 ;; ld8 r17 = [r18] shr r8 = r8, 8 ;; add r17 = r17, r18 add r16 = 16, sp ;; mov b6 = r17 br b6 ;; .label_state 1 .Lld_void: .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_int: .body .copy_state 1 ld8 r8 = [r16] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_float: .body .copy_state 1 ldfs f8 = [r16] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_double: .body .copy_state 1 ldfd f8 = [r16] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_ldouble: .body .copy_state 1 ldfe f8 = [r16] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_small_struct: .body .copy_state 1 add r17 = 8, r16 cmp.lt p6, p0 = 8, r8 cmp.lt p7, p0 = 16, r8 cmp.lt p8, p0 = 24, r8 ;; ld8 r8 = [r16], 16 (p6) ld8 r9 = [r17], 16 ;; (p7) ld8 r10 = [r16] (p8) ld8 r11 = [r17] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_hfa_float: .body .copy_state 1 add r17 = 4, r16 cmp.lt p6, p0 = 4, r8 ;; ldfs f8 = [r16], 8 (p6) ldfs f9 = [r17], 8 cmp.lt p7, p0 = 8, r8 cmp.lt p8, p0 = 12, r8 ;; (p7) ldfs f10 = [r16], 8 (p8) ldfs f11 = [r17], 8 cmp.lt p9, p0 = 16, r8 cmp.lt p10, p0 = 20, r8 ;; (p9) ldfs f12 = [r16], 8 (p10) ldfs f13 = [r17], 8 cmp.lt p6, p0 = 24, r8 cmp.lt p7, p0 = 28, r8 ;; (p6) ldfs f14 = [r16] (p7) ldfs f15 = [r17] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_hfa_double: .body .copy_state 1 add r17 = 8, r16 cmp.lt p6, p0 = 8, r8 ;; ldfd f8 = [r16], 16 (p6) ldfd f9 = [r17], 16 cmp.lt p7, p0 = 16, r8 cmp.lt p8, p0 = 24, r8 ;; (p7) ldfd f10 = [r16], 16 (p8) ldfd f11 = [r17], 16 cmp.lt p9, p0 = 32, r8 cmp.lt p10, p0 = 40, r8 ;; (p9) ldfd f12 = [r16], 16 (p10) ldfd f13 = [r17], 16 cmp.lt p6, p0 = 48, r8 cmp.lt p7, p0 = 56, r8 ;; (p6) ldfd f14 = [r16] (p7) ldfd f15 = [r17] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .Lld_hfa_ldouble: .body .copy_state 1 add r17 = 16, r16 cmp.lt p6, p0 = 16, r8 ;; ldfe f8 = [r16], 32 (p6) ldfe f9 = [r17], 32 cmp.lt p7, p0 = 32, r8 cmp.lt p8, p0 = 48, r8 ;; (p7) ldfe f10 = [r16], 32 (p8) ldfe f11 = [r17], 32 cmp.lt p9, p0 = 64, r8 cmp.lt p10, p0 = 80, r8 ;; (p9) ldfe f12 = [r16], 32 (p10) ldfe f13 = [r17], 32 cmp.lt p6, p0 = 96, r8 cmp.lt p7, p0 = 112, r8 ;; (p6) ldfe f14 = [r16] (p7) ldfe f15 = [r17] .restore sp add sp = FRAME_SIZE, sp br.ret.sptk.many b0 ;; .endp ffi_closure_unix .section .rodata .align 8 .Lst_table: data8 @pcrel(.Lst_void) // FFI_TYPE_VOID data8 @pcrel(.Lst_sint32) // FFI_TYPE_INT data8 @pcrel(.Lst_float) // FFI_TYPE_FLOAT data8 @pcrel(.Lst_double) // FFI_TYPE_DOUBLE data8 @pcrel(.Lst_ldouble) // FFI_TYPE_LONGDOUBLE data8 @pcrel(.Lst_uint8) // FFI_TYPE_UINT8 data8 @pcrel(.Lst_sint8) // FFI_TYPE_SINT8 data8 @pcrel(.Lst_uint16) // FFI_TYPE_UINT16 data8 @pcrel(.Lst_sint16) // FFI_TYPE_SINT16 data8 @pcrel(.Lst_uint32) // FFI_TYPE_UINT32 data8 @pcrel(.Lst_sint32) // FFI_TYPE_SINT32 data8 @pcrel(.Lst_int64) // FFI_TYPE_UINT64 data8 @pcrel(.Lst_int64) // FFI_TYPE_SINT64 data8 @pcrel(.Lst_void) // FFI_TYPE_STRUCT data8 @pcrel(.Lst_int64) // FFI_TYPE_POINTER data8 @pcrel(.Lst_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT data8 @pcrel(.Lst_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT data8 @pcrel(.Lst_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE data8 @pcrel(.Lst_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE .Lld_table: data8 @pcrel(.Lld_void) // FFI_TYPE_VOID data8 @pcrel(.Lld_int) // FFI_TYPE_INT data8 @pcrel(.Lld_float) // FFI_TYPE_FLOAT data8 @pcrel(.Lld_double) // FFI_TYPE_DOUBLE data8 @pcrel(.Lld_ldouble) // FFI_TYPE_LONGDOUBLE data8 @pcrel(.Lld_int) // FFI_TYPE_UINT8 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT8 data8 @pcrel(.Lld_int) // FFI_TYPE_UINT16 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT16 data8 @pcrel(.Lld_int) // FFI_TYPE_UINT32 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT32 data8 @pcrel(.Lld_int) // FFI_TYPE_UINT64 data8 @pcrel(.Lld_int) // FFI_TYPE_SINT64 data8 @pcrel(.Lld_void) // FFI_TYPE_STRUCT data8 @pcrel(.Lld_int) // FFI_TYPE_POINTER data8 @pcrel(.Lld_small_struct) // FFI_IA64_TYPE_SMALL_STRUCT data8 @pcrel(.Lld_hfa_float) // FFI_IA64_TYPE_HFA_FLOAT data8 @pcrel(.Lld_hfa_double) // FFI_IA64_TYPE_HFA_DOUBLE data8 @pcrel(.Lld_hfa_ldouble) // FFI_IA64_TYPE_HFA_LDOUBLE --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998 Red Hat, Inc. Copyright (c) 2000 Hewlett Packard Company IA64 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> #include <stdbool.h> #include <float.h> #include "ia64_flags.h" /* A 64-bit pointer value. In LP64 mode, this is effectively a plain pointer. In ILP32 mode, it's a pointer that's been extended to 64 bits by "addp4". */ typedef void *PTR64 __attribute__((mode(DI))); /* Memory image of fp register contents. This is the implementation specific format used by ldf.fill/stf.spill. All we care about is that it wants a 16 byte aligned slot. */ typedef struct { UINT64 x[2] __attribute__((aligned(16))); } fpreg; /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */ struct ia64_args { fpreg fp_regs[8]; /* Contents of 8 fp arg registers. */ UINT64 gp_regs[8]; /* Contents of 8 gp arg registers. */ UINT64 other_args[]; /* Arguments passed on stack, variable size. */ }; /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */ static inline void * endian_adjust (void *addr, size_t len) { #ifdef __BIG_ENDIAN__ return addr + (8 - len); #else return addr; #endif } /* Store VALUE to ADDR in the current cpu implementation's fp spill format. */ static inline void stf_spill(fpreg *addr, __float80 value) { asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value)); } /* Load a value from ADDR, which is in the current cpu implementation's fp spill format. */ static inline __float80 ldf_fill(fpreg *addr) { __float80 ret; asm ("ldf.fill %0 = %1%P1" : "=f"(ret) : "m"(*addr)); return ret; } /* Return the size of the C type associated with with TYPE. Which will be one of the FFI_IA64_TYPE_HFA_* values. */ static size_t hfa_type_size (int type) { switch (type) { case FFI_IA64_TYPE_HFA_FLOAT: return sizeof(float); case FFI_IA64_TYPE_HFA_DOUBLE: return sizeof(double); case FFI_IA64_TYPE_HFA_LDOUBLE: return sizeof(__float80); default: abort (); } } /* Load from ADDR a value indicated by TYPE. Which will be one of the FFI_IA64_TYPE_HFA_* values. */ static __float80 hfa_type_load (int type, void *addr) { switch (type) { case FFI_IA64_TYPE_HFA_FLOAT: return *(float *) addr; case FFI_IA64_TYPE_HFA_DOUBLE: return *(double *) addr; case FFI_IA64_TYPE_HFA_LDOUBLE: return *(__float80 *) addr; default: abort (); } } /* Load VALUE into ADDR as indicated by TYPE. Which will be one of the FFI_IA64_TYPE_HFA_* values. */ static void hfa_type_store (int type, void *addr, __float80 value) { switch (type) { case FFI_IA64_TYPE_HFA_FLOAT: *(float *) addr = value; break; case FFI_IA64_TYPE_HFA_DOUBLE: *(double *) addr = value; break; case FFI_IA64_TYPE_HFA_LDOUBLE: *(__float80 *) addr = value; break; default: abort (); } } /* Is TYPE a struct containing floats, doubles, or extended doubles, all of the same fp type? If so, return the element type. Return FFI_TYPE_VOID if not. */ static int hfa_element_type (ffi_type *type, int nested) { int element = FFI_TYPE_VOID; switch (type->type) { case FFI_TYPE_FLOAT: /* We want to return VOID for raw floating-point types, but the synthetic HFA type if we're nested within an aggregate. */ if (nested) element = FFI_IA64_TYPE_HFA_FLOAT; break; case FFI_TYPE_DOUBLE: /* Similarly. */ if (nested) element = FFI_IA64_TYPE_HFA_DOUBLE; break; case FFI_TYPE_LONGDOUBLE: /* Similarly, except that that HFA is true for double extended, but not quad precision. Both have sizeof == 16, so tell the difference based on the precision. */ if (LDBL_MANT_DIG == 64 && nested) element = FFI_IA64_TYPE_HFA_LDOUBLE; break; case FFI_TYPE_STRUCT: { ffi_type **ptr = &type->elements[0]; for (ptr = &type->elements[0]; *ptr ; ptr++) { int sub_element = hfa_element_type (*ptr, 1); if (sub_element == FFI_TYPE_VOID) return FFI_TYPE_VOID; if (element == FFI_TYPE_VOID) element = sub_element; else if (element != sub_element) return FFI_TYPE_VOID; } } break; default: return FFI_TYPE_VOID; } return element; } /* Perform machine dependent cif processing. */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { int flags; /* Adjust cif->bytes to include space for the bits of the ia64_args frame that preceeds the integer register portion. The estimate that the generic bits did for the argument space required is good enough for the integer component. */ cif->bytes += offsetof(struct ia64_args, gp_regs[0]); if (cif->bytes < sizeof(struct ia64_args)) cif->bytes = sizeof(struct ia64_args); /* Set the return type flag. */ flags = cif->rtype->type; switch (cif->rtype->type) { case FFI_TYPE_LONGDOUBLE: /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision, and encode quad precision as a two-word integer structure. */ if (LDBL_MANT_DIG != 64) flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8); break; case FFI_TYPE_STRUCT: { size_t size = cif->rtype->size; int hfa_type = hfa_element_type (cif->rtype, 0); if (hfa_type != FFI_TYPE_VOID) { size_t nelts = size / hfa_type_size (hfa_type); if (nelts <= 8) flags = hfa_type | (size << 8); } else { if (size <= 32) flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8); } } break; default: break; } cif->flags = flags; return FFI_OK; } extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(), UINT64); void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) { struct ia64_args *stack; long i, avn, gpcount, fpcount; ffi_type **p_arg; FFI_ASSERT (cif->abi == FFI_UNIX); /* If we have no spot for a return value, make one. */ if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID) rvalue = alloca (cif->rtype->size); /* Allocate the stack frame. */ stack = alloca (cif->bytes); gpcount = fpcount = 0; avn = cif->nargs; for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) { switch ((*p_arg)->type) { case FFI_TYPE_SINT8: stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i]; break; case FFI_TYPE_UINT8: stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i]; break; case FFI_TYPE_SINT16: stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i]; break; case FFI_TYPE_UINT16: stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i]; break; case FFI_TYPE_SINT32: stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i]; break; case FFI_TYPE_UINT32: stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; break; case FFI_TYPE_POINTER: stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i]; break; case FFI_TYPE_FLOAT: if (gpcount < 8 && fpcount < 8) stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]); stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; break; case FFI_TYPE_DOUBLE: if (gpcount < 8 && fpcount < 8) stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]); stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; break; case FFI_TYPE_LONGDOUBLE: if (gpcount & 1) gpcount++; if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]); memcpy (&stack->gp_regs[gpcount], avalue[i], 16); gpcount += 2; break; case FFI_TYPE_STRUCT: { size_t size = (*p_arg)->size; size_t align = (*p_arg)->alignment; int hfa_type = hfa_element_type (*p_arg, 0); FFI_ASSERT (align <= 16); if (align == 16 && (gpcount & 1)) gpcount++; if (hfa_type != FFI_TYPE_VOID) { size_t hfa_size = hfa_type_size (hfa_type); size_t offset = 0; size_t gp_offset = gpcount * 8; while (fpcount < 8 && offset < size && gp_offset < 8 * 8) { stf_spill (&stack->fp_regs[fpcount], hfa_type_load (hfa_type, avalue[i] + offset)); offset += hfa_size; gp_offset += hfa_size; fpcount += 1; } } memcpy (&stack->gp_regs[gpcount], avalue[i], size); gpcount += (size + 7) / 8; } break; default: abort (); } } ffi_call_unix (stack, rvalue, fn, cif->flags); } /* Closures represent a pair consisting of a function pointer, and some user data. A closure is invoked by reinterpreting the closure as a function pointer, and branching to it. Thus we can make an interpreted function callable as a C function: We turn the interpreter itself, together with a pointer specifying the interpreted procedure, into a closure. For IA64, function pointer are already pairs consisting of a code pointer, and a gp pointer. The latter is needed to access global variables. Here we set up such a pair as the first two words of the closure (in the "trampoline" area), but we replace the gp pointer with a pointer to the closure itself. We also add the real gp pointer to the closure. This allows the function entry code to both retrieve the user data, and to restire the correct gp pointer. */ extern void ffi_closure_unix (); ffi_status ffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) { /* The layout of a function descriptor. A C function pointer really points to one of these. */ struct ia64_fd { UINT64 code_pointer; UINT64 gp; }; struct ffi_ia64_trampoline_struct { UINT64 code_pointer; /* Pointer to ffi_closure_unix. */ UINT64 fake_gp; /* Pointer to closure, installed as gp. */ UINT64 real_gp; /* Real gp value. */ }; struct ffi_ia64_trampoline_struct *tramp; struct ia64_fd *fd; FFI_ASSERT (cif->abi == FFI_UNIX); tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp; fd = (struct ia64_fd *)(void *)ffi_closure_unix; tramp->code_pointer = fd->code_pointer; tramp->real_gp = fd->gp; tramp->fake_gp = (UINT64)(PTR64)closure; closure->cif = cif; closure->user_data = user_data; closure->fun = fun; return FFI_OK; } UINT64 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack, void *rvalue, void *r8) { ffi_cif *cif; void **avalue; ffi_type **p_arg; long i, avn, gpcount, fpcount; cif = closure->cif; avn = cif->nargs; avalue = alloca (avn * sizeof (void *)); /* If the structure return value is passed in memory get that location from r8 so as to pass the value directly back to the caller. */ if (cif->flags == FFI_TYPE_STRUCT) rvalue = r8; gpcount = fpcount = 0; for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) { switch ((*p_arg)->type) { case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1); break; case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2); break; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4); break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: avalue[i] = &stack->gp_regs[gpcount++]; break; case FFI_TYPE_POINTER: avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*)); break; case FFI_TYPE_FLOAT: if (gpcount < 8 && fpcount < 8) { void *addr = &stack->fp_regs[fpcount++]; avalue[i] = addr; *(float *)addr = ldf_fill (addr); } else avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4); gpcount++; break; case FFI_TYPE_DOUBLE: if (gpcount < 8 && fpcount < 8) { void *addr = &stack->fp_regs[fpcount++]; avalue[i] = addr; *(double *)addr = ldf_fill (addr); } else avalue[i] = &stack->gp_regs[gpcount]; gpcount++; break; case FFI_TYPE_LONGDOUBLE: if (gpcount & 1) gpcount++; if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) { void *addr = &stack->fp_regs[fpcount++]; avalue[i] = addr; *(__float80 *)addr = ldf_fill (addr); } else avalue[i] = &stack->gp_regs[gpcount]; gpcount += 2; break; case FFI_TYPE_STRUCT: { size_t size = (*p_arg)->size; size_t align = (*p_arg)->alignment; int hfa_type = hfa_element_type (*p_arg, 0); FFI_ASSERT (align <= 16); if (align == 16 && (gpcount & 1)) gpcount++; if (hfa_type != FFI_TYPE_VOID) { size_t hfa_size = hfa_type_size (hfa_type); size_t offset = 0; size_t gp_offset = gpcount * 8; void *addr = alloca (size); avalue[i] = addr; while (fpcount < 8 && offset < size && gp_offset < 8 * 8) { hfa_type_store (hfa_type, addr + offset, ldf_fill (&stack->fp_regs[fpcount])); offset += hfa_size; gp_offset += hfa_size; fpcount += 1; } if (offset < size) memcpy (addr + offset, (char *)stack->gp_regs + gp_offset, size - offset); } else avalue[i] = &stack->gp_regs[gpcount]; gpcount += (size + 7) / 8; } break; default: abort (); } } closure->fun (cif, rvalue, avalue, closure->user_data); return cif->flags; } --- NEW FILE: ia64_flags.h --- /* ----------------------------------------------------------------------- ia64_flags.h - Copyright (c) 2000 Hewlett Packard Company IA64/unix Foreign Function Interface Original author: Hans Boehm, HP Labs 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ /* "Type" codes used between assembly and C. When used as a part of a cfi->flags value, the low byte will be these extra type codes, and bits 8-31 will be the actual size of the type. */ /* Small structures containing N words in integer registers. */ #define FFI_IA64_TYPE_SMALL_STRUCT (FFI_TYPE_LAST + 1) /* Homogeneous Floating Point Aggregates (HFAs) which are returned in FP registers. */ #define FFI_IA64_TYPE_HFA_FLOAT (FFI_TYPE_LAST + 2) #define FFI_IA64_TYPE_HFA_DOUBLE (FFI_TYPE_LAST + 3) #define FFI_IA64_TYPE_HFA_LDOUBLE (FFI_TYPE_LAST + 4) --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for IA-64. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_ASM typedef unsigned long long ffi_arg; typedef signed long long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_UNIX, /* Linux and all Unix variants use the same conventions */ FFI_DEFAULT_ABI = FFI_UNIX, FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 24 /* Really the following struct, which */ /* can be interpreted as a C function */ /* descriptor: */ #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:24:52
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/frv In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15838 Added Files: ffitarget.h ffi.c eabi.S Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: eabi.S --- /* ----------------------------------------------------------------------- eabi.S - Copyright (c) 2004 Anthony Green FR-V Assembly glue. $Id: eabi.S,v 1.2 2006/03/03 20:24:46 theller Exp $ 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> .globl ffi_prep_args_EABI .text .p2align 4 .globl ffi_call_EABI .type ffi_call_EABI, @function # gr8 : ffi_prep_args # gr9 : &ecif # gr10: cif->bytes # gr11: fig->flags # gr12: ecif.rvalue # gr13: fn ffi_call_EABI: addi sp, #-80, sp sti fp, @(sp, #24) addi sp, #24, fp movsg lr, gr5 /* Make room for the new arguments. */ /* subi sp, fp, gr10 */ /* Store return address and incoming args on stack. */ sti gr5, @(fp, #8) sti gr8, @(fp, #-4) sti gr9, @(fp, #-8) sti gr10, @(fp, #-12) sti gr11, @(fp, #-16) sti gr12, @(fp, #-20) sti gr13, @(fp, #-24) sub sp, gr10, sp /* Call ffi_prep_args. */ ldi @(fp, #-4), gr4 addi sp, #0, gr8 ldi @(fp, #-8), gr9 #ifdef __FRV_FDPIC__ ldd @(gr4, gr0), gr14 calll @(gr14, gr0) #else calll @(gr4, gr0) #endif /* ffi_prep_args returns the new stack pointer. */ mov gr8, gr4 ldi @(sp, #0), gr8 ldi @(sp, #4), gr9 ldi @(sp, #8), gr10 ldi @(sp, #12), gr11 ldi @(sp, #16), gr12 ldi @(sp, #20), gr13 /* Always copy the return value pointer into the hidden parameter register. This is only strictly necessary when we're returning an aggregate type, but it doesn't hurt to do this all the time, and it saves a branch. */ ldi @(fp, #-20), gr3 /* Use the ffi_prep_args return value for the new sp. */ mov gr4, sp /* Call the target function. */ ldi @(fp, -24), gr4 #ifdef __FRV_FDPIC__ ldd @(gr4, gr0), gr14 calll @(gr14, gr0) #else calll @(gr4, gr0) #endif /* Store the result. */ ldi @(fp, #-16), gr10 /* fig->flags */ ldi @(fp, #-20), gr4 /* ecif.rvalue */ /* Is the return value stored in two registers? */ cmpi gr10, #8, icc0 bne icc0, 0, .L2 /* Yes, save them. */ sti gr8, @(gr4, #0) sti gr9, @(gr4, #4) bra .L3 .L2: /* Is the return value a structure? */ cmpi gr10, #-1, icc0 beq icc0, 0, .L3 /* No, save a 4 byte return value. */ sti gr8, @(gr4, #0) .L3: /* Restore the stack, and return. */ ldi @(fp, 8), gr5 ld @(fp, gr0), fp addi sp,#80,sp jmpl @(gr5,gr0) .size ffi_call_EABI, .-ffi_call_EABI --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 2004 Anthony Green FR-V 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ void *ffi_prep_args(char *stack, extended_cif *ecif) { register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; register int count = 0; p_argv = ecif->avalue; argp = stack; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++) { size_t z; z = (*p_arg)->size; if ((*p_arg)->type == FFI_TYPE_STRUCT) { z = sizeof(void*); *(void **) argp = *p_argv; } /* if ((*p_arg)->type == FFI_TYPE_FLOAT) { if (count > 24) { // This is going on the stack. Turn it into a double. *(double *) argp = (double) *(float*)(* p_argv); z = sizeof(double); } else *(void **) argp = *(void **)(* p_argv); } */ else if (z < sizeof(int)) { z = sizeof(int); switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); break; case FFI_TYPE_UINT8: *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); break; case FFI_TYPE_SINT16: *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); break; case FFI_TYPE_UINT16: *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); break; default: FFI_ASSERT(0); } } else if (z == sizeof(int)) { *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); } else { memcpy(argp, *p_argv, z); } p_argv++; argp += z; count += z; } return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8))); } /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { if (cif->rtype->type == FFI_TYPE_STRUCT) cif->flags = -1; else cif->flags = cif->rtype->size; cif->bytes = ALIGN (cif->bytes, 8); return FFI_OK; } extern void ffi_call_EABI(void *(*)(char *, extended_cif *), extended_cif *, unsigned, unsigned, unsigned *, void (*fn)()); void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca(cif->rtype->size); } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_EABI: ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; default: FFI_ASSERT(0); break; } } void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3, unsigned arg4, unsigned arg5, unsigned arg6) { /* This function is called by a trampoline. The trampoline stows a pointer to the ffi_closure object in gr7. We must save this pointer in a place that will persist while we do our work. */ register ffi_closure *creg __asm__ ("gr7"); ffi_closure *closure = creg; /* Arguments that don't fit in registers are found on the stack at a fixed offset above the current frame pointer. */ register char *frame_pointer __asm__ ("fp"); char *stack_args = frame_pointer + 16; /* Lay the register arguments down in a continuous chunk of memory. */ unsigned register_args[6] = { arg1, arg2, arg3, arg4, arg5, arg6 }; ffi_cif *cif = closure->cif; ffi_type **arg_types = cif->arg_types; void **avalue = alloca (cif->nargs * sizeof(void *)); char *ptr = (char *) register_args; int i; /* Find the address of each argument. */ for (i = 0; i < cif->nargs; i++) { switch (arg_types[i]->type) { case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: avalue[i] = ptr + 3; break; case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: avalue[i] = ptr + 2; break; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_FLOAT: avalue[i] = ptr; break; case FFI_TYPE_STRUCT: avalue[i] = *(void**)ptr; break; default: /* This is an 8-byte value. */ avalue[i] = ptr; ptr += 4; break; } ptr += 4; /* If we've handled more arguments than fit in registers, start looking at the those passed on the stack. */ if (ptr == ((char *)register_args + (6*4))) ptr = stack_args; } /* Invoke the closure. */ if (cif->rtype->type == FFI_TYPE_STRUCT) { /* The caller allocates space for the return structure, and passes a pointer to this space in gr3. Use this value directly as the return value. */ register void *return_struct_ptr __asm__("gr3"); (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data); } else { /* Allocate space for the return value and call the function. */ long long rvalue; (closure->fun) (cif, &rvalue, avalue, closure->user_data); /* Functions return 4-byte or smaller results in gr8. 8-byte values also use gr9. We fill the both, even for small return values, just to avoid a branch. */ asm ("ldi @(%0, #0), gr8" : : "r" (&rvalue)); asm ("ldi @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1])); } } ffi_status ffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data) { unsigned int *tramp = (unsigned int *) &closure->tramp[0]; unsigned long fn = (long) ffi_closure_eabi; unsigned long cls = (long) closure; #ifdef __FRV_FDPIC__ register void *got __asm__("gr15"); #endif int i; fn = (unsigned long) ffi_closure_eabi; #ifdef __FRV_FDPIC__ tramp[0] = &tramp[2]; tramp[1] = got; tramp[2] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */ tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */ tramp[4] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */ tramp[5] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */ tramp[6] = 0x9cc86000; /* ldi @(gr6, #0), gr14 */ tramp[7] = 0x8030e000; /* jmpl @(gr14, gr0) */ #else tramp[0] = 0x8cfc0000 + (fn & 0xffff); /* setlos lo(fn), gr6 */ tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7 */ tramp[2] = 0x8cf80000 + (fn >> 16); /* sethi hi(fn), gr6 */ tramp[3] = 0x8ef80000 + (cls >> 16); /* sethi hi(cls), gr7 */ tramp[4] = 0x80300006; /* jmpl @(gr0, gr6) */ #endif closure->cif = cif; closure->fun = fun; closure->user_data = user_data; /* Cache flushing. */ for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++) __asm__ volatile ("dcf @(%0,%1)\n\tici @(%0,%1)" :: "r" (tramp), "r" (i)); return FFI_OK; } --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2004 Red Hat, Inc. Target configuration macros for FR-V 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H /* ---- System specific configurations ----------------------------------- */ #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, #ifdef FRV FFI_EABI, FFI_DEFAULT_ABI = FFI_EABI, #endif FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_NATIVE_RAW_API 0 #ifdef __FRV_FDPIC__ /* Trampolines are 8 4-byte instructions long. */ #define FFI_TRAMPOLINE_SIZE (8*4) #else /* Trampolines are 5 4-byte instructions long. */ #define FFI_TRAMPOLINE_SIZE (5*4) #endif #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:24:43
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/cris In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15775 Added Files: sysv.S ffitarget.h ffi.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: sysv.S --- /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 2004 Simon Posnjak Copyright (c) 2005 Axis Communications AB CRIS 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 SIMON POSNJAK 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 <ffi.h> #define CONCAT(x,y) x ## y #define XCONCAT(x,y) CONCAT (x, y) #define L(x) XCONCAT (__USER_LABEL_PREFIX__, x) .text ;; OK, when we get called we should have this (according to ;; AXIS ETRAX 100LX Programmer's Manual chapter 6.3). ;; ;; R10: ffi_prep_args (func. pointer) ;; R11: &ecif ;; R12: cif->bytes ;; R13: fig->flags ;; sp+0: ecif.rvalue ;; sp+4: fn (function pointer to the function that we need to call) .globl L(ffi_call_SYSV) .type L(ffi_call_SYSV),@function .hidden L(ffi_call_SYSV) L(ffi_call_SYSV): ;; Save the regs to the stack. push $srp ;; Used for stack pointer saving. push $r6 ;; Used for function address pointer. push $r7 ;; Used for stack pointer saving. push $r8 ;; We save fig->flags to stack we will need them after we ;; call The Function. push $r13 ;; Saving current stack pointer. move.d $sp,$r8 move.d $sp,$r6 ;; Move address of ffi_prep_args to r13. move.d $r10,$r13 ;; Make room on the stack for the args of fn. sub.d $r12,$sp ;; Function void ffi_prep_args(char *stack, extended_cif *ecif) parameters are: ;; r10 <-- stack pointer ;; r11 <-- &ecif (already there) move.d $sp,$r10 ;; Call the function. jsr $r13 ;; Save the size of the structures which are passed on stack. move.d $r10,$r7 ;; Move first four args in to r10..r13. move.d [$sp+0],$r10 move.d [$sp+4],$r11 move.d [$sp+8],$r12 move.d [$sp+12],$r13 ;; Adjust the stack and check if any parameters are given on stack. addq 16,$sp sub.d $r7,$r6 cmp.d $sp,$r6 bpl go_on nop go_on_no_params_on_stack: move.d $r6,$sp go_on: ;; Discover if we need to put rval address in to r9. move.d [$r8+0],$r7 cmpq FFI_TYPE_STRUCT,$r7 bne call_now nop ;; Move rval address to $r9. move.d [$r8+20],$r9 call_now: ;; Move address of The Function in to r7. move.d [$r8+24],$r7 ;; Call The Function. jsr $r7 ;; Reset stack. move.d $r8,$sp ;; Load rval type (fig->flags) in to r13. pop $r13 ;; Detect rval type. cmpq FFI_TYPE_VOID,$r13 beq epilogue cmpq FFI_TYPE_STRUCT,$r13 beq epilogue cmpq FFI_TYPE_DOUBLE,$r13 beq return_double_or_longlong cmpq FFI_TYPE_UINT64,$r13 beq return_double_or_longlong cmpq FFI_TYPE_SINT64,$r13 beq return_double_or_longlong nop ;; Just return the 32 bit value. ba return nop return_double_or_longlong: ;; Load half of the rval to r10 and the other half to r11. move.d [$sp+16],$r13 move.d $r10,[$r13] addq 4,$r13 move.d $r11,[$r13] ba epilogue nop return: ;; Load the rval to r10. move.d [$sp+16],$r13 move.d $r10,[$r13] epilogue: pop $r8 pop $r7 pop $r6 Jump [$sp+] .size ffi_call_SYSV,.-ffi_call_SYSV /* Save R10..R13 into an array, somewhat like varargs. Copy the next argument too, to simplify handling of any straddling parameter. Save R9 and SP after those. Jump to function handling the rest. Since this is a template, copied and the main function filled in by the user. */ .globl L(ffi_cris_trampoline_template) .type L(ffi_cris_trampoline_template),@function .hidden L(ffi_cris_trampoline_template) L(ffi_cris_trampoline_template): 0: /* The value we get for "PC" is right after the prefix instruction, two bytes from the beginning, i.e. 0b+2. */ move.d $r10,[$pc+2f-(0b+2)] move.d $pc,$r10 1: addq 2f-1b+4,$r10 move.d $r11,[$r10+] move.d $r12,[$r10+] move.d $r13,[$r10+] move.d [$sp],$r11 move.d $r11,[$r10+] move.d $r9,[$r10+] move.d $sp,[$r10+] subq FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE,$r10 move.d 0,$r11 3: jump 0 2: .size ffi_cris_trampoline_template,.-0b /* This macro create a constant usable as "extern const int \name" in C from within libffi, when \name has no prefix decoration. */ .macro const name,value .globl \name .type \name,@object .hidden \name \name: .dword \value .size \name,4 .endm /* Constants for offsets within the trampoline. We could do this with just symbols, avoiding memory contents and memory accesses, but the C usage code would look a bit stranger. */ const L(ffi_cris_trampoline_fn_offset),2b-4-0b const L(ffi_cris_trampoline_closure_offset),3b-4-0b --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998 Cygnus Solutions Copyright (c) 2004 Simon Posnjak Copyright (c) 2005 Axis Communications AB CRIS 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 SIMON POSNJAK 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) static ffi_status initialize_aggregate_packed_struct (ffi_type * arg) { ffi_type **ptr; FFI_ASSERT (arg != NULL); FFI_ASSERT (arg->elements != NULL); FFI_ASSERT (arg->size == 0); FFI_ASSERT (arg->alignment == 0); ptr = &(arg->elements[0]); while ((*ptr) != NULL) { if (((*ptr)->size == 0) && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; FFI_ASSERT (ffi_type_test ((*ptr))); arg->size += (*ptr)->size; arg->alignment = (arg->alignment > (*ptr)->alignment) ? arg->alignment : (*ptr)->alignment; ptr++; } if (arg->size == 0) return FFI_BAD_TYPEDEF; else return FFI_OK; } int ffi_prep_args (char *stack, extended_cif * ecif) { unsigned int i; unsigned int struct_count = 0; void **p_argv; char *argp; ffi_type **p_arg; argp = stack; p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++) { size_t z; switch ((*p_arg)->type) { case FFI_TYPE_STRUCT: { z = (*p_arg)->size; if (z <= 4) { memcpy (argp, *p_argv, z); z = 4; } else if (z <= 8) { memcpy (argp, *p_argv, z); z = 8; } else { unsigned int uiLocOnStack; z = sizeof (void *); uiLocOnStack = 4 * ecif->cif->nargs + struct_count; struct_count = struct_count + (*p_arg)->size; *(unsigned int *) argp = (unsigned int) (UINT32 *) (stack + uiLocOnStack); memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size); } break; } default: z = (*p_arg)->size; if (z < sizeof (int)) { switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv); break; case FFI_TYPE_UINT8: *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv); break; case FFI_TYPE_SINT16: *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv); break; case FFI_TYPE_UINT16: *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv); break; default: FFI_ASSERT (0); } z = sizeof (int); } else if (z == sizeof (int)) *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv); else memcpy (argp, *p_argv, z); break; } p_argv++; argp += z; } return (struct_count); } ffi_status ffi_prep_cif (ffi_cif * cif, ffi_abi abi, unsigned int nargs, ffi_type * rtype, ffi_type ** atypes) { unsigned bytes = 0; unsigned int i; ffi_type **ptr; FFI_ASSERT (cif != NULL); FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); cif->abi = abi; cif->arg_types = atypes; cif->nargs = nargs; cif->rtype = rtype; cif->flags = 0; if ((cif->rtype->size == 0) && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK)) return FFI_BAD_TYPEDEF; FFI_ASSERT_VALID_TYPE (cif->rtype); for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) { if (((*ptr)->size == 0) && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; FFI_ASSERT_VALID_TYPE (*ptr); if (((*ptr)->alignment - 1) & bytes) bytes = ALIGN (bytes, (*ptr)->alignment); if ((*ptr)->type == FFI_TYPE_STRUCT) { if ((*ptr)->size > 8) { bytes += (*ptr)->size; bytes += sizeof (void *); } else { if ((*ptr)->size > 4) bytes += 8; else bytes += 4; } } else bytes += STACK_ARG_SIZE ((*ptr)->size); } cif->bytes = bytes; return ffi_prep_cif_machdep (cif); } ffi_status ffi_prep_cif_machdep (ffi_cif * cif) { switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: cif->flags = (unsigned) cif->rtype->type; break; default: cif->flags = FFI_TYPE_INT; break; } return FFI_OK; } extern void ffi_call_SYSV (int (*)(char *, extended_cif *), extended_cif *, unsigned, unsigned, unsigned *, void (*fn) ()) __attribute__ ((__visibility__ ("hidden"))); void ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { ecif.rvalue = alloca (cif->rtype->size); } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; default: FFI_ASSERT (0); break; } } /* Because the following variables are not exported outside libffi, we mark them hidden. */ /* Assembly code for the jump stub. */ extern const char ffi_cris_trampoline_template[] __attribute__ ((__visibility__ ("hidden"))); /* Offset into ffi_cris_trampoline_template of where to put the ffi_prep_closure_inner function. */ extern const int ffi_cris_trampoline_fn_offset __attribute__ ((__visibility__ ("hidden"))); /* Offset into ffi_cris_trampoline_template of where to put the closure data. */ extern const int ffi_cris_trampoline_closure_offset __attribute__ ((__visibility__ ("hidden"))); /* This function is sibling-called (jumped to) by the closure trampoline. We get R10..R13 at PARAMS[0..3] and a copy of [SP] at PARAMS[4] to simplify handling of a straddling parameter. A copy of R9 is at PARAMS[5] and SP at PARAMS[6]. These parameters are put at the appropriate place in CLOSURE which is then executed and the return value is passed back to the caller. */ static unsigned long long ffi_prep_closure_inner (void **params, ffi_closure* closure) { char *register_args = (char *) params; void *struct_ret = params[5]; char *stack_args = params[6]; char *ptr = register_args; ffi_cif *cif = closure->cif; ffi_type **arg_types = cif->arg_types; /* Max room needed is number of arguments as 64-bit values. */ void **avalue = alloca (closure->cif->nargs * sizeof(void *)); int i; int doing_regs; long long llret = 0; /* Find the address of each argument. */ for (i = 0, doing_regs = 1; i < cif->nargs; i++) { /* Types up to and including 8 bytes go by-value. */ if (arg_types[i]->size <= 4) { avalue[i] = ptr; ptr += 4; } else if (arg_types[i]->size <= 8) { avalue[i] = ptr; ptr += 8; } else { FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT); /* Passed by-reference, so copy the pointer. */ avalue[i] = *(void **) ptr; ptr += 4; } /* If we've handled more arguments than fit in registers, start looking at the those passed on the stack. Step over the first one if we had a straddling parameter. */ if (doing_regs && ptr >= register_args + 4*4) { ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0); doing_regs = 0; } } /* Invoke the closure. */ (closure->fun) (cif, cif->rtype->type == FFI_TYPE_STRUCT /* The caller allocated space for the return structure, and passed a pointer to this space in R9. */ ? struct_ret /* We take advantage of being able to ignore that the high part isn't set if the return value is not in R10:R11, but in R10 only. */ : (void *) &llret, avalue, closure->user_data); return llret; } /* API function: Prepare the trampoline. */ ffi_status ffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif *, void *, void **, void*), void *user_data) { void *innerfn = ffi_prep_closure_inner; FFI_ASSERT (cif->abi == FFI_SYSV); closure->cif = cif; closure->user_data = user_data; closure->fun = fun; memcpy (closure->tramp, ffi_cris_trampoline_template, FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE); memcpy (closure->tramp + ffi_cris_trampoline_fn_offset, &innerfn, sizeof (void *)); memcpy (closure->tramp + ffi_cris_trampoline_closure_offset, &closure, sizeof (void *)); return FFI_OK; } --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for CRIS. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_DEFAULT_ABI = FFI_SYSV, FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE 36 #define FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE (7*4) #define FFI_TRAMPOLINE_SIZE \ (FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE + FFI_CRIS_TRAMPOLINE_DATA_PART_SIZE) #define FFI_NATIVE_RAW_API 0 #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:24:35
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/arm In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15714 Added Files: sysv.S ffitarget.h ffi.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: sysv.S --- /* ----------------------------------------------------------------------- sysv.S - Copyright (c) 1998 Red Hat, Inc. ARM 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 CYGNUS SOLUTIONS 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> #ifdef HAVE_MACHINE_ASM_H #include <machine/asm.h> #else #ifdef __USER_LABEL_PREFIX__ #define CONCAT1(a, b) CONCAT2(a, b) #define CONCAT2(a, b) a ## b /* Use the right prefix for global labels. */ #define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) #else #define CNAME(x) x #endif #define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): #endif #ifdef __ELF__ #define LSYM(x) .x #else #define LSYM(x) x #endif /* We need a better way of testing for this, but for now, this is all we can do. */ @ This selects the minimum architecture level required. #define __ARM_ARCH__ 3 #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) # undef __ARM_ARCH__ # define __ARM_ARCH__ 4 #endif #if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ || defined(__ARM_ARCH_5TEJ__) # undef __ARM_ARCH__ # define __ARM_ARCH__ 5 #endif #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ || defined(__ARM_ARCH_6ZK__) # undef __ARM_ARCH__ # define __ARM_ARCH__ 6 #endif #if __ARM_ARCH__ >= 5 # define call_reg(x) blx x #elif defined (__ARM_ARCH_4T__) # define call_reg(x) mov lr, pc ; bx x # if defined(__thumb__) || defined(__THUMB_INTERWORK__) # define __INTERWORKING__ # endif #else # define call_reg(x) mov lr, pc ; mov pc, x #endif #if defined(__thumb__) && !defined(__THUMB_INTERWORK__) .macro ARM_FUNC_START name .text .align 0 .thumb .thumb_func ENTRY(\name) bx pc nop .arm /* A hook to tell gdb that we've switched to ARM mode. Also used to call directly from other local arm routines. */ _L__\name: .endm #else .macro ARM_FUNC_START name .text .align 0 .arm ENTRY(\name) .endm #endif .macro RETLDM regs=, cond=, dirn=ia #if defined (__INTERWORKING__) .ifc "\regs","" ldr\cond lr, [sp], #4 .else ldm\cond\dirn sp!, {\regs, lr} .endif bx\cond lr #else .ifc "\regs","" ldr\cond pc, [sp], #4 .else ldm\cond\dirn sp!, {\regs, pc} .endif #endif .endm @ r0: ffi_prep_args @ r1: &ecif @ r2: cif->bytes @ r3: fig->flags @ sp+0: ecif.rvalue @ sp+4: fn @ This assumes we are using gas. ARM_FUNC_START ffi_call_SYSV @ Save registers stmfd sp!, {r0-r3, fp, lr} mov fp, sp @ Make room for all of the new args. sub sp, fp, r2 @ Place all of the ffi_prep_args in position mov ip, r0 mov r0, sp @ r1 already set @ Call ffi_prep_args(stack, &ecif) call_reg(ip) @ move first 4 parameters in registers ldmia sp, {r0-r3} @ and adjust stack ldr ip, [fp, #8] cmp ip, #16 movhs ip, #16 add sp, sp, ip @ call (fn) (...) ldr ip, [fp, #28] call_reg(ip) @ Remove the space we pushed for the args mov sp, fp @ Load r2 with the pointer to storage for the return value ldr r2, [sp, #24] @ Load r3 with the return type code ldr r3, [sp, #12] @ If the return value pointer is NULL, assume no return value. cmp r2, #0 beq LSYM(Lepilogue) @ return INT cmp r3, #FFI_TYPE_INT #ifdef __SOFTFP__ cmpne r3, #FFI_TYPE_FLOAT #endif streq r0, [r2] beq LSYM(Lepilogue) @ return INT64 cmp r3, #FFI_TYPE_SINT64 #ifdef __SOFTFP__ cmpne r3, #FFI_TYPE_DOUBLE #endif stmeqia r2, {r0, r1} #ifndef __SOFTFP__ beq LSYM(Lepilogue) @ return FLOAT cmp r3, #FFI_TYPE_FLOAT stfeqs f0, [r2] beq LSYM(Lepilogue) @ return DOUBLE or LONGDOUBLE cmp r3, #FFI_TYPE_DOUBLE stfeqd f0, [r2] #endif LSYM(Lepilogue): RETLDM "r0-r3,fp" .ffi_call_SYSV_end: .size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998 Red Hat, Inc. ARM 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ /*@-exportheader@*/ void ffi_prep_args(char *stack, extended_cif *ecif) /*@=exportheader@*/ { register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; argp = stack; if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) { *(void **) argp = ecif->rvalue; argp += 4; } p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++) { size_t z; /* Align if necessary */ if (((*p_arg)->alignment - 1) & (unsigned) argp) { argp = (char *) ALIGN(argp, (*p_arg)->alignment); } z = (*p_arg)->size; if (z < sizeof(int)) { z = sizeof(int); switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); break; case FFI_TYPE_UINT8: *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); break; case FFI_TYPE_SINT16: *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); break; case FFI_TYPE_UINT16: *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); break; case FFI_TYPE_STRUCT: *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); break; default: FFI_ASSERT(0); } } else if (z == sizeof(int)) { *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); } else { memcpy(argp, *p_argv, z); } p_argv++; argp += z; } return; } /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { /* Round the stack up to a multiple of 8 bytes. This isn't needed everywhere, but it is on some platforms, and it doesn't harm anything when it isn't needed. */ cif->bytes = (cif->bytes + 7) & ~7; /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags = (unsigned) cif->rtype->type; break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: cif->flags = (unsigned) FFI_TYPE_SINT64; break; default: cif->flags = FFI_TYPE_INT; break; } return FFI_OK; } /*@-declundef@*/ /*@-exportheader@*/ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); /*@=declundef@*/ /*@=exportheader@*/ void ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; default: FFI_ASSERT(0); break; } } --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_DEFAULT_ABI = FFI_SYSV, FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 0 #define FFI_NATIVE_RAW_API 0 #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:24:29
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src/alpha In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15652 Added Files: osf.S ffitarget.h ffi.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: osf.S --- /* ----------------------------------------------------------------------- osf.S - Copyright (c) 1998, 2001 Red Hat Alpha/OSF Foreign Function Interface $Id: osf.S,v 1.2 2006/03/03 20:24:26 theller Exp $ 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 CYGNUS SOLUTIONS 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> .arch ev6 .text /* ffi_call_osf (void *args, unsigned long bytes, unsigned flags, void *raddr, void (*fnaddr)()); Bit o trickiness here -- ARGS+BYTES is the base of the stack frame for this function. This has been allocated by ffi_call. We also deallocate some of the stack that has been alloca'd. */ .align 3 .globl ffi_call_osf .ent ffi_call_osf ffi_call_osf: .frame $15, 32, $26, 0 .mask 0x4008000, -32 $LFB1: addq $16,$17,$1 mov $16, $30 stq $26, 0($1) stq $15, 8($1) stq $18, 16($1) mov $1, $15 $LCFI1: .prologue 0 stq $19, 24($1) mov $20, $27 # Load up all of the (potential) argument registers. ldq $16, 0($30) ldt $f16, 0($30) ldt $f17, 8($30) ldq $17, 8($30) ldt $f18, 16($30) ldq $18, 16($30) ldt $f19, 24($30) ldq $19, 24($30) ldt $f20, 32($30) ldq $20, 32($30) ldt $f21, 40($30) ldq $21, 40($30) # Deallocate the register argument area. lda $30, 48($30) jsr $26, ($27), 0 ldgp $29, 0($26) # If the return value pointer is NULL, assume no return value. ldq $19, 24($15) ldq $18, 16($15) ldq $26, 0($15) $LCFI2: beq $19, $noretval # Store the return value out in the proper type. cmpeq $18, FFI_TYPE_INT, $1 bne $1, $retint cmpeq $18, FFI_TYPE_FLOAT, $2 bne $2, $retfloat cmpeq $18, FFI_TYPE_DOUBLE, $3 bne $3, $retdouble .align 3 $noretval: ldq $15, 8($15) ret .align 4 $retint: stq $0, 0($19) nop ldq $15, 8($15) ret .align 4 $retfloat: sts $f0, 0($19) nop ldq $15, 8($15) ret .align 4 $retdouble: stt $f0, 0($19) nop ldq $15, 8($15) ret $LFE1: .end ffi_call_osf /* ffi_closure_osf(...) Receives the closure argument in $1. */ .align 3 .globl ffi_closure_osf .ent ffi_closure_osf ffi_closure_osf: .frame $30, 16*8, $26, 0 .mask 0x4000000, -16*8 $LFB2: ldgp $29, 0($27) subq $30, 16*8, $30 $LCFI5: stq $26, 0($30) $LCFI6: .prologue 1 # Store all of the potential argument registers in va_list format. stt $f16, 4*8($30) stt $f17, 5*8($30) stt $f18, 6*8($30) stt $f19, 7*8($30) stt $f20, 8*8($30) stt $f21, 9*8($30) stq $16, 10*8($30) stq $17, 11*8($30) stq $18, 12*8($30) stq $19, 13*8($30) stq $20, 14*8($30) stq $21, 15*8($30) # Call ffi_closure_osf_inner to do the bulk of the work. mov $1, $16 lda $17, 2*8($30) lda $18, 10*8($30) jsr $26, ffi_closure_osf_inner ldgp $29, 0($26) ldq $26, 0($30) # Load up the return value in the proper type. lda $1, $load_table s4addq $0, $1, $1 ldl $1, 0($1) addq $1, $29, $1 jmp $31, ($1), $load_32 .align 4 $load_none: addq $30, 16*8, $30 ret .align 4 $load_float: lds $f0, 16($30) nop addq $30, 16*8, $30 ret .align 4 $load_double: ldt $f0, 16($30) nop addq $30, 16*8, $30 ret .align 4 $load_u8: #ifdef __alpha_bwx__ ldbu $0, 16($30) nop #else ldq $0, 16($30) and $0, 255, $0 #endif addq $30, 16*8, $30 ret .align 4 $load_s8: #ifdef __alpha_bwx__ ldbu $0, 16($30) sextb $0, $0 #else ldq $0, 16($30) sll $0, 56, $0 sra $0, 56, $0 #endif addq $30, 16*8, $30 ret .align 4 $load_u16: #ifdef __alpha_bwx__ ldwu $0, 16($30) nop #else ldq $0, 16($30) zapnot $0, 3, $0 #endif addq $30, 16*8, $30 ret .align 4 $load_s16: #ifdef __alpha_bwx__ ldwu $0, 16($30) sextw $0, $0 #else ldq $0, 16($30) sll $0, 48, $0 sra $0, 48, $0 #endif addq $30, 16*8, $30 ret .align 4 $load_32: ldl $0, 16($30) nop addq $30, 16*8, $30 ret .align 4 $load_64: ldq $0, 16($30) nop addq $30, 16*8, $30 ret $LFE2: .end ffi_closure_osf #ifdef __ELF__ .section .rodata #else .rdata #endif $load_table: .gprel32 $load_none # FFI_TYPE_VOID .gprel32 $load_32 # FFI_TYPE_INT .gprel32 $load_float # FFI_TYPE_FLOAT .gprel32 $load_double # FFI_TYPE_DOUBLE .gprel32 $load_double # FFI_TYPE_LONGDOUBLE .gprel32 $load_u8 # FFI_TYPE_UINT8 .gprel32 $load_s8 # FFI_TYPE_SINT8 .gprel32 $load_u16 # FFI_TYPE_UINT16 .gprel32 $load_s16 # FFI_TYPE_SINT16 .gprel32 $load_32 # FFI_TYPE_UINT32 .gprel32 $load_32 # FFI_TYPE_SINT32 .gprel32 $load_64 # FFI_TYPE_UINT64 .gprel32 $load_64 # FFI_TYPE_SINT64 .gprel32 $load_none # FFI_TYPE_STRUCT .gprel32 $load_64 # FFI_TYPE_POINTER /* Assert that the table above is in sync with ffi.h. */ #if FFI_TYPE_FLOAT != 2 \ || FFI_TYPE_DOUBLE != 3 \ || FFI_TYPE_UINT8 != 5 \ || FFI_TYPE_SINT8 != 6 \ || FFI_TYPE_UINT16 != 7 \ || FFI_TYPE_SINT16 != 8 \ || FFI_TYPE_UINT32 != 9 \ || FFI_TYPE_SINT32 != 10 \ || FFI_TYPE_UINT64 != 11 \ || FFI_TYPE_SINT64 != 12 \ || FFI_TYPE_STRUCT != 13 \ || FFI_TYPE_POINTER != 14 \ || FFI_TYPE_LAST != 14 #error "osf.S out of sync with ffi.h" #endif #ifdef __ELF__ .section .eh_frame,EH_FRAME_FLAGS,@progbits __FRAME_BEGIN__: .4byte $LECIE1-$LSCIE1 # Length of Common Information Entry $LSCIE1: .4byte 0x0 # CIE Identifier Tag .byte 0x1 # CIE Version .ascii "zR\0" # CIE Augmentation .byte 0x1 # uleb128 0x1; CIE Code Alignment Factor .byte 0x78 # sleb128 -8; CIE Data Alignment Factor .byte 26 # CIE RA Column .byte 0x1 # uleb128 0x1; Augmentation size .byte 0x1b # FDE Encoding (pcrel sdata4) .byte 0xc # DW_CFA_def_cfa .byte 30 # uleb128 column 30 .byte 0 # uleb128 offset 0 .align 3 $LECIE1: $LSFDE1: .4byte $LEFDE1-$LASFDE1 # FDE Length $LASFDE1: .4byte $LASFDE1-__FRAME_BEGIN__ # FDE CIE offset .4byte $LFB1-. # FDE initial location .4byte $LFE1-$LFB1 # FDE address range .byte 0x0 # uleb128 0x0; Augmentation size .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI1-$LFB1 .byte 0x9a # DW_CFA_offset, column 26 .byte 4 # uleb128 4*-8 .byte 0x8f # DW_CFA_offset, column 15 .byte 0x3 # uleb128 3*-8 .byte 0xc # DW_CFA_def_cfa .byte 15 # uleb128 column 15 .byte 32 # uleb128 offset 32 .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI2-$LCFI1 .byte 0xda # DW_CFA_restore, column 26 .align 3 $LEFDE1: $LSFDE3: .4byte $LEFDE3-$LASFDE3 # FDE Length $LASFDE3: .4byte $LASFDE3-__FRAME_BEGIN__ # FDE CIE offset .4byte $LFB2-. # FDE initial location .4byte $LFE2-$LFB2 # FDE address range .byte 0x0 # uleb128 0x0; Augmentation size .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI5-$LFB2 .byte 0xe # DW_CFA_def_cfa_offset .byte 0x80,0x1 # uleb128 128 .byte 0x4 # DW_CFA_advance_loc4 .4byte $LCFI6-$LCFI5 .byte 0x9a # DW_CFA_offset, column 26 .byte 16 # uleb128 offset 16*-8 .align 3 $LEFDE3: #endif --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998, 2001 Red Hat, Inc. Alpha 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> extern void ffi_call_osf(void *, unsigned long, unsigned, void *, void (*)()); extern void ffi_closure_osf(void); ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { /* Adjust cif->bytes to represent a minimum 6 words for the temporary register argument loading area. */ if (cif->bytes < 6*FFI_SIZEOF_ARG) cif->bytes = 6*FFI_SIZEOF_ARG; /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_STRUCT: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: cif->flags = cif->rtype->type; break; default: cif->flags = FFI_TYPE_INT; break; } return FFI_OK; } void ffi_call(ffi_cif *cif, void (*fn)(), void *rvalue, void **avalue) { unsigned long *stack, *argp; long i, avn; ffi_type **arg_types; FFI_ASSERT (cif->abi == FFI_OSF); /* If the return value is a struct and we don't have a return value address then we need to make one. */ if (rvalue == NULL && cif->flags == FFI_TYPE_STRUCT) rvalue = alloca(cif->rtype->size); /* Allocate the space for the arguments, plus 4 words of temp space for ffi_call_osf. */ argp = stack = alloca(cif->bytes + 4*FFI_SIZEOF_ARG); if (cif->flags == FFI_TYPE_STRUCT) *(void **) argp++ = rvalue; i = 0; avn = cif->nargs; arg_types = cif->arg_types; while (i < avn) { switch ((*arg_types)->type) { case FFI_TYPE_SINT8: *(SINT64 *) argp = *(SINT8 *)(* avalue); break; case FFI_TYPE_UINT8: *(SINT64 *) argp = *(UINT8 *)(* avalue); break; case FFI_TYPE_SINT16: *(SINT64 *) argp = *(SINT16 *)(* avalue); break; case FFI_TYPE_UINT16: *(SINT64 *) argp = *(UINT16 *)(* avalue); break; case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: /* Note that unsigned 32-bit quantities are sign extended. */ *(SINT64 *) argp = *(SINT32 *)(* avalue); break; case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: *(UINT64 *) argp = *(UINT64 *)(* avalue); break; case FFI_TYPE_FLOAT: if (argp - stack < 6) { /* Note the conversion -- all the fp regs are loaded as doubles. The in-register format is the same. */ *(double *) argp = *(float *)(* avalue); } else *(float *) argp = *(float *)(* avalue); break; case FFI_TYPE_DOUBLE: *(double *) argp = *(double *)(* avalue); break; case FFI_TYPE_STRUCT: memcpy(argp, *avalue, (*arg_types)->size); break; default: FFI_ASSERT(0); } argp += ALIGN((*arg_types)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; i++, arg_types++, avalue++; } ffi_call_osf(stack, cif->bytes, cif->flags, rvalue, fn); } ffi_status ffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*, void*, void**, void*), void *user_data) { unsigned int *tramp; FFI_ASSERT (cif->abi == FFI_OSF); tramp = (unsigned int *) &closure->tramp[0]; tramp[0] = 0x47fb0401; /* mov $27,$1 */ tramp[1] = 0xa77b0010; /* ldq $27,16($27) */ tramp[2] = 0x6bfb0000; /* jmp $31,($27),0 */ tramp[3] = 0x47ff041f; /* nop */ *(void **) &tramp[4] = ffi_closure_osf; closure->cif = cif; closure->fun = fun; closure->user_data = user_data; /* Flush the Icache. Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal instead, since both Compaq as and gas can handle it. 0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>. */ asm volatile ("call_pal 0x86" : : : "memory"); return FFI_OK; } int ffi_closure_osf_inner(ffi_closure *closure, void *rvalue, unsigned long *argp) { ffi_cif *cif; void **avalue; ffi_type **arg_types; long i, avn, argn; cif = closure->cif; avalue = alloca(cif->nargs * sizeof(void *)); argn = 0; /* Copy the caller's structure return address to that the closure returns the data directly to the caller. */ if (cif->flags == FFI_TYPE_STRUCT) { rvalue = (void *) argp[0]; argn = 1; } i = 0; avn = cif->nargs; arg_types = cif->arg_types; /* Grab the addresses of the arguments from the stack frame. */ while (i < avn) { switch (arg_types[i]->type) { case FFI_TYPE_SINT8: case FFI_TYPE_UINT8: case FFI_TYPE_SINT16: case FFI_TYPE_UINT16: case FFI_TYPE_SINT32: case FFI_TYPE_UINT32: case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: case FFI_TYPE_POINTER: case FFI_TYPE_STRUCT: avalue[i] = &argp[argn]; break; case FFI_TYPE_FLOAT: if (argn < 6) { /* Floats coming from registers need conversion from double back to float format. */ *(float *)&argp[argn - 6] = *(double *)&argp[argn - 6]; avalue[i] = &argp[argn - 6]; } else avalue[i] = &argp[argn]; break; case FFI_TYPE_DOUBLE: avalue[i] = &argp[argn - (argn < 6 ? 6 : 0)]; break; default: FFI_ASSERT(0); } argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; i++; } /* Invoke the closure. */ (closure->fun) (cif, rvalue, avalue, closure->user_data); /* Tell ffi_closure_osf how to perform return type promotions. */ return cif->rtype->type; } --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for Alpha. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_OSF, FFI_DEFAULT_ABI = FFI_OSF, FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:24:26
|
Update of /cvsroot/ctypes/ctypes/source/libffi/src In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15610 Added Files: prep_cif.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: prep_cif.c --- /* ----------------------------------------------------------------------- prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* Round up to FFI_SIZEOF_ARG. */ #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) /* Perform machine independent initialization of aggregate type specifications. */ static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) { ffi_type **ptr; FFI_ASSERT(arg != NULL); /*@-usedef@*/ FFI_ASSERT(arg->elements != NULL); FFI_ASSERT(arg->size == 0); FFI_ASSERT(arg->alignment == 0); ptr = &(arg->elements[0]); while ((*ptr) != NULL) { if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; /* Perform a sanity check on the argument type */ FFI_ASSERT_VALID_TYPE(*ptr); arg->size = ALIGN(arg->size, (*ptr)->alignment); arg->size += (*ptr)->size; arg->alignment = (arg->alignment > (*ptr)->alignment) ? arg->alignment : (*ptr)->alignment; ptr++; } /* Structure size includes tail padding. This is important for structures that fit in one register on ABIs like the PowerPC64 Linux ABI that right justify small structs in a register. It's also needed for nested structure layout, for example struct A { long a; char b; }; struct B { struct A x; char y; }; should find y at an offset of 2*sizeof(long) and result in a total size of 3*sizeof(long). */ arg->size = ALIGN (arg->size, arg->alignment); if (arg->size == 0) return FFI_BAD_TYPEDEF; else return FFI_OK; /*@=usedef@*/ } #ifndef __CRIS__ /* The CRIS ABI specifies structure elements to have byte alignment only, so it completely overrides this functions, which assumes "natural" alignment and padding. */ /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, ffi_abi abi, unsigned int nargs, /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, /*@dependent@*/ ffi_type **atypes) { unsigned bytes = 0; unsigned int i; ffi_type **ptr; FFI_ASSERT(cif != NULL); FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); cif->abi = abi; cif->arg_types = atypes; cif->nargs = nargs; cif->rtype = rtype; cif->flags = 0; /* Initialize the return type if necessary */ /*@-usedef@*/ if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) return FFI_BAD_TYPEDEF; /*@=usedef@*/ /* Perform a sanity check on the return type */ FFI_ASSERT_VALID_TYPE(cif->rtype); /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ #if !defined M68K && !defined __x86_64__ && !defined S390 && !defined PA /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif ) bytes = STACK_ARG_SIZE(sizeof(void*)); #endif for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) { /* Initialize any uninitialized aggregate type definitions */ if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; /* Perform a sanity check on the argument type, do this check after the initialization. */ FFI_ASSERT_VALID_TYPE(*ptr); #if !defined __x86_64__ && !defined S390 && !defined PA #ifdef SPARC if (((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 16 || cif->abi != FFI_V9)) || ((*ptr)->type == FFI_TYPE_LONGDOUBLE && cif->abi != FFI_V9)) bytes += sizeof(void*); else #endif { /* Add any padding if necessary */ if (((*ptr)->alignment - 1) & bytes) bytes = ALIGN(bytes, (*ptr)->alignment); bytes += STACK_ARG_SIZE((*ptr)->size); } #endif } cif->bytes = bytes; /* Perform machine dependent cif processing */ return ffi_prep_cif_machdep(cif); } #endif /* not __CRIS__ */ |
From: Thomas H. <th...@us...> - 2006-03-03 20:24:21
|
Update of /cvsroot/ctypes/ctypes/source/libffi/include In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv15550 Added Files: ffi_common.h ffi.h.in Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: ffi_common.h --- /* ----------------------------------------------------------------------- ffi_common.h - Copyright (c) 1996 Red Hat, Inc. Common internal definitions and macros. Only necessary for building libffi. ----------------------------------------------------------------------- */ #ifndef FFI_COMMON_H #define FFI_COMMON_H #ifdef __cplusplus extern "C" { #endif #include <fficonfig.h> /* Do not move this. Some versions of AIX are very picky about where this is positioned. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # if HAVE_ALLOCA_H # include <alloca.h> # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); # endif # endif # endif #endif /* Check for the existence of memcpy. */ #if STDC_HEADERS # include <string.h> #else # ifndef HAVE_MEMCPY # define memcpy(d, s, n) bcopy ((s), (d), (n)) # endif #endif #if defined(FFI_DEBUG) #include <stdio.h> #endif #ifdef FFI_DEBUG /*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); void ffi_stop_here(void); void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); #define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) #define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) #define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) #else #define FFI_ASSERT(x) #define FFI_ASSERT_AT(x, f, l) #define FFI_ASSERT_VALID_TYPE(x) #endif #define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) #define ALIGN_DOWN(v, a) (((size_t) (v)) & -a) /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif); /* Extended cif, used in callback from assembly routine */ typedef struct { /*@dependent@*/ ffi_cif *cif; /*@dependent@*/ void *rvalue; /*@dependent@*/ void **avalue; } extended_cif; /* Terse sized type definitions. */ typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); typedef signed int SINT8 __attribute__((__mode__(__QI__))); typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); typedef signed int SINT16 __attribute__((__mode__(__HI__))); typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); typedef signed int SINT32 __attribute__((__mode__(__SI__))); typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); typedef signed int SINT64 __attribute__((__mode__(__DI__))); typedef float FLOAT32; #ifdef __cplusplus } #endif #endif --- NEW FILE: ffi.h.in --- /* -----------------------------------------------------------------*-C-*- libffi @VERSION@ - Copyright (c) 1996-2003 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------- The basic API is described in the README file. The raw API is designed to bypass some of the argument packing and unpacking on architectures for which it can be avoided. The closure API allows interpreted functions to be packaged up inside a C function pointer, so that they can be called as C functions, with no understanding on the client side that they are interpreted. It can also be used in other cases in which it is necessary to package up a user specified parameter and a function pointer as a single function pointer. The closure API must be implemented in order to get its functionality, e.g. for use by gij. Routines are provided to emulate the raw API if the underlying platform doesn't allow faster implementation. More details on the raw and cloure API can be found in: http://gcc.gnu.org/ml/java/1999-q3/msg00138.html and http://gcc.gnu.org/ml/java/1999-q3/msg00174.html -------------------------------------------------------------------- */ #ifndef LIBFFI_H #define LIBFFI_H #ifdef __cplusplus extern "C" { #endif /* Specify which architecture libffi is configured for. */ #define @TARGET@ /* ---- System configuration information --------------------------------- */ #include <ffitarget.h> #ifndef LIBFFI_ASM #include <stddef.h> #include <limits.h> /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). But we can find it either under the correct ANSI name, or under GNU C's internal name. */ #ifdef LONG_LONG_MAX # define FFI_LONG_LONG_MAX LONG_LONG_MAX #else # ifdef LLONG_MAX # define FFI_LONG_LONG_MAX LLONG_MAX # else # ifdef __GNUC__ # define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ # endif # endif #endif #if SCHAR_MAX == 127 # define ffi_type_uchar ffi_type_uint8 # define ffi_type_schar ffi_type_sint8 #else #error "char size not supported" #endif #if SHRT_MAX == 32767 # define ffi_type_ushort ffi_type_uint16 # define ffi_type_sshort ffi_type_sint16 #elif SHRT_MAX == 2147483647 # define ffi_type_ushort ffi_type_uint32 # define ffi_type_sshort ffi_type_sint32 #else #error "short size not supported" #endif #if INT_MAX == 32767 # define ffi_type_uint ffi_type_uint16 # define ffi_type_sint ffi_type_sint16 #elif INT_MAX == 2147483647 # define ffi_type_uint ffi_type_uint32 # define ffi_type_sint ffi_type_sint32 #elif INT_MAX == 9223372036854775807 # define ffi_type_uint ffi_type_uint64 # define ffi_type_sint ffi_type_sint64 #else #error "int size not supported" #endif #define ffi_type_ulong ffi_type_uint64 #define ffi_type_slong ffi_type_sint64 #if LONG_MAX == 2147483647 # if FFI_LONG_LONG_MAX != 9223372036854775807 #error "no 64-bit data type supported" # endif #elif LONG_MAX != 9223372036854775807 #error "long size not supported" #endif /* The closure code assumes that this works on pointers, i.e. a size_t */ /* can hold a pointer. */ typedef struct _ffi_type { size_t size; unsigned short alignment; unsigned short type; /*@null@*/ struct _ffi_type **elements; } ffi_type; /* These are defined in types.c */ extern ffi_type ffi_type_void; extern ffi_type ffi_type_uint8; extern ffi_type ffi_type_sint8; extern ffi_type ffi_type_uint16; extern ffi_type ffi_type_sint16; extern ffi_type ffi_type_uint32; extern ffi_type ffi_type_sint32; extern ffi_type ffi_type_uint64; extern ffi_type ffi_type_sint64; extern ffi_type ffi_type_float; extern ffi_type ffi_type_double; extern ffi_type ffi_type_longdouble; extern ffi_type ffi_type_pointer; typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, FFI_BAD_ABI } ffi_status; typedef unsigned FFI_TYPE; typedef struct { ffi_abi abi; unsigned nargs; /*@dependent@*/ ffi_type **arg_types; /*@dependent@*/ ffi_type *rtype; unsigned bytes; unsigned flags; #ifdef FFI_EXTRA_CIF_FIELDS FFI_EXTRA_CIF_FIELDS; #endif } ffi_cif; /* ---- Definitions for the raw API -------------------------------------- */ #ifndef FFI_SIZEOF_ARG # if LONG_MAX == 2147483647 # define FFI_SIZEOF_ARG 4 # elif LONG_MAX == 9223372036854775807 # define FFI_SIZEOF_ARG 8 # endif #endif typedef union { ffi_sarg sint; ffi_arg uint; float flt; char data[FFI_SIZEOF_ARG]; void* ptr; } ffi_raw; void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ ffi_raw *avalue); void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_raw_size (ffi_cif *cif); /* This is analogous to the raw API, except it uses Java parameter */ /* packing, even on 64-bit machines. I.e. on 64-bit machines */ /* longs and doubles are followed by an empty 64-bit word. */ void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ ffi_raw *avalue); void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_java_raw_size (ffi_cif *cif); /* ---- Definitions for closures ----------------------------------------- */ #if FFI_CLOSURES typedef struct { char tramp[FFI_TRAMPOLINE_SIZE]; ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; } ffi_closure __attribute__((aligned (8))); ffi_status ffi_prep_closure (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data); typedef struct { char tramp[FFI_TRAMPOLINE_SIZE]; ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* if this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the transaltion, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_raw*,void*); void *user_data; } ffi_raw_closure; ffi_status ffi_prep_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); ffi_status ffi_prep_java_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); #endif /* FFI_CLOSURES */ /* ---- Public interface definition -------------------------------------- */ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, ffi_abi abi, unsigned int nargs, /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, /*@dependent@*/ ffi_type **atypes); void ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue); /* Useful for eliminating compiler warnings */ #define FFI_FN(f) ((void (*)())f) /* ---- Definitions shared with assembly code ---------------------------- */ #endif /* If these change, update src/mips/ffitarget.h. */ #define FFI_TYPE_VOID 0 #define FFI_TYPE_INT 1 #define FFI_TYPE_FLOAT 2 #define FFI_TYPE_DOUBLE 3 #if @HAVE_LONG_DOUBLE@ #define FFI_TYPE_LONGDOUBLE 4 #else #define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE #endif #define FFI_TYPE_UINT8 5 #define FFI_TYPE_SINT8 6 #define FFI_TYPE_UINT16 7 #define FFI_TYPE_SINT16 8 #define FFI_TYPE_UINT32 9 #define FFI_TYPE_SINT32 10 #define FFI_TYPE_UINT64 11 #define FFI_TYPE_SINT64 12 #define FFI_TYPE_STRUCT 13 #define FFI_TYPE_POINTER 14 /* This should always refer to the last type code (for sanity checks) */ #define FFI_TYPE_LAST FFI_TYPE_POINTER #ifdef __cplusplus } #endif #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:20:25
|
Update of /cvsroot/ctypes/ctypes/wince In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12601 Added Files: _ctypes_test.vcp _ctypes.vcw _ctypes.vcp .cvsignore Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: .cvsignore --- ARMV4Dbg ARMV4Rel _ctypes.dep _ctypes.vcb _ctypes.vcl _ctypes.vcn _ctypes.vco _ctypes_test.dep _ctypes_test.vcb _ctypes_test.vcl _ctypes_test.vcn _ctypes_test.vco --- NEW FILE: _ctypes.vcp --- # Microsoft eMbedded Visual Tools Project File - Name="_ctypes" - Package Owner=<4> # Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02 # ** DO NOT EDIT ** # TARGTYPE "Win32 (WCE ARMV4T) Dynamic-Link Library" 0xa402 # TARGTYPE "Win32 (WCE x86) Dynamic-Link Library" 0x8302 # TARGTYPE "Win32 (WCE ARMV4) Dynamic-Link Library" 0xa302 # TARGTYPE "Win32 (WCE ARMV4I) Dynamic-Link Library" 0xa502 CFG=_ctypes - Win32 (WCE ARMV4) Debug !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "_ctypes.vcn". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "_ctypes.vcn" CFG="_ctypes - Win32 (WCE ARMV4) Debug" [...1727 lines suppressed...] "$(IntDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)" armasm -g -arch 4 $(InputPath) $(IntDir)\$(InputName).obj # End Custom Build !ELSEIF "$(CFG)" == "_ctypes - Win32 (WCE ARMV4T) Release" !ELSEIF "$(CFG)" == "_ctypes - Win32 (WCE ARMV4T) Debug" !ELSEIF "$(CFG)" == "_ctypes - Win32 (WCE x86) Release" !ELSEIF "$(CFG)" == "_ctypes - Win32 (WCE x86) Debug" !ENDIF # End Source File # End Group # End Target # End Project --- NEW FILE: _ctypes.vcw --- Microsoft eMbedded Visual Tools Workspace File, Format Version 4.00 # WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! ############################################################################### Project: "_ctypes"=.\_ctypes.vcp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Project: "_ctypes_test"=.\_ctypes_test.vcp - Package Owner=<4> Package=<5> {{{ }}} Package=<4> {{{ }}} ############################################################################### Global: Package=<5> {{{ }}} Package=<3> {{{ }}} ############################################################################### --- NEW FILE: _ctypes_test.vcp --- # Microsoft eMbedded Visual Tools Project File - Name="_ctypes_test" - Package Owner=<4> # Microsoft eMbedded Visual Tools Generated Build File, Format Version 6.02 # ** DO NOT EDIT ** # TARGTYPE "Win32 (WCE ARMV4T) Dynamic-Link Library" 0xa402 # TARGTYPE "Win32 (WCE x86) Dynamic-Link Library" 0x8302 # TARGTYPE "Win32 (WCE ARMV4) Dynamic-Link Library" 0xa302 # TARGTYPE "Win32 (WCE ARMV4I) Dynamic-Link Library" 0xa502 CFG=_CTYPES_TEST - WIN32 (WCE ARMV4) DEBUG !MESSAGE This is not a valid makefile. To build this project using NMAKE, !MESSAGE use the Export Makefile command and run !MESSAGE !MESSAGE NMAKE /f "_ctypes_test.vcn". !MESSAGE !MESSAGE You can specify a configuration when running NMAKE !MESSAGE by defining the macro CFG on the command line. For example: !MESSAGE !MESSAGE NMAKE /f "_ctypes_test.vcn" CFG="_CTYPES_TEST - WIN32 (WCE ARMV4) DEBUG" !MESSAGE !MESSAGE Possible choices for configuration are: !MESSAGE !MESSAGE "_ctypes_test - Win32 (WCE ARMV4I) Release" (based on "Win32 (WCE ARMV4I) Dynamic-Link Library") !MESSAGE "_ctypes_test - Win32 (WCE ARMV4I) Debug" (based on "Win32 (WCE ARMV4I) Dynamic-Link Library") !MESSAGE "_ctypes_test - Win32 (WCE ARMV4) Release" (based on "Win32 (WCE ARMV4) Dynamic-Link Library") !MESSAGE "_ctypes_test - Win32 (WCE ARMV4) Debug" (based on "Win32 (WCE ARMV4) Dynamic-Link Library") !MESSAGE "_ctypes_test - Win32 (WCE ARMV4T) Release" (based on "Win32 (WCE ARMV4T) Dynamic-Link Library") !MESSAGE "_ctypes_test - Win32 (WCE ARMV4T) Debug" (based on "Win32 (WCE ARMV4T) Dynamic-Link Library") !MESSAGE "_ctypes_test - Win32 (WCE x86) Release" (based on "Win32 (WCE x86) Dynamic-Link Library") !MESSAGE "_ctypes_test - Win32 (WCE x86) Debug" (based on "Win32 (WCE x86) Dynamic-Link Library") !MESSAGE # Begin Project # PROP AllowPerConfigDependencies 0 # PROP Scc_ProjName "" # PROP Scc_LocalPath "" # PROP ATL_Project 2 !IF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4I) Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "ARMV4IRel" # PROP BASE Intermediate_Dir "ARMV4IRel" # PROP BASE CPU_ID "{DC70F430-E78B-494F-A9D5-62ADC56443B8}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "ARMV4IRel" # PROP Intermediate_Dir "ARMV4IRel" # PROP CPU_ID "{DC70F430-E78B-494F-A9D5-62ADC56443B8}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4I" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4I" /r CPP=clarm.exe # ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "ARMV4I" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /O2 /M$(CECrtMT) /c # ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "ARMV4I" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /O2 /M$(CECrtMT) /c MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB # ADD LINK32 commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4I) Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "ARMV4IDbg" # PROP BASE Intermediate_Dir "ARMV4IDbg" # PROP BASE CPU_ID "{DC70F430-E78B-494F-A9D5-62ADC56443B8}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "ARMV4IDbg" # PROP Intermediate_Dir "ARMV4IDbg" # PROP CPU_ID "{DC70F430-E78B-494F-A9D5-62ADC56443B8}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4I" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4I" /r CPP=clarm.exe # ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "ARMV4I" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /M$(CECrtMTDebug) /c # ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "ARMV4I" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /M$(CECrtMTDebug) /c MTL=midl.exe # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB # ADD LINK32 commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4) Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "ARMV4Rel" # PROP BASE Intermediate_Dir "ARMV4Rel" # PROP BASE CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "ARMV4Rel" # PROP Intermediate_Dir "ARMV4Rel" # PROP CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "NDEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "NDEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /r CPP=clarm.exe # ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /O2 /M$(CECrtMT) /c # ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /O2 /M$(CECrtMT) /c MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM # ADD LINK32 commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"$(CENoDefaultLib)" /out:"ARMV4Rel/_ctypes_test.pyd" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4) Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "ARMV4Dbg" # PROP BASE Intermediate_Dir "ARMV4Dbg" # PROP BASE CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "ARMV4Dbg" # PROP Intermediate_Dir "ARMV4Dbg" # PROP CPU_ID "{ECBEA43D-CD7B-4852-AD55-D4227B5D624B}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "DEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "DEBUG" /d "UNICODE" /d "_UNICODE" /d "$(CePlatform)" /d "ARM" /d "_ARM_" /d "ARMV4" /r CPP=clarm.exe # ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /M$(CECrtMTDebug) /c # ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "ARM" /D "_ARM_" /D "ARMV4" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /M$(CECrtMTDebug) /c MTL=midl.exe # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM # ADD LINK32 commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"$(CENoDefaultLib)" /out:"ARMV4Dbg/_ctypes_test.pyd" /subsystem:$(CESubsystem) /align:"4096" /MACHINE:ARM !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4T) Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "ARMV4TRel" # PROP BASE Intermediate_Dir "ARMV4TRel" # PROP BASE CPU_ID "{F52316A9-3B7C-4FE7-A67F-68350B41240D}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "ARMV4TRel" # PROP Intermediate_Dir "ARMV4TRel" # PROP CPU_ID "{F52316A9-3B7C-4FE7-A67F-68350B41240D}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4T" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4T" /r CPP=clthumb.exe # ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "THUMB" /D "_THUMB_" /D "ARMV4T" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /O2 /M$(CECrtMT) /c # ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "THUMB" /D "_THUMB_" /D "ARMV4T" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /O2 /M$(CECrtMT) /c MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB # ADD LINK32 commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4T) Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "ARMV4TDbg" # PROP BASE Intermediate_Dir "ARMV4TDbg" # PROP BASE CPU_ID "{F52316A9-3B7C-4FE7-A67F-68350B41240D}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "ARMV4TDbg" # PROP Intermediate_Dir "ARMV4TDbg" # PROP CPU_ID "{F52316A9-3B7C-4FE7-A67F-68350B41240D}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4T" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "THUMB" /d "_THUMB_" /d "ARM" /d "_ARM_" /d "ARMV4T" /r CPP=clthumb.exe # ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "THUMB" /D "_THUMB_" /D "ARMV4T" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /M$(CECrtMTDebug) /c # ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "ARM" /D "_ARM_" /D "$(CePlatform)" /D "THUMB" /D "_THUMB_" /D "ARMV4T" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /QRarch4T /QRinterwork-return /M$(CECrtMTDebug) /c MTL=midl.exe # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB # ADD LINK32 commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"$(CENoDefaultLib)" /subsystem:$(CESubsystem) /MACHINE:THUMB !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE x86) Release" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 0 # PROP BASE Output_Dir "X86Rel" # PROP BASE Intermediate_Dir "X86Rel" # PROP BASE CPU_ID "{D6518FF3-710F-11D3-99F2-00105A0DF099}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 0 # PROP Output_Dir "X86Rel" # PROP Intermediate_Dir "X86Rel" # PROP CPU_ID "{D6518FF3-710F-11D3-99F2-00105A0DF099}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "NDEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /r CPP=cl.exe # ADD BASE CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "_i386_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /Gs8192 /GF /O2 /c # ADD CPP /nologo /W3 /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "_i386_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "NDEBUG" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /Gs8192 /GF /O2 /c MTL=midl.exe # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib $(CEx86Corelibc) /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"OLDNAMES.lib" /nodefaultlib:$(CENoDefaultLib) /subsystem:$(CESubsystem) /MACHINE:IX86 # ADD LINK32 $(CEx86Corelibc) commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /nodefaultlib:"OLDNAMES.lib" /nodefaultlib:$(CENoDefaultLib) /subsystem:$(CESubsystem) /MACHINE:IX86 !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE x86) Debug" # PROP BASE Use_MFC 0 # PROP BASE Use_Debug_Libraries 1 # PROP BASE Output_Dir "X86Dbg" # PROP BASE Intermediate_Dir "X86Dbg" # PROP BASE CPU_ID "{D6518FF3-710F-11D3-99F2-00105A0DF099}" # PROP BASE Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP BASE Target_Dir "" # PROP Use_MFC 0 # PROP Use_Debug_Libraries 1 # PROP Output_Dir "X86Dbg" # PROP Intermediate_Dir "X86Dbg" # PROP CPU_ID "{D6518FF3-710F-11D3-99F2-00105A0DF099}" # PROP Platform_ID "{8A9A2F80-6887-11D3-842E-005004848CBA}" # PROP Ignore_Export_Lib 0 # PROP Target_Dir "" RSC=rc.exe # ADD BASE RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /r # ADD RSC /l 0x409 /d UNDER_CE=$(CEVersion) /d _WIN32_WCE=$(CEVersion) /d "UNICODE" /d "_UNICODE" /d "DEBUG" /d "$(CePlatform)" /d "_X86_" /d "x86" /d "_i386_" /r CPP=cl.exe # ADD BASE CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "_i386_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /Gs8192 /GF /c # ADD CPP /nologo /W3 /Zi /Od /D "DEBUG" /D _WIN32_WCE=$(CEVersion) /D "$(CePlatform)" /D "_i386_" /D UNDER_CE=$(CEVersion) /D "UNICODE" /D "_UNICODE" /D "_X86_" /D "x86" /D "_USRDLL" /D "_CTYPES_TEST_EXPORTS" /YX /Gs8192 /GF /c MTL=midl.exe # ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 # ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o "NUL" /win32 BSC32=bscmake.exe # ADD BASE BSC32 /nologo # ADD BSC32 /nologo LINK32=link.exe # ADD BASE LINK32 commctrl.lib coredll.lib $(CEx86Corelibc) /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"OLDNAMES.lib" /nodefaultlib:$(CENoDefaultLib) /subsystem:$(CESubsystem) /MACHINE:IX86 # ADD LINK32 $(CEx86Corelibc) commctrl.lib coredll.lib oleaut32.lib /nologo /base:"0x00100000" /stack:0x10000,0x1000 /entry:"_DllMainCRTStartup" /dll /debug /nodefaultlib:"OLDNAMES.lib" /nodefaultlib:$(CENoDefaultLib) /subsystem:$(CESubsystem) /MACHINE:IX86 !ENDIF # Begin Target # Name "_ctypes_test - Win32 (WCE ARMV4I) Release" # Name "_ctypes_test - Win32 (WCE ARMV4I) Debug" # Name "_ctypes_test - Win32 (WCE ARMV4) Release" # Name "_ctypes_test - Win32 (WCE ARMV4) Debug" # Name "_ctypes_test - Win32 (WCE ARMV4T) Release" # Name "_ctypes_test - Win32 (WCE ARMV4T) Debug" # Name "_ctypes_test - Win32 (WCE x86) Release" # Name "_ctypes_test - Win32 (WCE x86) Debug" # Begin Group "Source Files" # PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" # Begin Source File SOURCE=..\source\_ctypes_test.c !IF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4I) Release" !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4I) Debug" !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4) Release" DEP_CPP__CTYP=\ {$(INCLUDE)}"abstract.h"\ {$(INCLUDE)}"basetsd.h"\ {$(INCLUDE)}"boolobject.h"\ {$(INCLUDE)}"bufferobject.h"\ {$(INCLUDE)}"cellobject.h"\ {$(INCLUDE)}"ceval.h"\ {$(INCLUDE)}"classobject.h"\ {$(INCLUDE)}"cobject.h"\ {$(INCLUDE)}"complexobject.h"\ {$(INCLUDE)}"descrobject.h"\ {$(INCLUDE)}"dictobject.h"\ {$(INCLUDE)}"enumobject.h"\ {$(INCLUDE)}"fileobject.h"\ {$(INCLUDE)}"floatobject.h"\ {$(INCLUDE)}"funcobject.h"\ {$(INCLUDE)}"import.h"\ {$(INCLUDE)}"intobject.h"\ {$(INCLUDE)}"intrcheck.h"\ {$(INCLUDE)}"iterobject.h"\ {$(INCLUDE)}"listobject.h"\ {$(INCLUDE)}"longobject.h"\ {$(INCLUDE)}"methodobject.h"\ {$(INCLUDE)}"modsupport.h"\ {$(INCLUDE)}"moduleobject.h"\ {$(INCLUDE)}"object.h"\ {$(INCLUDE)}"objimpl.h"\ {$(INCLUDE)}"patchlevel.h"\ {$(INCLUDE)}"pyconfig.h"\ {$(INCLUDE)}"pydebug.h"\ {$(INCLUDE)}"pyerrors.h"\ {$(INCLUDE)}"pyfpe.h"\ {$(INCLUDE)}"pymem.h"\ {$(INCLUDE)}"pyport.h"\ {$(INCLUDE)}"pystate.h"\ {$(INCLUDE)}"Python.h"\ {$(INCLUDE)}"pythonrun.h"\ {$(INCLUDE)}"rangeobject.h"\ {$(INCLUDE)}"sliceobject.h"\ {$(INCLUDE)}"stringobject.h"\ {$(INCLUDE)}"sysmodule.h"\ {$(INCLUDE)}"traceback.h"\ {$(INCLUDE)}"tupleobject.h"\ {$(INCLUDE)}"unicodeobject.h"\ {$(INCLUDE)}"weakrefobject.h"\ {$(INCLUDE)}"wince-compatibility.h"\ NODEP_CPP__CTYP=\ "..\..\..\PYTHON-2.3.5-WINCE\INCLUDE\unixstuff.h"\ !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4) Debug" DEP_CPP__CTYP=\ {$(INCLUDE)}"abstract.h"\ {$(INCLUDE)}"basetsd.h"\ {$(INCLUDE)}"boolobject.h"\ {$(INCLUDE)}"bufferobject.h"\ {$(INCLUDE)}"cellobject.h"\ {$(INCLUDE)}"ceval.h"\ {$(INCLUDE)}"classobject.h"\ {$(INCLUDE)}"cobject.h"\ {$(INCLUDE)}"complexobject.h"\ {$(INCLUDE)}"descrobject.h"\ {$(INCLUDE)}"dictobject.h"\ {$(INCLUDE)}"enumobject.h"\ {$(INCLUDE)}"fileobject.h"\ {$(INCLUDE)}"floatobject.h"\ {$(INCLUDE)}"funcobject.h"\ {$(INCLUDE)}"import.h"\ {$(INCLUDE)}"intobject.h"\ {$(INCLUDE)}"intrcheck.h"\ {$(INCLUDE)}"iterobject.h"\ {$(INCLUDE)}"listobject.h"\ {$(INCLUDE)}"longobject.h"\ {$(INCLUDE)}"methodobject.h"\ {$(INCLUDE)}"modsupport.h"\ {$(INCLUDE)}"moduleobject.h"\ {$(INCLUDE)}"object.h"\ {$(INCLUDE)}"objimpl.h"\ {$(INCLUDE)}"patchlevel.h"\ {$(INCLUDE)}"pyconfig.h"\ {$(INCLUDE)}"pydebug.h"\ {$(INCLUDE)}"pyerrors.h"\ {$(INCLUDE)}"pyfpe.h"\ {$(INCLUDE)}"pymem.h"\ {$(INCLUDE)}"pyport.h"\ {$(INCLUDE)}"pystate.h"\ {$(INCLUDE)}"Python.h"\ {$(INCLUDE)}"pythonrun.h"\ {$(INCLUDE)}"rangeobject.h"\ {$(INCLUDE)}"sliceobject.h"\ {$(INCLUDE)}"stringobject.h"\ {$(INCLUDE)}"sysmodule.h"\ {$(INCLUDE)}"traceback.h"\ {$(INCLUDE)}"tupleobject.h"\ {$(INCLUDE)}"unicodeobject.h"\ {$(INCLUDE)}"weakrefobject.h"\ {$(INCLUDE)}"wince-compatibility.h"\ NODEP_CPP__CTYP=\ "..\..\..\PYTHON-2.3.5-WINCE\INCLUDE\unixstuff.h"\ !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4T) Release" !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE ARMV4T) Debug" !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE x86) Release" !ELSEIF "$(CFG)" == "_ctypes_test - Win32 (WCE x86) Debug" !ENDIF # End Source File # End Group # Begin Group "Header Files" # PROP Default_Filter "h;hpp;hxx;hm;inl" # End Group # Begin Group "Resource Files" # PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" # End Group # End Target # End Project |
From: Thomas H. <th...@us...> - 2006-03-03 20:20:15
|
Update of /cvsroot/ctypes/ctypes/source/libffi_msvc In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12289 Added Files: win32.c win32.S types.c prep_cif.c ffitarget.h fficonfig.h ffi_common.h ffi.h ffi.c README.ctypes README LICENSE Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: ffi_common.h --- /* ----------------------------------------------------------------------- ffi_common.h - Copyright (c) 1996 Red Hat, Inc. Common internal definitions and macros. Only necessary for building libffi. ----------------------------------------------------------------------- */ #ifndef FFI_COMMON_H #define FFI_COMMON_H #ifdef __cplusplus extern "C" { #endif #include <fficonfig.h> /* Do not move this. Some versions of AIX are very picky about where this is positioned. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # if HAVE_ALLOCA_H # include <alloca.h> # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); # endif # endif # endif #endif /* Check for the existence of memcpy. */ #if STDC_HEADERS # include <string.h> #else # ifndef HAVE_MEMCPY # define memcpy(d, s, n) bcopy ((s), (d), (n)) # endif #endif #if defined(FFI_DEBUG) #include <stdio.h> #endif #ifdef FFI_DEBUG /*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); void ffi_stop_here(void); void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); #define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) #define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) #define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) #else #define FFI_ASSERT(x) #define FFI_ASSERT_AT(x, f, l) #define FFI_ASSERT_VALID_TYPE(x) #endif #define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif); /* Extended cif, used in callback from assembly routine */ typedef struct { /*@dependent@*/ ffi_cif *cif; /*@dependent@*/ void *rvalue; /*@dependent@*/ void **avalue; } extended_cif; /* Terse sized type definitions. */ typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); typedef signed int SINT8 __attribute__((__mode__(__QI__))); typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); typedef signed int SINT16 __attribute__((__mode__(__HI__))); typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); typedef signed int SINT32 __attribute__((__mode__(__SI__))); typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); typedef signed int SINT64 __attribute__((__mode__(__DI__))); typedef float FLOAT32; #ifdef __cplusplus } #endif #endif --- NEW FILE: LICENSE --- libffi - Copyright (c) 1996-2003 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for x86 and x86-64. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H /* ---- System specific configurations ----------------------------------- */ #if defined (X86_64) && defined (__i386__) #undef X86_64 #define X86 #endif /* ---- Generic type definitions ----------------------------------------- */ #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, /* ---- Intel x86 Win32 ---------- */ #if defined(X86_WIN32) || defined(_MSC_VER) FFI_SYSV, FFI_STDCALL, /* TODO: Add fastcall support for the sake of completeness */ FFI_DEFAULT_ABI = FFI_SYSV, #endif /* ---- Intel x86 and AMD x86-64 - */ #if !defined(X86_WIN32) && (defined(__i386__) || defined(__x86_64__)) FFI_SYSV, FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */ #ifdef __i386__ FFI_DEFAULT_ABI = FFI_SYSV, #else FFI_DEFAULT_ABI = FFI_UNIX64, #endif #endif FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #ifdef X86_64 #define FFI_TRAMPOLINE_SIZE 24 #define FFI_NATIVE_RAW_API 0 #else #ifdef _MSC_VER # define FFI_TRAMPOLINE_SIZE 15 #else # define FFI_TRAMPOLINE_SIZE 10 #endif #define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */ #endif #endif --- NEW FILE: win32.S --- /* ----------------------------------------------------------------------- win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. Copyright (c) 2001 John Beniton Copyright (c) 2002 Ranjit Mathew X86 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 CYGNUS SOLUTIONS 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> .text .globl ffi_prep_args # This assumes we are using gas. .balign 16 .globl _ffi_call_SYSV _ffi_call_SYSV: pushl %ebp movl %esp,%ebp # Make room for all of the new args. movl 16(%ebp),%ecx subl %ecx,%esp movl %esp,%eax # Place all of the ffi_prep_args in position pushl 12(%ebp) pushl %eax call *8(%ebp) # Return stack to previous state and call the function addl $8,%esp # FIXME: Align the stack to a 128-bit boundary to avoid # potential performance hits. call *28(%ebp) # Remove the space we pushed for the args movl 16(%ebp),%ecx addl %ecx,%esp # Load %ecx with the return type code movl 20(%ebp),%ecx # If the return value pointer is NULL, assume no return value. cmpl $0,24(%ebp) jne retint # Even if there is no space for the return value, we are # obliged to handle floating-point values. cmpl $FFI_TYPE_FLOAT,%ecx jne noretval fstp %st(0) jmp epilogue retint: cmpl $FFI_TYPE_INT,%ecx jne retfloat # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx movl %eax,0(%ecx) jmp epilogue retfloat: cmpl $FFI_TYPE_FLOAT,%ecx jne retdouble # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx fstps (%ecx) jmp epilogue retdouble: cmpl $FFI_TYPE_DOUBLE,%ecx jne retlongdouble # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx fstpl (%ecx) jmp epilogue retlongdouble: cmpl $FFI_TYPE_LONGDOUBLE,%ecx jne retint64 # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx fstpt (%ecx) jmp epilogue retint64: cmpl $FFI_TYPE_SINT64,%ecx jne retstruct # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx movl %eax,0(%ecx) movl %edx,4(%ecx) retstruct: # Nothing to do! noretval: epilogue: movl %ebp,%esp popl %ebp ret .ffi_call_SYSV_end: # This assumes we are using gas. .balign 16 .globl _ffi_call_STDCALL _ffi_call_STDCALL: pushl %ebp movl %esp,%ebp # Make room for all of the new args. movl 16(%ebp),%ecx subl %ecx,%esp movl %esp,%eax # Place all of the ffi_prep_args in position pushl 12(%ebp) pushl %eax call *8(%ebp) # Return stack to previous state and call the function addl $8,%esp # FIXME: Align the stack to a 128-bit boundary to avoid # potential performance hits. call *28(%ebp) # stdcall functions pop arguments off the stack themselves # Load %ecx with the return type code movl 20(%ebp),%ecx # If the return value pointer is NULL, assume no return value. cmpl $0,24(%ebp) jne sc_retint # Even if there is no space for the return value, we are # obliged to handle floating-point values. cmpl $FFI_TYPE_FLOAT,%ecx jne sc_noretval fstp %st(0) jmp sc_epilogue sc_retint: cmpl $FFI_TYPE_INT,%ecx jne sc_retfloat # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx movl %eax,0(%ecx) jmp sc_epilogue sc_retfloat: cmpl $FFI_TYPE_FLOAT,%ecx jne sc_retdouble # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx fstps (%ecx) jmp sc_epilogue sc_retdouble: cmpl $FFI_TYPE_DOUBLE,%ecx jne sc_retlongdouble # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx fstpl (%ecx) jmp sc_epilogue sc_retlongdouble: cmpl $FFI_TYPE_LONGDOUBLE,%ecx jne sc_retint64 # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx fstpt (%ecx) jmp sc_epilogue sc_retint64: cmpl $FFI_TYPE_SINT64,%ecx jne sc_retstruct # Load %ecx with the pointer to storage for the return value movl 24(%ebp),%ecx movl %eax,0(%ecx) movl %edx,4(%ecx) sc_retstruct: # Nothing to do! sc_noretval: sc_epilogue: movl %ebp,%esp popl %ebp ret .ffi_call_STDCALL_end: --- NEW FILE: prep_cif.c --- /* ----------------------------------------------------------------------- prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* Round up to FFI_SIZEOF_ARG. */ #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) /* Perform machine independent initialization of aggregate type specifications. */ static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) { ffi_type **ptr; FFI_ASSERT(arg != NULL); /*@-usedef@*/ FFI_ASSERT(arg->elements != NULL); FFI_ASSERT(arg->size == 0); FFI_ASSERT(arg->alignment == 0); ptr = &(arg->elements[0]); while ((*ptr) != NULL) { if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; /* Perform a sanity check on the argument type */ FFI_ASSERT_VALID_TYPE(*ptr); arg->size = ALIGN(arg->size, (*ptr)->alignment); arg->size += (*ptr)->size; arg->alignment = (arg->alignment > (*ptr)->alignment) ? arg->alignment : (*ptr)->alignment; ptr++; } /* Structure size includes tail padding. This is important for structures that fit in one register on ABIs like the PowerPC64 Linux ABI that right justify small structs in a register. It's also needed for nested structure layout, for example struct A { long a; char b; }; struct B { struct A x; char y; }; should find y at an offset of 2*sizeof(long) and result in a total size of 3*sizeof(long). */ arg->size = ALIGN (arg->size, arg->alignment); if (arg->size == 0) return FFI_BAD_TYPEDEF; else return FFI_OK; /*@=usedef@*/ } /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, ffi_abi abi, unsigned int nargs, /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, /*@dependent@*/ ffi_type **atypes) { unsigned bytes = 0; unsigned int i; ffi_type **ptr; FFI_ASSERT(cif != NULL); FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); cif->abi = abi; cif->arg_types = atypes; cif->nargs = nargs; cif->rtype = rtype; cif->flags = 0; /* Initialize the return type if necessary */ /*@-usedef@*/ if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) return FFI_BAD_TYPEDEF; /*@=usedef@*/ /* Perform a sanity check on the return type */ FFI_ASSERT_VALID_TYPE(cif->rtype); /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ #if !defined M68K && !defined __x86_64__ && !defined S390 /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT /* MSVC returns small structures in registers. But we have a different workaround: pretend int32 or int64 return type, and converting to structure afterwards. */ #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif ) bytes = STACK_ARG_SIZE(sizeof(void*)); #endif for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) { /* Initialize any uninitialized aggregate type definitions */ if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; /* Perform a sanity check on the argument type, do this check after the initialization. */ FFI_ASSERT_VALID_TYPE(*ptr); #if !defined __x86_64__ && !defined S390 #ifdef SPARC if (((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 16 || cif->abi != FFI_V9)) || ((*ptr)->type == FFI_TYPE_LONGDOUBLE && cif->abi != FFI_V9)) bytes += sizeof(void*); else #endif { #ifndef _MSC_VER /* Don't know if this is a libffi bug or not. At least on Windows with MSVC, function call parameters are *not* aligned in the same way as structure fields are, they are only aligned in integer boundaries. This doesn't do any harm for cdecl functions and closures, since the caller cleans up the stack, but it is wrong for stdcall functions where the callee cleans. */ /* Add any padding if necessary */ if (((*ptr)->alignment - 1) & bytes) bytes = ALIGN(bytes, (*ptr)->alignment); #endif bytes += STACK_ARG_SIZE((*ptr)->size); } #endif } cif->bytes = bytes; /* Perform machine dependent cif processing */ return ffi_prep_cif_machdep(cif); } --- NEW FILE: fficonfig.h --- /* fficonfig.h. Originally created by configure, now hand_maintained for MSVC. */ /* fficonfig.h. Generated automatically by configure. */ /* fficonfig.h.in. Generated automatically from configure.in by autoheader. */ /* Defines for MSVC */ #define __attribute__(x) /* */ #define alloca _alloca /*----------------------------------------------------------------*/ /* Define if using alloca.c. */ /* #undef C_ALLOCA */ /* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. This function is required for alloca.c support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define if you have alloca, as a function or macro. */ #define HAVE_ALLOCA 1 /* Define if you have <alloca.h> and it should be used (not on Ultrix). */ /* #define HAVE_ALLOCA_H 1 */ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define if you have the memcpy function. */ #define HAVE_MEMCPY 1 /* Define if read-only mmap of a plain file works. */ //#define HAVE_MMAP_FILE 1 /* Define if mmap of /dev/zero works. */ //#define HAVE_MMAP_DEV_ZERO 1 /* Define if mmap with MAP_ANON(YMOUS) works. */ //#define HAVE_MMAP_ANON 1 /* The number of bytes in type double */ #define SIZEOF_DOUBLE 8 /* The number of bytes in type long double */ #define SIZEOF_LONG_DOUBLE 12 /* Define if you have the long double type and it is bigger than a double */ #define HAVE_LONG_DOUBLE 1 /* whether byteorder is bigendian */ /* #undef WORDS_BIGENDIAN */ /* Define if the host machine stores words of multi-word integers in big-endian order. */ /* #undef HOST_WORDS_BIG_ENDIAN */ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ #define BYTEORDER 1234 /* Define if your assembler and linker support unaligned PC relative relocs. */ /* #undef HAVE_AS_SPARC_UA_PCREL */ /* Define if your assembler supports .register. */ /* #undef HAVE_AS_REGISTER_PSEUDO_OP */ /* Define if .eh_frame sections should be read-only. */ /* #undef HAVE_RO_EH_FRAME */ /* Define to the flags needed for the .section .eh_frame directive. */ /* #define EH_FRAME_FLAGS "aw" */ /* Define to the flags needed for the .section .eh_frame directive. */ /* #define EH_FRAME_FLAGS "aw" */ /* Define this if you want extra debugging. */ /* #undef FFI_DEBUG */ /* Define this is you do not want support for aggregate types. */ /* #undef FFI_NO_STRUCTS */ /* Define this is you do not want support for the raw API. */ /* #undef FFI_NO_RAW_API */ /* Define this if you are using Purify and want to suppress spurious messages. */ /* #undef USING_PURIFY */ --- NEW FILE: README.ctypes --- The purpose is to hack the libffi sources so that they can be compiled with MSVC, and to extend them so that they have the features I need for ctypes. I retrieved the libffi sources from the gcc cvs repository on 2004-01-27. Then I did 'configure' in a 'build' subdirectory on a x86 linux system, and copied the files I found useful. --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc. Copyright (c) 2002 Ranjit Mathew Copyright (c) 2002 Bo Thorsen Copyright (c) 2002 Roger Sayle x86 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef __x86_64__ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ /*@-exportheader@*/ void ffi_prep_args(char *stack, extended_cif *ecif) /*@=exportheader@*/ { register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; argp = stack; if (ecif->cif->rtype->type == FFI_TYPE_STRUCT) { *(void **) argp = ecif->rvalue; argp += 4; } p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i != 0; i--, p_arg++) { size_t z; /* Align if necessary */ if ((sizeof(int) - 1) & (unsigned) argp) argp = (char *) ALIGN(argp, sizeof(int)); z = (*p_arg)->size; if (z < sizeof(int)) { z = sizeof(int); switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); break; case FFI_TYPE_UINT8: *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); break; case FFI_TYPE_SINT16: *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); break; case FFI_TYPE_UINT16: *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); break; case FFI_TYPE_SINT32: *(signed int *) argp = (signed int)*(SINT32 *)(* p_argv); break; case FFI_TYPE_UINT32: *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); break; case FFI_TYPE_STRUCT: *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); break; default: FFI_ASSERT(0); } } else { memcpy(argp, *p_argv, z); } p_argv++; argp += z; } return; } /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: case FFI_TYPE_SINT64: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_LONGDOUBLE: cif->flags = (unsigned) cif->rtype->type; break; case FFI_TYPE_UINT64: cif->flags = FFI_TYPE_SINT64; break; default: cif->flags = FFI_TYPE_INT; break; } return FFI_OK; } /*@-declundef@*/ /*@-exportheader@*/ #ifdef _MSC_VER extern int #else extern void #endif ffi_call_SYSV(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); /*@=declundef@*/ /*@=exportheader@*/ #if defined(X86_WIN32) || defined(_MSC_VER) /*@-declundef@*/ /*@-exportheader@*/ #ifdef _MSC_VER extern int #else extern void #endif ffi_call_STDCALL(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); /*@=declundef@*/ /*@=exportheader@*/ #endif /* X86_WIN32 || _MSC_VER*/ #ifdef _MSC_VER int #else void #endif ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ #ifdef _MSC_VER return #endif ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #if defined(X86_WIN32) || defined(_MSC_VER) case FFI_STDCALL: /*@-usedef@*/ #ifdef _MSC_VER return #endif ffi_call_STDCALL(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; #endif /* X86_WIN32 */ default: FFI_ASSERT(0); break; } return -1; /* theller: Hrm. */ } /** private members **/ static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, void** args, ffi_cif* cif); #ifndef _MSC_VER static void ffi_closure_SYSV (ffi_closure *) __attribute__ ((regparm(1))); static void ffi_closure_raw_SYSV (ffi_raw_closure *) __attribute__ ((regparm(1))); #endif /* This function is jumped to by the trampoline */ #ifdef _MSC_VER static void __fastcall ffi_closure_SYSV (ffi_closure *closure, int *argp) #else static void ffi_closure_SYSV (closure) ffi_closure *closure; #endif { // this is our return value storage long double res; // our various things... ffi_cif *cif; void **arg_area; unsigned short rtype; void *resp = (void*)&res; #ifdef _MSC_VER void *args = &argp[1]; #else void *args = __builtin_dwarf_cfa (); #endif cif = closure->cif; arg_area = (void**) alloca (cif->nargs * sizeof (void*)); /* this call will initialize ARG_AREA, such that each * element in that array points to the corresponding * value on the stack; and if the function returns * a structure, it will re-set RESP to point to the * structure return address. */ ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif); (closure->fun) (cif, resp, arg_area, closure->user_data); rtype = cif->flags; #ifdef _MSC_VER /* now, do a generic return based on the value of rtype */ if (rtype == FFI_TYPE_INT) { _asm mov eax, resp ; _asm mov eax, [eax] ; } else if (rtype == FFI_TYPE_FLOAT) { _asm mov eax, resp ; _asm fld DWORD PTR [eax] ; // asm ("flds (%0)" : : "r" (resp) : "st" ); } else if (rtype == FFI_TYPE_DOUBLE) { _asm mov eax, resp ; _asm fld QWORD PTR [eax] ; // asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_LONGDOUBLE) { // asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_SINT64) { _asm mov edx, resp ; _asm mov eax, [edx] ; _asm mov edx, [edx + 4] ; // asm ("movl 0(%0),%%eax;" // "movl 4(%0),%%edx" // : : "r"(resp) // : "eax", "edx"); } #else /* now, do a generic return based on the value of rtype */ if (rtype == FFI_TYPE_INT) { asm ("movl (%0),%%eax" : : "r" (resp) : "eax"); } else if (rtype == FFI_TYPE_FLOAT) { asm ("flds (%0)" : : "r" (resp) : "st" ); } else if (rtype == FFI_TYPE_DOUBLE) { asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_LONGDOUBLE) { asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" ); } else if (rtype == FFI_TYPE_SINT64) { asm ("movl 0(%0),%%eax;" "movl 4(%0),%%edx" : : "r"(resp) : "eax", "edx"); } #endif } /*@-exportheader@*/ static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, ffi_cif *cif) /*@=exportheader@*/ { register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; argp = stack; if ( cif->rtype->type == FFI_TYPE_STRUCT ) { *rvalue = *(void **) argp; argp += 4; } p_argv = avalue; for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) { size_t z; /* Align if necessary */ if ((sizeof(int) - 1) & (unsigned) argp) { argp = (char *) ALIGN(argp, sizeof(int)); } z = (*p_arg)->size; /* because we're little endian, this is what it turns into. */ *p_argv = (void*) argp; p_argv++; argp += z; } return; } /* How to make a trampoline. Derived from gcc/config/i386/i386.c. */ /* MOV EDX, ESP is 0x8b 0xd4 */ #ifdef _MSC_VER #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,BYTES) \ { unsigned char *__tramp = (unsigned char*)(TRAMP); \ unsigned int __fun = (unsigned int)(FUN); \ unsigned int __ctx = (unsigned int)(CTX); \ unsigned int __dis = __fun - ((unsigned int) __tramp + 8 + 4); \ *(unsigned char*) &__tramp[0] = 0xb9; \ *(unsigned int*) &__tramp[1] = __ctx; /* mov ecx, __ctx */ \ *(unsigned char*) &__tramp[5] = 0x8b; \ *(unsigned char*) &__tramp[6] = 0xd4; \ *(unsigned char*) &__tramp[7] = 0xe8; \ *(unsigned int*) &__tramp[8] = __dis; /* call __fun */ \ *(unsigned char*) &__tramp[12] = 0xC2; /* ret BYTES */ \ *(unsigned short*) &__tramp[13] = BYTES; \ } #else #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX,BYTES) \ ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \ unsigned int __fun = (unsigned int)(FUN); \ unsigned int __ctx = (unsigned int)(CTX); \ unsigned int __dis = __fun - ((unsigned int) __tramp + FFI_TRAMPOLINE_SIZE); \ *(unsigned char*) &__tramp[0] = 0xb8; \ *(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \ *(unsigned char *) &__tramp[5] = 0xe9; \ *(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \ }) #endif /* the cif must already be prep'ed */ ffi_status ffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) { short bytes; FFI_ASSERT (cif->abi == FFI_SYSV); if (cif->abi == FFI_SYSV) bytes = 0; #ifdef _MSC_VER else if (cif->abi == FFI_STDCALL) bytes = cif->bytes; #endif else return FFI_BAD_ABI; FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV, (void*)closure, bytes); closure->cif = cif; closure->user_data = user_data; closure->fun = fun; return FFI_OK; } #endif /* __x86_64__ */ --- NEW FILE: win32.c --- /* ----------------------------------------------------------------------- win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc. Copyright (c) 2001 John Beniton Copyright (c) 2002 Ranjit Mathew X86 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ /* theller: almost verbatim translation from gas syntax to MSVC inline assembler code. */ /* theller: ffi_call_SYSV and ffi_call_STDCALL now return an integer - the difference of the stack pointer before and after the function call. If everything is ok, zero is returned. If stdcall functions are passed the wrong number of arguments, the difference will be nonzero. */ #include <ffi.h> #include <ffi_common.h> __declspec(naked) int ffi_call_SYSV(void (* prepfunc)(char *, extended_cif *), /* 8 */ extended_cif *ecif, /* 12 */ unsigned bytes, /* 16 */ unsigned flags, /* 20 */ unsigned *rvalue, /* 24 */ void (*fn)()) /* 28 */ { _asm { push ebp mov ebp, esp push esi // NEW: this register must be preserved across function calls // XXX SAVE ESP NOW! mov esi, esp // save stack pointer before the call // Make room for all of the new args. mov ecx, [ebp+16] sub esp, ecx // sub esp, bytes mov eax, esp // Place all of the ffi_prep_args in position push [ebp + 12] // ecif push eax call [ebp + 8] // prepfunc // Return stack to previous state and call the function add esp, 8 // FIXME: Align the stack to a 128-bit boundary to avoid // potential performance hits. call [ebp + 28] // Remove the space we pushed for the args mov ecx, [ebp + 16] add esp, ecx // XXX ASSERT THAT ESP IS THE SAME NOW THAN BEFORE! sub esi, esp // Load %ecx with the return type code mov ecx, [ebp + 20] // If the return value pointer is NULL, assume no return value. /* Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, otherwise only one BYTE will be compared (instead of a DWORD)! */ cmp DWORD PTR [ebp + 24], 0 jne sc_retint // Even if there is no space for the return value, we are // obliged to handle floating-point values. cmp ecx, FFI_TYPE_FLOAT jne sc_noretval // fstp %st(0) fstp st(0) jmp sc_epilogue sc_retint: cmp ecx, FFI_TYPE_INT jne sc_retfloat // # Load %ecx with the pointer to storage for the return value mov ecx, [ebp + 24] mov [ecx + 0], eax jmp sc_epilogue sc_retfloat: cmp ecx, FFI_TYPE_FLOAT jne sc_retdouble // Load %ecx with the pointer to storage for the return value mov ecx, [ebp+24] // fstps (%ecx) fstp DWORD PTR [ecx] jmp sc_epilogue sc_retdouble: cmp ecx, FFI_TYPE_DOUBLE jne sc_retlongdouble // movl 24(%ebp),%ecx mov ecx, [ebp+24] fstp QWORD PTR [ecx] jmp sc_epilogue jmp sc_retlongdouble // avoid warning about unused label sc_retlongdouble: cmp ecx, FFI_TYPE_LONGDOUBLE jne sc_retint64 // Load %ecx with the pointer to storage for the return value mov ecx, [ebp+24] // fstpt (%ecx) fstp QWORD PTR [ecx] /* XXX ??? */ jmp sc_epilogue sc_retint64: cmp ecx, FFI_TYPE_SINT64 jne sc_retstruct // Load %ecx with the pointer to storage for the return value mov ecx, [ebp+24] mov [ecx+0], eax mov [ecx+4], edx sc_retstruct: // Nothing to do! sc_noretval: sc_epilogue: mov eax, esi pop esi // NEW restore: must be preserved across function calls mov esp, ebp pop ebp ret } } __declspec(naked) int ffi_call_STDCALL(void (* prepfunc)(char *, extended_cif *), /* 8 */ extended_cif *ecif, /* 12 */ unsigned bytes, /* 16 */ unsigned flags, /* 20 */ unsigned *rvalue, /* 24 */ void (*fn)()) /* 28 */ { _asm { push ebp mov ebp, esp push esi // NEW: this register must be preserved across function calls // XXX SAVE ESP NOW! mov esi, esp // Make room for all of the new args. mov ecx, [ebp+16] sub esp, ecx mov eax, esp // Place all of the ffi_prep_args in position push [ebp + 12] // ecif push eax call [ebp + 8] // prepfunc // Return stack to previous state and call the function add esp, 8 // FIXME: Align the stack to a 128-bit boundary to avoid // potential performance hits. call [ebp + 28] // stdcall functions pop arguments off the stack themselves // XXX IS ESP NOW THE SAME AS BEFORE? sub esi, esp // Load %ecx with the return type code mov ecx, [ebp + 20] // If the return value pointer is NULL, assume no return value. /* Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction, otherwise only one BYTE will be compared (instead of a DWORD)! */ cmp DWORD PTR [ebp + 24], 0 jne sc_retint // Even if there is no space for the return value, we are // obliged to handle floating-point values. cmp ecx, FFI_TYPE_FLOAT jne sc_noretval // fstp %st(0) fstp st(0) jmp sc_epilogue sc_retint: cmp ecx, FFI_TYPE_INT jne sc_retfloat // # Load %ecx with the pointer to storage for the return value mov ecx, [ebp + 24] mov [ecx + 0], eax jmp sc_epilogue sc_retfloat: cmp ecx, FFI_TYPE_FLOAT jne sc_retdouble // Load %ecx with the pointer to storage for the return value mov ecx, [ebp+24] // fstps (%ecx) fstp DWORD PTR [ecx] jmp sc_epilogue sc_retdouble: cmp ecx, FFI_TYPE_DOUBLE jne sc_retlongdouble // movl 24(%ebp),%ecx mov ecx, [ebp+24] fstp QWORD PTR [ecx] jmp sc_epilogue jmp sc_retlongdouble // avoid warning about unused label sc_retlongdouble: cmp ecx, FFI_TYPE_LONGDOUBLE jne sc_retint64 // Load %ecx with the pointer to storage for the return value mov ecx, [ebp+24] // fstpt (%ecx) fstp QWORD PTR [ecx] /* XXX ??? */ jmp sc_epilogue sc_retint64: cmp ecx, FFI_TYPE_SINT64 jne sc_retstruct // Load %ecx with the pointer to storage for the return value mov ecx, [ebp+24] mov [ecx+0], eax mov [ecx+4], edx sc_retstruct: // Nothing to do! sc_noretval: sc_epilogue: mov eax, esi pop esi // NEW restore: must be preserved across function calls mov esp, ebp pop ebp ret } } --- NEW FILE: README --- This directory contains the libffi package, which is not part of GCC but shipped with GCC as convenience. Status ====== libffi-2.00 has not been released yet! This is a development snapshot! libffi-1.20 was released on October 5, 1998. Check the libffi web page for updates: <URL:http://sources.redhat.com/libffi/>. What is libffi? =============== Compilers for high level languages generate code that follow certain conventions. These conventions are necessary, in part, for separate compilation to work. One such convention is the "calling convention". The "calling convention" is essentially a set of assumptions made by the compiler about where function arguments will be found on entry to a function. A "calling convention" also specifies where the return value for a function is found. Some programs may not know at the time of compilation what arguments are to be passed to a function. For instance, an interpreter may be told at run-time about the number and types of arguments used to call a given function. Libffi can be used in such programs to provide a bridge from the interpreter program to compiled code. The libffi library provides a portable, high level programming interface to various calling conventions. This allows a programmer to call any function specified by a call interface description at run time. Ffi stands for Foreign Function Interface. A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. The libffi library really only provides the lowest, machine dependent layer of a fully featured foreign function interface. A layer must exist above libffi that handles type conversions for values passed between the two languages. Supported Platforms and Prerequisites ===================================== Libffi has been ported to: SunOS 4.1.3 & Solaris 2.x (SPARC-V8, SPARC-V9) Irix 5.3 & 6.2 (System V/o32 & n32) Intel x86 - Linux (System V ABI) Alpha - Linux and OSF/1 m68k - Linux (System V ABI) PowerPC - Linux (System V ABI, Darwin, AIX) ARM - Linux (System V ABI) Libffi has been tested with the egcs 1.0.2 gcc compiler. Chances are that other versions will work. Libffi has also been built and tested with the SGI compiler tools. On PowerPC, the tests failed (see the note below). You must use GNU make to build libffi. SGI's make will not work. Sun's probably won't either. If you port libffi to another platform, please let me know! I assume that some will be easy (x86 NetBSD), and others will be more difficult (HP). Installing libffi ================= [Note: before actually performing any of these installation steps, you may wish to read the "Platform Specific Notes" below.] First you must configure the distribution for your particular system. Go to the directory you wish to build libffi in and run the "configure" program found in the root directory of the libffi source distribution. You may want to tell configure where to install the libffi library and header files. To do that, use the --prefix configure switch. Libffi will install under /usr/local by default. If you want to enable extra run-time debugging checks use the the --enable-debug configure switch. This is useful when your program dies mysteriously while using libffi. Another useful configure switch is --enable-purify-safety. Using this will add some extra code which will suppress certain warnings when you are using Purify with libffi. Only use this switch when using Purify, as it will slow down the library. Configure has many other options. Use "configure --help" to see them all. Once configure has finished, type "make". Note that you must be using GNU make. SGI's make will not work. Sun's probably won't either. You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. To ensure that libffi is working as advertised, type "make test". To install the library and header files, type "make install". Using libffi ============ The Basics ---------- Libffi assumes that you have a pointer to the function you wish to call and that you know the number and types of arguments to pass it, as well as the return type of the function. The first thing you must do is create an ffi_cif object that matches the signature of the function you wish to call. The cif in ffi_cif stands for Call InterFace. To prepare a call interface object, use the following function: ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes); CIF is a pointer to the call interface object you wish to initialize. ABI is an enum that specifies the calling convention to use for the call. FFI_DEFAULT_ABI defaults to the system's native calling convention. Other ABI's may be used with care. They are system specific. NARGS is the number of arguments this function accepts. libffi does not yet support vararg functions. RTYPE is a pointer to an ffi_type structure that represents the return type of the function. Ffi_type objects describe the types of values. libffi provides ffi_type objects for many of the native C types: signed int, unsigned int, signed char, unsigned char, etc. There is also a pointer ffi_type object and a void ffi_type. Use &ffi_type_void for functions that don't return values. ATYPES is a vector of ffi_type pointers. ARGS must be NARGS long. If NARGS is 0, this is ignored. ffi_prep_cif will return a status code that you are responsible for checking. It will be one of the following: FFI_OK - All is good. FFI_BAD_TYPEDEF - One of the ffi_type objects that ffi_prep_cif came across is bad. Before making the call, the VALUES vector should be initialized with pointers to the appropriate argument values. To call the the function using the initialized ffi_cif, use the ffi_call function: void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues); CIF is a pointer to the ffi_cif initialized specifically for this function. FN is a pointer to the function you want to call. RVALUE is a pointer to a chunk of memory that is to hold the result of the function call. Currently, it must be at least one word in size (except for the n32 version under Irix 6.x, which must be a pointer to an 8 byte aligned value (a long long). It must also be at least word aligned (depending on the return type, and the system's alignment requirements). If RTYPE is &ffi_type_void, this is ignored. If RVALUE is NULL, the return value is discarded. AVALUES is a vector of void* that point to the memory locations holding the argument values for a call. If NARGS is 0, this is ignored. If you are expecting a return value from FN it will have been stored at RVALUE. An Example ---------- Here is a trivial example that calls puts() a few times. #include <stdio.h> #include <ffi.h> int main() { ffi_cif cif; ffi_type *args[1]; void *values[1]; char *s; int rc; /* Initialize the argument info vectors */ args[0] = &ffi_type_uint; values[0] = &s; /* Initialize the cif */ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args) == FFI_OK) { s = "Hello World!"; ffi_call(&cif, puts, &rc, values); /* rc now holds the result of the call to puts */ /* values holds a pointer to the function's arg, so to call puts() again all we need to do is change the value of s */ s = "This is cool!"; ffi_call(&cif, puts, &rc, values); } return 0; } Aggregate Types --------------- Although libffi has no special support for unions or bit-fields, it is perfectly happy passing structures back and forth. You must first describe the structure to libffi by creating a new ffi_type object for it. Here is the definition of ffi_type: typedef struct _ffi_type { unsigned size; short alignment; short type; struct _ffi_type **elements; } ffi_type; All structures must have type set to FFI_TYPE_STRUCT. You may set size and alignment to 0. These will be calculated and reset to the appropriate values by ffi_prep_cif(). elements is a NULL terminated array of pointers to ffi_type objects that describe the type of the structure elements. These may, in turn, be structure elements. The following example initializes a ffi_type object representing the tm struct from Linux's time.h: struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; /* Those are for future use. */ long int __tm_gmtoff__; __const char *__tm_zone__; }; { ffi_type tm_type; ffi_type *tm_type_elements[12]; int i; tm_type.size = tm_type.alignment = 0; tm_type.elements = &tm_type_elements; for (i = 0; i < 9; i++) tm_type_elements[i] = &ffi_type_sint; tm_type_elements[9] = &ffi_type_slong; tm_type_elements[10] = &ffi_type_pointer; tm_type_elements[11] = NULL; /* tm_type can now be used to represent tm argument types and return types for ffi_prep_cif() */ } Platform Specific Notes ======================= Intel x86 --------- There are no known problems with the x86 port. Sun SPARC - SunOS 4.1.3 & Solaris 2.x ------------------------------------- You must use GNU Make to build libffi on Sun platforms. MIPS - Irix 5.3 & 6.x --------------------- Irix 6.2 and better supports three different calling conventions: o32, n32 and n64. Currently, libffi only supports both o32 and n32 under Irix 6.x, but only o32 under Irix 5.3. Libffi will automatically be configured for whichever calling convention it was built for. By default, the configure script will try to build libffi with the GNU development tools. To build libffi with the SGI development tools, set the environment variable CC to either "cc -32" or "cc -n32" before running configure under Irix 6.x (depending on whether you want an o32 or n32 library), or just "cc" for Irix 5.3. With the n32 calling convention, when returning structures smaller than 16 bytes, be sure to provide an RVALUE that is 8 byte aligned. Here's one way of forcing this: double struct_storage[2]; my_small_struct *s = (my_small_struct *) struct_storage; /* Use s for RVALUE */ If you don't do this you are liable to get spurious bus errors. "long long" values are not supported yet. You must use GNU Make to build libffi on SGI platforms. ARM - System V ABI ------------------ The ARM port was performed on a NetWinder running ARM Linux ELF (2.0.31) and gcc 2.8.1. PowerPC System V ABI -------------------- There are two `System V ABI's which libffi implements for PowerPC. They differ only in how small structures are returned from functions. In the FFI_SYSV version, structures that are 8 bytes or smaller are returned in registers. This is what GCC does when it is configured for solaris, and is what the System V ABI I have (dated September 1995) says. In the FFI_GCC_SYSV version, all structures are returned the same way: by passing a pointer as the first argument to the function. This is what GCC does when it is configured for linux or a generic sysv target. EGCS 1.0.1 (and probably other versions of EGCS/GCC) also has a inconsistency with the SysV ABI: When a procedure is called with many floating-point arguments, some of them get put on the stack. They are all supposed to be stored in double-precision format, even if they are only single-precision, but EGCS stores single-precision arguments as single-precision anyway. This causes one test to fail (the `many arguments' test). What's With The Crazy Comments? =============================== You might notice a number of cryptic comments in the code, delimited by /*@ and @*/. These are annotations read by the program LCLint, a tool for statically checking C programs. You can read all about it at <http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>. History ======= 1.20 Oct-5-98 Raffaele Sena produces ARM port. 1.19 Oct-5-98 Fixed x86 long double and long long return support. m68k bug fixes from Andreas Schwab. Patch for DU assembler compatibility for the Alpha from Richard Henderson. 1.18 Apr-17-98 Bug fixes and MIPS configuration changes. 1.17 Feb-24-98 Bug fixes and m68k port from Andreas Schwab. PowerPC port from Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes. 1.16 Feb-11-98 Richard Henderson produces Alpha port. 1.15 Dec-4-97 Fixed an n32 ABI bug. New libtool, auto* support. 1.14 May-13-97 libtool is now used to generate shared and static libraries. Fixed a minor portability problem reported by Russ McManus <mc...@eq...>. 1.13 Dec-2-96 Added --enable-purify-safety to keep Purify from complaining about certain low level code. Sparc fix for calling functions with < 6 args. Linux x86 a.out fix. 1.12 Nov-22-96 Added missing ffi_type_void, needed for supporting void return types. Fixed test case for non MIPS machines. Cygnus Support is now Cygnus Solutions. 1.11 Oct-30-96 Added notes about GNU make. 1.10 Oct-29-96 Added configuration fix for non GNU compilers. 1.09 Oct-29-96 Added --enable-debug configure switch. Clean-ups based on LCLint feedback. ffi_mips.h is always installed. Many configuration fixes. Fixed ffitest.c for sparc builds. 1.08 Oct-15-96 Fixed n32 problem. Many clean-ups. 1.07 Oct-14-96 Gordon Irlam rewrites v8.S again. Bug fixes. 1.06 Oct-14-96 Gordon Irlam improved the sparc port. 1.05 Oct-14-96 Interface changes based on feedback. 1.04 Oct-11-96 Sparc port complete (modulo struct passing bug). 1.03 Oct-10-96 Passing struct args, and returning struct values works for all architectures/calling conventions. Expanded tests. 1.02 Oct-9-96 Added SGI n32 support. Fixed bugs in both o32 and Linux support. Added "make test". 1.01 Oct-8-96 Fixed float passing bug in mips version. Restructured some of the code. Builds cleanly with SGI tools. 1.00 Oct-7-96 First release. No public announcement. Authors & Credits ================= libffi was written by Anthony Green <gr...@cy...>. Portions of libffi were derived from Gianni Mariani's free gencall library for Silicon Graphics machines. The closure mechanism was designed and implemented by Kresten Krab Thorup. The Sparc port was derived from code contributed by the fine folks at Visible Decisions Inc <http://www.vdi.com>. Further enhancements were made by Gordon Irlam at Cygnus Solutions <http://www.cygnus.com>. The Alpha port was written by Richard Henderson at Cygnus Solutions. Andreas Schwab ported libffi to m68k Linux and provided a number of bug fixes. Geoffrey Keating ported libffi to the PowerPC. Raffaele Sena ported libffi to the ARM. Jesper Skov and Andrew Haley both did more than their fair share of stepping through the code and tracking down bugs. Thanks also to Tom Tromey for bug fixes and configuration help. Thanks to Jim Blandy, who provided some useful feedback on the libffi interface. If you have a problem, or have found a bug, please send a note to gr...@cy.... --- NEW FILE: types.c --- /* ----------------------------------------------------------------------- types.c - Copyright (c) 1996, 1998 Red Hat, Inc. Predefined ffi_types needed by libffi. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> /* Type definitions */ #define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL } #define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e } /* Size and alignment are fake here. They must not be 0. */ FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID); FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8); FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8); FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16); FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16); FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32); FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32); FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT); #if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \ || defined IA64 FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER); #else FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER); #endif #if defined X86 || defined X86_WIN32 || defined ARM || defined M68K FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); #elif defined SH FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64); FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64); #else FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64); FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64); #endif #if defined X86 || defined X86_WIN32 || defined M68K FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE); #elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE); #elif defined SPARC FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); #ifdef SPARC64 FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); #else FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE); #endif #elif defined X86_64 FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE); #else FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE); FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE); #endif --- NEW FILE: ffi.h --- /* -----------------------------------------------------------------*-C-*- libffi 2.00-beta - Copyright (c) 1996-2003 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------- The basic API is described in the README file. The raw API is designed to bypass some of the argument packing and unpacking on architectures for which it can be avoided. The closure API allows interpreted functions to be packaged up inside a C function pointer, so that they can be called as C functions, ... [truncated message content] |
Update of /cvsroot/ctypes/ctypes/source/libffi In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12058 Added Files: install-sh fficonfig.py.in fficonfig.h.in configure.ac configure config.sub config.guess aclocal.m4 README LICENSE Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: fficonfig.py.in --- ffi_sources = """ src/prep_cif.c """.split() ffi_platforms = { 'MIPS_IRIX': ['src/mips/ffi.c', 'src/mips/o32.S', 'src/mips/n32.S'], 'MIPS_LINUX': ['src/mips/ffi.c', 'src/mips/o32.S'], 'X86': ['src/x86/ffi.c', 'src/x86/sysv.S'], 'X86_WIN32': ['src/x86/ffi.c', 'src/x86/win32.S'], 'SPARC': ['src/sparc/ffi.c', 'src/sparc/v8.S', 'src/sparc/v9.S'], 'ALPHA': ['src/alpha/ffi.c', 'src/alpha/osf.S'], 'IA64': ['src/ia64/ffi.c', 'src/ia64/unix.S'], 'M32R': ['src/m32r/sysv.S', 'src/m32r/ffi.c'], 'M68K': ['src/m68k/ffi.c', 'src/m68k/sysv.S'], 'POWERPC': ['src/powerpc/ffi.c', 'src/powerpc/sysv.S', 'src/powerpc/ppc_closure.S', 'src/powerpc/linux64.S', 'src/powerpc/linux64_closure.S'], 'POWERPC_AIX': ['src/powerpc/ffi_darwin.c', 'src/powerpc/aix.S', 'src/powerpc/aix_closure.S'], 'POWERPC_DARWIN': ['src/powerpc/ffi_darwin.c', 'src/powerpc/darwin.S', 'src/powerpc/darwin_closure.S'], 'POWERPC_FREEBSD': ['src/powerpc/ffi.c', 'src/powerpc/sysv.S', 'src/powerpc/ppc_closure.S'], 'ARM': ['src/arm/sysv.S', 'src/arm/ffi.c'], 'LIBFFI_CRIS': ['src/cris/sysv.S', 'src/cris/ffi.c'], 'FRV': ['src/frv/eabi.S', 'src/frv/ffi.c'], 'S390': ['src/s390/sysv.S', 'src/s390/ffi.c'], 'X86_64': ['src/x86/ffi64.c', 'src/x86/unix64.S', 'src/x86/ffi.c', 'src/x86/sysv.S'], 'SH': ['src/sh/sysv.S', 'src/sh/ffi.c'], 'SH64': ['src/sh64/sysv.S', 'src/sh64/ffi.c'], 'PA': ['src/pa/linux.S', 'src/pa/ffi.c'], } ffi_srcdir = '@srcdir@' ffi_sources += ffi_platforms['@TARGET@'] ffi_sources = [os.path.join('@srcdir@', f) for f in ffi_sources] ffi_cflags = '@CFLAGS@' if sys.platform == "openbsd3": ffi_cflags += " -fno-stack-protector" --- NEW FILE: configure --- #! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.59 for libffi 2.1. # # Report bugs to <http://gcc.gnu.org/bugs.html>. # # Copyright (C) 2003 Free Software Foundation, Inc. # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## --------------------- ## ## M4sh Initialization. ## ## --------------------- ## # Be Bourne compatible if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then emulate sh NULLCMD=: # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. [...6839 lines suppressed...] # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || { (exit 1); exit 1; } fi --- NEW FILE: LICENSE --- libffi - Copyright (c) 1996-2003 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. --- NEW FILE: fficonfig.h.in --- /* fficonfig.h.in. Generated from configure.ac by autoheader. */ /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ #undef CRAY_STACKSEG_END /* Define to 1 if using `alloca.c'. */ #undef C_ALLOCA /* Define to the flags needed for the .section .eh_frame directive. */ #undef EH_FRAME_FLAGS /* Define this is you do not want support for the raw API. */ #undef FFI_NO_RAW_API /* Define to 1 if you have `alloca', as a function or macro. */ #undef HAVE_ALLOCA /* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H /* Define if your assembler supports .register. */ #undef HAVE_AS_REGISTER_PSEUDO_OP /* Define if your assembler and linker support unaligned PC relative relocs. */ #undef HAVE_AS_SPARC_UA_PCREL /* Define if __attribute__((visibility("hidden"))) is supported. */ #undef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H /* Define if you have the long double type and it is bigger than a double */ #undef HAVE_LONG_DOUBLE /* Define to 1 if you have the `memcpy' function. */ #undef HAVE_MEMCPY /* Define to 1 if you have the <memory.h> header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the `mmap' function. */ #undef HAVE_MMAP /* Define if mmap with MAP_ANON(YMOUS) works. */ #undef HAVE_MMAP_ANON /* Define if mmap of /dev/zero works. */ #undef HAVE_MMAP_DEV_ZERO /* Define if read-only mmap of a plain file works. */ #undef HAVE_MMAP_FILE /* Define if .eh_frame sections should be read-only. */ #undef HAVE_RO_EH_FRAME /* Define to 1 if you have the <stdint.h> header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the <stdlib.h> header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the <strings.h> header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the <string.h> header file. */ #undef HAVE_STRING_H /* Define to 1 if you have the <sys/mman.h> header file. */ #undef HAVE_SYS_MMAN_H /* Define to 1 if you have the <sys/stat.h> header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the <sys/types.h> header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the <unistd.h> header file. */ #undef HAVE_UNISTD_H /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* The size of a `double', as computed by sizeof. */ #undef SIZEOF_DOUBLE /* The size of a `long double', as computed by sizeof. */ #undef SIZEOF_LONG_DOUBLE /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ #undef WORDS_BIGENDIAN #ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE #ifdef LIBFFI_ASM #define FFI_HIDDEN(name) .hidden name #else #define FFI_HIDDEN __attribute__ ((visibility ("hidden"))) #endif #else #ifdef LIBFFI_ASM #define FFI_HIDDEN(name) #else #define FFI_HIDDEN #endif #endif --- NEW FILE: config.guess --- #! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc. timestamp='2004-11-12' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software [...1414 lines suppressed...] /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: --- NEW FILE: config.sub --- #! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. timestamp='2005-04-22' # This file is (in principle) common to ALL GNU software. # The presence of a machine in this file suggests that SOME GNU software # can handle that machine. It does not imply ALL GNU software can. # # This file is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 [...1530 lines suppressed...] -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: --- NEW FILE: aclocal.m4 --- # mmap(2) blacklisting. Some platforms provide the mmap library routine # but don't support all of the features we need from it. AC_DEFUN([AC_FUNC_MMAP_BLACKLIST], [ AC_CHECK_HEADER([sys/mman.h], [libffi_header_sys_mman_h=yes], [libffi_header_sys_mman_h=no]) AC_CHECK_FUNC([mmap], [libffi_func_mmap=yes], [libffi_func_mmap=no]) if test "$libffi_header_sys_mman_h" != yes \ || test "$libffi_func_mmap" != yes; then ac_cv_func_mmap_file=no ac_cv_func_mmap_dev_zero=no ac_cv_func_mmap_anon=no else AC_CACHE_CHECK([whether read-only mmap of a plain file works], ac_cv_func_mmap_file, [# Add a system to this blacklist if # mmap(0, stat_size, PROT_READ, MAP_PRIVATE, fd, 0) doesn't return a # memory area containing the same data that you'd get if you applied # read() to the same fd. The only system known to have a problem here # is VMS, where text files have record structure. case "$host_os" in vms* | ultrix*) ac_cv_func_mmap_file=no ;; *) ac_cv_func_mmap_file=yes;; esac]) AC_CACHE_CHECK([whether mmap from /dev/zero works], ac_cv_func_mmap_dev_zero, [# Add a system to this blacklist if it has mmap() but /dev/zero # does not exist, or if mmapping /dev/zero does not give anonymous # zeroed pages with both the following properties: # 1. If you map N consecutive pages in with one call, and then # unmap any subset of those pages, the pages that were not # explicitly unmapped remain accessible. # 2. If you map two adjacent blocks of memory and then unmap them # both at once, they must both go away. # Systems known to be in this category are Windows (all variants), # VMS, and Darwin. case "$host_os" in vms* | cygwin* | pe | mingw* | darwin* | ultrix* | hpux10* | hpux11.00) ac_cv_func_mmap_dev_zero=no ;; *) ac_cv_func_mmap_dev_zero=yes;; esac]) # Unlike /dev/zero, the MAP_ANON(YMOUS) defines can be probed for. AC_CACHE_CHECK([for MAP_ANON(YMOUS)], ac_cv_decl_map_anon, [AC_TRY_COMPILE( [#include <sys/types.h> #include <sys/mman.h> #include <unistd.h> #ifndef MAP_ANONYMOUS #define MAP_ANONYMOUS MAP_ANON #endif ], [int n = MAP_ANONYMOUS;], ac_cv_decl_map_anon=yes, ac_cv_decl_map_anon=no)]) if test $ac_cv_decl_map_anon = no; then ac_cv_func_mmap_anon=no else AC_CACHE_CHECK([whether mmap with MAP_ANON(YMOUS) works], ac_cv_func_mmap_anon, [# Add a system to this blacklist if it has mmap() and MAP_ANON or # MAP_ANONYMOUS, but using mmap(..., MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) # doesn't give anonymous zeroed pages with the same properties listed # above for use of /dev/zero. # Systems known to be in this category are Windows, VMS, and SCO Unix. case "$host_os" in vms* | cygwin* | pe | mingw* | sco* | udk* ) ac_cv_func_mmap_anon=no ;; *) ac_cv_func_mmap_anon=yes;; esac]) fi fi if test $ac_cv_func_mmap_file = yes; then AC_DEFINE(HAVE_MMAP_FILE, 1, [Define if read-only mmap of a plain file works.]) fi if test $ac_cv_func_mmap_dev_zero = yes; then AC_DEFINE(HAVE_MMAP_DEV_ZERO, 1, [Define if mmap of /dev/zero works.]) fi if test $ac_cv_func_mmap_anon = yes; then AC_DEFINE(HAVE_MMAP_ANON, 1, [Define if mmap with MAP_ANON(YMOUS) works.]) fi ]) --- NEW FILE: configure.ac --- dnl Process this with autoconf to create configure AC_PREREQ(2.59) AC_INIT([libffi], [2.1], [http://gcc.gnu.org/bugs.html]) AC_CONFIG_HEADERS([fficonfig.h]) AC_CANONICAL_SYSTEM target_alias=${target_alias-$host_alias} m4_rename([_AC_ARG_VAR_PRECIOUS],[real_PRECIOUS]) m4_define([_AC_ARG_VAR_PRECIOUS],[]) AC_PROG_CC m4_rename([real_PRECIOUS],[_AC_ARG_VAR_PRECIOUS]) AC_SUBST(CFLAGS) AC_CHECK_HEADERS(sys/mman.h) AC_CHECK_FUNCS(mmap) AC_FUNC_MMAP_BLACKLIST TARGETDIR="unknown" case "$host" in i*86-*-linux*) TARGET=X86; TARGETDIR=x86;; i*86-*-gnu*) TARGET=X86; TARGETDIR=x86;; i*86-*-solaris2.1[[0-9]]*) TARGET=X86_64; TARGETDIR=x86;; i*86-*-solaris*) TARGET=X86; TARGETDIR=x86;; i*86-*-beos*) TARGET=X86; TARGETDIR=x86;; i*86-*-freebsd* | i*86-*-kfreebsd*-gnu) TARGET=X86; TARGETDIR=x86;; i*86-*-netbsdelf* | i*86-*-knetbsd*-gnu) TARGET=X86; TARGETDIR=x86;; i*86-*-rtems*) TARGET=X86; TARGETDIR=x86;; i*86-*-win32*) TARGET=X86_WIN32; TARGETDIR=x86;; i*86-*-cygwin*) TARGET=X86_WIN32; TARGETDIR=x86;; i*86-*-mingw*) TARGET=X86_WIN32; TARGETDIR=x86;; frv-*-*) TARGET=FRV; TARGETDIR=frv;; sparc-sun-4*) TARGET=SPARC; TARGETDIR=sparc;; sparc*-sun-*) TARGET=SPARC; TARGETDIR=sparc;; sparc-*-linux* | sparc-*-netbsdelf* | sparc-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;; sparc*-*-rtems*) TARGET=SPARC; TARGETDIR=sparc;; sparc64-*-linux* | sparc64-*-freebsd* | sparc64-*-netbsd* | sparc64-*-knetbsd*-gnu) TARGET=SPARC; TARGETDIR=sparc;; alpha*-*-linux* | alpha*-*-osf* | alpha*-*-freebsd* | alpha*-*-kfreebsd*-gnu | alpha*-*-netbsd* | alpha*-*-knetbsd*-gnu) TARGET=ALPHA; TARGETDIR=alpha;; ia64*-*-*) TARGET=IA64; TARGETDIR=ia64;; m32r*-*-linux* ) TARGET=M32R; TARGETDIR=m32r;; m68k-*-linux*) TARGET=M68K; TARGETDIR=m68k;; mips64*-*);; mips-sgi-irix5.* | mips-sgi-irix6.*) TARGET=MIPS_IRIX; TARGETDIR=mips;; mips*-*-linux*) TARGET=MIPS_LINUX; TARGETDIR=mips;; powerpc*-*-linux* | powerpc-*-sysv*) TARGET=POWERPC; TARGETDIR=powerpc;; powerpc-*-beos*) TARGET=POWERPC; TARGETDIR=powerpc;; powerpc-*-darwin*) TARGET=POWERPC_DARWIN; TARGETDIR=powerpc;; powerpc-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; powerpc-*-freebsd*) TARGET=POWERPC_FREEBSD; TARGETDIR=powerpc;; powerpc*-*-rtems*) TARGET=POWERPC; TARGETDIR=powerpc;; rs6000-*-aix*) TARGET=POWERPC_AIX; TARGETDIR=powerpc;; arm*-*-linux-*) TARGET=ARM; TARGETDIR=arm;; arm*-*-netbsdelf* | arm*-*-knetbsd*-gnu) TARGET=ARM; TARGETDIR=arm;; arm*-*-rtems*) TARGET=ARM; TARGETDIR=arm;; cris-*-*) TARGET=LIBFFI_CRIS; TARGETDIR=cris;; s390-*-linux-*) TARGET=S390; TARGETDIR=s390;; s390x-*-linux-*) TARGET=S390; TARGETDIR=s390;; x86_64-*-linux* | x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) TARGET=X86_64; TARGETDIR=x86;; sh-*-linux* | sh[[34]]*-*-linux*) TARGET=SH; TARGETDIR=sh;; sh-*-rtems*) TARGET=SH; TARGETDIR=sh;; sh64-*-linux* | sh5*-*-linux*) TARGET=SH64; TARGETDIR=sh64;; hppa-*-linux* | parisc-*-linux*) TARGET=PA; TARGETDIR=pa;; esac if test $TARGETDIR = unknown; then AC_MSG_ERROR(["libffi has not been ported to $host."]) fi case x$TARGET in xMIPS*) TARGET=MIPS ;; *) ;; esac AC_HEADER_STDC AC_CHECK_FUNCS(memcpy) AC_FUNC_ALLOCA AC_CHECK_SIZEOF(double) AC_CHECK_SIZEOF(long double) # Also AC_SUBST this variable for ffi.h. HAVE_LONG_DOUBLE=0 if test $ac_cv_sizeof_double != $ac_cv_sizeof_long_double; then if test $ac_cv_sizeof_long_double != 0; then HAVE_LONG_DOUBLE=1 AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if you have the long double type and it is bigger than a double]) fi fi AC_SUBST(HAVE_LONG_DOUBLE) AC_C_BIGENDIAN if test x$TARGET = xSPARC; then AC_CACHE_CHECK([assembler and linker support unaligned pc related relocs], libffi_cv_as_sparc_ua_pcrel, [ save_CFLAGS="$CFLAGS" save_LDFLAGS="$LDFLAGS" CFLAGS="$CFLAGS -fpic" LDFLAGS="$LDFLAGS -shared" AC_TRY_LINK([asm (".text; foo: nop; .data; .align 4; .byte 0; .uaword %r_disp32(foo); .text");],, [libffi_cv_as_sparc_ua_pcrel=yes], [libffi_cv_as_sparc_ua_pcrel=no]) CFLAGS="$save_CFLAGS" LDFLAGS="$save_LDFLAGS"]) if test "x$libffi_cv_as_sparc_ua_pcrel" = xyes; then AC_DEFINE(HAVE_AS_SPARC_UA_PCREL, 1, [Define if your assembler and linker support unaligned PC relative relocs.]) fi AC_CACHE_CHECK([assembler .register pseudo-op support], libffi_cv_as_register_pseudo_op, [ libffi_cv_as_register_pseudo_op=unknown # Check if we have .register AC_TRY_COMPILE([asm (".register %g2, #scratch");],, [libffi_cv_as_register_pseudo_op=yes], [libffi_cv_as_register_pseudo_op=no]) ]) if test "x$libffi_cv_as_register_pseudo_op" = xyes; then AC_DEFINE(HAVE_AS_REGISTER_PSEUDO_OP, 1, [Define if your assembler supports .register.]) fi fi AC_CACHE_CHECK([whether .eh_frame section should be read-only], libffi_cv_ro_eh_frame, [ libffi_cv_ro_eh_frame=no echo 'extern void foo (void); void bar (void) { foo (); foo (); }' > conftest.c if $CC $CFLAGS -S -fpic -fexceptions -o conftest.s conftest.c > /dev/null 2>&1; then if grep '.section.*eh_frame.*"a"' conftest.s > /dev/null; then libffi_cv_ro_eh_frame=yes elif grep '.section.*eh_frame.*#alloc' conftest.c \ | grep -v '#write' > /dev/null; then libffi_cv_ro_eh_frame=yes fi fi rm -f conftest.* ]) if test "x$libffi_cv_ro_eh_frame" = xyes; then AC_DEFINE(HAVE_RO_EH_FRAME, 1, [Define if .eh_frame sections should be read-only.]) AC_DEFINE(EH_FRAME_FLAGS, "a", [Define to the flags needed for the .section .eh_frame directive.]) else AC_DEFINE(EH_FRAME_FLAGS, "aw", [Define to the flags needed for the .section .eh_frame directive.]) fi AC_CACHE_CHECK([for __attribute__((visibility("hidden")))], libffi_cv_hidden_visibility_attribute, [ echo 'int __attribute__ ((visibility ("hidden"))) foo (void) { return 1; }' > conftest.c libffi_cv_hidden_visibility_attribute=no if AC_TRY_COMMAND(${CC-cc} -Werror -S conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then if grep '\.hidden.*foo' conftest.s >/dev/null; then libffi_cv_hidden_visibility_attribute=yes fi fi rm -f conftest.* ]) if test $libffi_cv_hidden_visibility_attribute = yes; then AC_DEFINE(HAVE_HIDDEN_VISIBILITY_ATTRIBUTE, 1, [Define if __attribute__((visibility("hidden"))) is supported.]) fi AH_BOTTOM([ #ifdef HAVE_HIDDEN_VISIBILITY_ATTRIBUTE #ifdef LIBFFI_ASM #define FFI_HIDDEN(name) .hidden name #else #define FFI_HIDDEN __attribute__ ((visibility ("hidden"))) #endif #else #ifdef LIBFFI_ASM #define FFI_HIDDEN(name) #else #define FFI_HIDDEN #endif #endif ]) AC_SUBST(TARGET) AC_SUBST(TARGETDIR) AC_SUBST(SHELL) AC_DEFINE(FFI_NO_RAW_API, 1, [Define this is you do not want support for the raw API.]) AC_CONFIG_COMMANDS(include, [test -d include || mkdir include]) AC_CONFIG_COMMANDS(src, [ test -d src || mkdir src test -d src/$TARGETDIR || mkdir src/$TARGETDIR ], [TARGETDIR="$TARGETDIR"]) AC_CONFIG_LINKS(include/ffitarget.h:src/$TARGETDIR/ffitarget.h) AC_CONFIG_LINKS(include/ffi_common.h:include/ffi_common.h) AC_CONFIG_FILES(include/ffi.h fficonfig.py) AC_OUTPUT --- NEW FILE: README --- This directory contains the libffi package, which is not part of GCC but shipped with GCC as convenience. Status ====== libffi-2.00 has not been released yet! This is a development snapshot! libffi-1.20 was released on October 5, 1998. Check the libffi web page for updates: <URL:http://sources.redhat.com/libffi/>. What is libffi? =============== Compilers for high level languages generate code that follow certain conventions. These conventions are necessary, in part, for separate compilation to work. One such convention is the "calling convention". The "calling convention" is essentially a set of assumptions made by the compiler about where function arguments will be found on entry to a function. A "calling convention" also specifies where the return value for a function is found. Some programs may not know at the time of compilation what arguments are to be passed to a function. For instance, an interpreter may be told at run-time about the number and types of arguments used to call a given function. Libffi can be used in such programs to provide a bridge from the interpreter program to compiled code. The libffi library provides a portable, high level programming interface to various calling conventions. This allows a programmer to call any function specified by a call interface description at run time. Ffi stands for Foreign Function Interface. A foreign function interface is the popular name for the interface that allows code written in one language to call code written in another language. The libffi library really only provides the lowest, machine dependent layer of a fully featured foreign function interface. A layer must exist above libffi that handles type conversions for values passed between the two languages. Supported Platforms and Prerequisites ===================================== Libffi has been ported to: SunOS 4.1.3 & Solaris 2.x (SPARC-V8, SPARC-V9) Irix 5.3 & 6.2 (System V/o32 & n32) Intel x86 - Linux (System V ABI) Alpha - Linux and OSF/1 m68k - Linux (System V ABI) PowerPC - Linux (System V ABI, Darwin, AIX) ARM - Linux (System V ABI) Libffi has been tested with the egcs 1.0.2 gcc compiler. Chances are that other versions will work. Libffi has also been built and tested with the SGI compiler tools. On PowerPC, the tests failed (see the note below). You must use GNU make to build libffi. SGI's make will not work. Sun's probably won't either. If you port libffi to another platform, please let me know! I assume that some will be easy (x86 NetBSD), and others will be more difficult (HP). Installing libffi ================= [Note: before actually performing any of these installation steps, you may wish to read the "Platform Specific Notes" below.] First you must configure the distribution for your particular system. Go to the directory you wish to build libffi in and run the "configure" program found in the root directory of the libffi source distribution. You may want to tell configure where to install the libffi library and header files. To do that, use the --prefix configure switch. Libffi will install under /usr/local by default. If you want to enable extra run-time debugging checks use the the --enable-debug configure switch. This is useful when your program dies mysteriously while using libffi. Another useful configure switch is --enable-purify-safety. Using this will add some extra code which will suppress certain warnings when you are using Purify with libffi. Only use this switch when using Purify, as it will slow down the library. Configure has many other options. Use "configure --help" to see them all. Once configure has finished, type "make". Note that you must be using GNU make. SGI's make will not work. Sun's probably won't either. You can ftp GNU make from prep.ai.mit.edu:/pub/gnu. To ensure that libffi is working as advertised, type "make test". To install the library and header files, type "make install". Using libffi ============ The Basics ---------- Libffi assumes that you have a pointer to the function you wish to call and that you know the number and types of arguments to pass it, as well as the return type of the function. The first thing you must do is create an ffi_cif object that matches the signature of the function you wish to call. The cif in ffi_cif stands for Call InterFace. To prepare a call interface object, use the following function: ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs, ffi_type *rtype, ffi_type **atypes); CIF is a pointer to the call interface object you wish to initialize. ABI is an enum that specifies the calling convention to use for the call. FFI_DEFAULT_ABI defaults to the system's native calling convention. Other ABI's may be used with care. They are system specific. NARGS is the number of arguments this function accepts. libffi does not yet support vararg functions. RTYPE is a pointer to an ffi_type structure that represents the return type of the function. Ffi_type objects describe the types of values. libffi provides ffi_type objects for many of the native C types: signed int, unsigned int, signed char, unsigned char, etc. There is also a pointer ffi_type object and a void ffi_type. Use &ffi_type_void for functions that don't return values. ATYPES is a vector of ffi_type pointers. ARGS must be NARGS long. If NARGS is 0, this is ignored. ffi_prep_cif will return a status code that you are responsible for checking. It will be one of the following: FFI_OK - All is good. FFI_BAD_TYPEDEF - One of the ffi_type objects that ffi_prep_cif came across is bad. Before making the call, the VALUES vector should be initialized with pointers to the appropriate argument values. To call the the function using the initialized ffi_cif, use the ffi_call function: void ffi_call(ffi_cif *cif, void *fn, void *rvalue, void **avalues); CIF is a pointer to the ffi_cif initialized specifically for this function. FN is a pointer to the function you want to call. RVALUE is a pointer to a chunk of memory that is to hold the result of the function call. Currently, it must be at least one word in size (except for the n32 version under Irix 6.x, which must be a pointer to an 8 byte aligned value (a long long). It must also be at least word aligned (depending on the return type, and the system's alignment requirements). If RTYPE is &ffi_type_void, this is ignored. If RVALUE is NULL, the return value is discarded. AVALUES is a vector of void* that point to the memory locations holding the argument values for a call. If NARGS is 0, this is ignored. If you are expecting a return value from FN it will have been stored at RVALUE. An Example ---------- Here is a trivial example that calls puts() a few times. #include <stdio.h> #include <ffi.h> int main() { ffi_cif cif; ffi_type *args[1]; void *values[1]; char *s; int rc; /* Initialize the argument info vectors */ args[0] = &ffi_type_uint; values[0] = &s; /* Initialize the cif */ if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 1, &ffi_type_uint, args) == FFI_OK) { s = "Hello World!"; ffi_call(&cif, puts, &rc, values); /* rc now holds the result of the call to puts */ /* values holds a pointer to the function's arg, so to call puts() again all we need to do is change the value of s */ s = "This is cool!"; ffi_call(&cif, puts, &rc, values); } return 0; } Aggregate Types --------------- Although libffi has no special support for unions or bit-fields, it is perfectly happy passing structures back and forth. You must first describe the structure to libffi by creating a new ffi_type object for it. Here is the definition of ffi_type: typedef struct _ffi_type { unsigned size; short alignment; short type; struct _ffi_type **elements; } ffi_type; All structures must have type set to FFI_TYPE_STRUCT. You may set size and alignment to 0. These will be calculated and reset to the appropriate values by ffi_prep_cif(). elements is a NULL terminated array of pointers to ffi_type objects that describe the type of the structure elements. These may, in turn, be structure elements. The following example initializes a ffi_type object representing the tm struct from Linux's time.h: struct tm { int tm_sec; int tm_min; int tm_hour; int tm_mday; int tm_mon; int tm_year; int tm_wday; int tm_yday; int tm_isdst; /* Those are for future use. */ long int __tm_gmtoff__; __const char *__tm_zone__; }; { ffi_type tm_type; ffi_type *tm_type_elements[12]; int i; tm_type.size = tm_type.alignment = 0; tm_type.elements = &tm_type_elements; for (i = 0; i < 9; i++) tm_type_elements[i] = &ffi_type_sint; tm_type_elements[9] = &ffi_type_slong; tm_type_elements[10] = &ffi_type_pointer; tm_type_elements[11] = NULL; /* tm_type can now be used to represent tm argument types and return types for ffi_prep_cif() */ } Platform Specific Notes ======================= Intel x86 --------- There are no known problems with the x86 port. Sun SPARC - SunOS 4.1.3 & Solaris 2.x ------------------------------------- You must use GNU Make to build libffi on Sun platforms. MIPS - Irix 5.3 & 6.x --------------------- Irix 6.2 and better supports three different calling conventions: o32, n32 and n64. Currently, libffi only supports both o32 and n32 under Irix 6.x, but only o32 under Irix 5.3. Libffi will automatically be configured for whichever calling convention it was built for. By default, the configure script will try to build libffi with the GNU development tools. To build libffi with the SGI development tools, set the environment variable CC to either "cc -32" or "cc -n32" before running configure under Irix 6.x (depending on whether you want an o32 or n32 library), or just "cc" for Irix 5.3. With the n32 calling convention, when returning structures smaller than 16 bytes, be sure to provide an RVALUE that is 8 byte aligned. Here's one way of forcing this: double struct_storage[2]; my_small_struct *s = (my_small_struct *) struct_storage; /* Use s for RVALUE */ If you don't do this you are liable to get spurious bus errors. "long long" values are not supported yet. You must use GNU Make to build libffi on SGI platforms. ARM - System V ABI ------------------ The ARM port was performed on a NetWinder running ARM Linux ELF (2.0.31) and gcc 2.8.1. PowerPC System V ABI -------------------- There are two `System V ABI's which libffi implements for PowerPC. They differ only in how small structures are returned from functions. In the FFI_SYSV version, structures that are 8 bytes or smaller are returned in registers. This is what GCC does when it is configured for solaris, and is what the System V ABI I have (dated September 1995) says. In the FFI_GCC_SYSV version, all structures are returned the same way: by passing a pointer as the first argument to the function. This is what GCC does when it is configured for linux or a generic sysv target. EGCS 1.0.1 (and probably other versions of EGCS/GCC) also has a inconsistency with the SysV ABI: When a procedure is called with many floating-point arguments, some of them get put on the stack. They are all supposed to be stored in double-precision format, even if they are only single-precision, but EGCS stores single-precision arguments as single-precision anyway. This causes one test to fail (the `many arguments' test). What's With The Crazy Comments? =============================== You might notice a number of cryptic comments in the code, delimited by /*@ and @*/. These are annotations read by the program LCLint, a tool for statically checking C programs. You can read all about it at <http://larch-www.lcs.mit.edu:8001/larch/lclint/index.html>. History ======= 1.20 Oct-5-98 Raffaele Sena produces ARM port. 1.19 Oct-5-98 Fixed x86 long double and long long return support. m68k bug fixes from Andreas Schwab. Patch for DU assembler compatibility for the Alpha from Richard Henderson. 1.18 Apr-17-98 Bug fixes and MIPS configuration changes. 1.17 Feb-24-98 Bug fixes and m68k port from Andreas Schwab. PowerPC port from Geoffrey Keating. Various bug x86, Sparc and MIPS bug fixes. 1.16 Feb-11-98 Richard Henderson produces Alpha port. 1.15 Dec-4-97 Fixed an n32 ABI bug. New libtool, auto* support. 1.14 May-13-97 libtool is now used to generate shared and static libraries. Fixed a minor portability problem reported by Russ McManus <mc...@eq...>. 1.13 Dec-2-96 Added --enable-purify-safety to keep Purify from complaining about certain low level code. Sparc fix for calling functions with < 6 args. Linux x86 a.out fix. 1.12 Nov-22-96 Added missing ffi_type_void, needed for supporting void return types. Fixed test case for non MIPS machines. Cygnus Support is now Cygnus Solutions. 1.11 Oct-30-96 Added notes about GNU make. 1.10 Oct-29-96 Added configuration fix for non GNU compilers. 1.09 Oct-29-96 Added --enable-debug configure switch. Clean-ups based on LCLint feedback. ffi_mips.h is always installed. Many configuration fixes. Fixed ffitest.c for sparc builds. 1.08 Oct-15-96 Fixed n32 problem. Many clean-ups. 1.07 Oct-14-96 Gordon Irlam rewrites v8.S again. Bug fixes. 1.06 Oct-14-96 Gordon Irlam improved the sparc port. 1.05 Oct-14-96 Interface changes based on feedback. 1.04 Oct-11-96 Sparc port complete (modulo struct passing bug). 1.03 Oct-10-96 Passing struct args, and returning struct values works for all architectures/calling conventions. Expanded tests. 1.02 Oct-9-96 Added SGI n32 support. Fixed bugs in both o32 and Linux support. Added "make test". 1.01 Oct-8-96 Fixed float passing bug in mips version. Restructured some of the code. Builds cleanly with SGI tools. 1.00 Oct-7-96 First release. No public announcement. Authors & Credits ================= libffi was written by Anthony Green <gr...@cy...>. Portions of libffi were derived from Gianni Mariani's free gencall library for Silicon Graphics machines. The closure mechanism was designed and implemented by Kresten Krab Thorup. The Sparc port was derived from code contributed by the fine folks at Visible Decisions Inc <http://www.vdi.com>. Further enhancements were made by Gordon Irlam at Cygnus Solutions <http://www.cygnus.com>. The Alpha port was written by Richard Henderson at Cygnus Solutions. Andreas Schwab ported libffi to m68k Linux and provided a number of bug fixes. Geoffrey Keating ported libffi to the PowerPC. Raffaele Sena ported libffi to the ARM. Jesper Skov and Andrew Haley both did more than their fair share of stepping through the code and tracking down bugs. Thanks also to Tom Tromey for bug fixes and configuration help. Thanks to Jim Blandy, who provided some useful feedback on the libffi interface. If you have a problem, or have found a bug, please send a note to gr...@cy.... --- NEW FILE: install-sh --- #!/bin/sh # # install - install a program, script, or datafile # # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # 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 # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. It can only install one file at a time, a restriction # shared with many OS's install programs. # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit="${DOITPROG-}" # put in absolute paths if you don't have them in your path; or use env. vars. mvprog="${MVPROG-mv}" cpprog="${CPPROG-cp}" chmodprog="${CHMODPROG-chmod}" chownprog="${CHOWNPROG-chown}" chgrpprog="${CHGRPPROG-chgrp}" stripprog="${STRIPPROG-strip}" rmprog="${RMPROG-rm}" mkdirprog="${MKDIRPROG-mkdir}" transformbasename="" transform_arg="" instcmd="$mvprog" chmodcmd="$chmodprog 0755" chowncmd="" chgrpcmd="" stripcmd="" rmcmd="$rmprog -f" mvcmd="$mvprog" src="" dst="" dir_arg="" while [ x"$1" != x ]; do case $1 in -c) instcmd=$cpprog shift continue;; -d) dir_arg=true shift continue;; -m) chmodcmd="$chmodprog $2" shift shift continue;; -o) chowncmd="$chownprog $2" shift shift continue;; -g) chgrpcmd="$chgrpprog $2" shift shift continue;; -s) stripcmd=$stripprog shift continue;; -t=*) transformarg=`echo $1 | sed 's/-t=//'` shift continue;; -b=*) transformbasename=`echo $1 | sed 's/-b=//'` shift continue;; *) if [ x"$src" = x ] then src=$1 else # this colon is to work around a 386BSD /bin/sh bug : dst=$1 fi shift continue;; esac done if [ x"$src" = x ] then echo "$0: no input file specified" >&2 exit 1 else : fi if [ x"$dir_arg" != x ]; then dst=$src src="" if [ -d "$dst" ]; then instcmd=: chmodcmd="" else instcmd=$mkdirprog fi else # Waiting for this to be detected by the "$instcmd $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if [ -f "$src" ] || [ -d "$src" ] then : else echo "$0: $src does not exist" >&2 exit 1 fi if [ x"$dst" = x ] then echo "$0: no destination specified" >&2 exit 1 else : fi # If destination is a directory, append the input filename; if your system # does not like double slashes in filenames, you may need to add some logic if [ -d "$dst" ] then dst=$dst/`basename "$src"` else : fi fi ## this sed command emulates the dirname command dstdir=`echo "$dst" | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` # Make sure that the destination directory exists. # this part is taken from Noah Friedman's mkinstalldirs script # Skip lots of stat calls in the usual case. if [ ! -d "$dstdir" ]; then defaultIFS=' ' IFS="${IFS-$defaultIFS}" oIFS=$IFS # Some sh's can't handle IFS=/ for some reason. IFS='%' set - `echo "$dstdir" | sed -e 's@/@%@g' -e 's@^%@/@'` IFS=$oIFS pathcomp='' while [ $# -ne 0 ] ; do pathcomp=$pathcomp$1 shift if [ ! -d "$pathcomp" ] ; then $mkdirprog "$pathcomp" else : fi pathcomp=$pathcomp/ done fi if [ x"$dir_arg" != x ] then $doit $instcmd "$dst" && if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dst"; else : ; fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dst"; else : ; fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dst"; else : ; fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dst"; else : ; fi else # If we're going to rename the final executable, determine the name now. if [ x"$transformarg" = x ] then dstfile=`basename "$dst"` else dstfile=`basename "$dst" $transformbasename | sed $transformarg`$transformbasename fi # don't allow the sed command to completely eliminate the filename if [ x"$dstfile" = x ] then dstfile=`basename "$dst"` else : fi # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/#inst.$$# rmtmp=$dstdir/#rm.$$# # Trap to clean up temp files at exit. trap 'status=$?; rm -f "$dsttmp" "$rmtmp" && exit $status' 0 trap '(exit $?); exit' 1 2 13 15 # Move or copy the file name to the temp name $doit $instcmd "$src" "$dsttmp" && # and set any options; do chmod last to preserve setuid bits # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $instcmd $src $dsttmp" command. if [ x"$chowncmd" != x ]; then $doit $chowncmd "$dsttmp"; else :;fi && if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd "$dsttmp"; else :;fi && if [ x"$stripcmd" != x ]; then $doit $stripcmd "$dsttmp"; else :;fi && if [ x"$chmodcmd" != x ]; then $doit $chmodcmd "$dsttmp"; else :;fi && # Now remove or move aside any old file at destination location. We try this # two ways since rm can't unlink itself on some systems and the destination # file might be busy for other reasons. In this case, the final cleanup # might fail but the new file should still install successfully. { if [ -f "$dstdir/$dstfile" ] then $doit $rmcmd -f "$dstdir/$dstfile" 2>/dev/null || $doit $mvcmd -f "$dstdir/$dstfile" "$rmtmp" 2>/dev/null || { echo "$0: cannot unlink or rename $dstdir/$dstfile" >&2 (exit 1); exit } else : fi } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dstdir/$dstfile" fi && # The final little trick to "correctly" pass the exit status to the exit trap. { (exit 0); exit } |
From: Thomas H. <th...@us...> - 2006-03-03 20:20:06
|
Update of /cvsroot/ctypes/ctypes/source/libffi_arm_wince In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv12140 Added Files: sysv.asm prep_cif.c ffitarget.h fficonfig.h ffi_common.h ffi.h ffi.c debug.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: ffi_common.h --- /* ----------------------------------------------------------------------- ffi_common.h - Copyright (c) 1996 Red Hat, Inc. Common internal definitions and macros. Only necessary for building libffi. ----------------------------------------------------------------------- */ #ifndef FFI_COMMON_H #define FFI_COMMON_H #ifdef __cplusplus extern "C" { #endif #include <fficonfig.h> /* Do not move this. Some versions of AIX are very picky about where this is positioned. */ #ifdef __GNUC__ # define alloca __builtin_alloca #else # if HAVE_ALLOCA_H # include <alloca.h> # else # ifdef _AIX #pragma alloca # else # ifndef alloca /* predefined by HP cc +Olibcalls */ char *alloca (); # endif # endif # endif #endif /* Check for the existence of memcpy. */ #if STDC_HEADERS # include <string.h> #else # ifndef HAVE_MEMCPY # define memcpy(d, s, n) bcopy ((s), (d), (n)) # endif #endif #if defined(FFI_DEBUG) #include <stdio.h> #endif #ifdef FFI_DEBUG /*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line); void ffi_stop_here(void); void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line); #define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__)) #define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l))) #define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__) #else #define FFI_ASSERT(x) #define FFI_ASSERT_AT(x, f, l) #define FFI_ASSERT_VALID_TYPE(x) #endif #define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1) /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif); /* Extended cif, used in callback from assembly routine */ typedef struct { /*@dependent@*/ ffi_cif *cif; /*@dependent@*/ void *rvalue; /*@dependent@*/ void **avalue; } extended_cif; /* Terse sized type definitions. */ #if defined(__GNUC__) typedef unsigned int UINT8 __attribute__((__mode__(__QI__))); typedef signed int SINT8 __attribute__((__mode__(__QI__))); typedef unsigned int UINT16 __attribute__((__mode__(__HI__))); typedef signed int SINT16 __attribute__((__mode__(__HI__))); typedef unsigned int UINT32 __attribute__((__mode__(__SI__))); typedef signed int SINT32 __attribute__((__mode__(__SI__))); typedef unsigned int UINT64 __attribute__((__mode__(__DI__))); typedef signed int SINT64 __attribute__((__mode__(__DI__))); #elif defined(_MSC_VER) typedef unsigned __int8 UINT8; typedef signed __int8 SINT8; typedef unsigned __int16 UINT16; typedef signed __int16 SINT16; typedef unsigned __int32 UINT32; typedef signed __int32 SINT32; typedef unsigned __int64 UINT64; typedef signed __int64 SINT64; #else #error "Need typedefs here" #endif typedef float FLOAT32; #ifdef __cplusplus } #endif #endif --- NEW FILE: sysv.asm --- ; ----------------------------------------------------------------------- ; sysv.S - Copyright (c) 1998 Red Hat, Inc. ; ; ARM 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 CYGNUS SOLUTIONS 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> ;#ifdef HAVE_MACHINE_ASM_H ;#include <machine/asm.h> ;#else ;#ifdef __USER_LABEL_PREFIX__ ;#define CONCAT1(a, b) CONCAT2(a, b) ;#define CONCAT2(a, b) a ## b ;/* Use the right prefix for global labels. */ ;#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x) ;#else ;#define CNAME(x) x ;#endif ;#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x): ;#endif FFI_TYPE_VOID EQU 0 FFI_TYPE_INT EQU 1 FFI_TYPE_FLOAT EQU 2 FFI_TYPE_DOUBLE EQU 3 ;FFI_TYPE_LONGDOUBLE EQU 4 FFI_TYPE_UINT8 EQU 5 FFI_TYPE_SINT8 EQU 6 FFI_TYPE_UINT16 EQU 7 FFI_TYPE_SINT16 EQU 8 FFI_TYPE_UINT32 EQU 9 FFI_TYPE_SINT32 EQU 10 FFI_TYPE_UINT64 EQU 11 FFI_TYPE_SINT64 EQU 12 FFI_TYPE_STRUCT EQU 13 FFI_TYPE_POINTER EQU 14 ; WinCE always uses software floating point (I think) __SOFTFP__ EQU {TRUE} AREA |.text|, CODE, ARM ; .text ; a1: ffi_prep_args ; a2: &ecif ; a3: cif->bytes ; a4: fig->flags ; sp+0: ecif.rvalue ; sp+4: fn ; This assumes we are using gas. ;ENTRY(ffi_call_SYSV) EXPORT |ffi_call_SYSV| |ffi_call_SYSV| PROC ; Save registers stmfd sp!, {a1-a4, fp, lr} mov fp, sp ; Make room for all of the new args. sub sp, fp, a3 ; Place all of the ffi_prep_args in position mov ip, a1 mov a1, sp ; a2 already set ; And call mov lr, pc mov pc, ip ; move first 4 parameters in registers ldr a1, [sp, #0] ldr a2, [sp, #4] ldr a3, [sp, #8] ldr a4, [sp, #12] ; and adjust stack ldr ip, [fp, #8] cmp ip, #16 movge ip, #16 add sp, sp, ip ; call function mov lr, pc ldr pc, [fp, #28] ; Remove the space we pushed for the args mov sp, fp ; Load a3 with the pointer to storage for the return value ldr a3, [sp, #24] ; Load a4 with the return type code ldr a4, [sp, #12] ; If the return value pointer is NULL, assume no return value. cmp a3, #0 beq call_epilogue ; return INT cmp a4, #FFI_TYPE_INT streq a1, [a3] beq call_epilogue ; return FLOAT cmp a4, #FFI_TYPE_FLOAT [ __SOFTFP__ ;ifdef __SOFTFP__ streq a1, [a3] | ;else stfeqs f0, [a3] ] ;endif beq call_epilogue ; return DOUBLE or LONGDOUBLE cmp a4, #FFI_TYPE_DOUBLE [ __SOFTFP__ ;ifdef __SOFTFP__ stmeqia a3, {a1, a2} | ;else stfeqd f0, [a3] ] ;endif beq call_epilogue ; return SINT64 or UINT64 cmp a4, #FFI_TYPE_SINT64 stmeqia a3, {a1, a2} call_epilogue ldmfd sp!, {a1-a4, fp, pc} ;.ffi_call_SYSV_end: ;.size CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV) ENDP RESERVE_RETURN EQU 16 ; This function is called by the trampoline ; It is NOT callable from C ; ip = pointer to struct ffi_closure IMPORT |ffi_closure_SYSV_inner| EXPORT |ffi_closure_SYSV| |ffi_closure_SYSV| PROC ; Store the argument registers on the stack stmfd sp!, {a1-a4} ; Push the return address onto the stack stmfd sp!, {lr} mov a1, ip ; first arg = address of ffi_closure add a2, sp, #4 ; second arg = sp+4 (points to saved a1) ; Allocate space for a non-struct return value sub sp, sp, #RESERVE_RETURN mov a3, sp ; third arg = return value address ; static unsigned int ; ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue) bl ffi_closure_SYSV_inner ; a1 now contains the return type code ; At this point the return value is on the stack ; Transfer it to the correct registers if necessary ; return INT cmp a1, #FFI_TYPE_INT ldreq a1, [sp] beq closure_epilogue ; return FLOAT cmp a1, #FFI_TYPE_FLOAT [ __SOFTFP__ ;ifdef __SOFTFP__ ldreq a1, [sp] | ;else stfeqs f0, [sp] ] ;endif beq closure_epilogue ; return DOUBLE or LONGDOUBLE cmp a1, #FFI_TYPE_DOUBLE [ __SOFTFP__ ;ifdef __SOFTFP__ ldmeqia sp, {a1, a2} | ;else stfeqd f0, [sp] ] ;endif beq closure_epilogue ; return SINT64 or UINT64 cmp a1, #FFI_TYPE_SINT64 ldmeqia sp, {a1, a2} closure_epilogue add sp, sp, #RESERVE_RETURN ; remove return value buffer ldmfd sp!, {ip} ; ip = pop return address add sp, sp, #16 ; remove saved argument registers {a1-a4} from the stack mov pc, ip ; return ENDP ; ffi_closure_SYSV END --- NEW FILE: ffitarget.h --- /* -----------------------------------------------------------------*-C-*- ffitarget.h - Copyright (c) 1996-2003 Red Hat, Inc. Target configuration macros for ARM. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #ifndef LIBFFI_TARGET_H #define LIBFFI_TARGET_H #ifndef LIBFFI_ASM typedef unsigned long ffi_arg; typedef signed long ffi_sarg; typedef enum ffi_abi { FFI_FIRST_ABI = 0, FFI_SYSV, FFI_DEFAULT_ABI = FFI_SYSV, FFI_LAST_ABI = FFI_DEFAULT_ABI + 1 } ffi_abi; #endif /* ---- Definitions for closures ----------------------------------------- */ #define FFI_CLOSURES 1 #define FFI_TRAMPOLINE_SIZE 12 #define FFI_NATIVE_RAW_API 0 #endif --- NEW FILE: prep_cif.c --- /* ----------------------------------------------------------------------- prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> /* Round up to FFI_SIZEOF_ARG. */ #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG) /* Perform machine independent initialization of aggregate type specifications. */ static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg) { ffi_type **ptr; FFI_ASSERT(arg != NULL); /*@-usedef@*/ FFI_ASSERT(arg->elements != NULL); FFI_ASSERT(arg->size == 0); FFI_ASSERT(arg->alignment == 0); ptr = &(arg->elements[0]); while ((*ptr) != NULL) { if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; /* Perform a sanity check on the argument type */ FFI_ASSERT_VALID_TYPE(*ptr); arg->size = ALIGN(arg->size, (*ptr)->alignment); arg->size += (*ptr)->size; arg->alignment = (arg->alignment > (*ptr)->alignment) ? arg->alignment : (*ptr)->alignment; ptr++; } /* Structure size includes tail padding. This is important for structures that fit in one register on ABIs like the PowerPC64 Linux ABI that right justify small structs in a register. It's also needed for nested structure layout, for example struct A { long a; char b; }; struct B { struct A x; char y; }; should find y at an offset of 2*sizeof(long) and result in a total size of 3*sizeof(long). */ arg->size = ALIGN (arg->size, arg->alignment); if (arg->size == 0) return FFI_BAD_TYPEDEF; else return FFI_OK; /*@=usedef@*/ } /* Perform machine independent ffi_cif preparation, then call machine dependent routine. */ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, ffi_abi abi, unsigned int nargs, /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, /*@dependent@*/ ffi_type **atypes) { unsigned bytes = 0; unsigned int i; ffi_type **ptr; FFI_ASSERT(cif != NULL); FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI)); cif->abi = abi; cif->arg_types = atypes; cif->nargs = nargs; cif->rtype = rtype; cif->flags = 0; /* Initialize the return type if necessary */ /*@-usedef@*/ if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK)) return FFI_BAD_TYPEDEF; /*@=usedef@*/ /* Perform a sanity check on the return type */ FFI_ASSERT_VALID_TYPE(cif->rtype); /* x86-64 and s390 stack space allocation is handled in prep_machdep. */ #if !defined M68K && !defined __x86_64__ && !defined S390 /* Make space for the return structure pointer */ if (cif->rtype->type == FFI_TYPE_STRUCT /* MSVC returns small structures in registers. But we have a different workaround: pretend int32 or int64 return type, and converting to structure afterwards. */ #ifdef SPARC && (cif->abi != FFI_V9 || cif->rtype->size > 32) #endif ) bytes = STACK_ARG_SIZE(sizeof(void*)); #endif for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) { /* Initialize any uninitialized aggregate type definitions */ if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK)) return FFI_BAD_TYPEDEF; /* Perform a sanity check on the argument type, do this check after the initialization. */ FFI_ASSERT_VALID_TYPE(*ptr); #if !defined __x86_64__ && !defined S390 #ifdef SPARC if (((*ptr)->type == FFI_TYPE_STRUCT && ((*ptr)->size > 16 || cif->abi != FFI_V9)) || ((*ptr)->type == FFI_TYPE_LONGDOUBLE && cif->abi != FFI_V9)) bytes += sizeof(void*); else #endif { #ifndef _MSC_VER /* Don't know if this is a libffi bug or not. At least on Windows with MSVC, function call parameters are *not* aligned in the same way as structure fields are, they are only aligned in integer boundaries. This doesn't do any harm for cdecl functions and closures, since the caller cleans up the stack, but it is wrong for stdcall functions where the callee cleans. */ /* Add any padding if necessary */ if (((*ptr)->alignment - 1) & bytes) bytes = ALIGN(bytes, (*ptr)->alignment); #endif bytes += STACK_ARG_SIZE((*ptr)->size); } #endif } cif->bytes = bytes; /* Perform machine dependent cif processing */ return ffi_prep_cif_machdep(cif); } --- NEW FILE: fficonfig.h --- /* fficonfig.h created manually for Windows CE on ARM */ /* fficonfig.h.in. Generated from configure.ac by autoheader. */ /* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */ #define BYTEORDER 1234 /* Define to one of `_getb67', `GETB67', `getb67' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c' support on those systems. */ /* #undef CRAY_STACKSEG_END */ /* Define to 1 if using `alloca.c'. */ /* #undef C_ALLOCA */ /* Define to the flags needed for the .section .eh_frame directive. */ /* #undef EH_FRAME_FLAGS */ /* Define this if you want extra debugging. */ #ifdef DEBUG /* Defined by the project settings for Debug builds */ #define FFI_DEBUG #else #undef FFI_DEBUG #endif /* Define this is you do not want support for the raw API. */ /* #undef FFI_NO_RAW_API */ /* Define this is you do not want support for aggregate types. */ /* #undef FFI_NO_STRUCTS */ /* Define to 1 if you have `alloca', as a function or macro. */ #define HAVE_ALLOCA 1 /* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */ /* #undef HAVE_ALLOCA_H */ /* Define if your assembler supports .register. */ /* #undef HAVE_AS_REGISTER_PSEUDO_OP */ /* Define if your assembler and linker support unaligned PC relative relocs. */ /* #undef HAVE_AS_SPARC_UA_PCREL */ /* Define to 1 if you have the <inttypes.h> header file. */ /* #undef HAVE_INTTYPES_H */ /* Define if you have the long double type and it is bigger than a double */ /* This differs from the MSVC build, but even there it should not be defined */ /* #undef HAVE_LONG_DOUBLE */ /* Define to 1 if you have the `memcpy' function. */ #define HAVE_MEMCPY 1 /* Define to 1 if you have the <memory.h> header file. */ /* WinCE has this but I don't think we need to use it */ /* #undef HAVE_MEMORY_H */ /* Define to 1 if you have the `mmap' function. */ /* #undef HAVE_MMAP */ /* Define if mmap with MAP_ANON(YMOUS) works. */ /* #undef HAVE_MMAP_ANON */ /* Define if mmap of /dev/zero works. */ /* #undef HAVE_MMAP_DEV_ZERO */ /* Define if read-only mmap of a plain file works. */ /* #undef HAVE_MMAP_FILE */ /* Define if .eh_frame sections should be read-only. */ /* #undef HAVE_RO_EH_FRAME */ /* Define to 1 if you have the <stdint.h> header file. */ /* #undef HAVE_STDINT_H */ /* Define to 1 if you have the <stdlib.h> header file. */ #define HAVE_STDLIB_H 1 /* Define to 1 if you have the <strings.h> header file. */ /* #undef HAVE_STRINGS_H */ /* Define to 1 if you have the <string.h> header file. */ #define HAVE_STRING_H 1 /* Define to 1 if you have the <sys/mman.h> header file. */ /* #undef HAVE_SYS_MMAN_H */ /* Define to 1 if you have the <sys/stat.h> header file. */ /* #undef HAVE_SYS_STAT_H */ /* Define to 1 if you have the <sys/types.h> header file. */ /* #undef HAVE_SYS_TYPES_H */ /* Define to 1 if you have the <unistd.h> header file. */ /* #undef HAVE_UNISTD_H */ /* Define if the host machine stores words of multi-word integers in big-endian order. */ /* #undef HOST_WORDS_BIG_ENDIAN */ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ /* #undef NO_MINUS_C_MINUS_O */ /* Name of package */ /* #undef PACKAGE */ /* Define to the address where bug reports for this package should be sent. */ /* #undef PACKAGE_BUGREPORT */ /* Define to the full name of this package. */ /* #undef PACKAGE_NAME */ /* Define to the full name and version of this package. */ /* #undef PACKAGE_STRING */ /* Define to the one symbol short name of this package. */ /* #undef PACKAGE_TARNAME */ /* Define to the version of this package. */ /* #undef PACKAGE_VERSION */ /* The number of bytes in type double */ #define SIZEOF_DOUBLE 8 /* The number of bytes in type long double */ #define SIZEOF_LONG_DOUBLE 8 /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ /* #undef STACK_DIRECTION */ /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Define this if you are using Purify and want to suppress spurious messages. */ /* #undef USING_PURIFY */ /* Version number of package */ /* #undef VERSION */ /* whether byteorder is bigendian */ /* #undef WORDS_BIGENDIAN */ #define alloca _alloca #define abort() exit(999) --- NEW FILE: debug.c --- /* ----------------------------------------------------------------------- debug.c - Copyright (c) 1996 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> #include <stdio.h> /* General debugging routines */ void ffi_stop_here(void) { /* This function is only useful for debugging purposes. Place a breakpoint on ffi_stop_here to be notified of significant events. */ } /* This function should only be called via the FFI_ASSERT() macro */ void ffi_assert(char *expr, char *file, int line) { fprintf(stderr, "ASSERTION FAILURE: %s at %s:%d\n", expr, file, line); ffi_stop_here(); abort(); } /* Perform a sanity check on an ffi_type structure */ void ffi_type_test(ffi_type *a, char *file, int line) { FFI_ASSERT_AT(a != NULL, file, line); /*@-usedef@*/ FFI_ASSERT_AT(a->type <= FFI_TYPE_LAST, file, line); FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->size > 0, file, line); FFI_ASSERT_AT(a->type == FFI_TYPE_VOID || a->alignment > 0, file, line); FFI_ASSERT_AT(a->type != FFI_TYPE_STRUCT || a->elements != NULL, file, line); /*@=usedef@*/ } --- NEW FILE: ffi.c --- /* ----------------------------------------------------------------------- ffi.c - Copyright (c) 1998 Red Hat, Inc. ARM 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ #include <ffi.h> #include <ffi_common.h> #include <stdlib.h> #ifdef _WIN32_WCE #pragma warning (disable : 4142) /* benign redefinition of type */ #include <windows.h> #endif /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments */ /*@-exportheader@*/ void ffi_prep_args(char *stack, extended_cif *ecif) /*@=exportheader@*/ { register unsigned int i; register void **p_argv; register char *argp; register ffi_type **p_arg; argp = stack; if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) { *(void **) argp = ecif->rvalue; argp += 4; } p_argv = ecif->avalue; for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++) { size_t z; size_t argalign = (*p_arg)->alignment; #ifdef _WIN32_WCE if (argalign > 4) argalign = 4; #endif /* Align if necessary */ if ((argalign - 1) & (unsigned) argp) { argp = (char *) ALIGN(argp, argalign); } z = (*p_arg)->size; if (z < sizeof(int)) { z = sizeof(int); switch ((*p_arg)->type) { case FFI_TYPE_SINT8: *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv); break; case FFI_TYPE_UINT8: *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv); break; case FFI_TYPE_SINT16: *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv); break; case FFI_TYPE_UINT16: *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv); break; case FFI_TYPE_STRUCT: /* *p_argv may not be aligned for a UINT32 */ memcpy(argp, *p_argv, z); break; default: FFI_ASSERT(0); } } else if (z == sizeof(int)) { *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv); } else { memcpy(argp, *p_argv, z); } p_argv++; argp += z; } return; } /* Perform machine dependent cif processing */ ffi_status ffi_prep_cif_machdep(ffi_cif *cif) { /* Set the return type flag */ switch (cif->rtype->type) { case FFI_TYPE_VOID: case FFI_TYPE_STRUCT: case FFI_TYPE_FLOAT: case FFI_TYPE_DOUBLE: case FFI_TYPE_SINT64: cif->flags = (unsigned) cif->rtype->type; break; case FFI_TYPE_UINT64: cif->flags = FFI_TYPE_SINT64; break; default: cif->flags = FFI_TYPE_INT; break; } return FFI_OK; } /*@-declundef@*/ /*@-exportheader@*/ extern void ffi_call_SYSV(void (*)(char *, extended_cif *), /*@out@*/ extended_cif *, unsigned, unsigned, /*@out@*/ unsigned *, void (*fn)()); /*@=declundef@*/ /*@=exportheader@*/ /* Return type changed from void for ctypes */ int ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue) { extended_cif ecif; ecif.cif = cif; ecif.avalue = avalue; /* If the return value is a struct and we don't have a return */ /* value address then we need to make one */ if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) { /*@-sysunrecog@*/ ecif.rvalue = alloca(cif->rtype->size); /*@=sysunrecog@*/ } else ecif.rvalue = rvalue; switch (cif->abi) { case FFI_SYSV: /*@-usedef@*/ ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue, fn); /*@=usedef@*/ break; default: FFI_ASSERT(0); break; } /* I think calculating the real stack pointer delta is not useful because stdcall is not supported */ return 0; } /** private members **/ static void ffi_prep_incoming_args_SYSV (char *stack, void **ret, void** args, ffi_cif* cif); /* This function is called by ffi_closure_SYSV in sysv.asm */ unsigned int ffi_closure_SYSV_inner (ffi_closure *closure, char *in_args, void *rvalue) { ffi_cif *cif = closure->cif; void **out_args; out_args = (void **) alloca(cif->nargs * sizeof (void *)); /* this call will initialize out_args, such that each * element in that array points to the corresponding * value on the stack; and if the function returns * a structure, it will re-set rvalue to point to the * structure return address. */ ffi_prep_incoming_args_SYSV(in_args, &rvalue, out_args, cif); (closure->fun)(cif, rvalue, out_args, closure->user_data); /* Tell ffi_closure_SYSV what the returntype is */ return cif->flags; } /*@-exportheader@*/ static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue, ffi_cif *cif) /*@=exportheader@*/ { unsigned int i; void **p_argv; char *argp; ffi_type **p_arg; argp = stack; if ( cif->rtype->type == FFI_TYPE_STRUCT ) { *rvalue = *(void **) argp; argp += 4; } p_argv = avalue; for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) { size_t z; size_t argalign = (*p_arg)->alignment; #ifdef _WIN32_WCE if (argalign > 4) argalign = 4; #endif /* Align if necessary */ if ((argalign - 1) & (unsigned) argp) { argp = (char *) ALIGN(argp, argalign); } z = (*p_arg)->size; if (z < sizeof(int)) z = sizeof(int); *p_argv = (void*) argp; p_argv++; argp += z; } } /* add ip, pc, #-8 ; ip = address of this trampoline == address of ffi_closure ldr pc, [pc, #-4] ; jump to __fun DCD __fun */ #define FFI_INIT_TRAMPOLINE(TRAMP,FUN) \ { \ unsigned int *__tramp = (unsigned int *)(TRAMP); \ __tramp[0] = 0xe24fc008; /* add ip, pc, #-8 */ \ __tramp[1] = 0xe51ff004; /* ldr pc, [pc, #-4] */ \ __tramp[2] = (unsigned int)(FUN); \ } /* the cif must already be prep'ed */ /* defined in sysv.asm */ void ffi_closure_SYSV(void); ffi_status ffi_prep_closure (ffi_closure* closure, ffi_cif* cif, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data) { FFI_ASSERT (cif->abi == FFI_SYSV); FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_SYSV); closure->cif = cif; closure->user_data = user_data; closure->fun = fun; #ifdef _WIN32_WCE /* This is important to allow calling the trampoline safely */ FlushInstructionCache(GetCurrentProcess(), 0, 0); #endif return FFI_OK; } --- NEW FILE: ffi.h --- /* -----------------------------------------------------------------*-C-*- libffi 2.00-beta-wince - Copyright (c) 1996-2003 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. ----------------------------------------------------------------------- */ /* ------------------------------------------------------------------- The basic API is described in the README file. The raw API is designed to bypass some of the argument packing and unpacking on architectures for which it can be avoided. The closure API allows interpreted functions to be packaged up inside a C function pointer, so that they can be called as C functions, with no understanding on the client side that they are interpreted. It can also be used in other cases in which it is necessary to package up a user specified parameter and a function pointer as a single function pointer. The closure API must be implemented in order to get its functionality, e.g. for use by gij. Routines are provided to emulate the raw API if the underlying platform doesn't allow faster implementation. More details on the raw and cloure API can be found in: http://gcc.gnu.org/ml/java/1999-q3/msg00138.html and http://gcc.gnu.org/ml/java/1999-q3/msg00174.html -------------------------------------------------------------------- */ #ifndef LIBFFI_H #define LIBFFI_H #ifdef __cplusplus extern "C" { #endif /* Specify which architecture libffi is configured for. */ /*#define @TARGET@*/ /* ---- System configuration information --------------------------------- */ #include <ffitarget.h> #ifndef LIBFFI_ASM #include <stddef.h> #include <limits.h> /* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example). But we can find it either under the correct ANSI name, or under GNU C's internal name. */ #ifdef LONG_LONG_MAX # define FFI_LONG_LONG_MAX LONG_LONG_MAX #else # ifdef LLONG_MAX # define FFI_LONG_LONG_MAX LLONG_MAX # else # ifdef __GNUC__ # define FFI_LONG_LONG_MAX __LONG_LONG_MAX__ # endif # ifdef _MSC_VER # define FFI_LONG_LONG_MAX _I64_MAX # endif # endif #endif #if SCHAR_MAX == 127 # define ffi_type_uchar ffi_type_uint8 # define ffi_type_schar ffi_type_sint8 #else #error "char size not supported" #endif #if SHRT_MAX == 32767 # define ffi_type_ushort ffi_type_uint16 # define ffi_type_sshort ffi_type_sint16 #elif SHRT_MAX == 2147483647 # define ffi_type_ushort ffi_type_uint32 # define ffi_type_sshort ffi_type_sint32 #else #error "short size not supported" #endif #if INT_MAX == 32767 # define ffi_type_uint ffi_type_uint16 # define ffi_type_sint ffi_type_sint16 #elif INT_MAX == 2147483647 # define ffi_type_uint ffi_type_uint32 # define ffi_type_sint ffi_type_sint32 #elif INT_MAX == 9223372036854775807 # define ffi_type_uint ffi_type_uint64 # define ffi_type_sint ffi_type_sint64 #else #error "int size not supported" #endif #define ffi_type_ulong ffi_type_uint64 #define ffi_type_slong ffi_type_sint64 #if LONG_MAX == 2147483647 # if FFI_LONG_LONG_MAX != 9223372036854775807 #error "no 64-bit data type supported" # endif #elif LONG_MAX != 9223372036854775807 #error "long size not supported" #endif /* The closure code assumes that this works on pointers, i.e. a size_t */ /* can hold a pointer. */ typedef struct _ffi_type { size_t size; unsigned short alignment; unsigned short type; /*@null@*/ struct _ffi_type **elements; } ffi_type; /* These are defined in types.c */ extern ffi_type ffi_type_void; extern ffi_type ffi_type_uint8; extern ffi_type ffi_type_sint8; extern ffi_type ffi_type_uint16; extern ffi_type ffi_type_sint16; extern ffi_type ffi_type_uint32; extern ffi_type ffi_type_sint32; extern ffi_type ffi_type_uint64; extern ffi_type ffi_type_sint64; extern ffi_type ffi_type_float; extern ffi_type ffi_type_double; extern ffi_type ffi_type_longdouble; extern ffi_type ffi_type_pointer; typedef enum { FFI_OK = 0, FFI_BAD_TYPEDEF, FFI_BAD_ABI } ffi_status; typedef unsigned FFI_TYPE; typedef struct { ffi_abi abi; unsigned nargs; /*@dependent@*/ ffi_type **arg_types; /*@dependent@*/ ffi_type *rtype; unsigned bytes; unsigned flags; #ifdef FFI_EXTRA_CIF_FIELDS FFI_EXTRA_CIF_FIELDS; #endif } ffi_cif; /* ---- Definitions for the raw API -------------------------------------- */ #ifndef FFI_SIZEOF_ARG # if LONG_MAX == 2147483647 # define FFI_SIZEOF_ARG 4 # elif LONG_MAX == 9223372036854775807 # define FFI_SIZEOF_ARG 8 # endif #endif typedef union { ffi_sarg sint; ffi_arg uint; float flt; char data[FFI_SIZEOF_ARG]; void* ptr; } ffi_raw; void ffi_raw_call (/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ ffi_raw *avalue); void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_raw_size (ffi_cif *cif); /* This is analogous to the raw API, except it uses Java parameter */ /* packing, even on 64-bit machines. I.e. on 64-bit machines */ /* longs and doubles are followed by an empty 64-bit word. */ void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ ffi_raw *avalue); void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw); void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args); size_t ffi_java_raw_size (ffi_cif *cif); /* ---- Definitions for closures ----------------------------------------- */ #if FFI_CLOSURES typedef struct { char tramp[FFI_TRAMPOLINE_SIZE]; ffi_cif *cif; void (*fun)(ffi_cif*,void*,void**,void*); void *user_data; } ffi_closure; ffi_status ffi_prep_closure (ffi_closure*, ffi_cif *, void (*fun)(ffi_cif*,void*,void**,void*), void *user_data); typedef struct { char tramp[FFI_TRAMPOLINE_SIZE]; ffi_cif *cif; #if !FFI_NATIVE_RAW_API /* if this is enabled, then a raw closure has the same layout as a regular closure. We use this to install an intermediate handler to do the transaltion, void** -> ffi_raw*. */ void (*translate_args)(ffi_cif*,void*,void**,void*); void *this_closure; #endif void (*fun)(ffi_cif*,void*,ffi_raw*,void*); void *user_data; } ffi_raw_closure; ffi_status ffi_prep_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); ffi_status ffi_prep_java_raw_closure (ffi_raw_closure*, ffi_cif *cif, void (*fun)(ffi_cif*,void*,ffi_raw*,void*), void *user_data); #endif /* FFI_CLOSURES */ /* ---- Public interface definition -------------------------------------- */ ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif, ffi_abi abi, unsigned int nargs, /*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype, /*@dependent@*/ ffi_type **atypes); /* Return type changed from void for ctypes */ int ffi_call(/*@dependent@*/ ffi_cif *cif, void (*fn)(), /*@out@*/ void *rvalue, /*@dependent@*/ void **avalue); /* Useful for eliminating compiler warnings */ #define FFI_FN(f) ((void (*)())f) /* ---- Definitions shared with assembly code ---------------------------- */ #endif /* If these change, update src/mips/ffitarget.h. */ #define FFI_TYPE_VOID 0 #define FFI_TYPE_INT 1 #define FFI_TYPE_FLOAT 2 #define FFI_TYPE_DOUBLE 3 #if 0 /*@HAVE_LONG_DOUBLE@*/ #define FFI_TYPE_LONGDOUBLE 4 #else #define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE #endif #define FFI_TYPE_UINT8 5 #define FFI_TYPE_SINT8 6 #define FFI_TYPE_UINT16 7 #define FFI_TYPE_SINT16 8 #define FFI_TYPE_UINT32 9 #define FFI_TYPE_SINT32 10 #define FFI_TYPE_UINT64 11 #define FFI_TYPE_SINT64 12 #define FFI_TYPE_STRUCT 13 #define FFI_TYPE_POINTER 14 /* This should always refer to the last type code (for sanity checks) */ #define FFI_TYPE_LAST FFI_TYPE_POINTER #ifdef __cplusplus } #endif #endif |
From: Thomas H. <th...@us...> - 2006-03-03 20:17:21
|
Update of /cvsroot/ctypes/ctypes/source In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10301 Added Files: stgdict.c malloc_closure.c ctypes_dlfcn.h ctypes.h cfield.c callproc.c callbacks.c _ctypes_test.h _ctypes_test.c _ctypes.c Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: _ctypes_test.h --- extern int _testfunc_i_bhilfd(char b, short h, int i, long l, float f, double d); --- NEW FILE: ctypes_dlfcn.h --- /******************************************************************/ #ifndef _CTYPES_DLFCN_H_ #define _CTYPES_DLFCN_H_ #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ #ifndef MS_WIN32 #include <dlfcn.h> #ifndef CTYPES_DARWIN_DLFCN #define ctypes_dlsym dlsym #define ctypes_dlerror dlerror #define ctypes_dlopen dlopen #define ctypes_dlclose dlclose #define ctypes_dladdr dladdr #endif /* !CTYPES_DARWIN_DLFCN */ #endif /* !MS_WIN32 */ #ifdef __cplusplus } #endif /* __cplusplus */ #endif /* _CTYPES_DLFCN_H_ */ --- NEW FILE: ctypes.h --- /******************************************************************/ #ifndef MS_WIN32 #define max(a, b) ((a) > (b) ? (a) : (b)) #define min(a, b) ((a) < (b) ? (a) : (b)) #define PARAMFLAG_FIN 0x1 #define PARAMFLAG_FOUT 0x2 #define PARAMFLAG_FLCID 0x4 #endif /* Backwards compatibility: Python2.2 used LONG_LONG instead of PY_LONG_LONG */ #if defined(HAVE_LONG_LONG) && !defined(PY_LONG_LONG) #define PY_LONG_LONG LONG_LONG #endif typedef int (*THUNK)(void); typedef struct tagCDataObject CDataObject; /* A default buffer in CDataObject, which can be used for small C types. If this buffer is too small, PyMem_Malloc will be called to create a larger one, and this one is not used. Making CDataObject a variable size object would be a better solution, but more difficult in the presence of CFuncPtrObject. Maybe later. */ union value { char c[16]; short s; int i; long l; float f; double d; #ifdef HAVE_LONG_LONG PY_LONG_LONG ll; #endif }; /* Hm. Are there CDataObject's which do not need the b_objects member? In this case we probably should introduce b_flags to mark it as present... If b_objects is not present/unused b_length is unneeded as well. */ struct tagCDataObject { PyObject_HEAD char *b_ptr; /* pointer to memory block */ int b_needsfree; /* need _we_ free the memory? */ CDataObject *b_base; /* pointer to base object or NULL */ int b_size; /* size of memory block in bytes */ int b_length; /* number of references we need */ int b_index; /* index of this object into base's b_object list */ PyObject *b_objects; /* list of references we need to keep */ union value b_value; }; typedef struct { /* First part identical to tagCDataObject */ PyObject_HEAD char *b_ptr; /* pointer to memory block */ int b_needsfree; /* need _we_ free the memory? */ CDataObject *b_base; /* pointer to base object or NULL */ int b_size; /* size of memory block in bytes */ int b_length; /* number of references we need */ int b_index; /* index of this object into base's b_object list */ PyObject *b_objects; /* list of references we need to keep */ union value b_value; /* end of tagCDataObject, additional fields follow */ THUNK thunk; PyObject *callable; /* These two fields will override the ones in the type's stgdict if they are set */ PyObject *converters; PyObject *argtypes; PyObject *restype; PyObject *checker; PyObject *errcheck; #ifdef MS_WIN32 int index; GUID *iid; #endif PyObject *paramflags; } CFuncPtrObject; extern PyTypeObject StgDict_Type; #define StgDict_CheckExact(v) ((v)->ob_type == &StgDict_Type) #define StgDict_Check(v) PyObject_TypeCheck(v, &StgDict_Type) extern int StructUnionType_update_stgdict(PyObject *fields, PyObject *type, int isStruct); extern int PyType_stginfo(PyTypeObject *self, int *psize, int *palign, int *plength); extern int PyObject_stginfo(PyObject *self, int *psize, int *palign, int *plength); extern PyTypeObject CData_Type; #define CDataObject_CheckExact(v) ((v)->ob_type == &CData_Type) #define CDataObject_Check(v) PyObject_TypeCheck(v, &CData_Type) extern PyTypeObject SimpleType_Type; #define SimpleTypeObject_CheckExact(v) ((v)->ob_type == &SimpleType_Type) #define SimpleTypeObject_Check(v) PyObject_TypeCheck(v, &SimpleType_Type) extern PyTypeObject CField_Type; extern struct fielddesc *getentry(char *fmt); extern PyObject * CField_FromDesc(PyObject *desc, int index, int *pfield_size, int bitsize, int *pbitofs, int *psize, int *poffset, int *palign, int pack, int is_big_endian); extern PyObject *CData_AtAddress(PyObject *type, void *buf); extern PyObject *CData_FromBytes(PyObject *type, char *data, int length); extern PyTypeObject ArrayType_Type; extern PyTypeObject Array_Type; extern PyTypeObject PointerType_Type; extern PyTypeObject Pointer_Type; extern PyTypeObject CFuncPtr_Type; extern PyTypeObject CFuncPtrType_Type; extern PyTypeObject StructType_Type; #define ArrayTypeObject_Check(v) PyObject_TypeCheck(v, &ArrayType_Type) #define ArrayObject_Check(v) PyObject_TypeCheck(v, &Array_Type) #define PointerObject_Check(v) PyObject_TypeCheck(v, &Pointer_Type) #define PointerTypeObject_Check(v) PyObject_TypeCheck(v, &PointerType_Type) #define CFuncPtrObject_Check(v) PyObject_TypeCheck(v, &CFuncPtr_Type) #define CFuncPtrTypeObject_Check(v) PyObject_TypeCheck(v, &CFuncPtrType_Type) #define StructTypeObject_Check(v) PyObject_TypeCheck(v, &StructType_Type) extern PyObject * CreateArrayType(PyObject *itemtype, int length); extern void init_callbacks_in_module(PyObject *m); extern THUNK AllocFunctionCallback(PyObject *callable, PyObject *converters, PyObject *restype, int stdcall); extern void FreeCallback(THUNK); extern PyMethodDef module_methods[]; typedef PyObject *(* GETFUNC)(void *, unsigned size); typedef PyObject *(* SETFUNC)(void *, PyObject *value, unsigned size); /* a table entry describing a predefined ctypes type */ struct fielddesc { char code; SETFUNC setfunc; GETFUNC getfunc; ffi_type *pffi_type; /* always statically allocated */ SETFUNC setfunc_swapped; GETFUNC getfunc_swapped; }; typedef struct { PyObject_HEAD int offset; int size; int index; /* Index into CDataObject's object array */ PyObject *proto; /* a type or NULL */ GETFUNC getfunc; /* getter function if proto is NULL */ SETFUNC setfunc; /* setter function if proto is NULL */ } CFieldObject; /* A subclass of PyDictObject, used as the instance dictionary of ctypes metatypes */ typedef struct { PyDictObject dict; /* first part identical to PyDictObject */ /* The size and align fields are unneeded, they are in ffi_type as well. As an experiment shows, it's trivial to get rid of them, the only thing to remember is that in ArrayType_new the ffi_type fields must be filled in - so far it was unneeded because libffi doesn't support arrays at all (because they are passed as pointers to function calls anyway). But it's too much risk to change that now, and there are other fields which doen't belong into this structure anyway. Maybe in ctypes 2.0... (ctypes 2000?) */ int size; /* number of bytes */ int align; /* alignment requirements */ int length; /* number of fields */ ffi_type ffi_type; PyObject *proto; /* Only for Pointer/ArrayObject */ SETFUNC setfunc; /* Only for simple objects */ GETFUNC getfunc; /* Only for simple objects */ /* Following fields only used by CFuncPtrType_Type instances */ PyObject *argtypes; /* tuple of CDataObjects */ PyObject *converters; /* tuple([t.from_param for t in argtypes]) */ PyObject *restype; /* CDataObject or NULL */ PyObject *checker; int flags; /* calling convention and such */ } StgDictObject; /**************************************************************** StgDictObject fields setfunc and getfunc is only set for simple data types, it is copied from the corresponding fielddesc entry. These are functions to set and get the value in a memory block. They should probably by used by other types as well. proto is only used for Pointer and Array types - it points to the item type object. Probably all the magic ctypes methods (like from_param) should have C callable wrappers in the StgDictObject. For simple data type, for example, the fielddesc table could have entries for C codec from_param functions or other methods as well, if a subtype overrides this method in Python at construction time, or assigns to it later, tp_setattro should update the StgDictObject function to a generic one. Currently, CFuncPtr types have 'converters' and 'checker' entries in their type dict. They are only used to cache attributes from other entries, whihc is wrong. One use case is the .value attribute that all simple types have. But some complex structures, like VARIANT, represent a single value also, and should have this attribute. Another use case is a _check_retval_ function, which is called when a ctypes type is used as return type of a function to validate and compute the return value. Common ctypes protocol: - setfunc: store a python value in a memory block - getfunc: convert data from a memory block into a python value - checkfunc: validate and convert a return value from a function call - toparamfunc: convert a python value into a function argument *****************************************************************/ /* May return NULL, but does not set an exception! */ extern StgDictObject *PyType_stgdict(PyObject *obj); /* May return NULL, but does not set an exception! */ extern StgDictObject *PyObject_stgdict(PyObject *self); extern int StgDict_clone(StgDictObject *src, StgDictObject *dst); typedef int(* PPROC)(void); PyObject *_CallProc(PPROC pProc, PyObject *arguments, #ifdef MS_WIN32 IUnknown *pIUnk, GUID *iid, #endif int flags, PyObject *argtypes, PyObject *restype, PyObject *checker); #define FUNCFLAG_STDCALL 0x0 #define FUNCFLAG_CDECL 0x1 #define FUNCFLAG_HRESULT 0x2 #define FUNCFLAG_PYTHONAPI 0x4 #define DICTFLAG_FINAL 0x1000 typedef struct { PyObject_HEAD ffi_type *pffi_type; char tag; union { char c; char b; short h; int i; long l; #ifdef HAVE_LONG_LONG PY_LONG_LONG q; #endif double d; float f; void *p; } value; PyObject *obj; int size; /* for the 'V' tag */ } PyCArgObject; extern PyTypeObject PyCArg_Type; extern PyCArgObject *new_CArgObject(void); #define PyCArg_CheckExact(v) ((v)->ob_type == &PyCArg_Type) extern PyCArgObject *new_CArgObject(void); extern PyObject * CData_get(PyObject *type, GETFUNC getfunc, PyObject *src, int index, int size, char *ptr); extern int CData_set(PyObject *dst, PyObject *type, SETFUNC setfunc, PyObject *value, int index, int size, char *ptr); extern void Extend_Error_Info(PyObject *exc_class, char *fmt, ...); struct basespec { CDataObject *base; int index; char *adr; }; extern char basespec_string[]; extern ffi_type *GetType(PyObject *obj); /* exception classes */ extern PyObject *PyExc_ArgError; extern char *conversion_mode_encoding; extern char *conversion_mode_errors; /* Python 2.4 macros, which are not available in Python 2.3 */ #ifndef Py_CLEAR #define Py_CLEAR(op) \ do { \ if (op) { \ PyObject *tmp = (PyObject *)(op); \ (op) = NULL; \ Py_DECREF(tmp); \ } \ } while (0) #endif #ifndef Py_VISIT /* Utility macro to help write tp_traverse functions. * To use this macro, the tp_traverse function must name its arguments * "visit" and "arg". This is intended to keep tp_traverse functions * looking as much alike as possible. */ #define Py_VISIT(op) \ do { \ if (op) { \ int vret = visit((op), arg); \ if (vret) \ return vret; \ } \ } while (0) #endif /* Python's PyUnicode_*WideChar functions are broken ... */ #if defined(Py_USING_UNICODE) && defined(HAVE_WCHAR_H) # define CTYPES_UNICODE #endif #ifdef CTYPES_UNICODE # undef PyUnicode_FromWideChar # define PyUnicode_FromWideChar My_PyUnicode_FromWideChar # undef PyUnicode_AsWideChar # define PyUnicode_AsWideChar My_PyUnicode_AsWideChar extern PyObject *My_PyUnicode_FromWideChar(const wchar_t *, int); extern int My_PyUnicode_AsWideChar(PyUnicodeObject *, wchar_t *, int); #endif extern void FreeClosure(void *); extern void *MallocClosure(void); extern void _AddTraceback(char *, char *, int); extern PyObject *CData_FromBaseObj(PyObject *type, PyObject *base, int index, char *adr); /* XXX better name needed! */ extern int IsSimpleSubType(PyObject *obj); #ifdef MS_WIN32 extern PyObject *ComError; #endif /* Local Variables: compile-command: "python setup.py -q build install --home ~" End: */ --- NEW FILE: callproc.c --- /* * History: First version dated from 3/97, derived from my SCMLIB version * for win16. */ /* * Related Work: * - calldll http://www.nightmare.com/software.html * - libffi http://sourceware.cygnus.com/libffi/ * - ffcall http://clisp.cons.org/~haible/packages-ffcall.html * and, of course, Don Beaudry's MESS package, but this is more ctypes * related. */ /* How are functions called, and how are parameters converted to C ? 1. _ctypes.c::CFuncPtr_call receives an argument tuple 'inargs' and a keyword dictionary 'kwds'. [...1483 lines suppressed...] {"dlclose", py_dl_close, METH_VARARGS, "dlclose a library"}, {"dlsym", py_dl_sym, METH_VARARGS, "find symbol in shared library"}, #endif {"alignment", align_func, METH_O, alignment_doc}, {"sizeof", sizeof_func, METH_O, sizeof_doc}, {"byref", byref, METH_O, byref_doc}, {"addressof", addressof, METH_O, addressof_doc}, {"call_function", call_function, METH_VARARGS }, {"call_cdeclfunction", call_cdeclfunction, METH_VARARGS }, {"PyObj_FromPtr", My_PyObj_FromPtr, METH_VARARGS }, {"Py_INCREF", My_Py_INCREF, METH_O }, {"Py_DECREF", My_Py_DECREF, METH_O }, {NULL, NULL} /* Sentinel */ }; /* Local Variables: compile-command: "cd .. && python setup.py -q build -g && python setup.py -q build install --home ~" End: */ --- NEW FILE: cfield.c --- #include "Python.h" #include "structmember.h" #include <ffi.h> #ifdef MS_WIN32 #include <windows.h> #endif #include "ctypes.h" /******************************************************************/ /* CField_Type */ static PyObject * CField_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { CFieldObject *obj; obj = (CFieldObject *)type->tp_alloc(type, 0); return (PyObject *)obj; [...1524 lines suppressed...] ffi_type ffi_type_uint8 = { 1, 1, FFI_TYPE_UINT8 }; ffi_type ffi_type_sint8 = { 1, 1, FFI_TYPE_SINT8 }; ffi_type ffi_type_uint16 = { 2, 2, FFI_TYPE_UINT16 }; ffi_type ffi_type_sint16 = { 2, 2, FFI_TYPE_SINT16 }; ffi_type ffi_type_uint32 = { 4, 4, FFI_TYPE_UINT32 }; ffi_type ffi_type_sint32 = { 4, 4, FFI_TYPE_SINT32 }; ffi_type ffi_type_uint64 = { 8, LONG_LONG_ALIGN, FFI_TYPE_UINT64 }; ffi_type ffi_type_sint64 = { 8, LONG_LONG_ALIGN, FFI_TYPE_SINT64 }; ffi_type ffi_type_float = { sizeof(float), FLOAT_ALIGN, FFI_TYPE_FLOAT }; ffi_type ffi_type_double = { sizeof(double), DOUBLE_ALIGN, FFI_TYPE_DOUBLE }; /* ffi_type ffi_type_longdouble */ ffi_type ffi_type_pointer = { sizeof(void *), VOID_P_ALIGN, FFI_TYPE_POINTER }; /*---------------- EOF ----------------*/ --- NEW FILE: _ctypes_test.c --- #include <Python.h> /* Backwards compatibility: Python2.2 used LONG_LONG instead of PY_LONG_LONG */ #if defined(HAVE_LONG_LONG) && !defined(PY_LONG_LONG) #define PY_LONG_LONG LONG_LONG #endif #ifdef MS_WIN32 #include <windows.h> #endif #if defined(MS_WIN32) || defined(__CYGWIN__) #define EXPORT(x) __declspec(dllexport) x #else #define EXPORT(x) x #endif /* some functions handy for testing */ EXPORT(char *)my_strtok(char *token, const char *delim) { return strtok(token, delim); } EXPORT(char *)my_strchr(const char *s, int c) { return strchr(s, c); } EXPORT(double) my_sqrt(double a) { return sqrt(a); } EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*)) { qsort(base, num, width, compare); } EXPORT(int *) _testfunc_ai8(int a[8]) { return a; } EXPORT(void) _testfunc_v(int a, int b, int *presult) { *presult = a + b; } EXPORT(int) _testfunc_i_bhilfd(char b, short h, int i, long l, float f, double d) { // printf("_testfunc_i_bhilfd got %d %d %d %ld %f %f\n", // b, h, i, l, f, d); return (int)(b + h + i + l + f + d); } EXPORT(float) _testfunc_f_bhilfd(char b, short h, int i, long l, float f, double d) { // printf("_testfunc_f_bhilfd got %d %d %d %ld %f %f\n", // b, h, i, l, f, d); return (float)(b + h + i + l + f + d); } EXPORT(double) _testfunc_d_bhilfd(char b, short h, int i, long l, float f, double d) { // printf("_testfunc_d_bhilfd got %d %d %d %ld %f %f\n", // b, h, i, l, f, d); return (double)(b + h + i + l + f + d); } EXPORT(char *) _testfunc_p_p(void *s) { return s; } EXPORT(void *) _testfunc_c_p_p(int *argcp, char **argv) { return argv[(*argcp)-1]; } EXPORT(void *) get_strchr(void) { return (void *)strchr; } EXPORT(char *) my_strdup(char *src) { char *dst = malloc(strlen(src)+1); if (!dst) return NULL; strcpy(dst, src); return dst; } #ifdef HAVE_WCHAR_H EXPORT(wchar_t *) my_wcsdup(wchar_t *src) { int len = wcslen(src); wchar_t *ptr = malloc((len + 1) * sizeof(wchar_t)); if (ptr == NULL) return NULL; memcpy(ptr, src, (len+1) * sizeof(wchar_t)); return ptr; } EXPORT(size_t) my_wcslen(wchar_t *src) { return wcslen(src); } #endif #ifndef MS_WIN32 # ifndef __stdcall # define __stdcall /* */ # endif #endif typedef struct { int (*c)(int, int); int (__stdcall *s)(int, int); } FUNCS; EXPORT(int) _testfunc_callfuncp(FUNCS *fp) { fp->c(1, 2); fp->s(3, 4); return 0; } EXPORT(int) _testfunc_deref_pointer(int *pi) { return *pi; } #ifdef MS_WIN32 EXPORT(int) _testfunc_piunk(IUnknown FAR *piunk) { piunk->lpVtbl->AddRef(piunk); return piunk->lpVtbl->Release(piunk); } #endif EXPORT(int) _testfunc_callback_with_pointer(int (*func)(int *)) { int table[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; return (*func)(table); } #ifdef HAVE_LONG_LONG EXPORT(PY_LONG_LONG) _testfunc_q_bhilfdq(char b, short h, int i, long l, float f, double d, PY_LONG_LONG q) { return (PY_LONG_LONG)(b + h + i + l + f + d + q); } EXPORT(PY_LONG_LONG) _testfunc_q_bhilfd(char b, short h, int i, long l, float f, double d) { return (PY_LONG_LONG)(b + h + i + l + f + d); } EXPORT(int) _testfunc_callback_i_if(int value, int (*func)(int)) { int sum = 0; while (value != 0) { sum += func(value); value /= 2; } return sum; } EXPORT(PY_LONG_LONG) _testfunc_callback_q_qf(PY_LONG_LONG value, PY_LONG_LONG (*func)(PY_LONG_LONG)) { PY_LONG_LONG sum = 0; while (value != 0) { sum += func(value); value /= 2; } return sum; } #endif EXPORT(int) _testfunc_ppp(char ***p) { static char message[] = "Hello, World"; if (p) { *p = malloc(sizeof(char *)); printf("malloc returned %p\n", *p); **p = message; return 1; } return 0; } EXPORT(void) my_free(void *p) { printf("my_free got %p\n", p); } typedef struct { char *name; char *value; } SPAM; typedef struct { char *name; int num_spams; SPAM *spams; } EGG; SPAM my_spams[2] = { { "name1", "value1" }, { "name2", "value2" }, }; EGG my_eggs[1] = { { "first egg", 1, my_spams } }; EXPORT(int) getSPAMANDEGGS(EGG **eggs) { *eggs = my_eggs; return 1; } typedef struct tagpoint { int x; int y; } point; EXPORT(int) _testfunc_byval(point in, point *pout) { if (pout) { pout->x = in.x; pout->y = in.y; } return in.x + in.y; } EXPORT (int) an_integer = 42; EXPORT(int) get_an_integer(void) { return an_integer; } EXPORT(double) integrate(double a, double b, double (*f)(double), long nstep) { double x, sum=0.0, dx=(b-a)/(double)nstep; for(x=a+0.5*dx; (b-x)*(x-a)>0.0; x+=dx) sum += f(x); return sum/(double)nstep; } typedef struct { void (*initialize)(void *(*)(int), void(*)(void *)); } xxx_library; static void _xxx_init(void *(*Xalloc)(int), void (*Xfree)(void *)) { void *ptr; printf("_xxx_init got %p %p\n", Xalloc, Xfree); printf("calling\n"); ptr = Xalloc(32); Xfree(ptr); printf("calls done, ptr was %p\n", ptr); } xxx_library _xxx_lib = { _xxx_init }; EXPORT(xxx_library) *library_get(void) { return &_xxx_lib; } #ifdef MS_WIN32 /* See Don Box (german), pp 79ff. */ EXPORT(void) GetString(BSTR *pbstr) { *pbstr = SysAllocString(L"Goodbye!"); } #endif /* * Some do-nothing functions, for speed tests */ PyObject *py_func_si(PyObject *self, PyObject *args) { char *name; int i; if (!PyArg_ParseTuple(args, "si", &name, &i)) return NULL; Py_INCREF(Py_None); return Py_None; } EXPORT(void) _py_func_si(char *s, int i) { } PyObject *py_func(PyObject *self, PyObject *args) { Py_INCREF(Py_None); return Py_None; } EXPORT(void) _py_func(void) { } EXPORT(PY_LONG_LONG) last_tf_arg_s; EXPORT(unsigned PY_LONG_LONG) last_tf_arg_u; struct BITS { int A: 1, B:2, C:3, D:4, E: 5, F: 6, G: 7, H: 8, I: 9; short M: 1, N: 2, O: 3, P: 4, Q: 5, R: 6, S: 7; }; DL_EXPORT(void) set_bitfields(struct BITS *bits, char name, int value) { switch (name) { case 'A': bits->A = value; break; case 'B': bits->B = value; break; case 'C': bits->C = value; break; case 'D': bits->D = value; break; case 'E': bits->E = value; break; case 'F': bits->F = value; break; case 'G': bits->G = value; break; case 'H': bits->H = value; break; case 'I': bits->I = value; break; case 'M': bits->M = value; break; case 'N': bits->N = value; break; case 'O': bits->O = value; break; case 'P': bits->P = value; break; case 'Q': bits->Q = value; break; case 'R': bits->R = value; break; case 'S': bits->S = value; break; } } DL_EXPORT(int) unpack_bitfields(struct BITS *bits, char name) { switch (name) { case 'A': return bits->A; case 'B': return bits->B; case 'C': return bits->C; case 'D': return bits->D; case 'E': return bits->E; case 'F': return bits->F; case 'G': return bits->G; case 'H': return bits->H; case 'I': return bits->I; case 'M': return bits->M; case 'N': return bits->N; case 'O': return bits->O; case 'P': return bits->P; case 'Q': return bits->Q; case 'R': return bits->R; case 'S': return bits->S; } return 0; } PyMethodDef module_methods[] = { // {"get_last_tf_arg_s", get_last_tf_arg_s, METH_NOARGS}, // {"get_last_tf_arg_u", get_last_tf_arg_u, METH_NOARGS}, {"func_si", py_func_si, METH_VARARGS}, {"func", py_func, METH_NOARGS}, { NULL, NULL, 0, NULL}, }; #define S last_tf_arg_s = (PY_LONG_LONG)c #define U last_tf_arg_u = (unsigned PY_LONG_LONG)c EXPORT(char) tf_b(char c) { S; return c/3; } EXPORT(unsigned char) tf_B(unsigned char c) { U; return c/3; } EXPORT(short) tf_h(short c) { S; return c/3; } EXPORT(unsigned short) tf_H(unsigned short c) { U; return c/3; } EXPORT(int) tf_i(int c) { S; return c/3; } EXPORT(unsigned int) tf_I(unsigned int c) { U; return c/3; } EXPORT(long) tf_l(long c) { S; return c/3; } EXPORT(unsigned long) tf_L(unsigned long c) { U; return c/3; } EXPORT(PY_LONG_LONG) tf_q(PY_LONG_LONG c) { S; return c/3; } EXPORT(unsigned PY_LONG_LONG) tf_Q(unsigned PY_LONG_LONG c) { U; return c/3; } EXPORT(float) tf_f(float c) { S; return c/3; } EXPORT(double) tf_d(double c) { S; return c/3; } #ifdef MS_WIN32 EXPORT(char) __stdcall s_tf_b(char c) { S; return c/3; } EXPORT(unsigned char) __stdcall s_tf_B(unsigned char c) { U; return c/3; } EXPORT(short) __stdcall s_tf_h(short c) { S; return c/3; } EXPORT(unsigned short) __stdcall s_tf_H(unsigned short c) { U; return c/3; } EXPORT(int) __stdcall s_tf_i(int c) { S; return c/3; } EXPORT(unsigned int) __stdcall s_tf_I(unsigned int c) { U; return c/3; } EXPORT(long) __stdcall s_tf_l(long c) { S; return c/3; } EXPORT(unsigned long) __stdcall s_tf_L(unsigned long c) { U; return c/3; } EXPORT(PY_LONG_LONG) __stdcall s_tf_q(PY_LONG_LONG c) { S; return c/3; } EXPORT(unsigned PY_LONG_LONG) __stdcall s_tf_Q(unsigned PY_LONG_LONG c) { U; return c/3; } EXPORT(float) __stdcall s_tf_f(float c) { S; return c/3; } EXPORT(double) __stdcall s_tf_d(double c) { S; return c/3; } #endif /*******/ EXPORT(char) tf_bb(char x, char c) { S; return c/3; } EXPORT(unsigned char) tf_bB(char x, unsigned char c) { U; return c/3; } EXPORT(short) tf_bh(char x, short c) { S; return c/3; } EXPORT(unsigned short) tf_bH(char x, unsigned short c) { U; return c/3; } EXPORT(int) tf_bi(char x, int c) { S; return c/3; } EXPORT(unsigned int) tf_bI(char x, unsigned int c) { U; return c/3; } EXPORT(long) tf_bl(char x, long c) { S; return c/3; } EXPORT(unsigned long) tf_bL(char x, unsigned long c) { U; return c/3; } EXPORT(PY_LONG_LONG) tf_bq(char x, PY_LONG_LONG c) { S; return c/3; } EXPORT(unsigned PY_LONG_LONG) tf_bQ(char x, unsigned PY_LONG_LONG c) { U; return c/3; } EXPORT(float) tf_bf(char x, float c) { S; return c/3; } EXPORT(double) tf_bd(char x, double c) { S; return c/3; } EXPORT(void) tv_i(int c) { S; return; } #ifdef MS_WIN32 EXPORT(char) __stdcall s_tf_bb(char x, char c) { S; return c/3; } EXPORT(unsigned char) __stdcall s_tf_bB(char x, unsigned char c) { U; return c/3; } EXPORT(short) __stdcall s_tf_bh(char x, short c) { S; return c/3; } EXPORT(unsigned short) __stdcall s_tf_bH(char x, unsigned short c) { U; return c/3; } EXPORT(int) __stdcall s_tf_bi(char x, int c) { S; return c/3; } EXPORT(unsigned int) __stdcall s_tf_bI(char x, unsigned int c) { U; return c/3; } EXPORT(long) __stdcall s_tf_bl(char x, long c) { S; return c/3; } EXPORT(unsigned long) __stdcall s_tf_bL(char x, unsigned long c) { U; return c/3; } EXPORT(PY_LONG_LONG) __stdcall s_tf_bq(char x, PY_LONG_LONG c) { S; return c/3; } EXPORT(unsigned PY_LONG_LONG) __stdcall s_tf_bQ(char x, unsigned PY_LONG_LONG c) { U; return c/3; } EXPORT(float) __stdcall s_tf_bf(char x, float c) { S; return c/3; } EXPORT(double) __stdcall s_tf_bd(char x, double c) { S; return c/3; } EXPORT(void) __stdcall s_tv_i(int c) { S; return; } #endif /********/ #ifndef MS_WIN32 typedef struct { long x; long y; } POINT; typedef struct { long left; long top; long right; long bottom; } RECT; #endif EXPORT(int) PointInRect(RECT *prc, POINT pt) { if (pt.x < prc->left) return 0; if (pt.x > prc->right) return 0; if (pt.y < prc->top) return 0; if (pt.y > prc->bottom) return 0; return 1; } typedef struct { short x; short y; } S2H; EXPORT(S2H) ret_2h_func(S2H inp) { inp.x *= 2; inp.y *= 3; return inp; } typedef struct { int a, b, c, d, e, f, g, h; } S8I; EXPORT(S8I) ret_8i_func(S8I inp) { inp.a *= 2; inp.b *= 3; inp.c *= 4; inp.d *= 5; inp.e *= 6; inp.f *= 7; inp.g *= 8; inp.h *= 9; return inp; } EXPORT(int) GetRectangle(int flag, RECT *prect) { if (flag == 0) return 0; prect->left = (int)flag; prect->top = (int)flag + 1; prect->right = (int)flag + 2; prect->bottom = (int)flag + 3; return 1; } EXPORT(void) TwoOutArgs(int a, int *pi, int b, int *pj) { *pi += a; *pj += b; } #ifdef MS_WIN32 EXPORT(S2H) __stdcall s_ret_2h_func(S2H inp) { return ret_2h_func(inp); } EXPORT(S8I) __stdcall s_ret_8i_func(S8I inp) { return ret_8i_func(inp); } #endif #ifdef MS_WIN32 /* Should port this */ #include <stdlib.h> #include <search.h> EXPORT (HRESULT) KeepObject(IUnknown *punk) { static IUnknown *pobj; if (punk) punk->lpVtbl->AddRef(punk); if (pobj) pobj->lpVtbl->Release(pobj); pobj = punk; return S_OK; } #endif DL_EXPORT(void) init_ctypes_test(void) { Py_InitModule("_ctypes_test", module_methods); } --- NEW FILE: stgdict.c --- #include "Python.h" #include <ffi.h> #ifdef MS_WIN32 #include <windows.h> #endif #include "ctypes.h" /******************************************************************/ /* StdDict - a dictionary subclass, containing additional C accessible fields XXX blabla more */ /* Seems we need this, otherwise we get problems when calling * PyDict_SetItem() (ma_lookup is NULL) */ static int StgDict_init(StgDictObject *self, PyObject *args, PyObject *kwds) { if (PyDict_Type.tp_init((PyObject *)self, args, kwds) < 0) return -1; return 0; } static int StgDict_clear(StgDictObject *self) { Py_CLEAR(self->proto); Py_CLEAR(self->argtypes); Py_CLEAR(self->converters); Py_CLEAR(self->restype); Py_CLEAR(self->checker); return 0; } static void StgDict_dealloc(StgDictObject *self) { StgDict_clear(self); PyMem_Free(self->ffi_type.elements); PyDict_Type.tp_dealloc((PyObject *)self); } int StgDict_clone(StgDictObject *dst, StgDictObject *src) { char *d, *s; int size; StgDict_clear(dst); PyMem_Free(dst->ffi_type.elements); dst->ffi_type.elements = NULL; d = (char *)dst; s = (char *)src; memcpy(d + sizeof(PyDictObject), s + sizeof(PyDictObject), sizeof(StgDictObject) - sizeof(PyDictObject)); Py_XINCREF(dst->proto); Py_XINCREF(dst->argtypes); Py_XINCREF(dst->converters); Py_XINCREF(dst->restype); Py_XINCREF(dst->checker); if (src->ffi_type.elements == NULL) return 0; size = sizeof(ffi_type *) * (src->length + 1); dst->ffi_type.elements = PyMem_Malloc(size); if (dst->ffi_type.elements == NULL) return -1; memcpy(dst->ffi_type.elements, src->ffi_type.elements, size); return 0; } PyTypeObject StgDict_Type = { PyObject_HEAD_INIT(NULL) 0, "StgDict", sizeof(StgDictObject), 0, (destructor)StgDict_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ 0, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)StgDict_init, /* tp_init */ 0, /* tp_alloc */ 0, /* tp_new */ 0, /* tp_free */ }; /* May return NULL, but does not set an exception! */ StgDictObject * PyType_stgdict(PyObject *obj) { PyTypeObject *type; if (!PyType_Check(obj)) return NULL; type = (PyTypeObject *)obj; if (!PyType_HasFeature(type, Py_TPFLAGS_HAVE_CLASS)) return NULL; if (!type->tp_dict || !StgDict_Check(type->tp_dict)) return NULL; return (StgDictObject *)type->tp_dict; } /* May return NULL, but does not set an exception! */ StgDictObject * PyObject_stgdict(PyObject *self) { return PyType_stgdict((PyObject *)self->ob_type); } #if 0 /* work in progress: anonymous structure fields */ int GetFields(PyObject *desc, int *pindex, int *psize, int *poffset, int *palign, int pack); { int i; PyObject *tuples = PyObject_GetAttrString(desc, "_fields_"); if (tuples == NULL) return -1; if (!PyTuple_Check(tuples)) return -1; /* leak */ for (i = 0; i < PyTuple_GET_SIZE(tuples); ++i) { char *fname; PyObject *dummy; CFieldObject *field; PyObject *pair = PyTuple_GET_ITEM(tuples, i); if (!PyArg_ParseTuple(pair, "sO", &fname, &dummy)) return -1; /* leak */ field = PyObject_GetAttrString(desc, fname); Py_DECREF(field); } } #endif /* Retrive the (optional) _pack_ attribute from a type, the _fields_ attribute, and create an StgDictObject. Used for Structure and Union subclasses. */ int StructUnionType_update_stgdict(PyObject *type, PyObject *fields, int isStruct) { StgDictObject *stgdict, *basedict; int len, offset, size, align, i; int union_size, total_align; int field_size = 0; int bitofs; PyObject *isPacked; int pack = 0; int ffi_ofs; int big_endian; /* HACK Alert: I cannot be bothered to fix ctypes.com, so there has to be a way to use the old, broken sematics: _fields_ are not extended but replaced in subclasses. XXX Remove this in ctypes 1.0! */ int use_broken_old_ctypes_semantics; if (fields == NULL) return 0; #ifdef WORDS_BIGENDIAN big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 0 : 1; #else big_endian = PyObject_HasAttrString(type, "_swappedbytes_") ? 1 : 0; #endif use_broken_old_ctypes_semantics = \ PyObject_HasAttrString(type, "_use_broken_old_ctypes_structure_semantics_"); isPacked = PyObject_GetAttrString(type, "_pack_"); if (isPacked) { pack = PyInt_AsLong(isPacked); if (pack < 0 || PyErr_Occurred()) { Py_XDECREF(isPacked); PyErr_SetString(PyExc_ValueError, "_pack_ must be a non-negative integer"); return -1; } Py_DECREF(isPacked); } else PyErr_Clear(); len = PySequence_Length(fields); if (len == -1) { PyErr_SetString(PyExc_TypeError, "'_fields_' must be a sequence of pairs"); return -1; } stgdict = PyType_stgdict(type); if (!stgdict) return -1; if (stgdict->flags & DICTFLAG_FINAL) {/* is final ? */ PyErr_SetString(PyExc_AttributeError, "_fields_ is final"); return -1; } /* XXX This should probably be moved to a point when all this stuff is sucessfully finished. */ stgdict->flags |= DICTFLAG_FINAL; /* set final */ if (stgdict->ffi_type.elements) PyMem_Free(stgdict->ffi_type.elements); basedict = PyType_stgdict((PyObject *)((PyTypeObject *)type)->tp_base); if (basedict && !use_broken_old_ctypes_semantics) { size = offset = basedict->size; align = basedict->align; union_size = 0; total_align = align ? align : 1; stgdict->ffi_type.type = FFI_TYPE_STRUCT; stgdict->ffi_type.elements = PyMem_Malloc(sizeof(ffi_type *) * (basedict->length + len + 1)); memset(stgdict->ffi_type.elements, 0, sizeof(ffi_type *) * (basedict->length + len + 1)); memcpy(stgdict->ffi_type.elements, basedict->ffi_type.elements, sizeof(ffi_type *) * (basedict->length)); ffi_ofs = basedict->length; } else { offset = 0; size = 0; align = 0; union_size = 0; total_align = 1; stgdict->ffi_type.type = FFI_TYPE_STRUCT; stgdict->ffi_type.elements = PyMem_Malloc(sizeof(ffi_type *) * (len + 1)); memset(stgdict->ffi_type.elements, 0, sizeof(ffi_type *) * (len + 1)); ffi_ofs = 0; } #define realdict ((PyObject *)&stgdict->dict) for (i = 0; i < len; ++i) { PyObject *name = NULL, *desc = NULL; PyObject *pair = PySequence_GetItem(fields, i); PyObject *prop; StgDictObject *dict; int bitsize = 0; if (!pair || !PyArg_ParseTuple(pair, "OO|i", &name, &desc, &bitsize)) { PyErr_SetString(PyExc_AttributeError, "'_fields_' must be a sequence of pairs"); Py_XDECREF(pair); return -1; } dict = PyType_stgdict(desc); if (dict == NULL) { Py_DECREF(pair); PyErr_Format(PyExc_TypeError, "second item in _fields_ tuple (index %d) must be a C type", i); return -1; } stgdict->ffi_type.elements[ffi_ofs + i] = &dict->ffi_type; dict->flags |= DICTFLAG_FINAL; /* mark field type final */ if (PyTuple_Size(pair) == 3) { /* bits specified */ switch(dict->ffi_type.type) { case FFI_TYPE_UINT8: case FFI_TYPE_UINT16: case FFI_TYPE_UINT32: case FFI_TYPE_SINT64: case FFI_TYPE_UINT64: break; case FFI_TYPE_SINT8: case FFI_TYPE_SINT16: case FFI_TYPE_SINT32: if (dict->getfunc != getentry("c")->getfunc #ifdef CTYPES_UNICODE && dict->getfunc != getentry("u")->getfunc #endif ) break; /* else fall through */ default: PyErr_Format(PyExc_TypeError, "bit fields not allowed for type %s", ((PyTypeObject *)desc)->tp_name); Py_DECREF(pair); return -1; } if (bitsize <= 0 || bitsize > dict->size * 8) { PyErr_SetString(PyExc_ValueError, "number of bits invalid for bit field"); Py_DECREF(pair); return -1; } } else bitsize = 0; if (isStruct) { prop = CField_FromDesc(desc, i, &field_size, bitsize, &bitofs, &size, &offset, &align, pack, big_endian); } else /* union */ { size = 0; offset = 0; align = 0; prop = CField_FromDesc(desc, i, &field_size, bitsize, &bitofs, &size, &offset, &align, pack, big_endian); union_size = max(size, union_size); } total_align = max(align, total_align); if (!prop) { Py_DECREF(pair); Py_DECREF((PyObject *)stgdict); return -1; } if (-1 == PyDict_SetItem(realdict, name, prop)) { Py_DECREF(prop); Py_DECREF(pair); Py_DECREF((PyObject *)stgdict); return -1; } Py_DECREF(pair); Py_DECREF(prop); } #undef realdict if (!isStruct) size = union_size; /* Adjust the size according to the alignment requirements */ size = ((size + total_align - 1) / total_align) * total_align; stgdict->ffi_type.alignment = total_align; stgdict->ffi_type.size = size; stgdict->size = size; stgdict->align = total_align; stgdict->length = len; /* ADD ffi_ofs? */ return 0; } --- NEW FILE: malloc_closure.c --- #include <Python.h> #include <ffi.h> #ifdef MS_WIN32 #include <windows.h> #else #include <sys/mman.h> #include <unistd.h> # if !defined(MAP_ANONYMOUS) && defined(MAP_ANON) # define MAP_ANONYMOUS MAP_ANON # endif #endif #include "ctypes.h" /* BLOCKSIZE can be adjusted. Larger blocksize will take a larger memory overhead, but allocate less blocks from the system. It may be that some systems have a limit of how many mmap'd blocks can be open. */ #define BLOCKSIZE _pagesize /* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */ /******************************************************************/ typedef union _tagITEM { ffi_closure closure; union _tagITEM *next; } ITEM; static ITEM *free_list; int _pagesize; static void more_core(void) { ITEM *item; int count, i; /* determine the pagesize */ #ifdef MS_WIN32 if (!_pagesize) { SYSTEM_INFO systeminfo; GetSystemInfo(&systeminfo); _pagesize = systeminfo.dwPageSize; } #else if (!_pagesize) { _pagesize = getpagesize(); } #endif /* calculate the number of nodes to allocate */ count = BLOCKSIZE / sizeof(ITEM); /* allocate a memory block */ #ifdef MS_WIN32 item = (ITEM *)VirtualAlloc(NULL, count * sizeof(ITEM), MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (item == NULL) return; #else item = (ITEM *)mmap(NULL, count * sizeof(ITEM), PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (item == (void *)MAP_FAILED) return; #endif #ifdef MALLOC_CLOSURE_DEBUG printf("block at %p allocated (%d bytes), %d ITEMs\n", item, count * sizeof(ITEM), count); #endif /* put them into the free list */ for (i = 0; i < count; ++i) { item->next = free_list; free_list = item; ++item; } } /******************************************************************/ /* put the item back into the free list */ void FreeClosure(void *p) { ITEM *item = (ITEM *)p; item->next = free_list; free_list = item; } /* return one item from the free list, allocating more if needed */ void *MallocClosure(void) { ITEM *item; if (!free_list) more_core(); if (!free_list) return NULL; item = free_list; free_list = item->next; return item; } --- NEW FILE: _ctypes.c --- /* ToDo: Get rid of the checker (and also the converters) field in CFuncPtrObject and StgDictObject, and replace them by slot functions in StgDictObject. think about a buffer-like object (memory? bytes?) Should POINTER(c_char) and POINTER(c_wchar) have a .value property? What about c_char and c_wchar arrays then? Add from_mmap, from_file, from_string metaclass methods. Maybe we can get away with from_file (calls read) and with a from_buffer method? And what about the to_mmap, to_file, to_str(?) methods? They would clobber the namespace, probably. So, functions instead? And we already have memmove... */ [...4514 lines suppressed...] { register Py_UNICODE *u; register int i; u = PyUnicode_AS_UNICODE(unicode); /* In Python, the following line has a one-off error */ for (i = size; i > 0; i--) *w++ = *u++; } #endif return size; } #endif /* Local Variables: compile-command: "cd .. && python setup.py -q build -g && python setup.py -q build install --home ~" End: */ --- NEW FILE: callbacks.c --- #include "Python.h" #include "compile.h" /* required only for 2.3, as it seems */ #include "frameobject.h" #include <ffi.h> #ifdef MS_WIN32 #include <windows.h> #endif #include "ctypes.h" static void PrintError(char *msg, ...) { char buf[512]; PyObject *f = PySys_GetObject("stderr"); va_list marker; va_start(marker, msg); vsnprintf(buf, sizeof(buf), msg, marker); va_end(marker); if (f) PyFile_WriteString(buf, f); PyErr_Print(); } /* after code that pyrex generates */ void _AddTraceback(char *funcname, char *filename, int lineno) { PyObject *py_srcfile = 0; PyObject *py_funcname = 0; PyObject *py_globals = 0; PyObject *empty_tuple = 0; PyObject *empty_string = 0; PyCodeObject *py_code = 0; PyFrameObject *py_frame = 0; py_srcfile = PyString_FromString(filename); if (!py_srcfile) goto bad; py_funcname = PyString_FromString(funcname); if (!py_funcname) goto bad; py_globals = PyDict_New(); if (!py_globals) goto bad; empty_tuple = PyTuple_New(0); if (!empty_tuple) goto bad; empty_string = PyString_FromString(""); if (!empty_string) goto bad; py_code = PyCode_New( 0, /*int argcount,*/ 0, /*int nlocals,*/ 0, /*int stacksize,*/ 0, /*int flags,*/ empty_string, /*PyObject *code,*/ empty_tuple, /*PyObject *consts,*/ empty_tuple, /*PyObject *names,*/ empty_tuple, /*PyObject *varnames,*/ empty_tuple, /*PyObject *freevars,*/ empty_tuple, /*PyObject *cellvars,*/ py_srcfile, /*PyObject *filename,*/ py_funcname, /*PyObject *name,*/ lineno, /*int firstlineno,*/ empty_string /*PyObject *lnotab*/ ); if (!py_code) goto bad; py_frame = PyFrame_New( PyThreadState_Get(), /*PyThreadState *tstate,*/ py_code, /*PyCodeObject *code,*/ py_globals, /*PyObject *globals,*/ 0 /*PyObject *locals*/ ); if (!py_frame) goto bad; py_frame->f_lineno = lineno; PyTraceBack_Here(py_frame); bad: Py_XDECREF(py_globals); Py_XDECREF(py_srcfile); Py_XDECREF(py_funcname); Py_XDECREF(empty_tuple); Py_XDECREF(empty_string); Py_XDECREF(py_code); Py_XDECREF(py_frame); } #ifdef MS_WIN32 /* * We must call AddRef() on non-NULL COM pointers we receive as arguments * to callback functions - these functions are COM method implementations. * The Python instances we create have a __del__ method which calls Release(). * * The presence of a class attribute named '_needs_com_addref_' triggers this * behaviour. It would also be possible to call the AddRef() Python method, * after checking for PyObject_IsTrue(), but this would probably be somewhat * slower. */ static void TryAddRef(StgDictObject *dict, CDataObject *obj) { IUnknown *punk; if (NULL == PyDict_GetItemString((PyObject *)dict, "_needs_com_addref_")) return; punk = *(IUnknown **)obj->b_ptr; if (punk) punk->lpVtbl->AddRef(punk); return; } #endif /****************************************************************************** * * Call the python object with all arguments * */ static void _CallPythonObject(void *mem, ffi_type *restype, SETFUNC setfunc, PyObject *callable, PyObject *converters, void **pArgs) { int i; PyObject *result; PyObject *arglist = NULL; int nArgs; PyGILState_STATE state = PyGILState_Ensure(); nArgs = PySequence_Length(converters); /* Hm. What to return in case of error? For COM, 0xFFFFFFFF seems better than 0. */ if (nArgs < 0) { PrintError("BUG: PySequence_Length"); goto Done; } arglist = PyTuple_New(nArgs); if (!arglist) { PrintError("PyTuple_New()"); goto Done; } for (i = 0; i < nArgs; ++i) { /* Note: new reference! */ PyObject *cnv = PySequence_GetItem(converters, i); StgDictObject *dict; if (cnv) dict = PyType_stgdict(cnv); else { PrintError("Getting argument converter %d\n", i); goto Done; } if (dict && dict->getfunc && !IsSimpleSubType(cnv)) { PyObject *v = dict->getfunc(*pArgs, dict->size); if (!v) { PrintError("create argument %d:\n", i); Py_DECREF(cnv); goto Done; } PyTuple_SET_ITEM(arglist, i, v); /* XXX XXX XX We have the problem that c_byte or c_short have dict->size of 1 resp. 4, but these parameters are pushed as sizeof(int) bytes. BTW, the same problem occurrs when they are pushed as parameters */ } else if (dict) { /* Hm, shouldn't we use CData_AtAddress() or something like that instead? */ CDataObject *obj = (CDataObject *)PyObject_CallFunctionObjArgs(cnv, NULL); if (!obj) { PrintError("create argument %d:\n", i); Py_DECREF(cnv); goto Done; } if (!CDataObject_Check(obj)) { Py_DECREF(obj); Py_DECREF(cnv); PrintError("unexpected result of create argument %d:\n", i); goto Done; } memcpy(obj->b_ptr, *pArgs, dict->size); PyTuple_SET_ITEM(arglist, i, (PyObject *)obj); #ifdef MS_WIN32 TryAddRef(dict, obj); #endif } else { PyErr_SetString(PyExc_TypeError, "cannot build parameter"); PrintError("Parsing argument %d\n", i); Py_DECREF(cnv); goto Done; } Py_DECREF(cnv); /* XXX error handling! */ pArgs++; } #define CHECK(what, x) \ if (x == NULL) _AddTraceback(what, __FILE__, __LINE__ - 1), PyErr_Print() result = PyObject_CallObject(callable, arglist); CHECK("'calling callback function'", result); if ((restype != &ffi_type_void) && result && result != Py_None) { /* XXX What is returned for Py_None ? */ /* another big endian hack */ union { char c; short s; int i; long l; } r; PyObject *keep; assert(setfunc); switch (restype->size) { case 1: keep = setfunc(&r, result, 0); CHECK("'converting callback result'", keep); *(ffi_arg *)mem = r.c; break; case SIZEOF_SHORT: keep = setfunc(&r, result, 0); CHECK("'converting callback result'", keep); *(ffi_arg *)mem = r.s; break; case SIZEOF_INT: keep = setfunc(&r, result, 0); CHECK("'converting callback result'", keep); *(ffi_arg *)mem = r.i; break; #if (SIZEOF_LONG != SIZEOF_INT) case SIZEOF_LONG: keep = setfunc(&r, result, 0); CHECK("'converting callback result'", keep); *(ffi_arg *)mem = r.l; break; #endif default: keep = setfunc(mem, result, 0); CHECK("'converting callback result'", keep); break; } /* keep is an object we have to keep alive so that the result stays valid. If there is no such object, the setfunc will have returned Py_None. If there is such an object, we have no choice than to keep it alive forever - but a refcount and/or memory leak will be the result. EXCEPT when restype is py_object - Python itself knows how to manage the refcount of these objects. */ if (keep == NULL) /* Could not convert callback result. */ PyErr_WriteUnraisable(Py_None); else if (keep == Py_None) /* Nothing to keep */ Py_DECREF(keep); else if (setfunc != getentry("O")->setfunc) { if (-1 == PyErr_Warn(PyExc_RuntimeWarning, "memory leak in callback function.")) PyErr_WriteUnraisable(Py_None); } } Py_XDECREF(result); Done: Py_XDECREF(arglist); PyGILState_Release(state); } typedef struct { ffi_closure *pcl; /* the C callable */ ffi_cif cif; PyObject *converters; PyObject *callable; SETFUNC setfunc; ffi_type *restype; ffi_type *atypes[0]; } ffi_info; static void closure_fcn(ffi_cif *cif, void *resp, void **args, void *userdata) { ffi_info *p = userdata; _CallPythonObject(resp, p->restype, p->setfunc, p->callable, p->converters, args); } void FreeCallback(THUNK thunk) { FreeClosure(((ffi_info *)thunk)->pcl); PyMem_Free(thunk); } THUNK AllocFunctionCallback(PyObject *callable, PyObject *converters, PyObject *restype, int is_cdecl) { int result; ffi_info *p; int nArgs, i; ffi_abi cc; nArgs = PySequence_Size(converters); p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs + 1)); if (p == NULL) { PyErr_NoMemory(); return NULL; } p->pcl = MallocClosure(); if (p->pcl == NULL) { PyMem_Free(p); PyErr_NoMemory(); return NULL; } for (i = 0; i < nArgs; ++i) { PyObject *cnv = PySequence_GetItem(converters, i); p->atypes[i] = GetType(cnv); Py_DECREF(cnv); } p->atypes[i] = NULL; if (restype == Py_None) { p->setfunc = NULL; p->restype = &ffi_type_void; } else { StgDictObject *dict = PyType_stgdict(restype); if (dict == NULL) { PyMem_Free(p); return NULL; } p->setfunc = dict->setfunc; p->restype = &dict->ffi_type; } cc = FFI_DEFAULT_ABI; #if defined(MS_WIN32) && !defined(_WIN32_WCE) if (is_cdecl == 0) cc = FFI_STDCALL; #endif result = ffi_prep_cif(&p->cif, cc, nArgs, GetType(restype), &p->atypes[0]); if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_cif failed with %d", result); PyMem_Free(p); return NULL; } result = ffi_prep_closure(p->pcl, &p->cif, closure_fcn, p); if (result != FFI_OK) { PyErr_Format(PyExc_RuntimeError, "ffi_prep_closure failed with %d", result); PyMem_Free(p); return NULL; } p->converters = converters; p->callable = callable; return (THUNK)p; } /**************************************************************************** * * callback objects: initialization */ void init_callbacks_in_module(PyObject *m) { if (PyType_Ready((PyTypeObject *)&PyType_Type) < 0) return; } #ifdef MS_WIN32 static void LoadPython(void) { if (!Py_IsInitialized()) { PyEval_InitThreads(); Py_Initialize(); } } /******************************************************************/ long Call_GetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { PyObject *mod, *func, *result; long retval; static PyObject *context; if (context == NULL) context = PyString_FromString("_ctypes.DllGetClassObject"); mod = PyImport_ImportModule("ctypes"); if (!mod) { PyErr_WriteUnraisable(context ? context : Py_None); /* There has been a warning before about this already */ return E_FAIL; } func = PyObject_GetAttrString(mod, "DllGetClassObject"); Py_DECREF(mod); if (!func) { PyErr_WriteUnraisable(context ? context : Py_None); return E_FAIL; } result = PyObject_CallFunction(func, "iii", rclsid, riid, ppv); Py_DECREF(func); if (!result) { PyErr_WriteUnraisable(context ? context : Py_None); return E_FAIL; } retval = PyInt_AsLong(result); if (PyErr_Occurred()) { PyErr_WriteUnraisable(context ? context : Py_None); retval = E_FAIL; } Py_DECREF(result); return retval; } STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { long result; PyGILState_STATE state; LoadPython(); state = PyGILState_Ensure(); result = Call_GetClassObject(rclsid, riid, ppv); PyGILState_Release(state); return result; } long Call_CanUnloadNow(void) { PyObject *mod, *func, *result; long retval; static PyObject *context; if (context == NULL) context = PyString_FromString("_ctypes.DllCanUnloadNow"); mod = PyImport_ImportModule("ctypes"); if (!mod) { /* OutputDebugString("Could not import ctypes"); */ /* We assume that this error can only occur when shutting down, so we silently ignore it */ PyErr_Clear(); return E_FAIL; } /* Other errors cannot be raised, but are printed to stderr */ func = PyObject_GetAttrString(mod, "DllCanUnloadNow"); Py_DECREF(mod); if (!func) { PyErr_WriteUnraisable(context ? context : Py_None); return E_FAIL; } result = PyObject_CallFunction(func, NULL); Py_DECREF(func); if (!result) { PyErr_WriteUnraisable(context ? context : Py_None); return E_FAIL; } retval = PyInt_AsLong(result); if (PyErr_Occurred()) { PyErr_WriteUnraisable(context ? context : Py_None); retval = E_FAIL; } Py_DECREF(result); return retval; } /* DllRegisterServer and DllUnregisterServer still missing */ STDAPI DllCanUnloadNow(void) { long result; PyGILState_STATE state = PyGILState_Ensure(); result = Call_CanUnloadNow(); PyGILState_Release(state); return result; } #ifndef Py_NO_ENABLE_SHARED BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvRes) { switch(fdwReason) { case DLL_PROCESS_ATTACH: DisableThreadLibraryCalls(hinstDLL); break; } return TRUE; } #endif #endif /* Local Variables: compile-command: "cd .. && python setup.py -q build_ext" End: */ |
From: Thomas H. <th...@us...> - 2006-03-03 20:17:11
|
Update of /cvsroot/ctypes/ctypes/source/darwin In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv9989 Added Files: dlfcn_simple.c dlfcn.h README.Thomas README LICENSE Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: README --- dlcompat for Darwin ========================= This is dlcompat, a small library that emulates the dlopen() interface on top of Darwin's dyld API. dlcompat allows loading a ".dylib" library (as long as the RTLD_LOCAL flag isn't passed to dlopen()). It can be configured to yield a warning when trying to close it (dynamic libraries cannot currently be unloaded). It automatically searches for modules in several directories when no absolute path is specified and the module is not found in the current directory. The paths searched are those specified in the environment variables LD_LIBRARY_PATH and DYLD_LIBRARY_PATH plus /lib, /usr/local/lib and /usr/lib or the path specified in the environment variable DYLD_FALLBACK_LIBRARY_PATH. In the default install the behavior of dlsym is to automatically prepend an underscore to passed in symbol names, this allows easier porting of applications which were written specifically for ELF based lifeforms. Installation -------------- Type: ./configure make sudo make install This will compile the source file, generate both a static and shared library called libdl and install it into /usr/local/lib. The header file dlfcn.h will be installed in /usr/local/include. If you want to place the files somewhere else, run make clean ./configure --prefix=<prefix> make sudo make install where <prefix> is the hierarchy you want to install into, e.g. /usr for /usr/lib and /usr/include (_NOT_ recommended!). To enable debugging output (useful for me), run make clean ./configure --enable-debug make sudo make install If you want old dlcompat style behavior of not prepending the underscore on calls to dlsym then type: make clean ./configure --enable-fink make sudo make install Usage ------- Software that uses GNU autoconf will likely check for a library called libdl, that's why I named it that way. For software that doesn't find the library on its own, you must add a '-ldl' to the appropriate Makefile (or environment) variable, usually LIBS. If you installed dlcompat into a directory other than /usr/local/lib, you must tell the compiler where to find it. Add '-L<prefix>/lib' to LDFLAGS (or CFLAGS) and '-I<prefix>/include' to CPPFLAGS (or CFLAGS). Notes ----- If you are writing new software and plan to have Mac OX X compatibility you should look at the dyld api's in /usr/include/mach-o/dyld.h, rather than using dlcompat, using the native api's is the supported method of loading dynamically on Mac OS X, if you want an small example, look at dlfcn_simple.c, which should help get you started. Also note that the functions in dlcompat are not thread safe, and while it is not POSIX spec compliant, it is about as close to compliance as it is going to get though. You can always get the latest version from opendarwin cvs: cvs -d :pserver:ano...@an...:/cvs/od login cvs -z3 -d :pserver:ano...@an...:/cvs/od \ co -d dlcompat proj/dlcompat It is hoped that this library will be useful, and as bug free as possible, if you find any bugs please let us know about them so they can be fixed. Please send bug reports to Peter O'Gorman <og...@us...> Thanks. --- NEW FILE: dlfcn_simple.c --- /* Copyright (c) 2002 Peter O'Gorman <og...@us...> 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 AUTHORS OR COPYRIGHT HOLDERS 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. */ /* Just to prove that it isn't that hard to add Mac calls to your code :) This works with pretty much everything, including kde3 xemacs and the gimp, I'd guess that it'd work in at least 95% of cases, use this as your starting point, rather than the mess that is dlfcn.c, assuming that your code does not require ref counting or symbol lookups in dependent libraries */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <stdarg.h> #include <limits.h> #include <mach-o/dyld.h> #include <AvailabilityMacros.h> #include "dlfcn.h" #ifdef CTYPES_DARWIN_DLFCN #define ERR_STR_LEN 256 #ifndef MAC_OS_X_VERSION_10_3 #define MAC_OS_X_VERSION_10_3 1030 #endif #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 #define DARWIN_HAS_DLOPEN extern void * dlopen(const char *path, int mode) __attribute__((weak_import)); extern void * dlsym(void * handle, const char *symbol) __attribute__((weak_import)); extern const char * dlerror(void) __attribute__((weak_import)); extern int dlclose(void * handle) __attribute__((weak_import)); extern int dladdr(const void *, Dl_info *) __attribute__((weak_import)); #endif /* MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_3 */ #ifndef DARWIN_HAS_DLOPEN #define dlopen darwin_dlopen #define dlsym darwin_dlsym #define dlerror darwin_dlerror #define dlclose darwin_dlclose #define dladdr darwin_dladdr #endif void * (*ctypes_dlopen)(const char *path, int mode); void * (*ctypes_dlsym)(void * handle, const char *symbol); const char * (*ctypes_dlerror)(void); int (*ctypes_dlclose)(void * handle); int (*ctypes_dladdr)(const void *, Dl_info *); #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 /* Mac OS X 10.3+ has dlopen, so strip all this dead code to avoid warnings */ static void *dlsymIntern(void *handle, const char *symbol); static const char *error(int setget, const char *str, ...); /* Set and get the error string for use by dlerror */ static const char *error(int setget, const char *str, ...) { static char errstr[ERR_STR_LEN]; static int err_filled = 0; const char *retval; va_list arg; if (setget == 0) { va_start(arg, str); strncpy(errstr, "dlcompat: ", ERR_STR_LEN); vsnprintf(errstr + 10, ERR_STR_LEN - 10, str, arg); va_end(arg); err_filled = 1; retval = NULL; } else { if (!err_filled) retval = NULL; else retval = errstr; err_filled = 0; } return retval; } /* darwin_dlopen */ static void *darwin_dlopen(const char *path, int mode) { void *module = 0; NSObjectFileImage ofi = 0; NSObjectFileImageReturnCode ofirc; /* If we got no path, the app wants the global namespace, use -1 as the marker in this case */ if (!path) return (void *)-1; /* Create the object file image, works for things linked with the -bundle arg to ld */ ofirc = NSCreateObjectFileImageFromFile(path, &ofi); switch (ofirc) { case NSObjectFileImageSuccess: /* It was okay, so use NSLinkModule to link in the image */ module = NSLinkModule(ofi, path, NSLINKMODULE_OPTION_RETURN_ON_ERROR | (mode & RTLD_GLOBAL) ? 0 : NSLINKMODULE_OPTION_PRIVATE | (mode & RTLD_LAZY) ? 0 : NSLINKMODULE_OPTION_BINDNOW); NSDestroyObjectFileImage(ofi); break; case NSObjectFileImageInappropriateFile: /* It may have been a dynamic library rather than a bundle, try to load it */ module = (void *)NSAddImage(path, NSADDIMAGE_OPTION_RETURN_ON_ERROR); break; default: /* God knows what we got */ error(0, "Can not open \"%s\"", path); return 0; } if (!module) error(0, "Can not open \"%s\"", path); return module; } /* dlsymIntern is used by dlsym to find the symbol */ static void *dlsymIntern(void *handle, const char *symbol) { NSSymbol nssym = 0; /* If the handle is -1, if is the app global context */ if (handle == (void *)-1) { /* Global context, use NSLookupAndBindSymbol */ if (NSIsSymbolNameDefined(symbol)) { nssym = NSLookupAndBindSymbol(symbol); } } /* Now see if the handle is a struch mach_header* or not, use NSLookupSymbol in image for libraries, and NSLookupSymbolInModule for bundles */ else { /* Check for both possible magic numbers depending on x86/ppc byte order */ if ((((struct mach_header *)handle)->magic == MH_MAGIC) || (((struct mach_header *)handle)->magic == MH_CIGAM)) { if (NSIsSymbolNameDefinedInImage((struct mach_header *)handle, symbol)) { nssym = NSLookupSymbolInImage((struct mach_header *)handle, symbol, NSLOOKUPSYMBOLINIMAGE_OPTION_BIND | NSLOOKUPSYMBOLINIMAGE_OPTION_RETURN_ON_ERROR); } } else { nssym = NSLookupSymbolInModule(handle, symbol); } } if (!nssym) { error(0, "Symbol \"%s\" Not found", symbol); return NULL; } return NSAddressOfSymbol(nssym); } static const char *darwin_dlerror(void) { return error(1, (char *)NULL); } static int darwin_dlclose(void *handle) { if ((((struct mach_header *)handle)->magic == MH_MAGIC) || (((struct mach_header *)handle)->magic == MH_CIGAM)) { error(0, "Can't remove dynamic libraries on darwin"); return 0; } if (!NSUnLinkModule(handle, 0)) { error(0, "unable to unlink module %s", NSNameOfModule(handle)); return 1; } return 0; } /* dlsym, prepend the underscore and call dlsymIntern */ static void *darwin_dlsym(void *handle, const char *symbol) { static char undersym[257]; /* Saves calls to malloc(3) */ int sym_len = strlen(symbol); void *value = NULL; char *malloc_sym = NULL; if (sym_len < 256) { snprintf(undersym, 256, "_%s", symbol); value = dlsymIntern(handle, undersym); } else { malloc_sym = malloc(sym_len + 2); if (malloc_sym) { sprintf(malloc_sym, "_%s", symbol); value = dlsymIntern(handle, malloc_sym); free(malloc_sym); } else { error(0, "Unable to allocate memory"); } } return value; } static int darwin_dladdr(const void *handle, Dl_info *info) { return 0; } #endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 */ #if __GNUC__ < 4 #pragma CALL_ON_LOAD ctypes_dlfcn_init #else static void __attribute__ ((constructor)) ctypes_dlfcn_init(void); static #endif void ctypes_dlfcn_init(void) { if (dlopen != NULL) { ctypes_dlsym = dlsym; ctypes_dlopen = dlopen; ctypes_dlerror = dlerror; ctypes_dlclose = dlclose; ctypes_dladdr = dladdr; } else { #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 ctypes_dlsym = darwin_dlsym; ctypes_dlopen = darwin_dlopen; ctypes_dlerror = darwin_dlerror; ctypes_dlclose = darwin_dlclose; ctypes_dladdr = darwin_dladdr; #endif /* MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_3 */ } } #endif /* CTYPES_DARWIN_DLFCN */ --- NEW FILE: dlfcn.h --- /* Copyright (c) 2002 Jorge Acereda <jac...@us...> & Peter O'Gorman <og...@us...> Portions may be copyright others, see the AUTHORS file included with this distribution. Maintained by Peter O'Gorman <og...@us...> Bug Reports and other queries should go to <og...@us...> 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 AUTHORS OR COPYRIGHT HOLDERS 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. */ #ifndef _DLFCN_H_ #define _DLFCN_H_ #include <AvailabilityMacros.h> #ifdef __cplusplus extern "C" { #endif /* * Structure filled in by dladdr(). */ typedef struct dl_info { const char *dli_fname; /* Pathname of shared object */ void *dli_fbase; /* Base address of shared object */ const char *dli_sname; /* Name of nearest symbol */ void *dli_saddr; /* Address of nearest symbol */ } Dl_info; #if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_2 #warning CTYPES_DARWIN_DLFCN #define CTYPES_DARWIN_DLFCN extern void * (*ctypes_dlopen)(const char *path, int mode); extern void * (*ctypes_dlsym)(void * handle, const char *symbol); extern const char * (*ctypes_dlerror)(void); extern int (*ctypes_dlclose)(void * handle); extern int (*ctypes_dladdr)(const void *, Dl_info *); #else extern void * dlopen(const char *path, int mode); extern void * dlsym(void * handle, const char *symbol); extern const char * dlerror(void); extern int dlclose(void * handle); extern int dladdr(const void *, Dl_info *); #endif #define RTLD_LAZY 0x1 #define RTLD_NOW 0x2 #define RTLD_LOCAL 0x4 #define RTLD_GLOBAL 0x8 #define RTLD_NOLOAD 0x10 #define RTLD_NODELETE 0x80 /* These are from the Mac OS X 10.4 headers */ #define RTLD_NEXT ((void *) -1) /* Search subsequent objects. */ #define RTLD_DEFAULT ((void *) -2) /* Use default search algorithm. */ #ifdef __cplusplus } #endif #endif /* _DLFCN_H_ */ --- NEW FILE: README.Thomas --- The files in this directory are taken from http://www.opendarwin.org/cgi-bin/cvsweb.cgi/~checkout~/proj/dlcompat/ The LICENSE in this directory applies to these files. Thomas Heller, Jan 2003 These files have been modified so they fall back to the system dlfcn calls if available in libSystem. Bob Ippolito, Feb 2006 --- NEW FILE: LICENSE --- Copyright (c) 2002 Jorge Acereda <jac...@us...> & Peter O'Gorman <og...@us...> Portions may be copyright others, see the AUTHORS file included with this distribution. Maintained by Peter O'Gorman <og...@us...> Bug Reports and other queries should go to <og...@us...> 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 AUTHORS OR COPYRIGHT HOLDERS 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. |
Update of /cvsroot/ctypes/ctypes/ctypes/test In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5920 Added Files: test_win32.py test_values.py test_unicode.py test_structures.py test_struct_fields.py test_strings.py test_stringptr.py test_slicing.py test_sizes.py test_simplesubclasses.py test_returnfuncptrs.py test_repr.py test_refcounts.py test_random_things.py test_python_api.py test_prototypes.py test_posix.py test_pointers.py test_parameters.py test_numbers.py test_memfunctions.py test_macholib.py test_loading.py test_libc.py test_leaks.py test_keeprefs.py test_internals.py test_integers.py test_init.py test_incomplete.py test_functions.py test_funcptr.py test_errcheck.py test_checkretval.py test_cfuncs.py test_cast.py test_callbacks.py test_byteswap.py test_buffers.py test_bitfields.py test_arrays.py test_array_in_pointer.py runtests.py __init__.py .cvsignore Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: test_functions.py --- """ Here is probably the place to write the docs, since the test-cases show how the type behave. Later... """ from ctypes import * import sys, unittest try: WINFUNCTYPE except NameError: # fake to enable this test on Linux WINFUNCTYPE = CFUNCTYPE import _ctypes_test dll = cdll.load(_ctypes_test.__file__) if sys.platform == "win32": windll = windll.load(_ctypes_test.__file__) class FunctionTestCase(unittest.TestCase): def test_mro(self): # in Python 2.3, this raises TypeError: MRO conflict among bases classes, # in Python 2.2 it works. # # But in early versions of _ctypes.c, the result of tp_new # wasn't checked, and it even crashed Python. # Found by Greg Chapman. try: class X(object, Array): _length_ = 5 _type_ = "i" except TypeError: pass from _ctypes import _Pointer try: class X(object, _Pointer): pass except TypeError: pass from _ctypes import _SimpleCData try: class X(object, _SimpleCData): _type_ = "i" except TypeError: pass try: class X(object, Structure): _fields_ = [] except TypeError: pass def test_wchar_parm(self): try: c_wchar except NameError: return f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_wchar, c_int, c_long, c_float, c_double] result = f(1, u"x", 3, 4, 5.0, 6.0) self.failUnlessEqual(result, 139) self.failUnlessEqual(type(result), int) def test_wchar_result(self): try: c_wchar except NameError: return f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] f.restype = c_wchar result = f(0, 0, 0, 0, 0, 0) self.failUnlessEqual(result, u'\x00') def test_voidresult(self): f = dll._testfunc_v f.restype = None f.argtypes = [c_int, c_int, POINTER(c_int)] result = c_int() self.failUnlessEqual(None, f(1, 2, byref(result))) self.failUnlessEqual(result.value, 3) def test_intresult(self): f = dll._testfunc_i_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] result = f(1, 2, 3, 4, 5.0, 6.0) self.failUnlessEqual(result, 21) self.failUnlessEqual(type(result), int) result = f(-1, -2, -3, -4, -5.0, -6.0) self.failUnlessEqual(result, -21) self.failUnlessEqual(type(result), int) # If we declare the function to return a short, # is the high part split off? f.restype = c_short result = f(1, 2, 3, 4, 5.0, 6.0) self.failUnlessEqual(result, 21) self.failUnlessEqual(type(result), int) result = f(1, 2, 3, 0x10004, 5.0, 6.0) self.failUnlessEqual(result, 21) self.failUnlessEqual(type(result), int) # You cannot assing character format codes as restype any longer self.assertRaises(TypeError, setattr, f, "restype", "i") def test_floatresult(self): f = dll._testfunc_f_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] f.restype = c_float result = f(1, 2, 3, 4, 5.0, 6.0) self.failUnlessEqual(result, 21) self.failUnlessEqual(type(result), float) result = f(-1, -2, -3, -4, -5.0, -6.0) self.failUnlessEqual(result, -21) self.failUnlessEqual(type(result), float) def test_doubleresult(self): f = dll._testfunc_d_bhilfd f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] f.restype = c_double result = f(1, 2, 3, 4, 5.0, 6.0) self.failUnlessEqual(result, 21) self.failUnlessEqual(type(result), float) result = f(-1, -2, -3, -4, -5.0, -6.0) self.failUnlessEqual(result, -21) self.failUnlessEqual(type(result), float) def test_longlongresult(self): try: c_longlong except NameError: return f = dll._testfunc_q_bhilfd f.restype = c_longlong f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double] result = f(1, 2, 3, 4, 5.0, 6.0) self.failUnlessEqual(result, 21) f = dll._testfunc_q_bhilfdq f.restype = c_longlong f.argtypes = [c_byte, c_short, c_int, c_long, c_float, c_double, c_longlong] result = f(1, 2, 3, 4, 5.0, 6.0, 21) self.failUnlessEqual(result, 42) def test_stringresult(self): f = dll._testfunc_p_p f.argtypes = None f.restype = c_char_p result = f("123") self.failUnlessEqual(result, "123") result = f(None) self.failUnlessEqual(result, None) def test_pointers(self): f = dll._testfunc_p_p f.restype = POINTER(c_int) f.argtypes = [POINTER(c_int)] # This only works if the value c_int(42) passed to the # function is still alive while the pointer (the result) is # used. v = c_int(42) self.failUnlessEqual(pointer(v).contents.value, 42) result = f(pointer(v)) self.failUnlessEqual(type(result), POINTER(c_int)) self.failUnlessEqual(result.contents.value, 42) # This on works... result = f(pointer(v)) self.failUnlessEqual(result.contents.value, v.value) p = pointer(c_int(99)) result = f(p) self.failUnlessEqual(result.contents.value, 99) arg = byref(v) result = f(arg) self.failIfEqual(result.contents, v.value) self.assertRaises(ArgumentError, f, byref(c_short(22))) # It is dangerous, however, because you don't control the lifetime # of the pointer: result = f(byref(c_int(99))) self.failIfEqual(result.contents, 99) def test_errors(self): f = dll._testfunc_p_p f.restype = c_int class X(Structure): _fields_ = [("y", c_int)] self.assertRaises(TypeError, f, X()) #cannot convert parameter ################################################################ def test_shorts(self): f = dll._testfunc_callback_i_if args = [] expected = [262144, 131072, 65536, 32768, 16384, 8192, 4096, 2048, 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1] def callback(v): args.append(v) CallBack = CFUNCTYPE(c_int, c_int) cb = CallBack(callback) f(2**18, cb) self.failUnlessEqual(args, expected) ################################################################ def test_callbacks(self): f = dll._testfunc_callback_i_if f.restype = c_int MyCallback = CFUNCTYPE(c_int, c_int) def callback(value): #print "called back with", value return value cb = MyCallback(callback) result = f(-10, cb) self.failUnlessEqual(result, -18) # test with prototype f.argtypes = [c_int, MyCallback] cb = MyCallback(callback) result = f(-10, cb) self.failUnlessEqual(result, -18) AnotherCallback = WINFUNCTYPE(c_int, c_int, c_int, c_int, c_int) # check that the prototype works: we call f with wrong # argument types cb = AnotherCallback(callback) self.assertRaises(ArgumentError, f, -10, cb) def test_callbacks_2(self): # Can also use simple datatypes as argument type specifiers # for the callback function. # In this case the call receives an instance of that type f = dll._testfunc_callback_i_if f.restype = c_int MyCallback = CFUNCTYPE(c_int, c_int) f.argtypes = [c_int, MyCallback] def callback(value): #print "called back with", value self.failUnlessEqual(type(value), int) return value cb = MyCallback(callback) result = f(-10, cb) self.failUnlessEqual(result, -18) def test_longlong_callbacks(self): f = dll._testfunc_callback_q_qf f.restype = c_longlong MyCallback = CFUNCTYPE(c_longlong, c_longlong) f.argtypes = [c_longlong, MyCallback] def callback(value): self.failUnless(isinstance(value, (int, long))) return value & 0x7FFFFFFF cb = MyCallback(callback) self.failUnlessEqual(13577625587, f(1000000000000, cb)) def test_errors(self): self.assertRaises(AttributeError, getattr, dll, "_xxx_yyy") self.assertRaises(ValueError, c_int.in_dll, dll, "_xxx_yyy") def test_byval(self): class POINT(Structure): _fields_ = [("x", c_int), ("y", c_int)] # without prototype ptin = POINT(1, 2) ptout = POINT() # EXPORT int _testfunc_byval(point in, point *pout) result = dll._testfunc_byval(ptin, byref(ptout)) got = result, ptout.x, ptout.y expected = 3, 1, 2 self.failUnlessEqual(got, expected) # with prototype ptin = POINT(101, 102) ptout = POINT() dll._testfunc_byval.argtypes = (POINT, POINTER(POINT)) dll._testfunc_byval.restype = c_int result = dll._testfunc_byval(ptin, byref(ptout)) got = result, ptout.x, ptout.y expected = 203, 101, 102 self.failUnlessEqual(got, expected) def test_struct_return_2H(self): class S2H(Structure): _fields_ = [("x", c_short), ("y", c_short)] dll.ret_2h_func.restype = S2H dll.ret_2h_func.argtypes = [S2H] inp = S2H(99, 88) s2h = dll.ret_2h_func(inp) self.failUnlessEqual((s2h.x, s2h.y), (99*2, 88*3)) if sys.platform == "win32": def test_struct_return_2H_stdcall(self): class S2H(Structure): _fields_ = [("x", c_short), ("y", c_short)] windll.s_ret_2h_func.restype = S2H windll.s_ret_2h_func.argtypes = [S2H] s2h = windll.s_ret_2h_func(S2H(99, 88)) self.failUnlessEqual((s2h.x, s2h.y), (99*2, 88*3)) def test_struct_return_8H(self): class S8I(Structure): _fields_ = [("a", c_int), ("b", c_int), ("c", c_int), ("d", c_int), ("e", c_int), ("f", c_int), ("g", c_int), ("h", c_int)] dll.ret_8i_func.restype = S8I dll.ret_8i_func.argtypes = [S8I] inp = S8I(9, 8, 7, 6, 5, 4, 3, 2) s8i = dll.ret_8i_func(inp) self.failUnlessEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h), (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) if sys.platform == "win32": def test_struct_return_8H_stdcall(self): class S8I(Structure): _fields_ = [("a", c_int), ("b", c_int), ("c", c_int), ("d", c_int), ("e", c_int), ("f", c_int), ("g", c_int), ("h", c_int)] windll.s_ret_8i_func.restype = S8I windll.s_ret_8i_func.argtypes = [S8I] inp = S8I(9, 8, 7, 6, 5, 4, 3, 2) s8i = windll.s_ret_8i_func(inp) self.failUnlessEqual((s8i.a, s8i.b, s8i.c, s8i.d, s8i.e, s8i.f, s8i.g, s8i.h), (9*2, 8*3, 7*4, 6*5, 5*6, 4*7, 3*8, 2*9)) if __name__ == '__main__': unittest.main() --- NEW FILE: test_values.py --- """ A testcase which accesses *values* in a dll. """ import unittest from ctypes import * import _ctypes_test class ValuesTestCase(unittest.TestCase): def test_an_integer(self): ctdll = cdll.load(_ctypes_test.__file__) an_integer = c_int.in_dll(ctdll, "an_integer") x = an_integer.value self.failUnlessEqual(x, ctdll.get_an_integer()) an_integer.value *= 2 self.failUnlessEqual(x*2, ctdll.get_an_integer()) def test_undefined(self): ctdll = cdll.load(_ctypes_test.__file__) self.assertRaises(ValueError, c_int.in_dll, ctdll, "Undefined_Symbol") class Win_ValuesTestCase(unittest.TestCase): """This test only works when python itself is a dll/shared library""" def test_optimizeflag(self): # This test accesses the Py_OptimizeFlag intger, which is # exported by the Python dll. # It's value is set depending on the -O and -OO flags: # if not given, it is 0 and __debug__ is 1. # If -O is given, the flag is 1, for -OO it is 2. # docstrings are also removed in the latter case. opt = c_int.in_dll(pydll, "Py_OptimizeFlag").value if __debug__: self.failUnlessEqual(opt, 0) elif ValuesTestCase.__doc__ is not None: self.failUnlessEqual(opt, 1) else: self.failUnlessEqual(opt, 2) def test_frozentable(self): # Python exports a PyImport_FrozenModules symbol. This is a # pointer to an array of struct _frozen entries. The end of the # array is marked by an entry containing a NULL name and zero # size. # In standard Python, this table contains a __hello__ # module, and a __phello__ package containing a spam # module. class struct_frozen(Structure): _fields_ = [("name", c_char_p), ("code", POINTER(c_ubyte)), ("size", c_int)] FrozenTable = POINTER(struct_frozen) ft = FrozenTable.in_dll(pydll, "PyImport_FrozenModules") # ft is a pointer to the struct_frozen entries: items = [] for entry in ft: # This is dangerous. We *can* iterate over a pointer, but # the loop will not terminate (maybe with an access # violation;-) because the pointer instance has no size. if entry.name is None: break items.append((entry.name, entry.size)) import sys if sys.version_info[:2] >= (2, 3): expected = [("__hello__", 104), ("__phello__", -104), ("__phello__.spam", 104)] else: expected = [("__hello__", 100), ("__phello__", -100), ("__phello__.spam", 100)] self.failUnlessEqual(items, expected) from ctypes import _pointer_type_cache del _pointer_type_cache[struct_frozen] def test_undefined(self): self.assertRaises(ValueError, c_int.in_dll, pydll, "Undefined_Symbol") if __name__ == '__main__': unittest.main() --- NEW FILE: test_python_api.py --- from ctypes import * import unittest, sys ################################################################ # This section should be moved into ctypes\__init__.py, when it's ready. from _ctypes import PyObj_FromPtr ################################################################ from sys import getrefcount as grc class PythonAPITestCase(unittest.TestCase): def test_PyString_FromStringAndSize(self): PyString_FromStringAndSize = pythonapi.PyString_FromStringAndSize PyString_FromStringAndSize.restype = py_object PyString_FromStringAndSize.argtypes = c_char_p, c_int self.failUnlessEqual(PyString_FromStringAndSize("abcdefghi", 3), "abc") def test_PyString_FromString(self): pythonapi.PyString_FromString.restype = py_object pythonapi.PyString_FromString.argtypes = (c_char_p,) s = "abc" refcnt = grc(s) pyob = pythonapi.PyString_FromString(s) self.failUnlessEqual(grc(s), refcnt) self.failUnlessEqual(s, pyob) del pyob self.failUnlessEqual(grc(s), refcnt) def test_PyInt_Long(self): ref42 = grc(42) pythonapi.PyInt_FromLong.restype = py_object self.failUnlessEqual(pythonapi.PyInt_FromLong(42), 42) self.failUnlessEqual(grc(42), ref42) pythonapi.PyInt_AsLong.argtypes = (py_object,) pythonapi.PyInt_AsLong.restype = c_long res = pythonapi.PyInt_AsLong(42) self.failUnlessEqual(grc(res), ref42 + 1) del res self.failUnlessEqual(grc(42), ref42) def test_PyObj_FromPtr(self): s = "abc def ghi jkl" ref = grc(s) # id(python-object) is the address pyobj = PyObj_FromPtr(id(s)) self.failUnless(s is pyobj) self.failUnlessEqual(grc(s), ref + 1) del pyobj self.failUnlessEqual(grc(s), ref) def test_PyOS_snprintf(self): PyOS_snprintf = pythonapi.PyOS_snprintf PyOS_snprintf.argtypes = POINTER(c_char), c_int, c_char_p buf = c_buffer(256) PyOS_snprintf(buf, sizeof(buf), "Hello from %s", "ctypes") self.failUnlessEqual(buf.value, "Hello from ctypes") PyOS_snprintf(buf, sizeof(buf), "Hello from %s", "ctypes", 1, 2, 3) self.failUnlessEqual(buf.value, "Hello from ctypes") # not enough arguments self.failUnlessRaises(TypeError, PyOS_snprintf, buf) if __name__ == "__main__": unittest.main() --- NEW FILE: test_libc.py --- import sys, os import unittest from ctypes import * import _ctypes_test lib = cdll.load(_ctypes_test.__file__) class LibTest(unittest.TestCase): def test_sqrt(self): lib.my_sqrt.argtypes = c_double, lib.my_sqrt.restype = c_double self.failUnlessEqual(lib.my_sqrt(4.0), 2.0) import math self.failUnlessEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) def test_qsort(self): comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc lib.my_qsort.restype = None def sort(a, b): return cmp(a[0], b[0]) chars = create_string_buffer("spam, spam, and spam") lib.my_qsort(chars, len(chars)-1, sizeof(c_char), comparefunc(sort)) self.failUnlessEqual(chars.raw, " ,,aaaadmmmnpppsss\x00") if __name__ == "__main__": unittest.main() --- NEW FILE: test_refcounts.py --- import unittest import ctypes import gc MyCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int) OtherCallback = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_ulonglong) import _ctypes_test dll = ctypes.cdll.load(_ctypes_test.__file__) class RefcountTestCase(unittest.TestCase): def test_1(self): from sys import getrefcount as grc f = dll._testfunc_callback_i_if f.restype = ctypes.c_int f.argtypes = [ctypes.c_int, MyCallback] def callback(value): #print "called back with", value return value self.failUnlessEqual(grc(callback), 2) cb = MyCallback(callback) self.failUnless(grc(callback) > 2) result = f(-10, cb) self.failUnlessEqual(result, -18) cb = None gc.collect() self.failUnlessEqual(grc(callback), 2) def test_refcount(self): from sys import getrefcount as grc def func(*args): pass # this is the standard refcount for func self.failUnlessEqual(grc(func), 2) # the CFuncPtr instance holds atr least one refcount on func: f = OtherCallback(func) self.failUnless(grc(func) > 2) # and may release it again del f self.failUnless(grc(func) >= 2) # but now it must be gone gc.collect() self.failUnless(grc(func) == 2) class X(ctypes.Structure): _fields_ = [("a", OtherCallback)] x = X() x.a = OtherCallback(func) # the CFuncPtr instance holds atr least one refcount on func: self.failUnless(grc(func) > 2) # and may release it again del x self.failUnless(grc(func) >= 2) # and now it must be gone again gc.collect() self.failUnlessEqual(grc(func), 2) f = OtherCallback(func) # the CFuncPtr instance holds atr least one refcount on func: self.failUnless(grc(func) > 2) # create a cycle f.cycle = f del f gc.collect() self.failUnlessEqual(grc(func), 2) class AnotherLeak(unittest.TestCase): def test_callback(self): import sys proto = ctypes.CFUNCTYPE(ctypes.c_int, ctypes.c_int, ctypes.c_int) def func(a, b): return a * b * 2 f = proto(func) a = sys.getrefcount(ctypes.c_int) f(1, 2) self.failUnlessEqual(sys.getrefcount(ctypes.c_int), a) if __name__ == '__main__': unittest.main() --- NEW FILE: test_cfuncs.py --- # A lot of failures in these tests on Mac OS X. # Byte order related? import unittest from ctypes import * import _ctypes_test class CFunctions(unittest.TestCase): _dll = cdll.load(_ctypes_test.__file__) def S(self): return c_longlong.in_dll(self._dll, "last_tf_arg_s").value def U(self): return c_ulonglong.in_dll(self._dll, "last_tf_arg_u").value def test_byte(self): self._dll.tf_b.restype = c_byte self._dll.tf_b.argtypes = (c_byte,) self.failUnlessEqual(self._dll.tf_b(-126), -42) self.failUnlessEqual(self.S(), -126) def test_byte_plus(self): self._dll.tf_bb.restype = c_byte self._dll.tf_bb.argtypes = (c_byte, c_byte) self.failUnlessEqual(self._dll.tf_bb(0, -126), -42) self.failUnlessEqual(self.S(), -126) def test_ubyte(self): self._dll.tf_B.restype = c_ubyte self._dll.tf_B.argtypes = (c_ubyte,) self.failUnlessEqual(self._dll.tf_B(255), 85) self.failUnlessEqual(self.U(), 255) def test_ubyte_plus(self): self._dll.tf_bB.restype = c_ubyte self._dll.tf_bB.argtypes = (c_byte, c_ubyte) self.failUnlessEqual(self._dll.tf_bB(0, 255), 85) self.failUnlessEqual(self.U(), 255) def test_short(self): self._dll.tf_h.restype = c_short self.failUnlessEqual(self._dll.tf_h(-32766), -10922) self.failUnlessEqual(self.S(), -32766) def test_short_plus(self): self._dll.tf_bh.restype = c_short self.failUnlessEqual(self._dll.tf_bh(0, -32766), -10922) self.failUnlessEqual(self.S(), -32766) def test_ushort(self): self._dll.tf_H.restype = c_ushort self.failUnlessEqual(self._dll.tf_H(65535), 21845) self.failUnlessEqual(self.U(), 65535) def test_ushort_plus(self): self._dll.tf_bH.restype = c_ushort self.failUnlessEqual(self._dll.tf_bH(0, 65535), 21845) self.failUnlessEqual(self.U(), 65535) def test_int(self): self._dll.tf_i.restype = c_int self.failUnlessEqual(self._dll.tf_i(-2147483646), -715827882) self.failUnlessEqual(self.S(), -2147483646) def test_int_plus(self): self._dll.tf_bi.restype = c_int self.failUnlessEqual(self._dll.tf_bi(0, -2147483646), -715827882) self.failUnlessEqual(self.S(), -2147483646) def test_uint(self): self._dll.tf_I.restype = c_uint self.failUnlessEqual(self._dll.tf_I(4294967295), 1431655765) self.failUnlessEqual(self.U(), 4294967295) def test_uint_plus(self): self._dll.tf_bI.restype = c_uint self.failUnlessEqual(self._dll.tf_bI(0, 4294967295), 1431655765) self.failUnlessEqual(self.U(), 4294967295) def test_long(self): self._dll.tf_l.restype = c_long self._dll.tf_l.argtypes = (c_long,) self.failUnlessEqual(self._dll.tf_l(-2147483646), -715827882) self.failUnlessEqual(self.S(), -2147483646) def test_long_plus(self): self._dll.tf_bl.restype = c_long self._dll.tf_bl.argtypes = (c_byte, c_long) self.failUnlessEqual(self._dll.tf_bl(0, -2147483646), -715827882) self.failUnlessEqual(self.S(), -2147483646) def test_ulong(self): self._dll.tf_L.restype = c_ulong self._dll.tf_L.argtypes = (c_ulong,) self.failUnlessEqual(self._dll.tf_L(4294967295), 1431655765) self.failUnlessEqual(self.U(), 4294967295) def test_ulong_plus(self): self._dll.tf_bL.restype = c_ulong self._dll.tf_bL.argtypes = (c_char, c_ulong) self.failUnlessEqual(self._dll.tf_bL(' ', 4294967295), 1431655765) self.failUnlessEqual(self.U(), 4294967295) def test_longlong(self): self._dll.tf_q.restype = c_longlong self._dll.tf_q.argtypes = (c_longlong, ) self.failUnlessEqual(self._dll.tf_q(-9223372036854775806), -3074457345618258602) self.failUnlessEqual(self.S(), -9223372036854775806) def test_longlong_plus(self): self._dll.tf_bq.restype = c_longlong self._dll.tf_bq.argtypes = (c_byte, c_longlong) self.failUnlessEqual(self._dll.tf_bq(0, -9223372036854775806), -3074457345618258602) self.failUnlessEqual(self.S(), -9223372036854775806) def test_ulonglong(self): self._dll.tf_Q.restype = c_ulonglong self._dll.tf_Q.argtypes = (c_ulonglong, ) self.failUnlessEqual(self._dll.tf_Q(18446744073709551615), 6148914691236517205) self.failUnlessEqual(self.U(), 18446744073709551615) def test_ulonglong_plus(self): self._dll.tf_bQ.restype = c_ulonglong self._dll.tf_bQ.argtypes = (c_byte, c_ulonglong) self.failUnlessEqual(self._dll.tf_bQ(0, 18446744073709551615), 6148914691236517205) self.failUnlessEqual(self.U(), 18446744073709551615) def test_float(self): self._dll.tf_f.restype = c_float self._dll.tf_f.argtypes = (c_float,) self.failUnlessEqual(self._dll.tf_f(-42.), -14.) self.failUnlessEqual(self.S(), -42) def test_float_plus(self): self._dll.tf_bf.restype = c_float self._dll.tf_bf.argtypes = (c_byte, c_float) self.failUnlessEqual(self._dll.tf_bf(0, -42.), -14.) self.failUnlessEqual(self.S(), -42) def test_double(self): self._dll.tf_d.restype = c_double self._dll.tf_d.argtypes = (c_double,) self.failUnlessEqual(self._dll.tf_d(42.), 14.) self.failUnlessEqual(self.S(), 42) def test_double_plus(self): self._dll.tf_bd.restype = c_double self._dll.tf_bd.argtypes = (c_byte, c_double) self.failUnlessEqual(self._dll.tf_bd(0, 42.), 14.) self.failUnlessEqual(self.S(), 42) def test_callwithresult(self): def process_result(result): return result * 2 self._dll.tf_i.restype = process_result self._dll.tf_i.argtypes = (c_int,) self.failUnlessEqual(self._dll.tf_i(42), 28) self.failUnlessEqual(self.S(), 42) self.failUnlessEqual(self._dll.tf_i(-42), -28) self.failUnlessEqual(self.S(), -42) def test_void(self): self._dll.tv_i.restype = None self._dll.tv_i.argtypes = (c_int,) self.failUnlessEqual(self._dll.tv_i(42), None) self.failUnlessEqual(self.S(), 42) self.failUnlessEqual(self._dll.tv_i(-42), None) self.failUnlessEqual(self.S(), -42) # The following repeates the above tests with stdcall functions (where # they are available) try: WinDLL except NameError: pass else: class stdcall_dll(WinDLL): def __getattr__(self, name): if name[:2] == '__' and name[-2:] == '__': raise AttributeError, name func = self._FuncPtr("s_" + name, self) setattr(self, name, func) return func class stdcallCFunctions(CFunctions): _dll = stdcall_dll(_ctypes_test.__file__) pass if __name__ == '__main__': unittest.main() --- NEW FILE: test_byteswap.py --- import sys, unittest, struct, math from binascii import hexlify from ctypes import * def bin(s): return hexlify(buffer(s)).upper() # Each *simple* type that supports different byte orders has an # __ctype_be__ attribute that specifies the same type in BIG ENDIAN # byte order, and a __ctype_le__ attribute that is the same type in # LITTLE ENDIAN byte order. # # For Structures and Unions, these types are created on demand. class Test(unittest.TestCase): def X_test(self): print sys.byteorder for i in range(32): bits = BITS() setattr(bits, "i%s" % i, 1) dump(bits) def test_endian_short(self): if sys.byteorder == "little": self.failUnless(c_short.__ctype_le__ is c_short) self.failUnless(c_short.__ctype_be__.__ctype_le__ is c_short) else: self.failUnless(c_short.__ctype_be__ is c_short) self.failUnless(c_short.__ctype_le__.__ctype_be__ is c_short) s = c_short.__ctype_be__(0x1234) self.failUnlessEqual(bin(struct.pack(">h", 0x1234)), "1234") self.failUnlessEqual(bin(s), "1234") self.failUnlessEqual(s.value, 0x1234) s = c_short.__ctype_le__(0x1234) self.failUnlessEqual(bin(struct.pack("<h", 0x1234)), "3412") self.failUnlessEqual(bin(s), "3412") self.failUnlessEqual(s.value, 0x1234) s = c_ushort.__ctype_be__(0x1234) self.failUnlessEqual(bin(struct.pack(">h", 0x1234)), "1234") self.failUnlessEqual(bin(s), "1234") self.failUnlessEqual(s.value, 0x1234) s = c_ushort.__ctype_le__(0x1234) self.failUnlessEqual(bin(struct.pack("<h", 0x1234)), "3412") self.failUnlessEqual(bin(s), "3412") self.failUnlessEqual(s.value, 0x1234) def test_endian_int(self): if sys.byteorder == "little": self.failUnless(c_int.__ctype_le__ is c_int) self.failUnless(c_int.__ctype_be__.__ctype_le__ is c_int) else: self.failUnless(c_int.__ctype_be__ is c_int) self.failUnless(c_int.__ctype_le__.__ctype_be__ is c_int) s = c_int.__ctype_be__(0x12345678) self.failUnlessEqual(bin(struct.pack(">i", 0x12345678)), "12345678") self.failUnlessEqual(bin(s), "12345678") self.failUnlessEqual(s.value, 0x12345678) s = c_int.__ctype_le__(0x12345678) self.failUnlessEqual(bin(struct.pack("<i", 0x12345678)), "78563412") self.failUnlessEqual(bin(s), "78563412") self.failUnlessEqual(s.value, 0x12345678) s = c_uint.__ctype_be__(0x12345678) self.failUnlessEqual(bin(struct.pack(">I", 0x12345678)), "12345678") self.failUnlessEqual(bin(s), "12345678") self.failUnlessEqual(s.value, 0x12345678) s = c_uint.__ctype_le__(0x12345678) self.failUnlessEqual(bin(struct.pack("<I", 0x12345678)), "78563412") self.failUnlessEqual(bin(s), "78563412") self.failUnlessEqual(s.value, 0x12345678) def test_endian_longlong(self): if sys.byteorder == "little": self.failUnless(c_longlong.__ctype_le__ is c_longlong) self.failUnless(c_longlong.__ctype_be__.__ctype_le__ is c_longlong) else: self.failUnless(c_longlong.__ctype_be__ is c_longlong) self.failUnless(c_longlong.__ctype_le__.__ctype_be__ is c_longlong) s = c_longlong.__ctype_be__(0x1234567890ABCDEF) self.failUnlessEqual(bin(struct.pack(">q", 0x1234567890ABCDEF)), "1234567890ABCDEF") self.failUnlessEqual(bin(s), "1234567890ABCDEF") self.failUnlessEqual(s.value, 0x1234567890ABCDEF) s = c_longlong.__ctype_le__(0x1234567890ABCDEF) self.failUnlessEqual(bin(struct.pack("<q", 0x1234567890ABCDEF)), "EFCDAB9078563412") self.failUnlessEqual(bin(s), "EFCDAB9078563412") self.failUnlessEqual(s.value, 0x1234567890ABCDEF) s = c_ulonglong.__ctype_be__(0x1234567890ABCDEF) self.failUnlessEqual(bin(struct.pack(">Q", 0x1234567890ABCDEF)), "1234567890ABCDEF") self.failUnlessEqual(bin(s), "1234567890ABCDEF") self.failUnlessEqual(s.value, 0x1234567890ABCDEF) s = c_ulonglong.__ctype_le__(0x1234567890ABCDEF) self.failUnlessEqual(bin(struct.pack("<Q", 0x1234567890ABCDEF)), "EFCDAB9078563412") self.failUnlessEqual(bin(s), "EFCDAB9078563412") self.failUnlessEqual(s.value, 0x1234567890ABCDEF) def test_endian_float(self): if sys.byteorder == "little": self.failUnless(c_float.__ctype_le__ is c_float) self.failUnless(c_float.__ctype_be__.__ctype_le__ is c_float) else: self.failUnless(c_float.__ctype_be__ is c_float) self.failUnless(c_float.__ctype_le__.__ctype_be__ is c_float) s = c_float(math.pi) self.failUnlessEqual(bin(struct.pack("f", math.pi)), bin(s)) # Hm, what's the precision of a float compared to a double? self.failUnlessAlmostEqual(s.value, math.pi, 6) s = c_float.__ctype_le__(math.pi) self.failUnlessAlmostEqual(s.value, math.pi, 6) self.failUnlessEqual(bin(struct.pack("<f", math.pi)), bin(s)) s = c_float.__ctype_be__(math.pi) self.failUnlessAlmostEqual(s.value, math.pi, 6) self.failUnlessEqual(bin(struct.pack(">f", math.pi)), bin(s)) def test_endian_double(self): if sys.byteorder == "little": self.failUnless(c_double.__ctype_le__ is c_double) self.failUnless(c_double.__ctype_be__.__ctype_le__ is c_double) else: self.failUnless(c_double.__ctype_be__ is c_double) self.failUnless(c_double.__ctype_le__.__ctype_be__ is c_double) s = c_double(math.pi) self.failUnlessEqual(s.value, math.pi) self.failUnlessEqual(bin(struct.pack("d", math.pi)), bin(s)) s = c_double.__ctype_le__(math.pi) self.failUnlessEqual(s.value, math.pi) self.failUnlessEqual(bin(struct.pack("<d", math.pi)), bin(s)) s = c_double.__ctype_be__(math.pi) self.failUnlessEqual(s.value, math.pi) self.failUnlessEqual(bin(struct.pack(">d", math.pi)), bin(s)) def test_endian_other(self): self.failUnless(c_byte.__ctype_le__ is c_byte) self.failUnless(c_byte.__ctype_be__ is c_byte) self.failUnless(c_ubyte.__ctype_le__ is c_ubyte) self.failUnless(c_ubyte.__ctype_be__ is c_ubyte) self.failUnless(c_char.__ctype_le__ is c_char) self.failUnless(c_char.__ctype_be__ is c_char) def test_struct_fields(self): if sys.byteorder == "little": base = BigEndianStructure else: base = LittleEndianStructure class T(base): pass _fields_ = [("a", c_ubyte), ("b", c_byte), ("c", c_short), ("d", c_ushort), ("e", c_int), ("f", c_uint), ("g", c_long), ("h", c_ulong), ("i", c_longlong), ("k", c_ulonglong), ("l", c_float), ("m", c_double), ("n", c_char), ("b1", c_byte, 3), ("b2", c_byte, 3), ("b3", c_byte, 2), ("a", c_int * 3 * 3 * 3)] T._fields_ = _fields_ # these fields do not support different byte order: for typ in c_wchar, c_void_p, POINTER(c_int): _fields_.append(("x", typ)) class T(base): pass self.assertRaises(TypeError, setattr, T, "_fields_", [("x", typ)]) def test_struct_struct(self): # Nested structures with different byte order not (yet) supported if sys.byteorder == "little": base = BigEndianStructure else: base = LittleEndianStructure class T(Structure): _fields_ = [("a", c_int), ("b", c_int)] class S(base): pass self.assertRaises(TypeError, setattr, S, "_fields_", [("s", T)]) def test_struct_fields(self): if sys.byteorder == "little": base = BigEndianStructure fmt = ">bhid" else: base = LittleEndianStructure fmt = "<bhid" class S(base): _pack_ = 1 # struct with '<' or '>' uses standard alignment. _fields_ = [("b", c_byte), ("h", c_short), ("i", c_int), ("d", c_double)] s1 = S(0x12, 0x1234, 0x12345678, 3.14) s2 = struct.pack(fmt, 0x12, 0x1234, 0x12345678, 3.14) self.failUnlessEqual(bin(s1), bin(s2)) if __name__ == "__main__": unittest.main() --- NEW FILE: test_numbers.py --- from ctypes import * import unittest import sys, struct def valid_ranges(*types): # given a sequence of numeric types, collect their _type_ # attribute, which is a single format character compatible with # the struct module, use the struct module to calculate the # minimum and maximum value allowed for this format. # Returns a list of (min, max) values. result = [] for t in types: fmt = t._type_ size = struct.calcsize(fmt) a = struct.unpack(fmt, ("\x00"*32)[:size])[0] b = struct.unpack(fmt, ("\xFF"*32)[:size])[0] c = struct.unpack(fmt, ("\x7F"+"\x00"*32)[:size])[0] d = struct.unpack(fmt, ("\x80"+"\xFF"*32)[:size])[0] result.append((min(a, b, c, d), max(a, b, c, d))) return result ArgType = type(c_int(0)._as_parameter_) unsigned_types = [c_ubyte, c_ushort, c_uint, c_ulong] signed_types = [c_byte, c_short, c_int, c_long, c_longlong] float_types = [c_double, c_float] try: c_ulonglong c_longlong except NameError: pass else: unsigned_types.append(c_ulonglong) signed_types.append(c_longlong) unsigned_ranges = valid_ranges(*unsigned_types) signed_ranges = valid_ranges(*signed_types) ################################################################ class NumberTestCase(unittest.TestCase): def test_default_init(self): # default values are set to zero for t in signed_types + unsigned_types + float_types: self.failUnlessEqual(t().value, 0) def test_unsigned_values(self): # the value given to the constructor is available # as the 'value' attribute for t, (l, h) in zip(unsigned_types, unsigned_ranges): self.failUnlessEqual(t(l).value, l) self.failUnlessEqual(t(h).value, h) def test_signed_values(self): # see above for t, (l, h) in zip(signed_types, signed_ranges): self.failUnlessEqual(t(l).value, l) self.failUnlessEqual(t(h).value, h) def test_typeerror(self): # Only numbers are allowed in the contructor, # otherwise TypeError is raised for t in signed_types + unsigned_types + float_types: self.assertRaises(TypeError, t, "") self.assertRaises(TypeError, t, None) ## def test_valid_ranges(self): ## # invalid values of the correct type ## # raise ValueError (not OverflowError) ## for t, (l, h) in zip(unsigned_types, unsigned_ranges): ## self.assertRaises(ValueError, t, l-1) ## self.assertRaises(ValueError, t, h+1) def test_from_param(self): # the from_param class method attribute always # returns PyCArgObject instances for t in signed_types + unsigned_types + float_types: self.failUnlessEqual(ArgType, type(t.from_param(0))) def test_as_parameter(self): # The _as_parameter_ property must also # be a PyCArgObject instance for t in signed_types + unsigned_types + float_types: parm = t()._as_parameter_ self.failUnlessEqual(ArgType, type(parm)) # _as_parameter_ is readonly! # # Python 2.3 and 2.4 raise a TypeError when trying to set # a readonly attribute, 2.5 raises an AttributeError. self.assertRaises((AttributeError, TypeError), setattr, t(), "_as_parameter_", None) def test_byref(self): # calling byref returns also a PyCArgObject instance for t in signed_types + unsigned_types + float_types: parm = byref(t()) self.failUnlessEqual(ArgType, type(parm)) def test_floats(self): # c_float and c_double can be created from # Python int, long and float for t in float_types: self.failUnlessEqual(t(2.0).value, 2.0) self.failUnlessEqual(t(2).value, 2.0) self.failUnlessEqual(t(2L).value, 2.0) def test_integers(self): # integers cannot be constructed from floats for t in signed_types + unsigned_types: self.assertRaises(TypeError, t, 3.14) def test_sizes(self): for t in signed_types + unsigned_types + float_types: size = struct.calcsize(t._type_) # sizeof of the type... self.failUnlessEqual(sizeof(t), size) # and sizeof of an instance self.failUnlessEqual(sizeof(t()), size) def test_alignments(self): for t in signed_types + unsigned_types + float_types: code = t._type_ # the typecode align = struct.calcsize("c%c" % code) - struct.calcsize(code) # alignment of the type... self.failUnlessEqual((code, alignment(t)), (code, align)) # and alignment of an instance self.failUnlessEqual((code, alignment(t())), (code, align)) def test_int_from_address(self): from array import array for t in signed_types + unsigned_types: # the array module doesn't suppport all format codes # (no 'q' or 'Q') try: array(t._type_) except ValueError: continue a = array(t._type_, [100]) # v now is an integer at an 'external' memory location v = t.from_address(a.buffer_info()[0]) self.failUnlessEqual(v.value, a[0]) self.failUnlessEqual(type(v), t) # changing the value at the memory location changes v's value also a[0] = 42 self.failUnlessEqual(v.value, a[0]) def test_float_from_address(self): from array import array for t in float_types: a = array(t._type_, [3.14]) v = t.from_address(a.buffer_info()[0]) self.failUnlessEqual(v.value, a[0]) self.failUnless(type(v) is t) a[0] = 2.3456e17 self.failUnlessEqual(v.value, a[0]) self.failUnless(type(v) is t) def test_char_from_address(self): from ctypes import c_char from array import array a = array('c', 'x') v = c_char.from_address(a.buffer_info()[0]) self.failUnlessEqual(v.value, a[0]) self.failUnless(type(v) is c_char) a[0] = '?' self.failUnlessEqual(v.value, a[0]) def test_init(self): # c_int() can be initialized from Python's int, and c_int. # Not from c_long or so, which seems strange, abd should # probably be changed: self.assertRaises(TypeError, c_int, c_long(42)) ## def test_perf(self): ## check_perf() from ctypes import _SimpleCData class c_int_S(_SimpleCData): _type_ = "i" __slots__ = [] def run_test(rep, msg, func, arg=None): ## items = [None] * rep items = range(rep) from time import clock if arg is not None: start = clock() for i in items: func(arg); func(arg); func(arg); func(arg); func(arg) stop = clock() else: start = clock() for i in items: func(); func(); func(); func(); func() stop = clock() print "%15s: %.2f us" % (msg, ((stop-start)*1e6/5/rep)) def check_perf(): # Construct 5 objects from ctypes import c_int REP = 200000 run_test(REP, "int()", int) run_test(REP, "int(999)", int) run_test(REP, "c_int()", c_int) run_test(REP, "c_int(999)", c_int) run_test(REP, "c_int_S()", c_int_S) run_test(REP, "c_int_S(999)", c_int_S) # Python 2.3 -OO, win2k, P4 700 MHz: # # int(): 0.87 us # int(999): 0.87 us # c_int(): 3.35 us # c_int(999): 3.34 us # c_int_S(): 3.23 us # c_int_S(999): 3.24 us # Python 2.2 -OO, win2k, P4 700 MHz: # # int(): 0.89 us # int(999): 0.89 us # c_int(): 9.99 us # c_int(999): 10.02 us # c_int_S(): 9.87 us # c_int_S(999): 9.85 us if __name__ == '__main__': ## check_perf() unittest.main() --- NEW FILE: test_macholib.py --- import os import sys import unittest # Bob Ippolito: """ Ok.. the code to find the filename for __getattr__ should look something like: import os from macholib.dyld import dyld_find def find_lib(name): possible = ['lib'+name+'.dylib', name+'.dylib', name+'.framework/'+name] for dylib in possible: try: return os.path.realpath(dyld_find(dylib)) except ValueError: pass raise ValueError, "%s not found" % (name,) It'll have output like this: >>> find_lib('pthread') '/usr/lib/libSystem.B.dylib' >>> find_lib('z') '/usr/lib/libz.1.dylib' >>> find_lib('IOKit') '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit' -bob """ from ctypes.macholib.dyld import dyld_find def find_lib(name): possible = ['lib'+name+'.dylib', name+'.dylib', name+'.framework/'+name] for dylib in possible: try: return os.path.realpath(dyld_find(dylib)) except ValueError: pass raise ValueError, "%s not found" % (name,) class MachOTest(unittest.TestCase): if sys.platform == "darwin": def test_find(self): self.failUnlessEqual(find_lib('pthread'), '/usr/lib/libSystem.B.dylib') result = find_lib('z') self.failUnless(result.startswith('/usr/lib/libz.1')) self.failUnless(result.endswith('.dylib')) self.failUnlessEqual(find_lib('IOKit'), '/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit') if __name__ == "__main__": unittest.main() --- NEW FILE: test_integers.py --- # superseeded by test_numbers.py import unittest if __name__ == '__main__': unittest.main() --- NEW FILE: test_win32.py --- # Windows specific tests from ctypes import * import unittest, sys import _ctypes_test if sys.platform == "win32": class WindowsTestCase(unittest.TestCase): def test_callconv_1(self): # Testing stdcall function IsWindow = windll.user32.IsWindow # ValueError: Procedure probably called with not enough arguments (4 bytes missing) self.assertRaises(ValueError, IsWindow) # This one should succeeed... self.failUnlessEqual(0, IsWindow(0)) # ValueError: Procedure probably called with too many arguments (8 bytes in excess) self.assertRaises(ValueError, IsWindow, 0, 0, 0) def test_callconv_2(self): # Calling stdcall function as cdecl IsWindow = cdll.user32.IsWindow # ValueError: Procedure called with not enough arguments (4 bytes missing) # or wrong calling convention self.assertRaises(ValueError, IsWindow, None) def test_SEH(self): # Call functions with invalid arguments, and make sure that access violations # are trapped and raise an exception. # # Normally, in a debug build of the _ctypes extension # module, exceptions are not trapped, so we can only run # this test in a release build. import sys if not hasattr(sys, "getobjects"): self.assertRaises(WindowsError, windll.kernel32.GetModuleHandleA, 32) class Structures(unittest.TestCase): def test_struct_by_value(self): class POINT(Structure): _fields_ = [("x", c_long), ("y", c_long)] class RECT(Structure): _fields_ = [("left", c_long), ("top", c_long), ("right", c_long), ("bottom", c_long)] dll = cdll.load(_ctypes_test.__file__) pt = POINT(10, 10) rect = RECT(0, 0, 20, 20) self.failUnlessEqual(1, dll.PointInRect(byref(rect), pt)) if __name__ == '__main__': unittest.main() --- NEW FILE: test_sizes.py --- # Test specifically-sized containers. import unittest from ctypes import * class SizesTestCase(unittest.TestCase): def test_8(self): self.failUnlessEqual(1, sizeof(c_int8)) self.failUnlessEqual(1, sizeof(c_uint8)) def test_16(self): self.failUnlessEqual(2, sizeof(c_int16)) self.failUnlessEqual(2, sizeof(c_uint16)) def test_32(self): self.failUnlessEqual(4, sizeof(c_int32)) self.failUnlessEqual(4, sizeof(c_uint32)) def test_64(self): self.failUnlessEqual(8, sizeof(c_int64)) self.failUnlessEqual(8, sizeof(c_uint64)) if __name__ == "__main__": unittest.main() --- NEW FILE: test_random_things.py --- from ctypes import * import unittest, sys def callback_func(arg): 42 / arg raise ValueError, arg if sys.platform == "win32": class call_function_TestCase(unittest.TestCase): # _ctypes.call_function is deprecated and private, but used by # Gary Bishp's readline module. If we have it, we must test it as well. def test(self): from _ctypes import call_function hdll = windll.kernel32.LoadLibraryA("kernel32") funcaddr = windll.kernel32.GetProcAddress(hdll, "GetModuleHandleA") self.failUnlessEqual(call_function(funcaddr, (None,)), windll.kernel32.GetModuleHandleA(None)) class CallbackTracbackTestCase(unittest.TestCase): # When an exception is raised in a ctypes callback function, the C # code prints a traceback. # # This test makes sure the exception types *and* the exception # value is printed correctly. # # Changed in 0.9.3: No longer is '(in callback)' prepended to the # error message - instead a additional frame for the C code is # created, then a full traceback printed. When SystemExit is # raised in a callback function, the interpreter exits. def capture_stderr(self, func, *args, **kw): # helper - call function 'func', and return the captured stderr import StringIO old_stderr = sys.stderr logger = sys.stderr = StringIO.StringIO() try: func(*args, **kw) finally: sys.stderr = old_stderr return logger.getvalue() def test_ValueError(self): cb = CFUNCTYPE(c_int, c_int)(callback_func) out = self.capture_stderr(cb, 42) self.failUnlessEqual(out.splitlines()[-1], "ValueError: 42") def test_IntegerDivisionError(self): cb = CFUNCTYPE(c_int, c_int)(callback_func) out = self.capture_stderr(cb, 0) self.failUnlessEqual(out.splitlines()[-1], "ZeroDivisionError: " "integer division or modulo by zero") def test_FloatDivisionError(self): cb = CFUNCTYPE(c_int, c_double)(callback_func) out = self.capture_stderr(cb, 0.0) self.failUnlessEqual(out.splitlines()[-1], "ZeroDivisionError: " "float division") def test_TypeErrorDivisionError(self): cb = CFUNCTYPE(c_int, c_char_p)(callback_func) out = self.capture_stderr(cb, "spam") self.failUnlessEqual(out.splitlines()[-1], "TypeError: " "unsupported operand type(s) for /: 'int' and 'str'") if __name__ == '__main__': unittest.main() --- NEW FILE: test_bitfields.py --- from ctypes import * import unittest import os import ctypes import _ctypes_test class BITS(Structure): _fields_ = [("A", c_int, 1), ("B", c_int, 2), ("C", c_int, 3), ("D", c_int, 4), ("E", c_int, 5), ("F", c_int, 6), ("G", c_int, 7), ("H", c_int, 8), ("I", c_int, 9), ("M", c_short, 1), ("N", c_short, 2), ("O", c_short, 3), ("P", c_short, 4), ("Q", c_short, 5), ("R", c_short, 6), ("S", c_short, 7)] func = cdll.load(_ctypes_test.__file__).unpack_bitfields func.argtypes = POINTER(BITS), c_char ##for n in "ABCDEFGHIMNOPQRS": ## print n, hex(getattr(BITS, n).size), getattr(BITS, n).offset class C_Test(unittest.TestCase): def test_ints(self): for i in range(512): for name in "ABCDEFGHI": b = BITS() setattr(b, name, i) self.failUnlessEqual((name, i, getattr(b, name)), (name, i, func(byref(b), name))) def test_shorts(self): for i in range(256): for name in "MNOPQRS": b = BITS() setattr(b, name, i) self.failUnlessEqual((name, i, getattr(b, name)), (name, i, func(byref(b), name))) signed_int_types = (c_byte, c_short, c_int, c_long, c_longlong) unsigned_int_types = (c_ubyte, c_ushort, c_uint, c_ulong, c_ulonglong) int_types = unsigned_int_types + signed_int_types class BitFieldTest(unittest.TestCase): def test_longlong(self): class X(Structure): _fields_ = [("a", c_longlong, 1), ("b", c_longlong, 62), ("c", c_longlong, 1)] self.failUnlessEqual(sizeof(X), sizeof(c_longlong)) x = X() x.a, x.b, x.c = -1, 7, -1 self.failUnlessEqual((x.a, x.b, x.c), (-1, 7, -1)) def test_ulonglong(self): class X(Structure): _fields_ = [("a", c_ulonglong, 1), ("b", c_ulonglong, 62), ("c", c_ulonglong, 1)] self.failUnlessEqual(sizeof(X), sizeof(c_longlong)) x = X() self.failUnlessEqual((x.a, x.b, x.c), (0, 0, 0)) x.a, x.b, x.c = 7, 7, 7 self.failUnlessEqual((x.a, x.b, x.c), (1, 7, 1)) def test_signed(self): for c_typ in signed_int_types: class X(Structure): _fields_ = [("dummy", c_typ), ("a", c_typ, 3), ("b", c_typ, 3), ("c", c_typ, 1)] self.failUnlessEqual(sizeof(X), sizeof(c_typ)*2) x = X() self.failUnlessEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0)) x.a = -1 self.failUnlessEqual((c_typ, x.a, x.b, x.c), (c_typ, -1, 0, 0)) x.a, x.b = 0, -1 self.failUnlessEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, -1, 0)) def test_unsigned(self): for c_typ in unsigned_int_types: class X(Structure): _fields_ = [("a", c_typ, 3), ("b", c_typ, 3), ("c", c_typ, 1)] self.failUnlessEqual(sizeof(X), sizeof(c_typ)) x = X() self.failUnlessEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 0, 0)) x.a = -1 self.failUnlessEqual((c_typ, x.a, x.b, x.c), (c_typ, 7, 0, 0)) x.a, x.b = 0, -1 self.failUnlessEqual((c_typ, x.a, x.b, x.c), (c_typ, 0, 7, 0)) def fail_fields(self, *fields): return self.get_except(type(Structure), "X", (), {"_fields_": fields}) def test_nonint_types(self): # bit fields are not allowed on non-integer types. result = self.fail_fields(("a", c_char_p, 1)) self.failUnlessEqual(result, (TypeError, 'bit fields not allowed for type c_char_p')) result = self.fail_fields(("a", c_void_p, 1)) self.failUnlessEqual(result, (TypeError, 'bit fields not allowed for type c_void_p')) if c_int != c_long: result = self.fail_fields(("a", POINTER(c_int), 1)) self.failUnlessEqual(result, (TypeError, 'bit fields not allowed for type LP_c_int')) result = self.fail_fields(("a", c_char, 1)) self.failUnlessEqual(result, (TypeError, 'bit fields not allowed for type c_char')) try: c_wchar except NameError: pass else: result = self.fail_fields(("a", c_wchar, 1)) self.failUnlessEqual(result, (TypeError, 'bit fields not allowed for type c_wchar')) class Dummy(Structure): _fields_ = [] result = self.fail_fields(("a", Dummy, 1)) self.failUnlessEqual(result, (TypeError, 'bit fields not allowed for type Dummy')) def test_single_bitfield_size(self): for c_typ in int_types: result = self.fail_fields(("a", c_typ, -1)) self.failUnlessEqual(result, (ValueError, 'number of bits invalid for bit field')) result = self.fail_fields(("a", c_typ, 0)) self.failUnlessEqual(result, (ValueError, 'number of bits invalid for bit field')) class X(Structure): _fields_ = [("a", c_typ, 1)] self.failUnlessEqual(sizeof(X), sizeof(c_typ)) class X(Structure): _fields_ = [("a", c_typ, sizeof(c_typ)*8)] self.failUnlessEqual(sizeof(X), sizeof(c_typ)) result = self.fail_fields(("a", c_typ, sizeof(c_typ)*8 + 1)) self.failUnlessEqual(result, (ValueError, 'number of bits invalid for bit field')) def test_multi_bitfields_size(self): class X(Structure): _fields_ = [("a", c_short, 1), ("b", c_short, 14), ("c", c_short, 1)] self.failUnlessEqual(sizeof(X), sizeof(c_short)) class X(Structure): _fields_ = [("a", c_short, 1), ("a1", c_short), ("b", c_short, 14), ("c", c_short, 1)] self.failUnlessEqual(sizeof(X), sizeof(c_short)*3) self.failUnlessEqual(X.a.offset, 0) self.failUnlessEqual(X.a1.offset, sizeof(c_short)) self.failUnlessEqual(X.b.offset, sizeof(c_short)*2) self.failUnlessEqual(X.c.offset, sizeof(c_short)*2) class X(Structure): _fields_ = [("a", c_short, 3), ("b", c_short, 14), ("c", c_short, 14)] self.failUnlessEqual(sizeof(X), sizeof(c_short)*3) self.failUnlessEqual(X.a.offset, sizeof(c... [truncated message content] |
From: Thomas H. <th...@us...> - 2006-03-03 20:11:35
|
Update of /cvsroot/ctypes/ctypes/ctypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5995 Added Files: wintypes.py util.py decorators.py _loader.py _endian.py __init__.py .cvsignore .CTYPES_DEVEL Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: .cvsignore --- *.pyc *.pyo com --- NEW FILE: .CTYPES_DEVEL --- # -*- python -*- def install(): import sys, os from distutils.util import get_platform plat_specifier = ".%s-%s" % (get_platform(), sys.version[0:3]) build_dir = os.path.join("..", 'build', 'lib' + plat_specifier) p = os.path.abspath(os.path.join(os.path.dirname(__file__), build_dir)) sys.path.insert(0, p) del sys install() del install --- NEW FILE: _loader.py --- # WORK IN PROGRESS! DO NOT (yet) USE! import sys, os import ctypes __all__ = ["LibraryLoader", "RTLD_LOCAL", "RTLD_GLOBAL"] if os.name in ("nt", "ce"): from _ctypes import LoadLibrary as dlopen RTLD_LOCAL = RTLD_GLOBAL = None else: from _ctypes import dlopen, RTLD_LOCAL, RTLD_GLOBAL # _findLib(name) returns an iterable of possible names for a library. if os.name in ("nt", "ce"): def _findLib(name): return [name] if os.name == "posix" and sys.platform == "darwin": from ctypes.macholib.dyld import dyld_find as _dyld_find def _findLib(name): possible = ['lib%s.dylib' % name, '%s.dylib' % name, '%s.framework/%s' % (name, name)] for name in possible: try: return [_dyld_find(name)] except ValueError: continue return [] elif os.name == "posix": # Andreas Degert's find functions, using gcc, /sbin/ldconfig, objdump import re, tempfile def _findLib_gcc(name): expr = '[^\(\)\s]*lib%s\.[^\(\)\s]*' % name cmd = 'if type gcc &>/dev/null; then CC=gcc; else CC=cc; fi;' \ '$CC -Wl,-t -o /dev/null 2>&1 -l' + name try: fdout, outfile = tempfile.mkstemp() fd = os.popen(cmd) trace = fd.read() err = fd.close() finally: try: os.unlink(outfile) except OSError, e: if e.errno != errno.ENOENT: raise res = re.search(expr, trace) if not res: return None return res.group(0) def _findLib_ld(name): expr = '/[^\(\)\s]*lib%s\.[^\(\)\s]*' % name res = re.search(expr, os.popen('/sbin/ldconfig -p 2>/dev/null').read()) if not res: return None return res.group(0) def _get_soname(f): cmd = "objdump -p -j .dynamic 2>/dev/null " + f res = re.search(r'\sSONAME\s+([^\s]+)', os.popen(cmd).read()) if not res: return f return res.group(1) def _findLib(name): lib = _findLib_ld(name) if not lib: lib = _findLib_gcc(name) if not lib: return [name] return [_get_soname(lib)] class LibraryLoader(object): """Loader for shared libraries. Shared libraries are accessed when compiling/linking a program, and when the program is run. The purpose of the 'find' method is to locate a library similar to what the compiler does (on machines with several versions of a shared library the most recent should be loaded), while 'load' acts like when the program is run, and uses the runtime loader directly. 'load_version' works like 'load' but tries to be platform independend (for cases where this makes sense). Loading via attribute access is a shorthand notation especially useful for interactive use.""" def __init__(self, dlltype, mode=RTLD_LOCAL): """Create a library loader instance which loads libraries by creating an instance of 'dlltype'. 'mode' can be RTLD_LOCAL or RTLD_GLOBAL, it is ignored on Windows. """ self._dlltype = dlltype self._mode = mode def load(self, libname, mode=None): """Load and return the library with the given libname. On most systems 'libname' is the filename of the shared library; when it's not a pathname it will be searched in a system dependend list of locations (on many systems additional search paths can be specified by an environment variable). Sometimes the extension (like '.dll' on Windows) can be omitted. 'mode' allows to override the default flags specified in the constructor, it is ignored on Windows. """ if mode is None: mode = self._mode return self._load(libname, mode) def load_library(self, libname, mode=None): """Load and return the library with the given libname. This method passes the specified 'libname' directly to the platform's library loading function (dlopen, or LoadLibrary). 'mode' allows to override the default flags specified in the constructor, it is ignored on Windows. """ if mode is None: mode = self._mode return self._dlltype(libname, mode) # alias name for backwards compatiblity LoadLibrary = load_library # Helpers for load and load_version - assembles a filename from name and filename if os.name in ("nt", "ce"): # Windows (XXX what about cygwin?) def _plat_load_version(self, name, version, mode): # not sure if this makes sense if version is not None: return self.load(name + version, mode) return self.load(name, mode) _load = load_library elif os.name == "posix" and sys.platform == "darwin": # Mac OS X def _plat_load_version(self, name, version, mode): if version: return self.load("lib%s.%s.dylib" % (name, version), mode) return self.load("lib%s.dylib" % name, mode) def _load(self, libname, mode): # _dyld_find raises ValueError, convert this into OSError try: pathname = _dyld_find(libname) except ValueError: raise OSError("Library %s could not be found" % libname) return self.load_library(pathname, mode) elif os.name == "posix": # Posix def _plat_load_version(self, name, version, mode): if version: return self.load("lib%s.so.%s" % (name, version), mode) return self.load("lib%s.so" % name, mode) _load = load_library else: # Others, TBD def _plat_load_version(self, name, version, mode=None): return self.load(name, mode) _load = load_library def load_version(self, name, version=None, mode=None): """Build a (system dependend) filename from 'name' and 'version', then load and return it. 'name' is the library name without any prefix like 'lib' and suffix like '.so' or '.dylib'. This method should be used if a library is available on different platforms, using the particular naming convention of each platform. 'mode' allows to override the default flags specified in the constructor, it is ignored on Windows. """ return self._plat_load_version(name, version, mode) def find(self, name, mode=None): """Try to find a library, load and return it. 'name' is the library name without any prefix like 'lib', suffix like '.so', '.dylib' or version number (this is the form used for the posix linker option '-l'). 'mode' allows to override the default flags specified in the constructor, it is ignored on Windows. On windows, this method does the same as the 'load' method. On other platforms, this function might call other programs like the compiler to find the library. When using ctypes to write a shared library wrapping, consider using .load() or .load_version() instead. """ for libname in _findLib(name): try: return self.load(libname, mode) except OSError: continue raise OSError("Library %r not found" % name) def __getattr__(self, name): """Load a library via attribute access. Calls .load_version(). The result is cached.""" if name.startswith("_"): raise AttributeError(name) dll = self.load_version(name) setattr(self, name, dll) return dll ################################################################ # test code class CDLL(object): def __init__(self, name, mode): self._handle = dlopen(name, mode) self._name = name def __repr__(self): return "<%s '%s', handle %x at %x>" % \ (self.__class__.__name__, self._name, (self._handle & (sys.maxint*2 + 1)), id(self)) cdll = LibraryLoader(CDLL) def test(): if os.name == "nt": print cdll.msvcrt print cdll.load("msvcrt") # load_version looks more like an artefact: print cdll.load_version("msvcr", "t") print cdll.find("msvcrt") if os.name == "posix": # find and load_version print cdll.find("m") print cdll.find("c") print cdll.load_version("crypto", "0.9.7") # getattr print cdll.m print cdll.bz2 # load if sys.platform == "darwin": print cdll.load("libm.dylib") print cdll.load("libcrypto.dylib") print cdll.load("libSystem.dylib") print cdll.load("System.framework/System") else: print cdll.load("libm.so") print cdll.load("libcrypt.so") print cdll.find("crypt") if __name__ == "__main__": test() --- NEW FILE: decorators.py --- """ This module implements decorators for native api function calls. name_library(name, so_name) cdecl(restype, dllname, argtypes) stdcall(restype, dllname, argtypes) - windows only """ LOGGING = False import os import ctypes def cdecl(restype, dllname, argtypes, logging=False): """cdecl(restype, dllname, argtypes, logging=False) -> decorator. The decorator, when applied to a function, attaches an '_api_' attribute to the function. Calling this attribute calls the function exported from the dll, using the standard C calling convention. restype - result type dll - name or instance of a dll/shared library argtypes - list of argument types logging - if this is True, the result of each function call is printed to stderr. """ def decorate(func): library = ctypes.cdll.find(dllname, False) api = ctypes.CFUNCTYPE(restype, *argtypes)(func.func_name, library) func._api_ = api # The following few lines trigger a pychecker bug, see # https://sourceforge.net/tracker/index.php?func=detail&aid=1114902&group_id=24686&atid=382217 if logging or LOGGING: def f(*args): result = func(*args) print >> sys.stderr, "# function call: %s%s -> %s" % (func.func_name, args, result) return result return f return func return decorate if os.name == "nt": def stdcall(restype, dllname, argtypes, logging=False): """stdcall(restype, dllname, argtypes, logging=False) -> decorator. The decorator, when applied to a function, attaches an '_api_' attribute to the function. Calling this attribute calls the function exported from the dll, using the MS '__stdcall' calling convention. restype - result type dll - name or instance of a dll argtypes - list of argument types logging - if this is True, the result of each function call is printed to stderr. """ def decorate(func): library = ctypes.windll.find(dllname, False) api = ctypes.WINFUNCTYPE(restype, *argtypes)(func.func_name, library) func._api_ = api # The following few lines trigger a pychecker bug, see # https://sourceforge.net/tracker/index.php?func=detail&aid=1114902&group_id=24686&atid=382217 if logging or LOGGING: def f(*args): result = func(*args) print >> sys.stderr, "# function call: %s%s -> %s" % (func.func_name, args, result) return result return f return func return decorate ################################################################ def _test(): import os, sys from ctypes import c_char, c_int, c_ulong, c_double, \ POINTER, create_string_buffer, sizeof if os.name == "nt": from ctypes import WinError #@ stdcall(ctypes.c_ulong, "kernel32", [c_ulong, POINTER(c_char), c_ulong]) def GetModuleFileNameA(handle=0): buf = create_string_buffer(256) if 0 == GetModuleFileNameA._api_(handle, buf, sizeof(buf)): raise WinError() return buf.value GetModuleFileNameA = stdcall(ctypes.c_ulong, "kernel32", [c_ulong, POINTER(c_char), c_ulong])(GetModuleFileNameA) assert(sys.executable == GetModuleFileNameA()) #@ cdecl(c_double, 'libm', [c_double]) def sqrt(value): return sqrt._api_(value) sqrt = cdecl(c_double, 'm', [c_double])(sqrt) assert sqrt(4.0) == 2.0 if __name__ == "__main__": _test() --- NEW FILE: _endian.py --- import sys from ctypes import * _array_type = type(c_int * 3) def _other_endian(typ): """Return the type with the 'other' byte order. Simple types like c_int and so on already have __ctype_be__ and __ctype_le__ attributes which contain the types, for more complicated types only arrays are supported. """ try: return getattr(typ, _OTHER_ENDIAN) except AttributeError: if type(typ) == _array_type: return _other_endian(typ._type_) * typ._length_ raise TypeError("This type does not support other endian: %s" % typ) class _swapped_meta(type(Structure)): def __setattr__(self, attrname, value): if attrname == "_fields_": fields = [] for desc in value: name = desc[0] typ = desc[1] rest = desc[2:] fields.append((name, _other_endian(typ)) + rest) value = fields super(_swapped_meta, self).__setattr__(attrname, value) ################################################################ # Note: The Structure metaclass checks for the *presence* (not the # value!) of a _swapped_bytes_ attribute to determine the bit order in # structures containing bit fields. if sys.byteorder == "little": _OTHER_ENDIAN = "__ctype_be__" LittleEndianStructure = Structure class BigEndianStructure(Structure): """Structure with big endian byte order""" __metaclass__ = _swapped_meta _swappedbytes_ = None elif sys.byteorder == "big": _OTHER_ENDIAN = "__ctype_le__" BigEndianStructure = Structure class LittleEndianStructure(Structure): """Structure with little endian byte order""" __metaclass__ = _swapped_meta _swappedbytes_ = None else: raise RuntimeError("Invalid byteorder") --- NEW FILE: util.py --- # ctypes.util is no longer used. --- NEW FILE: __init__.py --- """create and manipulate C data types in Python""" # special developer support to use ctypes from the CVS sandbox, # without installing it import os as _os, sys as _sys from itertools import chain as _chain _magicfile = _os.path.join(_os.path.dirname(__file__), ".CTYPES_DEVEL") if _os.path.isfile(_magicfile): execfile(_magicfile) del _magicfile __version__ = "0.9.9.4" from _ctypes import Union, Structure, Array from _ctypes import _Pointer from _ctypes import CFuncPtr as _CFuncPtr from _ctypes import __version__ as _ctypes_version try: from _ctypes import RTLD_LOCAL, RTLD_GLOBAL except (ImportError, AttributeError): RTLD_GLOBAL = RTLD_LOCAL = None from _ctypes import ArgumentError from struct import calcsize as _calcsize if __version__ != _ctypes_version: raise Exception, ("Version number mismatch", __version__, _ctypes_version) if _os.name in ("nt", "ce"): from _ctypes import FormatError from _ctypes import FUNCFLAG_CDECL as _FUNCFLAG_CDECL, \ FUNCFLAG_PYTHONAPI as _FUNCFLAG_PYTHONAPI from ctypes._loader import LibraryLoader """ WINOLEAPI -> HRESULT WINOLEAPI_(type) STDMETHODCALLTYPE STDMETHOD(name) STDMETHOD_(type, name) STDAPICALLTYPE """ def create_string_buffer(init, size=None): """create_string_buffer(aString) -> character array create_string_buffer(anInteger) -> character array create_string_buffer(aString, anInteger) -> character array """ if isinstance(init, (str, unicode)): if size is None: size = len(init)+1 buftype = c_char * size buf = buftype() buf.value = init return buf elif isinstance(init, (int, long)): buftype = c_char * init buf = buftype() return buf raise TypeError, init def c_buffer(init, size=None): ## "deprecated, use create_string_buffer instead" ## import warnings ## warnings.warn("c_buffer is deprecated, use create_string_buffer instead", ## DeprecationWarning, stacklevel=2) return create_string_buffer(init, size) _c_functype_cache = {} def CFUNCTYPE(restype, *argtypes): """CFUNCTYPE(restype, *argtypes) -> function prototype. restype: the result type argtypes: a sequence specifying the argument types The function prototype can be called in three ways to create a callable object: prototype(funct) - returns a C callable function calling funct prototype(vtbl_index, method_name[, paramflags]) - a Python callable that calls a COM method prototype(funct_name, dll[, paramflags]) - a Python callable that calls an exported function in a dll """ try: return _c_functype_cache[(restype, argtypes)] except KeyError: class CFunctionType(_CFuncPtr): _argtypes_ = argtypes _restype_ = restype _flags_ = _FUNCFLAG_CDECL _c_functype_cache[(restype, argtypes)] = CFunctionType return CFunctionType if _os.name in ("nt", "ce"): from _ctypes import LoadLibrary as _dlopen from _ctypes import FUNCFLAG_STDCALL as _FUNCFLAG_STDCALL if _os.name == "ce": # 'ce' doesn't have the stdcall calling convention _FUNCFLAG_STDCALL = _FUNCFLAG_CDECL _win_functype_cache = {} def WINFUNCTYPE(restype, *argtypes): # docstring set later (very similar to CFUNCTYPE.__doc__) try: return _win_functype_cache[(restype, argtypes)] except KeyError: class WinFunctionType(_CFuncPtr): _argtypes_ = argtypes _restype_ = restype _flags_ = _FUNCFLAG_STDCALL _win_functype_cache[(restype, argtypes)] = WinFunctionType return WinFunctionType if WINFUNCTYPE.__doc__: WINFUNCTYPE.__doc__ = CFUNCTYPE.__doc__.replace("CFUNCTYPE", "WINFUNCTYPE") elif _os.name == "posix": from _ctypes import dlopen as _dlopen from _ctypes import sizeof, byref, addressof, alignment from _ctypes import _SimpleCData class py_object(_SimpleCData): _type_ = "O" class c_short(_SimpleCData): _type_ = "h" class c_ushort(_SimpleCData): _type_ = "H" class c_long(_SimpleCData): _type_ = "l" class c_ulong(_SimpleCData): _type_ = "L" if _calcsize("i") == _calcsize("l"): # if int and long have the same size, make c_int an alias for c_long c_int = c_long c_uint = c_ulong else: class c_int(_SimpleCData): _type_ = "i" class c_uint(_SimpleCData): _type_ = "I" class c_float(_SimpleCData): _type_ = "f" class c_double(_SimpleCData): _type_ = "d" if _calcsize("l") == _calcsize("q"): # if long and long long have the same size, make c_longlong an alias for c_long c_longlong = c_long c_ulonglong = c_ulong else: class c_longlong(_SimpleCData): _type_ = "q" class c_ulonglong(_SimpleCData): _type_ = "Q" ## def from_param(cls, val): ## return ('d', float(val), val) ## from_param = classmethod(from_param) class c_ubyte(_SimpleCData): _type_ = "B" c_ubyte.__ctype_le__ = c_ubyte.__ctype_be__ = c_ubyte # backward compatibility: ##c_uchar = c_ubyte class c_byte(_SimpleCData): _type_ = "b" c_byte.__ctype_le__ = c_byte.__ctype_be__ = c_byte class c_char(_SimpleCData): _type_ = "c" c_char.__ctype_le__ = c_char.__ctype_be__ = c_char class c_char_p(_SimpleCData): _type_ = "z" class c_void_p(_SimpleCData): _type_ = "P" c_voidp = c_void_p # backwards compatibility (to a bug) # This cache maps types to pointers to them. _pointer_type_cache = {} def POINTER(cls): try: return _pointer_type_cache[cls] except KeyError: pass if type(cls) is str: klass = type(_Pointer)("LP_%s" % cls, (_Pointer,), {}) _pointer_type_cache[id(klass)] = klass return klass else: name = "LP_%s" % cls.__name__ klass = type(_Pointer)(name, (_Pointer,), {'_type_': cls}) _pointer_type_cache[cls] = klass return klass try: from _ctypes import set_conversion_mode except ImportError: pass else: if _os.name in ("nt", "ce"): set_conversion_mode("mbcs", "ignore") else: set_conversion_mode("ascii", "strict") class c_wchar_p(_SimpleCData): _type_ = "Z" class c_wchar(_SimpleCData): _type_ = "u" POINTER(c_wchar).from_param = c_wchar_p.from_param #_SimpleCData.c_wchar_p_from_param def create_unicode_buffer(init, size=None): """create_unicode_buffer(aString) -> character array create_unicode_buffer(anInteger) -> character array create_unicode_buffer(aString, anInteger) -> character array """ if isinstance(init, (str, unicode)): if size is None: size = len(init)+1 buftype = c_wchar * size buf = buftype() buf.value = init return buf elif isinstance(init, (int, long)): buftype = c_wchar * init buf = buftype() return buf raise TypeError, init POINTER(c_char).from_param = c_char_p.from_param #_SimpleCData.c_char_p_from_param # XXX Deprecated def SetPointerType(pointer, cls): if _pointer_type_cache.get(cls, None) is not None: raise RuntimeError, \ "This type already exists in the cache" if not _pointer_type_cache.has_key(id(pointer)): raise RuntimeError, \ "What's this???" pointer.set_type(cls) _pointer_type_cache[cls] = pointer del _pointer_type_cache[id(pointer)] def pointer(inst): return POINTER(type(inst))(inst) # XXX Deprecated def ARRAY(typ, len): return typ * len ################################################################ class CDLL(object): """An instance of this class represents a loaded dll/shared library, exporting functions using the standard C calling convention (named 'cdecl' on Windows). The exported functions can be accessed as attributes, or by indexing with the function name. Examples: <obj>.qsort -> callable object <obj>['qsort'] -> callable object Calling the functions releases the Python GIL during the call and reaquires it afterwards. """ class _FuncPtr(_CFuncPtr): _flags_ = _FUNCFLAG_CDECL _restype_ = c_int # default, can be overridden in instances def __init__(self, name, mode=RTLD_LOCAL, handle=None): self._name = name if handle is None: self._handle = _dlopen(self._name, mode) else: self._handle = handle def __repr__(self): return "<%s '%s', handle %x at %x>" % \ (self.__class__.__name__, self._name, (self._handle & (_sys.maxint*2 + 1)), id(self)) def __getattr__(self, name): if name.startswith('__') and name.endswith('__'): raise AttributeError, name return self.__getitem__(name) def __getitem__(self, name): func = self._FuncPtr(name, self) func.__name__ = name setattr(self, name, func) return func class PyDLL(CDLL): """This class represents the Python library itself. It allows to access Python API functions. The GIL is not released, and Python exceptions are handled correctly. """ class _FuncPtr(_CFuncPtr): _flags_ = _FUNCFLAG_CDECL | _FUNCFLAG_PYTHONAPI _restype_ = c_int # default, can be overridden in instances if _os.name in ("nt", "ce"): class WinDLL(CDLL): """This class represents a dll exporting functions using the Windows stdcall calling convention. """ class _FuncPtr(_CFuncPtr): _flags_ = _FUNCFLAG_STDCALL _restype_ = c_int # default, can be overridden in instances # XXX Hm, what about HRESULT as normal parameter? # Mustn't it derive from c_long then? from _ctypes import _check_HRESULT, _SimpleCData class HRESULT(_SimpleCData): _type_ = "l" # _check_retval_ is called with the function's result when it # is used as restype. It checks for the FAILED bit, and # raises a WindowsError if it is set. # # The _check_retval_ method is implemented in C, so that the # method definition itself is not included in the traceback # when it raises an error - that is what we want (and Python # doesn't have a way to raise an exception in the caller's # frame). _check_retval_ = _check_HRESULT class OleDLL(CDLL): """This class represents a dll exporting functions using the Windows stdcall calling convention, and returning HRESULT. HRESULT error values are automatically raised as WindowsError exceptions. """ class _FuncPtr(_CFuncPtr): _flags_ = _FUNCFLAG_STDCALL _restype_ = HRESULT cdll = LibraryLoader(CDLL) pydll = LibraryLoader(PyDLL) if _os.name in ("nt", "ce"): pythonapi = PyDLL("python dll", None, _sys.dllhandle) elif _sys.platform == "cygwin": pythonapi = PyDLL("libpython%d.%d.dll" % _sys.version_info[:2]) else: pythonapi = PyDLL(None) if _os.name in ("nt", "ce"): windll = LibraryLoader(WinDLL) oledll = LibraryLoader(OleDLL) if _os.name == "nt": GetLastError = windll.kernel32.GetLastError else: GetLastError = windll.coredll.GetLastError def WinError(code=None, descr=None): if code is None: code = GetLastError() if descr is None: descr = FormatError(code).strip() return WindowsError(code, descr) _pointer_type_cache[None] = c_void_p # functions from _ctypes import _memmove_addr, _memset_addr, _string_at_addr, cast if sizeof(c_uint) == sizeof(c_void_p): c_size_t = c_uint elif sizeof(c_ulong) == sizeof(c_void_p): c_size_t = c_ulong ## void *memmove(void *, const void *, size_t); memmove = CFUNCTYPE(c_void_p, c_void_p, c_void_p, c_size_t)(_memmove_addr) ## void *memset(void *, int, size_t) memset = CFUNCTYPE(c_void_p, c_void_p, c_int, c_size_t)(_memset_addr) _string_at = CFUNCTYPE(py_object, c_void_p, c_int)(_string_at_addr) def string_at(ptr, size=0): """string_at(addr[, size]) -> string Return the string at addr.""" return _string_at(ptr, size) try: from _ctypes import _wstring_at_addr except ImportError: pass else: _wstring_at = CFUNCTYPE(py_object, c_void_p, c_int)(_wstring_at_addr) def wstring_at(ptr, size=0): """wstring_at(addr[, size]) -> string Return the string at addr.""" return _wstring_at(ptr, size) from decorators import cdecl if _os.name == "nt": from decorators import stdcall if _os.name == "nt": # COM stuff def DllGetClassObject(rclsid, riid, ppv): # First ask ctypes.com.server than comtypes.server for the # class object. # trick py2exe by doing dynamic imports result = -2147221231 # CLASS_E_CLASSNOTAVAILABLE try: ctcom = __import__("ctypes.com.server", globals(), locals(), ['*']) except ImportError: pass else: result = ctcom.DllGetClassObject(rclsid, riid, ppv) if result == -2147221231: # CLASS_E_CLASSNOTAVAILABLE try: ccom = __import__("comtypes.server", globals(), locals(), ['*']) except ImportError: pass else: result = ccom.DllGetClassObject(rclsid, riid, ppv) return result def DllCanUnloadNow(): # First ask ctypes.com.server than comtypes.server if we can unload or not. # trick py2exe by doing dynamic imports result = 0 # S_OK try: ctcom = __import__("ctypes.com.server", globals(), locals(), ['*']) except ImportError: pass else: result = ctcom.DllCanUnloadNow() if result != 0: # != S_OK return result try: ccom = __import__("comtypes.server", globals(), locals(), ['*']) except ImportError: return result try: return ccom.DllCanUnloadNow() except AttributeError: pass return result from ctypes._endian import BigEndianStructure, LittleEndianStructure # Fill in specifically-sized types c_int8 = c_byte c_uint8 = c_ubyte for kind in [c_short, c_int, c_long, c_longlong]: if sizeof(kind) == 2: c_int16 = kind elif sizeof(kind) == 4: c_int32 = kind elif sizeof(kind) == 8: c_int64 = kind for kind in [c_ushort, c_uint, c_ulong, c_ulonglong]: if sizeof(kind) == 2: c_uint16 = kind elif sizeof(kind) == 4: c_uint32 = kind elif sizeof(kind) == 8: c_uint64 = kind del(kind) --- NEW FILE: wintypes.py --- from ctypes import * DWORD = c_ulong WORD = c_ushort BYTE = c_byte ULONG = c_ulong LONG = c_long LARGE_INTEGER = c_longlong ULARGE_INTEGER = c_ulonglong HANDLE = c_ulong # in the header files: void * HWND = HANDLE HDC = HANDLE HMODULE = HANDLE HINSTANCE = HANDLE HRGN = HANDLE HTASK = HANDLE HKEY = HANDLE HPEN = HANDLE HGDIOBJ = HANDLE HMENU = HANDLE LCID = DWORD WPARAM = c_uint LPARAM = c_long BOOL = c_long VARIANT_BOOL = c_short LPCOLESTR = LPOLESTR = OLESTR = c_wchar_p LPCWSTR = LPWSTR = c_wchar_p LPCSTR = LPSTR = c_char_p class RECT(Structure): _fields_ = [("left", c_long), ("top", c_long), ("right", c_long), ("bottom", c_long)] RECTL = RECT class POINT(Structure): _fields_ = [("x", c_long), ("y", c_long)] POINTL = POINT class SIZE(Structure): _fields_ = [("cx", c_long), ("cy", c_long)] SIZEL = SIZE def RGB(red, green, blue): return red + (green << 8) + (blue << 16) class FILETIME(Structure): _fields_ = [("dwLowDateTime", DWORD), ("dwHighDateTime", DWORD)] class MSG(Structure): _fields_ = [("hWnd", HWND), ("message", c_uint), ("wParam", WPARAM), ("lParam", LPARAM), ("time", DWORD), ("pt", POINT)] MAX_PATH = 260 class WIN32_FIND_DATAA(Structure): _fields_ = [("dwFileAttributes", DWORD), ("ftCreationTime", FILETIME), ("ftLastAccessTime", FILETIME), ("ftLastWriteTime", FILETIME), ("nFileSizeHigh", DWORD), ("nFileSizeLow", DWORD), ("dwReserved0", DWORD), ("dwReserved1", DWORD), ("cFileName", c_char * MAX_PATH), ("cAlternameFileName", c_char * 14)] class WIN32_FIND_DATAW(Structure): _fields_ = [("dwFileAttributes", DWORD), ("ftCreationTime", FILETIME), ("ftLastAccessTime", FILETIME), ("ftLastWriteTime", FILETIME), ("nFileSizeHigh", DWORD), ("nFileSizeLow", DWORD), ("dwReserved0", DWORD), ("dwReserved1", DWORD), ("cFileName", c_wchar * MAX_PATH), ("cAlternameFileName", c_wchar * 14)] |
From: Thomas H. <th...@us...> - 2006-03-03 20:11:23
|
Update of /cvsroot/ctypes/ctypes/ctypes/macholib In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5851 Added Files: framework.py fetch_macholib.bat fetch_macholib dylib.py dyld.py __init__.py README.ctypes .cvsignore Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: .cvsignore --- *.pyc *.pyo .svn --- NEW FILE: fetch_macholib --- #!/bin/sh svn export --force http://svn.red-bean.com/bob/macholib/trunk/macholib/ . --- NEW FILE: README.ctypes --- Files in this directory from from Bob Ippolito's py2app. License: Any components of the py2app suite may be distributed under the MIT or PSF open source licenses. This is version 1.0, SVN revision 789, from 2006/01/25. The main repository is http://svn.red-bean.com/bob/macholib/trunk/macholib/ --- NEW FILE: __init__.py --- """ Enough Mach-O to make your head spin. See the relevant header files in /usr/include/mach-o And also Apple's documentation. """ __version__ = '1.0' --- NEW FILE: dyld.py --- """ dyld emulation """ import os from framework import framework_info from dylib import dylib_info from itertools import * __all__ = [ 'dyld_find', 'framework_find', 'framework_info', 'dylib_info', ] # These are the defaults as per man dyld(1) # DEFAULT_FRAMEWORK_FALLBACK = [ os.path.expanduser("~/Library/Frameworks"), "/Library/Frameworks", "/Network/Library/Frameworks", "/System/Library/Frameworks", ] DEFAULT_LIBRARY_FALLBACK = [ os.path.expanduser("~/lib"), "/usr/local/lib", "/lib", "/usr/lib", ] def ensure_utf8(s): """Not all of PyObjC and Python understand unicode paths very well yet""" if isinstance(s, unicode): return s.encode('utf8') return s def dyld_env(env, var): if env is None: env = os.environ rval = env.get(var) if rval is None: return [] return rval.split(':') def dyld_image_suffix(env=None): if env is None: env = os.environ return env.get('DYLD_IMAGE_SUFFIX') def dyld_framework_path(env=None): return dyld_env(env, 'DYLD_FRAMEWORK_PATH') def dyld_library_path(env=None): return dyld_env(env, 'DYLD_LIBRARY_PATH') def dyld_fallback_framework_path(env=None): return dyld_env(env, 'DYLD_FALLBACK_FRAMEWORK_PATH') def dyld_fallback_library_path(env=None): return dyld_env(env, 'DYLD_FALLBACK_LIBRARY_PATH') def dyld_image_suffix_search(iterator, env=None): """For a potential path iterator, add DYLD_IMAGE_SUFFIX semantics""" suffix = dyld_image_suffix(env) if suffix is None: return iterator def _inject(iterator=iterator, suffix=suffix): for path in iterator: if path.endswith('.dylib'): yield path[:-len('.dylib')] + suffix + '.dylib' else: yield path + suffix yield path return _inject() def dyld_override_search(name, env=None): # If DYLD_FRAMEWORK_PATH is set and this dylib_name is a # framework name, use the first file that exists in the framework # path if any. If there is none go on to search the DYLD_LIBRARY_PATH # if any. framework = framework_info(name) if framework is not None: for path in dyld_framework_path(env): yield os.path.join(path, framework['name']) # If DYLD_LIBRARY_PATH is set then use the first file that exists # in the path. If none use the original name. for path in dyld_library_path(env): yield os.path.join(path, os.path.basename(name)) def dyld_executable_path_search(name, executable_path=None): # If we haven't done any searching and found a library and the # dylib_name starts with "@executable_path/" then construct the # library name. if name.startswith('@executable_path/') and executable_path is not None: yield os.path.join(executable_path, name[len('@executable_path/'):]) def dyld_default_search(name, env=None): yield name framework = framework_info(name) if framework is not None: fallback_framework_path = dyld_fallback_framework_path(env) for path in fallback_framework_path: yield os.path.join(path, framework['name']) fallback_library_path = dyld_fallback_library_path(env) for path in fallback_library_path: yield os.path.join(path, os.path.basename(name)) if framework is not None and not fallback_framework_path: for path in DEFAULT_FRAMEWORK_FALLBACK: yield os.path.join(path, framework['name']) if not fallback_library_path: for path in DEFAULT_LIBRARY_FALLBACK: yield os.path.join(path, os.path.basename(name)) def dyld_find(name, executable_path=None, env=None): """ Find a library or framework using dyld semantics """ name = ensure_utf8(name) executable_path = ensure_utf8(executable_path) for path in dyld_image_suffix_search(chain( dyld_override_search(name, env), dyld_executable_path_search(name, executable_path), dyld_default_search(name, env), ), env): if os.path.isfile(path): return path raise ValueError, "dylib %s could not be found" % (name,) def framework_find(fn, executable_path=None, env=None): """ Find a framework using dyld semantics in a very loose manner. Will take input such as: Python Python.framework Python.framework/Versions/Current """ try: return dyld_find(fn, executable_path=executable_path, env=env) except ValueError, e: pass fmwk_index = fn.rfind('.framework') if fmwk_index == -1: fmwk_index = len(fn) fn += '.framework' fn = os.path.join(fn, os.path.basename(fn[:fmwk_index])) try: return dyld_find(fn, executable_path=executable_path, env=env) except ValueError: raise e def test_dyld_find(): env = {} assert dyld_find('libSystem.dylib') == '/usr/lib/libSystem.dylib' assert dyld_find('System.framework/System') == '/System/Library/Frameworks/System.framework/System' if __name__ == '__main__': test_dyld_find() --- NEW FILE: framework.py --- """ Generic framework path manipulation """ import re __all__ = ['framework_info'] STRICT_FRAMEWORK_RE = re.compile(r"""(?x) (?P<location>^.*)(?:^|/) (?P<name> (?P<shortname>\w+).framework/ (?:Versions/(?P<version>[^/]+)/)? (?P=shortname) (?:_(?P<suffix>[^_]+))? )$ """) def framework_info(filename): """ A framework name can take one of the following four forms: Location/Name.framework/Versions/SomeVersion/Name_Suffix Location/Name.framework/Versions/SomeVersion/Name Location/Name.framework/Name_Suffix Location/Name.framework/Name returns None if not found, or a mapping equivalent to: dict( location='Location', name='Name.framework/Versions/SomeVersion/Name_Suffix', shortname='Name', version='SomeVersion', suffix='Suffix', ) Note that SomeVersion and Suffix are optional and may be None if not present """ is_framework = STRICT_FRAMEWORK_RE.match(filename) if not is_framework: return None return is_framework.groupdict() def test_framework_info(): def d(location=None, name=None, shortname=None, version=None, suffix=None): return dict( location=location, name=name, shortname=shortname, version=version, suffix=suffix ) assert framework_info('completely/invalid') is None assert framework_info('completely/invalid/_debug') is None assert framework_info('P/F.framework') is None assert framework_info('P/F.framework/_debug') is None assert framework_info('P/F.framework/F') == d('P', 'F.framework/F', 'F') assert framework_info('P/F.framework/F_debug') == d('P', 'F.framework/F_debug', 'F', suffix='debug') assert framework_info('P/F.framework/Versions') is None assert framework_info('P/F.framework/Versions/A') is None assert framework_info('P/F.framework/Versions/A/F') == d('P', 'F.framework/Versions/A/F', 'F', 'A') assert framework_info('P/F.framework/Versions/A/F_debug') == d('P', 'F.framework/Versions/A/F_debug', 'F', 'A', 'debug') if __name__ == '__main__': test_framework_info() --- NEW FILE: fetch_macholib.bat --- svn export --force http://svn.red-bean.com/bob/macholib/trunk/macholib/ . --- NEW FILE: dylib.py --- """ Generic dylib path manipulation """ import re __all__ = ['dylib_info'] DYLIB_RE = re.compile(r"""(?x) (?P<location>^.*)(?:^|/) (?P<name> (?P<shortname>\w+?) (?:\.(?P<version>[^._]+))? (?:_(?P<suffix>[^._]+))? \.dylib$ ) """) def dylib_info(filename): """ A dylib name can take one of the following four forms: Location/Name.SomeVersion_Suffix.dylib Location/Name.SomeVersion.dylib Location/Name_Suffix.dylib Location/Name.dylib returns None if not found or a mapping equivalent to: dict( location='Location', name='Name.SomeVersion_Suffix.dylib', shortname='Name', version='SomeVersion', suffix='Suffix', ) Note that SomeVersion and Suffix are optional and may be None if not present. """ is_dylib = DYLIB_RE.match(filename) if not is_dylib: return None return is_dylib.groupdict() def test_dylib_info(): def d(location=None, name=None, shortname=None, version=None, suffix=None): return dict( location=location, name=name, shortname=shortname, version=version, suffix=suffix ) assert dylib_info('completely/invalid') is None assert dylib_info('completely/invalide_debug') is None assert dylib_info('P/Foo.dylib') == d('P', 'Foo.dylib', 'Foo') assert dylib_info('P/Foo_debug.dylib') == d('P', 'Foo_debug.dylib', 'Foo', suffix='debug') assert dylib_info('P/Foo.A.dylib') == d('P', 'Foo.A.dylib', 'Foo', 'A') assert dylib_info('P/Foo_debug.A.dylib') == d('P', 'Foo_debug.A.dylib', 'Foo_debug', 'A') assert dylib_info('P/Foo.A_debug.dylib') == d('P', 'Foo.A_debug.dylib', 'Foo', 'A', 'debug') if __name__ == '__main__': test_dylib_info() |
From: Thomas H. <th...@us...> - 2006-03-03 20:08:10
|
Update of /cvsroot/ctypes/ctypes In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv3363 Added Files: winssh.txt test-cf.py setup.py ctypes-dev.el README.txt README.CVS NEWS.txt MANIFEST.in LICENSE.txt ChangeLog ANNOUNCE ACKS .cvsignore Log Message: Moving files from branch_1_0 to HEAD. --- NEW FILE: .cvsignore --- *.c *.h *.ilk *.log *.pdb *.pyc *.pyo *.tlb *.zip MANIFEST _ctypes.pyd _ctypes_d.pyd archive build dist extensions test.output comtypes --- NEW FILE: ctypes-dev.el --- ;; In the ~/init.el file, write: ;; (setq load-path (cons "c:\\sf\\ctypes" load-path) ;; (require 'ctypes-dev) ;; ;; Try M-x customize-group ctypes-dev ;; ;; Based on twisted-dev.el (provide 'ctypes-dev) (defgroup ctypes-dev nil "Various ctypes development utilities" :group 'development) (defcustom ctypes-dev-directory "c:\\sf\\ctypes_dist" "ctypes root directory" :group 'ctypes-dev :type 'string) (setenv "PYTHONPATH" ctypes-dev-directory) (defmacro with-cd (dirname &rest code) `(let ((old-dirname default-directory) (start-buffer (current-buffer))) (cd ,dirname) (unwind-protect (progn ,@code) (let ((end-buffer (current-buffer))) ;; (cd ,dirname) (set-buffer start-buffer) (cd old-dirname) (set-buffer end-buffer))))) (defun ctypes-dev-build () (interactive) (with-cd ctypes-dev-directory (compile "python setup.py build"))) (defun ctypes-dev-build-debug () (interactive) (with-cd ctypes-dev-directory (compile "py_d setup.py build -g"))) (defun ctypes-dev-rebuild () (interactive) (with-cd ctypes-dev-directory (compile "python setup.py build -f"))) (defun ctypes-dev-test () (interactive) (with-cd (concat ctypes-dev-directory "\\unittests") (compile "python runtests.py"))) (defun ctypes-dev-test-debug () (interactive) (with-cd (concat ctypes-dev-directory "\\unittests") (compile "py_d runtests.py"))) (defun comtypes-test () (interactive) (with-cd (concat ctypes-dev-directory "\\comtypes\\unittests") (compile "python runtests.py"))) (defun comtypes-test-debug () (interactive) (with-cd (concat ctypes-dev-directory "\\comtypes\\unittests") (compile "py_d runtests.py"))) (define-minor-mode ctypes-dev-mode "Toggle ctypes-dev mode. With no argument, this command toggles the mode. Non-null prefix argument turns on the mode. Null prefix argument turns off the mode." ;; The initial value. nil ;; The indicator for the mode line. " ctypes" ;; The minor mode bindings. '( ;; ([f6] . ctypes-dev-genapidoc) ;; ([f7] . ctypes-dev-gendoc) ('(shift f8) . ctypes-dev-build-debug) ([f8] . ctypes-dev-build) ('(shift f9) . ctypes-dev-test-debug) ([f9] . ctypes-dev-test) ([f10] . comtypes-test) ('(shift f10) . comtypes-test-debug) ;; ([f11] . ctypes-dev-grep) ;; ([f12] . ctypes-dev-gendocs) )) (add-hook 'find-file-hooks (lambda () (let ((full-ctypes-path (expand-file-name ctypes-dev-directory))) (if (> (length (buffer-file-name)) (length full-ctypes-path)) (if (string= (substring (buffer-file-name) 0 (length full-ctypes-path)) full-ctypes-path) (ctypes-dev-mode) ))))) ;(add-hook ; 'python-mode-hook ; (lambda () ; (ctypes-dev-mode t))) --- NEW FILE: winssh.txt --- This file was originally here: http://www.python.org/dev/winssh.txt I grabbed it before it was removed (Python core development doesn't use CVS anymore, but other projects do!). Thomas Heller, 11/2005 Setting up a cmdline CVS to work with SourceForge under Windows --------------------------------------------------------------- 28-Jun-2000 Original by Andy Robinson (an...@re...) 03-Jul-2000 Modified by Tim Peters (ti...@ms...) 16-Aug-2000 Modified by Riaan Booysen (riaan@e.co.za) 25-Aug-2000 Modified by Tim Peters (ti...@ms...) 1. Get ftp.reportlab.com/tools/cvs-1.10-win.zip ftp.reportlab.com/tools/ssh-1.2.14-win32bin.zip (copied from somewhere obscure for safety, I forget where) 2. Unzip these to a location on your path. Type 'cvs' and 'ssh' from somewhere else to verify. 3. Choose where to keep your CVS projects; let's assume C:\Code 4. Create a subdirectory C:\Code\.ssh (yes, dot-ssh) 5. (see #8 for an alternative) Create two environment variables: HOME=C:\Code CVS_RSH=ssh HOME must point to the directory above your .ssh directory. On Win9x, this can be done in a batch file or autoexec.bat; e.g., set HOME=c:\Code set CVS_RSH=ssh Run the batch file, or reboot if you're using autoexec.bat. On NT or 2000, go to Control Panel | System | Environment and set them at either user or machine level. 6. If not done so, get a Sourceforge account and a project you can log in to. 7. OPTIONAL (& if you skip this now, you can do it later if you change your mind). If you want to avoid typing in your SourceForge password before every CVS operation, generate the ssh public and private identity keys like this: ssh-keygen -C $KEY -f C:\Code\.ssh\identity where $KEY is just some identifier (like your name or email address; this is not used for authentication, it's just stored in the public identity file as a reminder to you why you created this key). Note that you must use -f! ssh-keygen fails to work without it on Windows. When asked for a passphrase, security experts will tell you to choose a long and hard-to-guess string. But then you have to type *that* all the time instead of your SourceForge password. If you just hit ENTER (leave the passphrase empty), you won't be bothered with SourceForge passwords or ssh passphrases again. This is a security tradeoff only you can make. If in doubt, ChOOzAl0Ng&HaRDtoGUessSTr1Ng. ssh-keygen creates two files under .ssh\: identity This is your private key, and is a binary file. NEVER reveal it to anyone. Do NOT share your .ssh directory across a network either. The scheme is only as secure as this file. identity.pub This is your public key, a text file, full of lots of digits and the mnemonic $KEY you gave to ssh-keygen. This file can be shared freely, and indeed must be shared for the scheme to be of any use. On your SourceForge account page, in the 'Shell Account Information' section click the [Edit Keys] link. Copy/paste the contents of the generated identity.pub file as one line into the Authorized Keys text box. After the next cron job (max 6 hours) your information should be updated. 8. Teach SSH about your project's home, by doing ssh -l $USERNAME $MYPROJECT.sourceforge.net where $USERNAME is your SourceForge login name and $MYPROJECT your SourceForge project name. You'll see Host "$MYPROJECT.sourceforge.net" added to the list of known hosts. and then Creating random seed file ~/.ssh/random_seed This may take a while. After a while it will prompt for a password. Type your SourceForge password and hit ENTER. After some SourceForge msgs scroll by, you'll be left at a SourceForge shell prompt. Type exit and hit ENTER. Now you're back at the DOS prompt. 9. You will need either a lengthy command line or a batch file for each sourceforge project. I set cvsroot in a batch file in my 'c:\code' directory, and have one such file for each CVS project I use (about ten of them!): set CVSROOT=:ext:$USERNAME@cvs.$MYPROJECT.sourceforge.net:/cvsroot/$DIRNAME where $USERNAME and $MYPROJECT are again your SourceForge login and project names, and $DIRNAME is the top-level directory in the SourceForge CVS tree; a project can have several, but usually there is just one. Note: you can keep HOME and CVS_RSH out of your permanent environment (see #5) by adding those definitions to this batch file instead. 10. Execute this batch file. You can now go to C:\Code and do cvs -z7 checkout $MYPROJECT (z7 means 'compress network traffic', handy over dialup lines) 11. From now on, just use CVS normally, running this batch file first each time you bring up a DOS box you're going to use for CVS work. Note: If you did not follow step 7, you'll be asked for your password each time you enter a CVS command. I wouldn't survive without Karl Fogel's book "Open Source Development with CVS", Coriolis Press. The CVS reference material (about 225 printed pages!) from this book is available for free download from http://cvsbook.red-bean.com/ Footnote: for anonymous checkout, I think you just omit the 'my_user_name@' part from the CVSROOT variable. I hope this helps; let me know if people have any problems with the instructions. - Andy Robinson ReportLab --- NEW FILE: ChangeLog --- 2006-03-03 Thomas Heller <th...@py...> * ctypes/__init__.py, ctypes/test/test_sizes.py: Added c_int8, c_int16, c_int32, c_int64, c_uint8, c_uint16, c_uint32, c_uint64 types. Patch and unittest provided by Joe Wreschnig. * (Repository): Removed the codegenerator in ctypes/wrap completely. The last state has been tagged in CVS as 'BEFORE_REMOVAL'. It will be revived later - not yet sure where. * Changed the version number to 0.9.9.4. 2006-03-01 Thomas Heller <th...@py...> * (Repository): Removed the samples subdirectory completely, because it has become out of sync. * (Repository): Moved the ctypes.wintypes module into the ctypes/ directory, got rid of the platform specific modules magic in setup.py [...1096 lines suppressed...] no two conversions take place. This is now used by SimpleType_from_param(), byref(), and Pointer_as_parameter(), and is understood by ConvParam(). In the long run this should be the only thing (besides primitive Python data types with trivial conversions) used by ConvParam(). Also ConvParam should probably *return* these things. 2003-01-17 Thomas Heller <th...@py...> * source/_ctypes.c: Rewrite of SimpleType_from_param complete. unittests/test_parameters.py shows that it does the right things in most cases. * (Repository): Moved everything from local CVS to the SF repository, and restructured the directories. --- NEW FILE: MANIFEST.in --- # standard files include ACKS ANNOUNCE ChangeLog MANIFEST MANIFEST.in LICENSE.txt NEWS.txt README* # support files for development include ctypes-dev.el include ctypes/.CTYPES_DEVEL include setup.py include test-cf.py include setup.cfg # libffi build files include source/libffi/aclocal.m4 include source/libffi/config.guess include source/libffi/config.sub include source/libffi/configure include source/libffi/configure.ac include source/libffi/fficonfig.h.in include source/libffi/fficonfig.py.in include source/libffi/install-sh include source/libffi/LICENSE include source/libffi/README # all source files recursive-include source *.c *.h *.S *.asm *.in # windows CE project files include wince/_ctypes.vcw wince/_ctypes.vcp wince/_ctypes_test.vcp # docs/manual include docs/manual/*.txt include docs/manual/*.html --- NEW FILE: NEWS.txt --- ctypes News - http://starship.python.net/crew/theller/ctypes.html Changes in 0.9.1 ================ ctypes 0.9.1 should be fully compatible again with Gary Bishop's readline module which is also used by IPython. ctypes changes The internal conversions that ctypes does between unicode and strings can now use a specified encoding and error handling. A set_conversion_mode() function allows to set them, it returns the previous values. The inital values are ('mbcs', 'ignore') on Windows, and ('ascii', 'strict') on other systems. When internal processing of an argument for a function call fails, the new ctypes.ArgumentError is raised. CDLL and its subclasses now accept an optional second handle parameter. If this is supplied, it is used instead of calling LoadLibrary() or dlopen() to get one. Sometimes objects have been freed too early when calling functions where argtypes have been set. Fixed the create_unicode_buffer function - it was returning c_char arrays instead of c_wchar arrays. Both create_string_buffer and create_unicode_buffer can now be called with string and unicode instances, they will do the needed conversions themselves. ctypes now allows calling Python C api functions. The 'pythonapi' symbol should be used to access these functions, this will automatically use the correct calling convention and exception handling. The 'py_object' type is the ctypes variant of 'PyObject *'. This feature should also work if you are using a static python build. It is now possible to call cdecl functions with more arguments than the length of the argtypes sequence specifies - this allows to provide functions like sprintf() with a proper prototype. It is now possible to create strings or unicode strings if you have the integer address by calling c_char_p(address) or c_wchar_p(address). Integers can also be assigned to structure fields of type c_char_p and c_wchar_p. c_char_p and c_wchar_p both accept strings and unicode strings - if needed they are encoded or decoded using 'strict' error handling. The _ctypes.call_function function, although private and deprecated, has been put back in - it is used by Gary Bishop's readline module. Array and pointer instances now support slicing, for pointers only getslice is implemented (setslice is too dangerous, probably). Slices are represented as lists of the elements, except for character and unicode character pointer and arrays, where strings resp. unicode strings are used instead. On windows, the include files were missing from the source distribution. The alignment function was not exported by the ctypes module. It returns the alignment requirements in bytes of a type or instance. ctypes.com changes Applied a patch from Bruce Dodson which fixes an infinite loop in readtlb.py if a typelib references types defined in another typelib. readtlb still generates bad code for such cases, but the results could be edited by hand if the dependencies can be sorted out. ctypes now caches the types that WINFUNCTYPE and CFUNCTYPE creates, to avoid unneeeded creation of classes. This makes importing files containing a lot of COM interfaces (like the ones that the readtlb tool generates) a lot (10 x) faster. COM servers now print a short usage message when they are run without the /regserver or /unregserver flag. VARIANT does now handle the COM DATE type (VT_DATE) as Python datetime. VARIANT now handles integers and longs correctly - if longs are too large they are stored as doubles (VT_R8). Integers are now stored as VT_I4 instead of VT_INT. Cache the types that WINFUNCTYPE and CFUNCTYPE creates, to avoid creation of a lot of similar classes. Rearrange the code to use try:except: instead of dict.get(xxx, None), the former is faster if lookup mostly succeeds - as is the case for POINTER imo. This makes importing large COM files created by readtlb a lot faster, since WINFUNCTYPE is called for every COM method. The python wrapper for mshtml.tlb, which contains nearly 600 interfaces, now imports in 3 seconds instead of 40! Array and POINTER instance now support slicing, for POINTER only getslice is implemented (setslice is too dangerous, probably). Slices are accepted or returned as lists of the elements, except for character and unicode character pointer and arrays, where strings resp. unicode strings are used - much more convenient. Changes in 0.9.0 ================ ctypes now requires Python 2.3 or higher, Python 2.2 is no longer supported. The big change is that ctypes now uses the same code base on all platforms, many, many bug should have been fixed this way on non-windows systems. The destribution now contains libffi, no need to find, download, build and install a compatible version. There have been lots of improvements and additions both to ctypes itself, and to the ctypes.com windows framework, too many to remember now and document here. Most prominent additions to ctypes.com are: A ctypes.com.client module supporting dynamic dispatch An internet explorer toolband sample Many improvements to the stoplite sample Other Versions: no news recorded in this file! Please see the CVS commit messages. Version 0.4.0, 2003-02-07: This an intermediate release, there is still a lot to be done. Changes: ctypes works with Python 2.2 and Python 2.3 now. Structure and Union fields have now readonly .size and .offset properties, see the docs. POINTER instances can now be indexed as if they point to arrays of objects instead of only a single object. CFunction instances now have a .from_param class method. (This is the protocol which allows to validate and convert function call arguments from Python to C - in other words, you can now use a CFunction subclass in the argtype attribute for a function from a DLL to specify the type of the callback function. Does anyone understand this?) Argument conversion from Python to C is somewhat faster now. I added a lot of unittests, which not only check for bugs, but also 'describe the current behaviour'. Unittest rocks! Lots and lots of bugs and potential crashes have been fixed: Alignment and sizes of structures and unions is now correct as far as I can see. Assigning Python numbers to mutable integer types (c_short, c_int, c_long and so on) now correctly checks for valid range, you can no longer assign a negative Python number to an unsigned C data type for example. General News: I moved the sources from local CVS to SourceForge CVS repository. Version 0.3.5, 2003-01-14: Runs under linux now, and hopefully also other systems where libffi works. More changes, like enabling the Python garbage collector on CFunction objects. Version 0.2.0, 2002-11-12: Allows to assign callables to functions' restype attribute. Refactored _CallProc, for much clearer and less buggy code. Plugged some gross memory leaks. License is MIT, not BSD. --- NEW FILE: ACKS --- Acknowledgements ---------------- This list is probably incomplete, but I would like to thank everybody who contributed code, patches, bug reports, encouragement, ... Apologies if I have forgotten anyone. -- Thomas Heller ---------------- Nick Adams Robin Becker Dave Brueck Hye-Shik Chang Greg Chapman David Creemer Andreas Daegert Bruce Dodson Luke Dunstan Chuck Esterbrook Mike Fletcher David Foster Richie Hindle Shane Holloway Andrew MacIntyre Paul Moore Ronald Oussoren Henk Punt Jimmy Retzlaff Just van Rossum Alexander Semenov Wolfgang Strobl Niki Spahiev --- NEW FILE: test-cf.py --- # Script to build and test ctypes on the compile-farm servers. # Accepts the same arguments as setup.py hostinfo = [ # Not python 2.3 or newer: ## ("x86-openbsd1", "/usr/local/bin/python -u"), ("x86-solaris1", "env PATH=/opt/SUNWspro/bin:/usr/local/bin:/usr/local/sbin:$PATH python -u"), ("x86-linux1", "/usr/bin/python -u"), ("x86-linux2", "/usr/bin/python -u"), # Host key verification failed ("x86-freebsd1", "/usr/local/bin/python -u"), # ImportError: _ctypes.so: Undefined PLT symbol "PyGILState_Ensure" # Python without threading module??? ("x86-netbsd1", "/usr/pkg/bin/python2.3 -u"), ("amd64-linux1", "/usr/bin/python -u"), # Same platform as the previous one: ## ("amd64-linux2", "/usr/bin/python -u"), # Host key verification failed ("alpha-linux1", "/usr/bin/python -u"), # No route to host: ("ppc-osx1", "/sw/bin/python -u"), # No route to host: ("ppc-osx2", "/usr/bin/python -u"), # Not python 2.3 or newer: ## ("sparc-solaris1", "/usr/local/bin/python -u"), ## ("sparc-solaris2", "/usr/local/bin/python -u"), ("openpower-linux1", "python -u")] import sys, os for hostname, python in hostinfo: print "*" * 20, hostname, "*" * 20 if len(sys.argv) > 1: cmd = "cd ~/ctypes; %s setup.py %s" % (python, " ".join(sys.argv[1:])) else: cmd = "cd ~/ctypes; %s setup.py -q build_ext -f test -v " % python print cmd ret = os.system('ssh -l theller cf-shell.sf.net "ssh %s \'%s\'"' % (hostname, cmd)) if ret: print "(RETCODE %s)" % ret print "-" * 50 print --- NEW FILE: README.CVS --- I added support to run ctypes from a CVS sandbox without the need to install the package. This even works for different Python versions on the same machine. This behaviour is triggered by the presence of a .CTYPE_DEVEL file in the ctypes package directory. Just do a 'setup.py build' and insert the top-level directory into sys.path (with setting the PYTHONPATH env variable, with a .pth file, or however), and it should work. --- NEW FILE: ANNOUNCE --- ctypes 0.9.9.3 released - Feb 15, 2006 ====================================== Overview ctypes is an advanced ffi (Foreign Function Interface) package for Python 2.3 and higher. ctypes allows to call functions exposed from dlls/shared libraries and has extensive facilities to create, access and manipulate simple and complicated C data types in Python - in other words: wrap libraries in pure Python. It is even possible to implement C callback functions in pure Python. ctypes includes a code generator toolchain which allows automatic creation of library wrappers from C header files. This feature is still experimental and beta quality. ctypes runs on Windows, Windows CE, MacOS X, Linux, Solaris, FreeBSD, OpenBSD. It may also run on other systems, provided that libffi supports this platform. Important If you download the source distribution, please choose the ZIP file for Windows, and the .tar.gz file for other machines. These archive have different contents! There have been lots of changes - if you are the author or user of a package that uses ctypes, please test it with this release and report problems on the ctypes-users mailing list. Changes in 0.9.9.3 (These are the most important changes, see the ChangeLog for complete details) Windows The ctypes.com package is no longer included and supported. It is replaced by the comtypes package which will be released separately. ctypes has been ported to Windows CE by Luke Dunstan. Other platforms Hye-Shik Chang has written a new build system for libffi which should remove possible licensing issues. All platforms The library loading code has been rewritten by Andreas Degert, there are now sophisticated methods to find shared libraries. On OS X, this uses files from Bob Ippolito's macholib. See the manual for details. Finally I started to write the manual, it is available online: http://tinyurl.com/7bpg4 New 'errcheck' protocol to check the return values of foreign functions, suggested by Mike Fletcher. Lots of bug fixes, especially for 64-bit platforms. Improved performance when creating ctypes instances. Subclasses of simple types (c_int, c_void_p, and so on) now behave as expected - they are not automatically converted into native Python types any longer. Support for explicit byte ordering in structures has been added (BigEndianStructure, LittleEndianStructure base classes). call byref() automatically, if needed, for POINTER types in argtypes. Lots of improvements to the code generator. Changes in 0.9.6 Thanks to all of you who reported bugs so quickly, and those who tried out the codegenerator toolchain. Bug fixes: - keyword arguments in Structure/Union initializers had no effect. - it was impossible to override the from_parm class method in subclasses of c_void_p, c_char_p, and c_wchar_p. - removed the __del__ method of _CDLL. It caused uncollectable garbage in Python's gc. - ctypes.com.register: enclose the Python script to run a com server in quotes, otherwise it won't run correctly when the directory name contains spaces. Enhancements: - Several changes have been made to the h2xml script from the codegenerator toolchain. See the documentation (linked below) for details. Additions in 0.9.5 New package ctypes.wrap. This contains decorators usable for easier creation of wrapper functions. This package also contains a toolchain for (semi)automatic creation of wrappers for external libraries - it can parse C header files and generate ctypes code for the declarations in them. It can even handle preprocessor definitions! For details, see http://starship.python.net/crew/theller/ctypes/codegen.html Changes in 0.9.5 On systems where sizeof(int) == sizeof(long), c_int/c_long and c_uint/c_ulong are now aliases. Similar for c_long/c_longlong and c_ulong/c_ulonglong. This prevents unneeded type errors. If an exception occurs in a callback function, a full traceback is now printed. Raising SystemExit in a callback function now correctly exists Python. HRESULT is now a proper ctype - no longer a function. This allows to use it in the argtypes sequence for function prototypes. An easier way to define structures and unions that reference themselves, or have dependencies to other data types. The _fields_ attribute can now be set *after* the Structure/Union class has been created. This makes the SetPointerType function obsolete. The semantics of the _fields_ attribute in sub-subclasses of Structure and Union has been fixed. The baseclasses _fields_ list is extended, not replaced, in subclasses. Assigning _fields_ when it is no longer possible raises an error now. Structures and unions now work as restype and in the argtypes list for functions. An important bug has been fixed with pointers. Detailed changelog is in CVS: <http://cvs.sourceforge.net/viewcvs.py/ctypes/ctypes/ChangeLog?rev=1.86.2.39> Download Downloads are available in the sourceforge files section <http://sourceforge.net/project/showfiles.php?group_id=71702> Separate source distributions are available for windows and non-windows systems. Please use the .zip file for Windows and Windows CE, and use the .tar.gz file for non-Windows systems (it contains the complete cross-platform libffi sources). Binary windows installers, which contain compiled extension modules, are also available, be sure to download the correct one for the Python version you are using. Homepage <http://starship.python.net/crew/theller/ctypes/> Enjoy, Thomas --- NEW FILE: setup.py --- #!/usr/bin/env python # # $Id: setup.py,v 1.129 2006/03/03 20:07:59 theller Exp $ # # """ctypes is a Python package to create and manipulate C data types in Python, and to call functions in dynamic link libraries/shared dlls. It allows wrapping these libraries in pure Python. """ LIBFFI_SOURCES='source/libffi' __version__ = "0.9.9.4" ################################################################ ##from ez_setup import use_setuptools ##use_setuptools() import os, sys if sys.version_info < (2, 3): raise Exception, "ctypes %s requires Python 2.3 or better" % __version__ from distutils.core import setup, Extension, Command import distutils.core from distutils.errors import DistutilsOptionError from distutils.command import build_py, build_ext, clean from distutils.command import install_data from distutils.dir_util import mkpath from distutils.util import get_platform ################################################################ # Manipulate the environment for the build process. # if get_platform() in ["solaris-2.9-sun4u", "linux-x86_64"]: os.environ["CFLAGS"] = "-fPIC" ################################################################ # Additional and overridden distutils commands # class test(Command): # Original version of this class posted # by Berthold Hoellmann to dis...@py... description = "run tests" user_options = [ ('tests=', 't', "comma-separated list of packages that contain test modules"), ('use-resources=', 'u', "resources to use - resource names are defined by tests"), ('refcounts', 'r', "repeat tests to search for refcount leaks (requires 'sys.gettotalrefcount')"), ] boolean_options = ["refcounts"] def initialize_options(self): self.build_base = 'build' self.use_resources = "" self.refcounts = False if sys.platform == "win32": self.tests = "ctypes.test,comtypes.test" else: self.tests = "ctypes.test" # initialize_options() def finalize_options(self): if self.refcounts and not hasattr(sys, "gettotalrefcount"): raise DistutilsOptionError("refcount option requires Python debug build") self.tests = self.tests.split(",") self.use_resources = self.use_resources.split(",") # finalize_options() def run(self): self.run_command('build') import ctypes.test ctypes.test.use_resources.extend(self.use_resources) for name in self.tests: package = __import__(name, globals(), locals(), ['*']) print "Testing package", name ctypes.test.run_tests(package, "test_*.py", self.verbose, self.refcounts) # run() # class test class my_build_py(build_py.build_py): def find_package_modules (self, package, package_dir): """We extend distutils' build_py.find_package_modules() method to include all modules found in the platform specific root package directory into the 'ctypes' root package.""" import glob, sys result = build_py.build_py.find_package_modules(self, package, package_dir) if package == 'ctypes': for pathname in glob.glob(os.path.join(sys.platform, "*.py")): modname = os.path.splitext(os.path.basename(pathname))[0] result.append(('ctypes', modname, pathname)) return result def find_file_in_subdir(dirname, filename): # if <filename> is in <dirname> or any subdirectory thereof, # return the directory name, else None for d, _, names in os.walk(dirname): if filename in names: return d return None class my_build_ext(build_ext.build_ext): def finalize_options(self): if self.debug is None: import imp self.debug = ('_d.pyd', 'rb', imp.C_EXTENSION) in imp.get_suffixes() build_ext.build_ext.finalize_options(self) # First configure a libffi library, then build the _ctypes extension. def build_extensions(self): self.configure_libffi() # Add .S (preprocessed assembly) to C compiler source extensions. self.compiler.src_extensions.append('.S') build_ext.build_ext.build_extensions(self) def fix_extension(self, ffi_dir): fficonfigfile = os.path.join(ffi_dir, 'fficonfig.py') if not os.path.exists(fficonfigfile): return 0 incdir = find_file_in_subdir(os.path.join(ffi_dir, "include"), "ffi.h") if not incdir: return 0 incdir_2 = find_file_in_subdir(ffi_dir, "fficonfig.h") if not incdir_2: return 0 fficonfig = {} execfile(fficonfigfile, globals(), fficonfig) srcdir = os.path.join(fficonfig['ffi_srcdir'], 'src') for ext in self.extensions: if ext.name == "_ctypes": ext.include_dirs.append(incdir) ext.include_dirs.append(incdir_2) ext.include_dirs.append(srcdir) ext.sources.extend(fficonfig['ffi_sources']) if fficonfig['ffi_cflags'].strip(): ext.extra_compile_args.extend( fficonfig['ffi_cflags'].split()) return 1 def configure_libffi(self): if sys.platform == "win32": return if LIBFFI_SOURCES == None: return src_dir = os.path.abspath(LIBFFI_SOURCES) # Building libffi in a path containing spaces doesn't work: self.build_temp = self.build_temp.replace(" ", "") build_dir = os.path.join(self.build_temp, 'libffi') if not self.force and self.fix_extension(build_dir): return mkpath(build_dir) config_args = [] # Pass empty CFLAGS because we'll just append the resulting CFLAGS # to Python's; -g or -O2 is to be avoided. cmd = "cd %s && env CFLAGS='' '%s/configure' %s" \ % (build_dir, src_dir, " ".join(config_args)) print 'Configuring static FFI library:' print cmd res = os.system(cmd) if res: print "Failed" sys.exit(res) assert self.fix_extension(build_dir), "Could not find libffi after building it" # Since we mangle the build_temp dir, we must also do this in the clean command. class my_clean(clean.clean): def run(self): self.build_temp = self.build_temp.replace(" ", "") clean.clean.run(self) class my_install_data(install_data.install_data): """A custom install_data command, which will install it's files into the standard directories (normally lib/site-packages). """ def finalize_options(self): if self.install_dir is None: installobj = self.distribution.get_command_obj('install') self.install_dir = installobj.install_lib print 'Installing data files to %s' % self.install_dir install_data.install_data.finalize_options(self) ################################################################ # Specify the _ctypes extension # kw = {} # common source files kw["sources"] = ["source/_ctypes.c", "source/callbacks.c", "source/callproc.c", "source/stgdict.c", "source/cfield.c", "source/malloc_closure.c"] # common header file kw["depends"] = ["source/ctypes.h"] if sys.platform == "win32": kw["sources"].extend([ # types.c is no longer needed, ffi_type defs are in cfield.c "source/libffi_msvc/ffi.c", "source/libffi_msvc/prep_cif.c", "source/libffi_msvc/win32.c", ]) extensions = [Extension("_ctypes", export_symbols=["DllGetClassObject,PRIVATE", "DllCanUnloadNow,PRIVATE"], libraries=["ole32", "user32", "oleaut32"], include_dirs=["source/libffi_msvc"], **kw), Extension("_ctypes_test", libraries=["oleaut32", "user32"], sources=["source/_ctypes_test.c"], include_dirs=["source/libffi_msvc"], ) ] if kw.has_key("depends"): kw["depends"].extend(["source/libffi_msvc/ffi.h", "source/libffi_msvc/fficonfig.h", "source/libffi_msvc/ffitarget.h", "source/libffi_msvc/ffi_common.h"]) else: include_dirs = [] library_dirs = [] extra_link_args = [] if sys.platform == "darwin": kw["sources"].append("source/darwin/dlfcn_simple.c") extra_link_args.extend(['-read_only_relocs', 'warning']) include_dirs.append("source/darwin") elif sys.platform == "sunos5": extra_link_args.extend(['-mimpure-text']) extensions = [Extension("_ctypes", include_dirs=include_dirs, library_dirs=library_dirs, extra_link_args=extra_link_args, **kw), Extension("_ctypes_test", sources=["source/_ctypes_test.c"]) ] ################################################################ # the ctypes package # packages = ["ctypes", "ctypes.macholib", "ctypes.test"] ################################################################ # pypi classifiers # classifiers = [ 'Development Status :: 4 - Beta', 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: MacOS :: MacOS X', 'Operating System :: Microsoft :: Windows', 'Operating System :: POSIX', 'Programming Language :: C', 'Programming Language :: Python', 'Topic :: Software Development :: Libraries :: Python Modules', ] ################################################################ # main section # ##from ce import ce_install_lib if __name__ == '__main__': setup(name="ctypes", ## entry_points = {"console_scripts" : ["xml2py = ctypes.wrap.xml2py:main", ## "h2xml = ctypes.wrap.h2xml:main"]}, ext_modules = extensions, packages = packages, classifiers = classifiers, version=__version__, description="create and manipulate C data types in Python, call functions in shared libraries", long_description = __doc__, author="Thomas Heller", author_email="th...@py...", license="MIT License", url="http://starship.python.net/crew/theller/ctypes.html", platforms=["windows", "Linux", "MacOS X", "Solaris", "FreeBSD"], cmdclass = {'test': test, 'build_py': my_build_py, 'build_ext': my_build_ext, 'clean': my_clean, 'install_data': my_install_data, ## 'ce_install_lib': ce_install_lib }, ) ## Local Variables: ## compile-command: "python setup.py build" ## End: --- NEW FILE: LICENSE.txt --- Copyright (c) 2000, 2001, 2002, 2003, 2004 Thomas Heller 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 AUTHORS OR COPYRIGHT HOLDERS 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. --- NEW FILE: README.txt --- Overview ctypes is a ffi (Foreign Function Interface) package for Python. It allows to call functions exposed from dlls/shared libraries and has extensive facilities to create, access and manipulate simpole and complicated C data types transparently from Python - in other words: wrap libraries in pure Python. ctypes runs on Windows, MacOS X, Linux, Solaris, FreeBSD. It may also run on other systems, provided that libffi supports this platform. On Windows, ctypes contains (the beginning of) a COM framework mainly targetted to use and implement custom COM interfaces. News ctypes now uses the same code base and libffi on all platforms. For easier installation, the libffi sources are now included in the source distribution - no need to find, build, and install a compatible libffi version. Requirements ctypes 0.9 requires Python 2.3 or higher, since it makes intensive use of the new type system. ctypes uses libffi, which is copyright Red Hat, Inc. Complete license see below. Installation Windows On Windows, it is the easiest to download the executable installer for your Python version and execute this. Installation from source Separate source distributions are available for windows and non-windows systems. Please use the .zip file for Windows (it contains the ctypes.com framework), and use the .tar.gz file for non-Windows systems (it contains the complete cross-platform libffi sources). To install ctypes from source, unpack the distribution, enter the ctypes-0.9.x source directory, and enter python setup.py build This will build the Python extension modules. A C compiler is required. On OS X, the segment attribute live_support must be defined. If your compiler doesn't know about it, upgrade or set the environment variable CCASFLAGS="-Dno_live_support". To run the supplied tests, enter python setup.py test To install ctypes, enter python setup.py install --help to see the avaibable options, and finally python setup.py install [options] For Windows CE, a project file is provided in wince\_ctypes.vcw. MS embedded Visual C 4.0 is required to build the extension modules. Additional notes Current version: 0.9.9.3 Homepage: http://starship.python.net/crew/theller/ctypes.html ctypes license Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006 Thomas Heller 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 AUTHORS OR COPYRIGHT HOLDERS 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. libffi license libffi - Copyright (c) 1996-2003 Red Hat, Inc. 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 CYGNUS SOLUTIONS 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. |
From: Thomas H. <th...@us...> - 2006-03-03 19:50:38
|
Update of /cvsroot/ctypes/ctypes/scripts In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv23805 Removed Files: fetch_libffi cvs-switch README Log Message: Remove all files, will add them from 'branch_1_0' again. --- README DELETED --- --- cvs-switch DELETED --- --- fetch_libffi DELETED --- |
From: Thomas H. <th...@us...> - 2006-03-03 19:48:30
|
Update of /cvsroot/ctypes/ctypes/win32 In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22132 Removed Files: wintypes.py .cvsignore Log Message: Remove all files, will add them from 'branch_1_0' again. --- .cvsignore DELETED --- --- wintypes.py DELETED --- |
From: Thomas H. <th...@us...> - 2006-03-03 19:48:21
|
Update of /cvsroot/ctypes/ctypes/win32/com In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22069 Removed Files: w_getopt.py storage.py shelllink.py server.py register.py persist.py oleobject.py ole.py moniker.py mallocspy.py hresult.py errorinfo.py connectionpoints.py client.py automation.py __init__.py ChangeLog .cvsignore Log Message: Remove all files, will add them from 'branch_1_0' again. --- .cvsignore DELETED --- --- shelllink.py DELETED --- --- hresult.py DELETED --- --- ChangeLog DELETED --- --- oleobject.py DELETED --- --- automation.py DELETED --- --- __init__.py DELETED --- --- persist.py DELETED --- --- mallocspy.py DELETED --- --- ole.py DELETED --- --- register.py DELETED --- --- client.py DELETED --- --- server.py DELETED --- --- connectionpoints.py DELETED --- --- moniker.py DELETED --- --- errorinfo.py DELETED --- --- storage.py DELETED --- --- w_getopt.py DELETED --- |
From: Thomas H. <th...@us...> - 2006-03-03 19:48:14
|
Update of /cvsroot/ctypes/ctypes/win32/com/tools In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21909 Removed Files: readtlb.py __init__.py .cvsignore Log Message: Remove all files, will add them from 'branch_1_0' again. --- .cvsignore DELETED --- --- __init__.py DELETED --- --- readtlb.py DELETED --- |
From: Thomas H. <th...@us...> - 2006-03-03 19:48:07
|
Update of /cvsroot/ctypes/ctypes/win32/com/samples In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21660 Removed Files: iexplorer.py ie6_gen.py .cvsignore Log Message: Remove all files, will add them from 'branch_1_0' again. --- .cvsignore DELETED --- --- ie6_gen.py DELETED --- --- iexplorer.py DELETED --- |