Skip to content

Commit b818297

Browse files
committed
Merge pull request #499 from java-native-access/490-fix-win32-struct-return
Fixes issue #490
2 parents 6da17d6 + d0225db commit b818297

File tree

10 files changed

+97
-76
lines changed

10 files changed

+97
-76
lines changed

CHANGES.md

+1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ Features
5353
* [#483] (https://github.com/twall/jna/pull/483): Found and fixed duplicate method definitions for the same API in 'com.sun.jna.platform.win32' - [@lgoldstein](https://github.com/lgoldstein).
5454
* [#485] (https://github.com/twall/jna/pull/485): Implemented Comparable interface for many of the base types in 'com.sun.jna.platform.win32.WinDef' - [@lgoldstein](https://github.com/lgoldstein).
5555
* [#488] (https://github.com/twall/jna/pull/488): Added GetRawInputDeviceList definition and utility to 'com.sun.jna.platform.win32' User32 and User32Util - [@lgoldstein](https://github.com/lgoldstein).
56+
* [#490](https://github.com/twall/jna/issues/490): Allow arbitrary calling convention specification, including FFI_MS_CDECL which alters handling of struct return values, and multiple Linux/PowerPC conventions - [@twall](https://github.com/twall).
5657

5758
Bug Fixes
5859
---------

build.xml

+6-2
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,9 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
689689
<!-- ensure ARCH is set properly for 64-bit capable platforms -->
690690
<!-- use ANT_OPTS=-d64/-d32 to build 64-bit/32-bit if not the platform default -->
691691
<property name="ARCH" value="${os.arch}"/>
692+
<condition property="make.USE_MSVC" value="USE_MSVC=${USE_MSVC}" else="IGNORE=">
693+
<isset property="USE_MSVC"/>
694+
</condition>
692695
<condition property="make.CC" value="CC=${CC}" else="IGNORE=">
693696
<isset property="CC"/>
694697
</condition>
@@ -774,6 +777,7 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
774777
<arg value="CFLAGS_EXTRA=${cflags_extra.native}"/>
775778
<arg value="DYNAMIC_LIBFFI=${dynlink.native}"/>
776779
<arg value="${make.CC}"/>
780+
<arg value="${make.USE_MSVC}"/>
777781
<arg value="${make.BUILD}"/>
778782
<arg value="${make.SDKROOT}"/>
779783
<arg value="${make.ARCH}"/>
@@ -916,8 +920,8 @@ osname=macosx;processor=x86;processor=x86-64;processor=ppc
916920
<target name="test" depends="-enable-native,jar,compile-tests" unless="cross-compile"
917921
description="Run all unit tests">
918922
<property name="test.fork" value="yes"/>
919-
<property name="reports.junit" location="${reports}/junit"/>
920-
<property name="results.junit" location="${build}/junit-results"/>
923+
<property name="reports.junit" location="${reports}/junit/${os.prefix}"/>
924+
<property name="results.junit" location="${build}/junit-results/${os.prefix}"/>
921925
<mkdir dir="${results.junit}"/>
922926
<echo>Saving test results in ${results.junit}</echo>
923927
<property name="tests.stdcall" value="**/win32/*StdCallTest.java"/>

lib/native/win32-x86-64.jar

1.22 KB
Binary file not shown.

lib/native/win32-x86.jar

1.06 KB
Binary file not shown.

native/Makefile

+22-18
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,18 @@ STRIP=@echo
176176
LIBPFX=
177177
LIBSFX=.dll
178178
TESTLIB_TRUNC=$(BUILD)/testlib-truncated.dll
179+
ifeq ($(ARCH),amd64)
180+
MINGW_PREFIX?=x86_64-w64-mingw32-
181+
FFI_CONFIG+=--host=x86_64-w64-mingw32
182+
# Need windres from mingw distribution, even if building with MSVC
183+
WINDRES=$(MINGW_PREFIX)windres
184+
MINGW=$(MINGW_PREFIX)gcc
185+
else
186+
MINGW_PREFIX?=i686-pc-mingw32-
187+
endif
179188

180-
ifdef USE_MSVC
189+
ifeq ($(USE_MSVC),true)
190+
# MS compiler
181191
CC=$(FFI_SRC)/msvcc.sh
182192
COPT=
183193
CPP=cl -nologo -EP
@@ -187,37 +197,31 @@ LIBS=psapi.lib
187197
ARSFX=.lib
188198
ifeq ($(ARCH),amd64)
189199
CC+= -m64
190-
FFI_CONFIG+=--host=x86_64-w64-mingw32
191200
endif
192201
FFI_CONFIG+= && rm -f include/ffitarget.h && cp $(FFI_SRC)/include/*.h $(FFI_SRC)/src/x86/ffitarget.h include
193202
FFI_ENV+=LD="$(LD)" CPP="$(CPP)" CXXCPP="$(CPP)"
194203
EXTRAOBJS+=$(DLLCB)
204+
195205
else
196-
MINGW_PREFIX?=i686-pc-mingw32-
206+
# Mingw compiler
207+
LDFLAGS=-o $@ -shared
208+
FFI_ENV+=CXXCPP="$(CPP)"
209+
210+
ifneq ($(ARCH),amd64)
197211
CC=$(MINGW_PREFIX)gcc
198-
LDFLAGS=-o $@ -shared -Wl,--add-stdcall-alias
212+
CPP=$(MINGW_PREFIX)gcc -E
213+
LDFLAGS+=-Wl,--add-stdcall-alias
199214
LIBS=-lpsapi
200-
endif
201-
202-
ifeq ($(ARCH),amd64)
203-
# Undefine USE_MSVC to enable mingw64 cross compiler; ensure $(MINGW) is in
204-
# PATH. Should build properly as of 111121, but lacks SEH, so MSVC build is
205-
# preferred
206-
MINGW_PREFIX?=x86_64-w64-mingw32-
207-
MINGW=$(MINGW_PREFIX)gcc
208-
# Need windres from mingw distribution, even if building with MSVC
209-
WINDRES=$(MINGW_PREFIX)windres
210-
211-
ifndef USE_MSVC
215+
else
216+
# mingw64 lacks SEH, so MSVC build is preferred
212217
CC=$(MINGW)
213218
# No SEH under mingw64, thus no HAVE_PROTECTION
214219
CDEFINES=-DPSAPI_VERSION=1
215220
LD = $(CC)
216-
LDFLAGS=-o $@ -shared
217221
LIBS= -lmingwex -lpsapi -lkernel32 -lmsvcrt
218222
endif
219-
220223
endif
224+
221225
endif
222226

223227
ifeq ($(OS),linux)

native/dispatch.c

+10-6
Original file line numberDiff line numberDiff line change
@@ -598,11 +598,15 @@ dispatch(JNIEnv *env, void* func, jint flags, jobjectArray args,
598598
break;
599599
#endif // _WIN32
600600
default:
601-
snprintf(msg, sizeof(msg),
602-
"Unrecognized calling convention: %d", (int)callconv);
603-
throw_type = EIllegalArgument;
604-
throw_msg = msg;
605-
goto cleanup;
601+
abi = (int)callconv;
602+
if (!(abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)) {
603+
snprintf(msg, sizeof(msg),
604+
"Unrecognized calling convention: %d", abi);
605+
throw_type = EIllegalArgument;
606+
throw_msg = msg;
607+
goto cleanup;
608+
}
609+
break;
606610
}
607611

608612
status = ffi_prep_cif(&cif, abi, nargs, return_type, arg_types);
@@ -1142,7 +1146,7 @@ toNativeTypeMapped(JNIEnv* env, jobject obj, void* valuep, size_t size, jobject
11421146
static void
11431147
fromNativeTypeMapped(JNIEnv* env, jobject from_native,
11441148
void* native_return_value,
1145-
int jtype, int size,
1149+
int jtype, size_t size,
11461150
jclass java_return_class,
11471151
void* result_storage,
11481152
const char* encoding) {

native/libffi/src/x86/ffi.c

+17-6
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2828
DEALINGS IN THE SOFTWARE.
2929
----------------------------------------------------------------------- */
30-
30+
#include <stdio.h>
3131
#if !defined(__x86_64__) || defined(_WIN64) || defined(__CYGWIN__)
3232

3333
#ifdef _WIN64
@@ -65,7 +65,10 @@ unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
6565
if ((ecif->cif->flags == FFI_TYPE_STRUCT
6666
|| ecif->cif->flags == FFI_TYPE_MS_STRUCT)
6767
#ifdef X86_WIN64
68-
&& ((ecif->cif->rtype->size & (1 | 2 | 4 | 8)) == 0)
68+
&& ((ecif->cif->rtype->size != 1
69+
&& ecif->cif->rtype->size != 2
70+
&& ecif->cif->rtype->size != 4
71+
&& ecif->cif->rtype->size != 8))
6972
#endif
7073
)
7174
{
@@ -108,7 +111,7 @@ unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
108111
#ifdef X86_WIN64
109112
if (z > FFI_SIZEOF_ARG
110113
|| ((*p_arg)->type == FFI_TYPE_STRUCT
111-
&& (z & (1 | 2 | 4 | 8)) == 0)
114+
&& (z != 1 && z != 2 && z != 4 && z != 8))
112115
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
113116
|| ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
114117
#endif
@@ -363,7 +366,10 @@ void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
363366
#ifdef X86_WIN64
364367
if (rvalue == NULL
365368
&& cif->flags == FFI_TYPE_STRUCT
366-
&& ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0))
369+
&& ((cif->rtype->size != 1
370+
&& cif->rtype->size != 2
371+
&& cif->rtype->size != 4
372+
&& cif->rtype->size != 8)))
367373
{
368374
ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
369375
}
@@ -548,7 +554,10 @@ ffi_prep_incoming_args(char *stack, void **rvalue, void **avalue,
548554
if ((cif->flags == FFI_TYPE_STRUCT
549555
|| cif->flags == FFI_TYPE_MS_STRUCT)
550556
#ifdef X86_WIN64
551-
&& ((cif->rtype->size & (1 | 2 | 4 | 8)) == 0)
557+
&& ((cif->rtype->size != 1
558+
&& cif->rtype->size != 2
559+
&& cif->rtype->size != 4
560+
&& cif->rtype->size != 8))
552561
#endif
553562
)
554563
{
@@ -612,7 +621,7 @@ ffi_prep_incoming_args(char *stack, void **rvalue, void **avalue,
612621
#ifdef X86_WIN64
613622
if (z > FFI_SIZEOF_ARG
614623
|| ((*p_arg)->type == FFI_TYPE_STRUCT
615-
&& (z & (1 | 2 | 4 | 8)) == 0)
624+
&& (z != 1 && z != 2 && z != 4 && z != 8))
616625
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
617626
|| ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
618627
#endif
@@ -934,3 +943,5 @@ ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
934943

935944
#endif /* !__x86_64__ || X86_WIN64 */
936945

946+
947+

native/libffi/src/x86/win32.S

+22-9
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ ca_jumpdata:
137137
dd offset ca_retint64 ;; FFI_TYPE_SINT64
138138
dd offset ca_epilogue ;; FFI_TYPE_STRUCT
139139
dd offset ca_retint ;; FFI_TYPE_POINTER
140+
dd offset ca_epilogue ;; FFI_TYPE_COMPLEX
140141
dd offset ca_retstruct1b ;; FFI_TYPE_SMALL_STRUCT_1B
141142
dd offset ca_retstruct2b ;; FFI_TYPE_SMALL_STRUCT_2B
142143
dd offset ca_retint ;; FFI_TYPE_SMALL_STRUCT_4B
@@ -268,6 +269,7 @@ cs_jumpdata:
268269
dd offset cs_retint64 ;; FFI_TYPE_SINT64
269270
dd offset cs_retstruct ;; FFI_TYPE_STRUCT
270271
dd offset cs_retint ;; FFI_TYPE_POINTER
272+
dd offset cs_epilogue ;; FFI_TYPE_COMPLEX
271273
dd offset cs_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
272274
dd offset cs_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
273275
dd offset cs_retint ;; FFI_TYPE_SMALL_STRUCT_4B
@@ -312,13 +314,12 @@ cs_retlongdouble:
312314

313315
cs_retstruct:
314316
;; Caller expects us to pop struct return value pointer hidden arg.
315-
;; Epilogue code is autogenerated.
316-
ret 4
317+
jmp cs_epilogue
317318

318319
cs_retmsstruct:
319320
;; Caller expects us to return a pointer to the real return value.
320321
mov eax, ecx
321-
;; Caller doesn't expects us to pop struct return value pointer hidden arg.
322+
;; Caller will pop struct return value pointer hidden arg.
322323
jmp cs_epilogue
323324

324325
cs_epilogue:
@@ -377,6 +378,7 @@ cr_jumpdata:
377378
dd offset cr_retint64 ;; FFI_TYPE_SINT64
378379
dd offset cr_epilogue ;; FFI_TYPE_STRUCT
379380
dd offset cr_retint ;; FFI_TYPE_POINTER
381+
dd offset cr_epilogue ;; FFI_TYPE_COMPLEX
380382
dd offset cr_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
381383
dd offset cr_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
382384
dd offset cr_retint ;; FFI_TYPE_SMALL_STRUCT_4B
@@ -427,7 +429,7 @@ ffi_closure_raw_SYSV ENDP
427429
#endif /* !FFI_NO_RAW_API */
428430

429431
ffi_closure_STDCALL PROC NEAR FORCEFRAME
430-
mov eax, [esp] ;; the ffi_closure ctx passed by the trampoline.
432+
mov eax, [esp+4] ;; the ffi_closure ctx passed by the trampoline.
431433

432434
sub esp, 40
433435
lea edx, [ebp - 24]
@@ -463,9 +465,11 @@ cd_jumpdata:
463465
dd offset cd_retint64 ;; FFI_TYPE_SINT64
464466
dd offset cd_epilogue ;; FFI_TYPE_STRUCT
465467
dd offset cd_retint ;; FFI_TYPE_POINTER
468+
dd offset cd_epilogue ;; FFI_TYPE_COMPLEX
466469
dd offset cd_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
467470
dd offset cd_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
468471
dd offset cd_retint ;; FFI_TYPE_SMALL_STRUCT_4B
472+
dd offset cd_epilogue ;; FFI_TYPE_MS_STRUCT
469473

470474
cd_retuint8:
471475
movzx eax, BYTE PTR [ecx]
@@ -624,6 +628,7 @@ USCORE_SYMBOL(ffi_call_win32):
624628
.long .Lretint64-.Lstore_table /* FFI_TYPE_SINT64 */
625629
.long .Lretstruct-.Lstore_table /* FFI_TYPE_STRUCT */
626630
.long .Lretint-.Lstore_table /* FFI_TYPE_POINTER */
631+
.long 0 /* FFI_TYPE_COMPLEX */
627632
.long .Lretstruct1b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_1B */
628633
.long .Lretstruct2b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_2B */
629634
.long .Lretstruct4b-.Lstore_table /* FFI_TYPE_SMALL_STRUCT_4B */
@@ -807,6 +812,7 @@ USCORE_SYMBOL(ffi_closure_SYSV):
807812
.long .Lcls_retllong-.Lcls_store_table /* FFI_TYPE_SINT64 */
808813
.long .Lcls_retstruct-.Lcls_store_table /* FFI_TYPE_STRUCT */
809814
.long .Lcls_retint-.Lcls_store_table /* FFI_TYPE_POINTER */
815+
.long 0 /* FFI_TYPE_COMPLEX */
810816
.long .Lcls_retstruct1-.Lcls_store_table /* FFI_TYPE_SMALL_STRUCT_1B */
811817
.long .Lcls_retstruct2-.Lcls_store_table /* FFI_TYPE_SMALL_STRUCT_2B */
812818
.long .Lcls_retstruct4-.Lcls_store_table /* FFI_TYPE_SMALL_STRUCT_4B */
@@ -872,14 +878,12 @@ USCORE_SYMBOL(ffi_closure_SYSV):
872878

873879
.Lcls_retstruct:
874880
# Caller expects us to pop struct return value pointer hidden arg.
875-
movl %ebp, %esp
876-
popl %ebp
877-
ret $0x4
881+
jmp .Lcls_epilogue
878882

879883
.Lcls_retmsstruct:
880884
# Caller expects us to return a pointer to the real return value.
881885
mov %ecx, %eax
882-
# Caller doesn't expects us to pop struct return value pointer hidden arg.
886+
# Caller will pop struct return value pointer hidden arg.
883887
jmp .Lcls_epilogue
884888

885889
.Lcls_noretval:
@@ -962,10 +966,11 @@ USCORE_SYMBOL(ffi_closure_raw_SYSV):
962966
.long .Lrcls_retllong-.Lrcls_store_table /* FFI_TYPE_SINT64 */
963967
.long .Lrcls_retstruct-.Lrcls_store_table /* FFI_TYPE_STRUCT */
964968
.long .Lrcls_retint-.Lrcls_store_table /* FFI_TYPE_POINTER */
969+
.long 0 /* FFI_TYPE_COMPLEX */
965970
.long .Lrcls_retstruct1-.Lrcls_store_table /* FFI_TYPE_SMALL_STRUCT_1B */
966971
.long .Lrcls_retstruct2-.Lrcls_store_table /* FFI_TYPE_SMALL_STRUCT_2B */
967972
.long .Lrcls_retstruct4-.Lrcls_store_table /* FFI_TYPE_SMALL_STRUCT_4B */
968-
.long .Lrcls_retstruct-.Lrcls_store_table /* FFI_TYPE_MS_STRUCT */
973+
.long .Lrcls_retmsstruct-.Lrcls_store_table /* FFI_TYPE_MS_STRUCT */
969974
1:
970975
shl $2, %eax
971976
add (%esp),%eax
@@ -1024,6 +1029,9 @@ USCORE_SYMBOL(ffi_closure_raw_SYSV):
10241029
movl -24(%ebp), %eax
10251030
jmp .Lrcls_epilogue
10261031

1032+
.Lrcls_retmsstruct:
1033+
# FIXME
1034+
10271035
.Lrcls_retstruct:
10281036
# Nothing to do!
10291037

@@ -1097,9 +1105,11 @@ USCORE_SYMBOL(ffi_closure_STDCALL):
10971105
.long .Lscls_retllong-.Lscls_store_table /* FFI_TYPE_SINT64 */
10981106
.long .Lscls_retstruct-.Lscls_store_table /* FFI_TYPE_STRUCT */
10991107
.long .Lscls_retint-.Lscls_store_table /* FFI_TYPE_POINTER */
1108+
.long 0 /* FFI_TYPE_COMPLEX */
11001109
.long .Lscls_retstruct1-.Lscls_store_table /* FFI_TYPE_SMALL_STRUCT_1B */
11011110
.long .Lscls_retstruct2-.Lscls_store_table /* FFI_TYPE_SMALL_STRUCT_2B */
11021111
.long .Lscls_retstruct4-.Lscls_store_table /* FFI_TYPE_SMALL_STRUCT_4B */
1112+
.long .Lscls_retmsstruct-.Lscls_store_table /* FFI_TYPE_MS_STRUCT */
11031113
1:
11041114
shl $2, %eax
11051115
add (%esp),%eax
@@ -1158,6 +1168,9 @@ USCORE_SYMBOL(ffi_closure_STDCALL):
11581168
movl (%ecx), %eax
11591169
jmp .Lscls_epilogue
11601170

1171+
.Lscls_retmsstruct:
1172+
# FIXME
1173+
11611174
.Lscls_retstruct:
11621175
# Nothing to do!
11631176

src/com/sun/jna/Function.java

+5-9
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ public interface PostCallRead {
5555
/** Standard C calling convention. */
5656
public static final int C_CONVENTION = 0;
5757
/** First alternate convention (currently used only for w32 stdcall). */
58-
public static final int ALT_CONVENTION = 1;
58+
public static final int ALT_CONVENTION = 0x3F;
5959

60-
private static final int MASK_CC = 0x3;
60+
private static final int MASK_CC = 0x3F;
6161
/** Whether to throw an exception if last error is non-zero after call. */
62-
public static final int THROW_LAST_ERROR = (1<<2);
62+
public static final int THROW_LAST_ERROR = 0x40;
6363

6464
static final Integer INTEGER_TRUE = new Integer(-1);
6565
static final Integer INTEGER_FALSE = new Integer(0);
@@ -242,11 +242,8 @@ public static Function getFunction(Pointer p, int callFlags) {
242242

243243
private void checkCallingConvention(int convention)
244244
throws IllegalArgumentException {
245-
switch(convention) {
246-
case C_CONVENTION:
247-
case ALT_CONVENTION:
248-
break;
249-
default:
245+
// TODO: perform per-platform calling convention checks
246+
if ((convention & MASK_CC) != convention) {
250247
throw new IllegalArgumentException("Unrecognized calling convention: "
251248
+ convention);
252249
}
@@ -256,7 +253,6 @@ public String getName() {
256253
return functionName;
257254
}
258255

259-
260256
public int getCallingConvention() {
261257
return callFlags & MASK_CC;
262258
}

0 commit comments

Comments
 (0)