Sign in to follow this  
asgeirb

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

Recommended Posts

as_callfunc_x64_gcc.cpp does not compile correctly.


The following output is produced using "angelscript/projects/gnuc macosx/makefile":
[code]mkdir obj
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_atomic.o -c ../../source/as_atomic.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_builder.o -c ../../source/as_builder.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_bytecode.o -c ../../source/as_bytecode.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc.o -c ../../source/as_callfunc.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc_arm.o -c ../../source/as_callfunc_arm.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc_mips.o -c ../../source/as_callfunc_mips.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc_ppc.o -c ../../source/as_callfunc_ppc.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc_ppc_64.o -c ../../source/as_callfunc_ppc_64.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc_sh4.o -c ../../source/as_callfunc_sh4.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc_x86.o -c ../../source/as_callfunc_x86.cpp
c++ -g -Wall -fPIC -arch i386 -arch x86_64 -o obj/as_callfunc_x64_gcc.o -c ../../source/as_callfunc_x64_gcc.cpp
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:170:suffix or operands invalid for `movq'
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:173:suffix or operands invalid for `movq'
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:176:suffix or operands invalid for `movq'
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:179:suffix or operands invalid for `movq'
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:182:suffix or operands invalid for `movq'
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:185:suffix or operands invalid for `movq'
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:188:suffix or operands invalid for `movq'
/var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccQb3SXj.s:191:suffix or operands invalid for `movq'
lipo: can't open input file: /var/folders/iG/iGgRv-pOHVq8lMdjYzTz0E+++TI/-Tmp-//ccDlZLXb.out (No such file or directory)
make: *** [obj/as_callfunc_x64_gcc.o] Error 1[/code]


Which seems to correspond to the following lines in as_callfunc_x64_gcc.cpp
[code] POP_LONG( "%xmm7" );
POP_LONG( "%xmm6" );
POP_LONG( "%xmm5" );
POP_LONG( "%xmm4" );
POP_LONG( "%xmm3" );
POP_LONG( "%xmm2" );
POP_LONG( "%xmm1" );
POP_LONG( "%xmm0" );[/code]

Moving from a general purpose register to an xmm register doesn't seem to be supported, only xmm to xmm, memory to xmm and xmm to memory. [url="http://siyobik.info/index.php?module=x86&id=201"]According to this[/url]

I'm by no means an assembly programmer but wouldn't it be possible to just use movq using the stack pointer to reference memory and then pop into rax after the move?
Maybe something like this?
[code]#define POP_LONG( reg ) \
__asm__ __volatile__ ( \
"add %%rsp, 8\n" \
"movq (%%rsp), %" reg \
: \
: \
: reg \
)[/code]

Share this post


Link to post
Share on other sites
I wish I could test this, but I don't have a 64bit mac.

Anyway the problem is most likely caused by the latest changes in the file. Can you help me determine which revision from the svn was the latest to still work?

Share this post


Link to post
Share on other sites
Hmm. That version of the file is very old and is no longer compatible with the current library code. Version 640 was the one that introduced the new assembly code, and it was contributed by a Mac developer that couldn't compile the previous version.

I think the problem you're having is because of a difference in the compiler version that you use. I think it is necessary to write the assembly code slightly differently depending on the version of the compiler.

Which xcode version are you using, and which version of gcc is it using (it should hopefully appear in the build logs)?

Share this post


Link to post
Share on other sites
I'm using XCode 3.2.5 (1760) which has gcc 4.2.1 (Apple Inc. build 5664)

I did a little testing using nasm and otool. Here are the files I used:

Makefile[code]all: libctest.o
gcc -m64 -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk -o libctest libctest.o

libctest.o: libctest.asm
nasm -f macho64 -o libctest.o libctest.asm[/code]

libctest.asm[code]section .data
message: db 'xmm0 contents %016lx', 10, 0
messagelen: equ $ - message

section .bss
xmmcontents: resq 1

section .text
default rel

extern _printf
global _main

_main:
push qword rbp
mov rbp, rsp

mov rsi, 0xcafebabefeedface
movq xmm0, rsi
movq qword [xmmcontents], xmm0

mov rdi, qword message
mov rsi, qword [xmmcontents]
xor eax, eax
call _printf

