SOLVED: BUG: AngelScript 2.20.2 - Mac OS X - 64-bit compilation doesn't work - g++ 4.2.1

Started by
27 comments, last by kainjow 13 years, 1 month ago
This diff seems to do the trick for me. I do still get a segfault in test_feature after "-- TestDictionary passed" but at least it does compile so it's a starting point.
Index: sdk/angelscript/source/as_callfunc_x64_gcc.cpp
===================================================================
--- sdk/angelscript/source/as_callfunc_x64_gcc.cpp (revision 812)
+++ sdk/angelscript/source/as_callfunc_x64_gcc.cpp (working copy)
@@ -69,14 +69,38 @@
: "%rax" \
)

+// While movq really should be used to move from general
+// purpose register to xmm register, GNUC accepts movd for
+// backward compatibility.
+// http ://gcc.gnu.org/bugzilla/show_bug.cgi?id=43215
+#if __GNUC__ <= 4 && __GNUC_MINOR__ <= 2
#define POP_LONG( reg ) \
- __asm__ __volatile__ ( \
- "popq %%rax\n" \
- "movq %%rax, %" reg \
- : \
- : \
- : "%rax", reg \
- )
+ __asm__ __volatile__ ( \
+ "popq %%rax\n" \
+ "movq %%rax, %" reg \
+ : \
+ : \
+ : "%rax", reg \
+ )
+#define POP_LONG_XMM( reg ) \
+ __asm__ __volatile__ ( \
+ "popq %%rax\n" \
+ "movd %%rax, %" reg \
+ : \
+ : \
+ : "%rax", reg \
+ )
+#else
+#define POP_LONG( reg ) \
+ __asm__ __volatile__ ( \
+ "popq %%rax\n" \
+ "movq %%rax, %" reg \
+ : \
+ : \
+ : "%rax", reg \
+ )
+#define POP_LONG_XMM( reg ) POP_LONG( reg )
+#endif


#define ASM_GET_REG( name, dest ) \
@@ -105,6 +129,7 @@
: "%rax", reg \
)

+#define POP_LONG_XMM( reg ) POP_LONG( reg )

#define ASM_GET_REG( name, dest ) \
__asm__ __volatile__ ( \
@@ -181,14 +206,14 @@
}

/* now pop the registers in reverse order and make the call */
- POP_LONG( "%xmm7" );
- POP_LONG( "%xmm6" );
- POP_LONG( "%xmm5" );
- POP_LONG( "%xmm4" );
- POP_LONG( "%xmm3" );
- POP_LONG( "%xmm2" );
- POP_LONG( "%xmm1" );
- POP_LONG( "%xmm0" );
+ POP_LONG_XMM( "%xmm7" );
+ POP_LONG_XMM( "%xmm6" );
+ POP_LONG_XMM( "%xmm5" );
+ POP_LONG_XMM( "%xmm4" );
+ POP_LONG_XMM( "%xmm3" );
+ POP_LONG_XMM( "%xmm2" );
+ POP_LONG_XMM( "%xmm1" );
+ POP_LONG_XMM( "%xmm0" );

POP_LONG( "%r9" );
POP_LONG( "%r8" );
Advertisement
Progress. Yay! :D

The TestVector3() is possibly failing for a completely different reason, probably due to the change to make value types be allocated on the stack that I did in version 2.20.1. Can you comment it and see how far else you get with the tests?

It would be very helpful in knowing exactly which of the tests fails. Especially if any of the tests in the group at the end within {} that are designed to test the native calling convention.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

The only test that fails is TestVector3. smile.gif
I have attached the patch as a file because the forum seems to mangle the tabs making it impossible to apply it correctly.
Ah, that is good to hear. Thanks for helping out with the solution.I'll see if the problem with TestVector3 is happening on my 64bit windows machine, though I suspect it doesn't, so I'll probably need help to find out what problem is for that too.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Looks like the TestVector3 crash is possibly due to the POP_LONG_XMM change, since it originates from within X64_CallFunction()'s call(), puking on scriptmath3d.cpp:31
It seems that the Vector3 constructor is getting NULL as the this pointer.
Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000000
0x00000001000ba3ca in Vector3::Vector3 (this=0x0, _x=2, _y=0, _z=0) at ../../../../add_on/scriptmath3d/scriptmath3d.cpp:31
31 x = _x;

<br class="Apple-interchange-newline">

