Sign in to follow this  
namtabmai

Linux x64 build.

Recommended Posts

namtabmai    122
Hi, I've been poking around Angelscript again on my machine ( Linux/gcc 64bit as the title might suggest :) ) and found a few problems with it. Mostly minor things, but one thing that did require reading through the spec on 64bit calling convention. First the minor things; 1) The angelscript makefile required a little update to include somethings it was missing. 2) Same for the test_feature makefile. 3) I modified asGetLibraryOptions to report AS_X64_GCC ( and AS_X64_MSVC while I was there ), these are needed for some of the other changes below. 4) test_registertype.cpp seemed to be missing a couple of lines of the error message it returned, which in turn was causing that test to fail. It's possible that this test should just be ignored on this platform. Now the bigger issue ( I think, please feel free to correct me if I'm wrong ), and I'll quote from ABI.pdf here ( the spec on 64bit calling conv ). "If the type has class MEMORY, then the caller provides space for the return value and passes the address of this storage in %rdi as if it were the first argument to the function. In effect, this address becomes a “hidden” first argument. On return %rax will contain the address that has been passed in by the caller in %rdi." Basically if a function returns a object then the first parameter to that function should be a pointer the pre-allocated memory for the return object. With the code the way it was the test_vector3 operator overload functions caused a segfaults as it expected the first parameter to be a pointer to the return pointer allocated memory but got 0 or float instead. Of course this is made more difficult by having to identify if the class has non-trivial copy constructor/destructor or not. I'd prefer if someone with a bit more knowledge of this could look over the code, but the changes I made to as_callfunc_x64_gcc.cpp seem to have done the trick. Just added a bit of code to check the return type and then readjust paramBuffer/argsType to include the retPointer as the first parameter. Unfortunately angelscript currently doesn't have a object flag to tell if a registered class has a copy constructor or not. I've checked against asOBJ_APP_CLASS_CA, which seems to work on the current test cases, but I think this is just plain luck. Without something like, asOBJ_APP_CLASS_K ( K for copy constructor? ) the engine just can't test for this. And lastly another minor thing, I created a makefile for test_performance on this platform, renamed utils.cpp to win32_utils.cpp and create a linux_utils.cpp with a corresponding GetSystemTimer function. Not sure if this is worth including or not thou. I've put up my changes as patches files here; http://www.keyboardcowboy.co.uk/angelscript-patches.tbz2 Again, I'm not 100% confident in all these changes but at least they get angelscript building and passing most of test_feature tests. Oh and one very last thing ( honestly ), test_stack2 still fails but only because the exception is reported as coming from myCompare rather than testclass.

Share this post


Link to post
Share on other sites
WitchLord    4677
This is new. No previous compiler has made a difference by the existance of the copy constructor. Do you have any documentation that says it is this that makes the compiler treat the type different? If it is, then I definitely need to add that flag as well to the library.

I took a quick look at the patches you provided, and it does look correct to me. I'll apply the changes and check them into the SVN.

Hopefully someone else will also be able to confirm that they are not breaking anything.

The test_stack2 is probably throwing the exception at a different location, due to the pointer size being different. I'll verify this, and make a differentiation in the test case.

Share this post


Link to post
Share on other sites
namtabmai    122
I was going by this;

www.x86-64.org/documentation/abi.pdf

Page 19 ( regarding classifying parameters );
'If a C++ object has either a non-trivial copy constructor or a non-trivial
destructor [11], it is passed by invisible reference (the object is replaced in the parameter list by a pointer that has class INTEGER) [12]'

Footnote from page 19;
'[12]An object with either a non-trivial copy constructor or a non-trivial destructor cannot be passed by value because such objects must have well defined addresses. Similar issues apply when returning an object from a function.'

Page 22 ( regarding returning values );
'If the type has class MEMORY, then the caller provides space for the return value and passes the address of this storage in %rdi as if it were the first argument to the function. In effect, this address becomes a “hidden” first argument. On return %rax"'

Hmm looking at this again, there should probably be some checks as well on the size of the class ( if they are not already there ).

Share this post


Link to post
Share on other sites
namtabmai    122
New fun bug. I posted it here rather than starting a new thread, I hope that's o.k.

I tried compiling the library with -O3 ( on x64 Linux ) and it crashed when trying to call a native function.

Seems X64_CallFunction gets inlined and it treats pArgs as values on the stack. So when it goes through pushing the parameters on to the stack, the first time it's o.k. grabs the value then pushes that on to the stack. But the second time, it grabs the value just pushed on to the stack instead of the next pArg. On top of this the registers POP_LONG fills get clobbered.

I have a patch of sorts but I'm hesitant to post it as my assembler sucks. Anyway, I predeclared X64_CallFunction and added "__attribute__((noinline))" and added the register being used to the clobber list in POP_LONG.

It still crashing, but not in as_callfunc_x64_gcc.cpp.

Share this post


Link to post
Share on other sites
gargltk    125
Quote:
Original post by namtabmai
New fun bug. I posted it here rather than starting a new thread, I hope that's o.k.

I tried compiling the library with -O3 ( on x64 Linux ) and it crashed when trying to call a native function.

Seems X64_CallFunction gets inlined and it treats pArgs as values on the stack. So when it goes through pushing the parameters on to the stack, the first time it's o.k. grabs the value then pushes that on to the stack. But the second time, it grabs the value just pushed on to the stack instead of the next pArg. On top of this the registers POP_LONG fills get clobbered.

I have a patch of sorts but I'm hesitant to post it as my assembler sucks. Anyway, I predeclared X64_CallFunction and added "__attribute__((noinline))" and added the register being used to the clobber list in POP_LONG.

It still crashing, but not in as_callfunc_x64_gcc.cpp.


I have to admit I've never tested the code when compiled with -O3.

The object pArgs points to is in fact on the stack (it points to a local array declared in CallSystemFunction()). However I'm not sure I understand exactly what it is that gets clobbered by the pushing/popping of registers in X64_CallFunction(). I will look into this when I get some spare time and hopefully will have a patch "Soon (tm)"

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