mov eax, 0
leave
ret
[/code]

And here is the disassembly from otool -tV[code]libctest:
(__TEXT,__text) section
start:
0000000100000ecc pushq $0x00
0000000100000ece movq %rsp,%rbp
0000000100000ed1 andq $0xf0,%rsp
0000000100000ed5 movq 0x08(%rbp),%rdi
0000000100000ed9 leaq 0x10(%rbp),%rsi
0000000100000edd movl %edi,%edx
0000000100000edf addl $0x01,%edx
0000000100000ee2 shll $0x03,%edx
0000000100000ee5 addq %rsi,%rdx
0000000100000ee8 movq %rdx,%rcx
0000000100000eeb jmp 0x100000ef1
0000000100000eed addq $0x08,%rcx
0000000100000ef1 cmpq $0x00,(%rcx)
0000000100000ef5 jne 0x200000eed
0000000100000ef7 addq $0x08,%rcx
0000000100000efb callq _main
0000000100000f00 movl %eax,%edi
0000000100000f02 callq 0x100000f5c ; symbol stub for: _exit
0000000100000f07 hlt
dyld_stub_binding_helper:
0000000100000f08 pushq %r11
0000000100000f0a leaq 0xfffff0ef(%rip),%r11
0000000100000f11 pushq %r11
0000000100000f13 jmp *0x000000e7(%rip)
0000000100000f19 nopl (%rax)
__dyld_func_lookup:
0000000100000f1c jmp *0x000000e6(%rip)
_main:
0000000100000f22 pushq %rbp
0000000100000f23 movq %rsp,%rbp
0000000100000f26 movq $0xcafebabefeedface,%rsi
0000000100000f30 movd %rsi,%xmm0
0000000100000f35 movq %xmm0,0x0000014d(%rip)
0000000100000f3d movq $message,%rdi
0000000100000f47 movq 0x0000013c(%rip),%rsi
0000000100000f4e xorl %eax,%eax
0000000100000f50 callq 0x100000f62 ; symbol stub for: _printf
0000000100000f55 movl $0x00000000,%eax
0000000100000f5a leave
0000000100000f5b ret
[/code]

This will print out: xmm0 contents cafebabefeedface
So clearly all 64 bits are being moved into the xmmcontents variable.

According to the disassembly it seems that the correct instruction to move a qword from a general purpose register into an xmm register is not movq but movd.

This C code gives the same stdout printout as the above nasm code:[code]#include <stdio.h>

#define PUSH_REGISTER( val ) \
__asm__ __volatile__ ( \
"movq %0, %%rax\n" \
"movd %%rax, %%xmm0" \
: \
: "m" ( val ) \
: "%rax", "%xmm0" \
)

#define POP_REGISTER( val ) \
__asm__ __volatile__ ( \
"movq %%xmm0, %0" \
: \
: "m" (val) \
)


long unsigned int g_mmxvalue = 0;

int main(int argc, char *argv[])
{
long unsigned int foo = 0xcafebabefeedfaceL;

PUSH_REGISTER(foo);
POP_REGISTER(g_mmxvalue);

printf("xmm0 contents %016lx\n", g_mmxvalue);

return 0;
}
[/code]

Share this post


Link to post
Share on other sites
Can you try the following code for the POP_LONG macro? It seems GNUC is doing some weirdness in order to keep backward compatibility. I suspect this has been changed for newer versions of GNUC, so I'll differentiate with the code for your version.

[code]
// 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" \
"movd %%rax, %" reg \
: \
: \
: "%rax", reg \
)
#else
#define POP_LONG( reg ) \
__asm__ __volatile__ ( \
"popq %%rax\n" \
"movq %%rax, %" reg \
: \
: \
: "%rax", reg \
)
#endif
[/code]

Share this post


Link to post
Share on other sites
I got the same error, even with your changes.

However, using a test case I was able to get this to compile:

[code]#define POP_LONG( reg ) \
__asm__ __volatile__ ( \
"popq %%rax\n" \
"movq %%rax, %" reg \
: \
: \
: "%rax", reg \
)

#define POP_LONG2( reg ) \
__asm__ __volatile__ ( \
"popq %%rax\n" \
"movd %%rax, %" reg \
: \
: \
: "%rax", reg \
)