Here is the stacktrace from the time of failure:
#0 0x00000001000ba3ca in Vector3::Vector3 (this=0x0, _x=2, _y=0, _z=0) at ../../../../add_on/scriptmath3d/scriptmath3d.cpp:31
#1 0x00000001000ba7ce in operator* (v=@0x1008033f4, s=2) at ../../../../add_on/scriptmath3d/scriptmath3d.cpp:115
#2 0x0000000100219c1b in X64_CallFunction (pArgs=0x7fff5fbfe190, pArgsType=0x7fff5fbfe3d0 "\001\001", func=0x1000ba77c) at ../../source/as_callfunc_x64_gcc.cpp:230
#3 0x000000010021a9ac in CallSystemFunctionNative (context=0x10041b2a0, descr=0x100411770, obj=0x1008033f4, args=0x1008033dc, retPointer=0x0, retQW2=@0x7fff5fbfe490) at ../../source/as_callfunc_x64_gcc.cpp:543
#4 0x0000000100218912 in CallSystemFunction (id=41, context=0x10041b2a0, objectPointer=0x0) at ../../source/as_callfunc.cpp:424
#5 0x000000010024ec99 in asCContext::ExecuteNext (this=0x10041b2a0) at ../../source/as_context.cpp:1954
#6 0x0000000100254924 in asCContext::Execute (this=0x10041b2a0) at ../../source/as_context.cpp:983
#7 0x000000010009db9a in ExecuteString (engine=0x100801600, code=0x1000f6858 "vector3 v(1,0,0); assert( (v*2).length() == 2 );", mod=0x0, ctx=0x0) at ../../../../add_on/scripthelper/scripthelper.cpp:154
#8 0x000000010007d171 in TestVector3 () at ../../source/test_vector3.cpp:111
#9 0x0000000100003850 in main (argc=1, argv=0x7fff5fbfeda8) at ../../source/main.cpp:224


I did some disassembly and here is what I think is going on:
operator*(Vector3 const& v, float s):
00000001000ba77c pushq %rbp ; store and initialize base pointer
00000001000ba77d movq %rsp,%rbp
00000001000ba780 pushq %rbx ; store rbx
00000001000ba781 subq $0x28,%rsp ; align stack
00000001000ba785 movq %rdi,%rbx ; store new Vector3 instance in rbx
00000001000ba788 movq %rsi,0xd8(%rbp) ; store pointer to v in calling frame?
00000001000ba78c movss %xmm0,0xd4(%rbp) ; store s in the calling frame?
00000001000ba791 movq 0xd8(%rbp),%rax ; move pointer to v to rax
00000001000ba795 movss 0x08(%rax),%xmm0 ; move v.z to xmm0
00000001000ba79a movaps %xmm0,%xmm1 ; move v.z to xmm1
00000001000ba79d mulss 0xd4(%rbp),%xmm1 ; multiply v.z by s
00000001000ba7a2 movq 0xd8(%rbp),%rax ; move pointer to v to rax
00000001000ba7a6 movss 0x04(%rax),%xmm0 ; move v.y to xmm0
00000001000ba7ab movaps %xmm0,%xmm3 ; move v.y to xmm3
00000001000ba7ae mulss 0xd4(%rbp),%xmm3 ; multiply v.y by s
00000001000ba7b3 movq 0xd8(%rbp),%rax ; move pointer to v to rax
00000001000ba7b7 movss (%rax),%xmm0 ; move v.x to xmm0
00000001000ba7bb mulss 0xd4(%rbp),%xmm0 ; multilpy v.x by s
00000001000ba7c0 movq %rbx,%rdi ; return new Vector3 instance back to rdi
00000001000ba7c3 movaps %xmm1,%xmm2 ; move v.z to xmm2
00000001000ba7c6 movaps %xmm3,%xmm1 ; move v.y to xmm1
00000001000ba7c9 callq __ZN7Vector3C1Efff ; call Vector3::Vector3(float, float, float)
00000001000ba7ce movq %rbx,%rax
00000001000ba7d1 addq $0x28,%rsp
00000001000ba7d5 popq %rbx
00000001000ba7d6 leave
00000001000ba7d7 ret

Vector3::Vector3(float _x, float _y, float _z):
00000001000ba3ac pushq %rbp ; store and initialize base pointer
00000001000ba3ad movq %rsp,%rbp
00000001000ba3b0 movq %rdi,0xf8(%rbp) ; store new Vector3 instance in calling frame?
00000001000ba3b4 movss %xmm0,0xf4(%rbp) ; store _x in calling frame?
00000001000ba3b9 movss %xmm1,0xf0(%rbp) ; store _y in calling frame?
00000001000ba3be movss %xmm2,0xec(%rbp) ; store _z in calling frame?
00000001000ba3c3 movq 0xf8(%rbp),%rdx ; move new Vector3 instance to rdx
00000001000ba3c7 movl 0xf4(%rbp),%eax ; move _x to eax
00000001000ba3ca movl %eax,(%rdx) ; store _x as x in new Vector3 instance
00000001000ba3cc movq 0xf8(%rbp),%rdx ; move new Vector3 instance to rdx
00000001000ba3d0 movl 0xf0(%rbp),%eax ; move _y to eax
00000001000ba3d3 movl %eax,0x04(%rdx) ; store _y as y in new Vector3 instance
00000001000ba3d6 movq 0xf8(%rbp),%rdx ; move new Vector3 instance to rdx
00000001000ba3da movl 0xec(%rbp),%eax ; move _z to eax
00000001000ba3dd movl %eax,0x08(%rdx) ; store _z as z in new Vector3 instance
00000001000ba3e0 leave
00000001000ba3e1 ret