int main(int argc, char *argv[])
{
POP_LONG("%r9");
POP_LONG2("%xmm0");
return 0;
}[/code]

It seems like it can't be movq or movd for both? My assembly knowledge is minimal so not even sure if this is right.

I'm wondering if there's some GCC setting that can be tweaked to make it work without the code change.

Share this post


Link to post
Share on other sites
This POP_LONG macro works for the xmm registers but fails for the general purpose ones.
It seems that for general purpose -> xmm register the correct opcode is movd but for a general purpose -> general purpose register the correct opcode is movq.
I was reading the Intel opcode reference yesterday and the movq that does gp -> xmm is filed with movd but it's name is still given as movq.Clear as mud. [img]http://public.gamedev.net/public/style_emoticons/default/rolleyes.gif[/img]

Share this post


Link to post
Share on other sites
I think it is a bug in the version of GNUC that you're using that makes the movq not work with the xmm registers. This bug was fixed in a later version of GNUC, which is why others are able to compile the code just fine. According to the article I linked to they left the movd instruction for xmm registers for backwards compatibility, so it should be working even on the newer versions of GNUC.

Can you try kainjow's solution with two different versions of the POP_LONG macro, and then update the X64_CallFunction to use the right version with the right register?

Share this post


Link to post
Share on other sites
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.
[code]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" );[/code]

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
The only test that fails is TestVector3. [img]http://public.gamedev.net/public/style_emoticons/default/smile.gif[/img]
I have attached the patch as a file because the forum seems to mangle the tabs making it impossible to apply it correctly.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
It seems that the Vector3 constructor is getting NULL as the this pointer.
[code]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;
[/code]
<br class="Apple-interchange-newline">

Here is the stacktrace from the time of failure:
[code]#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
[/code]

I did some disassembly and here is what I think is going on:
[code]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[/code]

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:[code]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
[/code]

For reference, here is the gdb step-through (without the changes to as_config.h):[code]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
[/code]

Share this post


Link to post
Share on other sites
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:

[code]
#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
[/code]

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.

Share this post


Link to post
Share on other sites
Those #defines resulted in [code]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
[/code]

Share this post


Link to post
Share on other sites
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 [code]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
[/code]

Share this post


Link to post
Share on other sites
After reading up on the [url="http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html#//apple_ref/doc/uid/TP40005035-SW1"]64bit Mac OS X ABI[/url] I see the problem is that the Vector3 class is classified to be returned in memory due to its non-trivial copy constructor. I'll have to add support for telling AngelScript about the existance of the copy constructor in order to fix this.

In the meantime, on 64bit Mac you can work around this by changing the registration of the Vector3 to the following:

[code]
r = engine->RegisterObjectType("vector3", sizeof(Vector3), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CDA); assert( r >= 0 );
[/code]

The asOBJ_APP_CLASS_CDA will trick AngelScript into believing the object has a destructor, which is also classified to be returned in memory. Of course I cannot do this change for all platforms, because it may break the way the class is handled by them.

Share this post


Link to post
Share on other sites
Please give revision 818 a try. I added the flag asOBJ_APP_CLASS_COPY_CONSTRUCTOR, and changed the configuration for 64bit Mac OS X to recognize classes with this flag as complex types and return them in memory.

Share this post


Link to post
Share on other sites
All the tests now pass on x86_64!

However, I get a SIGABRT on 32-bit (i386 and ppc):

[code]TestCDecl_ClassK: Failed to assign object returned from function. c1.a = BFFFEDCC
Failed on line 114 in ../../../tests/test_feature/source/testcdecl_class_k.cpp
TestCDecl_ClassK: Failed to assign object returned from function. c2.a = BFFFEDCC
Failed on line 131 in ../../../tests/test_feature/source/testcdecl_class_k.cpp
TestCDecl_ClassK: Failed to assign object returned from function. c2.b = BFFFEDCC
Failed on line 137 in ../../../tests/test_feature/source/testcdecl_class_k.cpp
../../../tests/test_feature/source/testcdecl_class_k.cpp:62: failed assertion `c.a == 0xDEADC0DE'[/code]
FYI ppc is ran via "arch -ppc ./test_feature" using [url=http://en.wikipedia.org/wiki/Rosetta_(software)]Rosetta[/url].

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this