My theory is that the newly allocated Vector3 is not being passed in rdi. Does that make any sense?

I tried modifying as_config.h by adding #define CDECL_RETURN_SIMPLE_IN_MEMORY for 64-bit mac because I saw that CallSystemFunctionNative was being passed a NULL retPointer which seemed to cause it to incorrectly call operator*(Vector3 const& v, float s). This did make the Vector3 test pass but here are the tests it didn't work on:TestCDecl_Class: Failed to assign object returned from function. c1.a = 1
Failed on line 108 in ../../source/testcdecl_class.cpp
TestCDecl_Class: Failed to assign object returned from function. c2.a = 1
Failed on line 125 in ../../source/testcdecl_class.cpp
TestCDecl_Class: Failed to assign object returned from function. c2.b = 44F6D2
Failed on line 131 in ../../source/testcdecl_class.cpp


For reference, here is the gdb step-through (without the changes to as_config.h):CallSystemFunctionNative (context=0x10041b2a0, descr=0x100411770, obj=0x1008033f4, args=0x1008033dc, retPointer=0x0, retQW2=@0x7fff5fbfe490) at ../../source/as_callfunc_x64_gcc.cpp:240
240 asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2)
(gdb) print obj
$2 = (void *) 0x1008033f4
(gdb) n
242 asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
(gdb)
243 int callConv = sysFunc->callConv;
(gdb)
245 asQWORD retQW = 0;
(gdb)
246 void *func = ( void * )sysFunc->func;
(gdb)
247 asDWORD *stack_pointer = args;
(gdb)
248 funcptr_t *vftable = NULL;
(gdb)
249 int totalArgumentCount = 0;
(gdb)
250 int n = 0;
(gdb)
251 int base_n = 0;
(gdb)
252 int a = 0;
(gdb)
253 int param_pre = 0;
(gdb)
254 int param_post = 0;
(gdb)
255 int argIndex = 0;
(gdb)
256 int argumentCount = 0;
(gdb)
258 asDWORD tempBuff[CALLSTACK_MULTIPLIER * X64_CALLSTACK_SIZE] = { 0 };
(gdb)
259 asBYTE tempType[X64_CALLSTACK_SIZE] = { 0 };
(gdb)
261 asDWORD paramBuffer[CALLSTACK_MULTIPLIER * X64_CALLSTACK_SIZE] = { 0 };
(gdb)
262 asBYTE argsType[X64_CALLSTACK_SIZE] = { 0 };
(gdb)
264 asBYTE argsSet[X64_CALLSTACK_SIZE] = { 0 };
(gdb)
266 if( sysFunc->hostReturnInMemory ) {
(gdb)
271 argumentCount = ( int )descr->parameterTypes.GetLength();
(gdb)
272 assert( argumentCount <= X64_MAX_ARGS );
(gdb) print argumentCount
$3 = 1
(gdb) n
275 for( a = 0; a < argumentCount; ++a, ++argIndex ) {
(gdb)
277 argsType[argIndex] = x64INTARG;
(gdb)
278 if ( descr->parameterTypes[a].IsFloatType() && !descr->parameterTypes[a].IsReference() ) {
(gdb)
279 argsType[argIndex] = x64FLOATARG;
(gdb)
281 if ( descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() ) {
(gdb)
284 if ( descr->parameterTypes[a].GetSizeOnStackDWords() == 2 && !descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() ) {
(gdb)
288 if ( IsVariableArgument( descr->parameterTypes[a] ) ) {
(gdb)
275 for( a = 0; a < argumentCount; ++a, ++argIndex ) {
(gdb)
292 assert( argIndex == argumentCount );
(gdb)
294 for ( a = 0; a < argumentCount && totalArgumentCount <= X64_MAX_ARGS; a++ ) {
(gdb)
295 switch ( argsType[a] ) {
(gdb)
300 if ( totalArgumentCount < X64_MAX_ARGS )
(gdb)
301 tempType[totalArgumentCount++] = argsType[a];
(gdb)
302 break;
(gdb)
294 for ( a = 0; a < argumentCount && totalArgumentCount <= X64_MAX_ARGS; a++ ) {
(gdb)
314 assert( totalArgumentCount <= X64_MAX_ARGS );
(gdb)
315 if ( totalArgumentCount > argumentCount ) {
(gdb)
318 memset( tempType, 0, sizeof( tempType ) );
(gdb)
368 if ( obj && ( callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) ) {
(gdb)
373 switch ( callConv ) {
(gdb)
390 if ( totalArgumentCount ) {
(gdb)
391 memmove( argsType + 1, argsType, totalArgumentCount );
(gdb)
393 memcpy( paramBuffer, &obj, sizeof( obj ) );
(gdb)
394 argsType[0] = x64INTARG;
(gdb)
396 param_pre = 1;
(gdb)
398 break;
(gdb)
443 int adjust = 0;
(gdb)
444 for( n = 0; n < ( int )( param_pre + totalArgumentCount + param_post ); n++ ) {
(gdb)
445 int copy_count = 0;
(gdb)
446 if ( n >= param_pre && n < ( int )( param_pre + totalArgumentCount ) ) {
(gdb)
455 if ( copy_count > CALLSTACK_MULTIPLIER ) {
(gdb)
466 if ( copy_count ) {
(gdb)
444 for( n = 0; n < ( int )( param_pre + totalArgumentCount + param_post ); n++ ) {
(gdb)
445 int copy_count = 0;
(gdb)
446 if ( n >= param_pre && n < ( int )( param_pre + totalArgumentCount ) ) {
(gdb)
447 copy_count = descr->parameterTypes[n - param_pre - adjust].GetSizeOnStackDWords();
(gdb)
449 if ( argsType[n] == x64VARIABLE ) {
(gdb)
455 if ( copy_count > CALLSTACK_MULTIPLIER ) {
(gdb)
466 if ( copy_count ) {
(gdb)
467 memcpy( paramBuffer + n * CALLSTACK_MULTIPLIER, stack_pointer, copy_count * sizeof( asDWORD ) );
(gdb)
468 stack_pointer += copy_count;
(gdb)
444 for( n = 0; n < ( int )( param_pre + totalArgumentCount + param_post ); n++ ) {
(gdb)
475 if( descr->returnType.IsObject() && ( descr->returnType.GetObjectType()->flags & asOBJ_APP_CLASS_CA ) == asOBJ_APP_CLASS_CA &&
(gdb)
478 if ( totalArgumentCount )
(gdb)
480 memmove( paramBuffer + CALLSTACK_MULTIPLIER, paramBuffer, ( CALLSTACK_MULTIPLIER * ( X64_CALLSTACK_SIZE - 1 ) ) );
(gdb)
481 memmove( argsType + 1, argsType, X64_CALLSTACK_SIZE - 1 );
(gdb)
483 memcpy( paramBuffer, &retPointer, sizeof( retPointer ) );
(gdb) print retPointer
$4 = (void *) 0x0
Based on the result of testcdecl_class it seems the size of the class has to be larger than 8 bytes to be returned in memory. So try adding the following to the configuration:


#define CDECL_RETURN_SIMPLE_IN_MEMORY
#define STDCALL_RETURN_SIMPLE_IN_MEMORY
#define THISCALL_RETURN_SIMPLE_IN_MEMORY
#undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE
#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 3
#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 3
#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 3


I've checked in the as_callfunc_x64_gcc.cpp changes in revision 816. Let me know if the config changes work and I'll have those checked in as well.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Those #defines resulted in TestCDecl_Class: Failed to assign object returned from function. c2.a = A
Failed on line 125 in ../../source/testcdecl_class.cpp
TestCDecl_Class: Failed to assign object returned from function. c2.b = 411F8D
Failed on line 131 in ../../source/testcdecl_class.cpp
Progress.

If you set the MIN_SIZE to 2 instead of 3 it will probably work.

AngelCode.com - game development and more - Reference DB - game developer references
AngelScript - free scripting library - BMFont - free bitmap font generator - Tower - free puzzle game

Setting MIN_SIZE to 2 for THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE, CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE and STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE resulted in TestCDecl_Class: Failed to assign object returned from function. c1.a = B
Failed on line 108 in ../../source/testcdecl_class.cpp
TestCDecl_Class: Failed to assign object returned from function. c2.a = B
Failed on line 125 in ../../source/testcdecl_class.cpp
TestCDecl_Class: Failed to assign object returned from function. c2.b = 411F86
Failed on line 131 in ../../source/testcdecl_class.cpp

This topic is closed to new replies.

Advertisement