Jump to content
  • Advertisement
Pto

Creating 64bit iOS native calling support

Recommended Posts

I have a little game running on windows that I've used AngelScript for and I'm now trying to port to iOS. A bit of googling showed native calling isn't currently supporting on 64bit arm devices so I looked into the generic calling convention.  However since I don't want to give up native calling on windows I'm going to either have to re-write all my existing code to try to maintain two different calling conventions (native+generic).... or take you up on this very old offer:

Quote

unfortunately native calling conventions on iOS 64bit is not yet supported (nor is any other 64bit ARM platform). I don't have access to any 64bit ARM platform so I can't implement this support myself, but if you want to give it a try on your own I can guide you through it. It usually doesn't take more than a week or two to get it to work. Although it involves assembler code it doesn't require a lot of understanding of assembler code since most of the time it is just a matter of copying existing code obtained by disassembling C++ compiled functions :).

 

My assembly skills are very limited but I can follow instructions.  If the offer to guide someone through the process is still available I'd love to try.  Just let me know where to start.  I have a mac with xCode installed and an iPhone 8 that I can install builds on (and PC with VC 2017 if that's at all helpful).

 

If however you're not able to help at the moment for any reason, no worries at all.  Thanks for creating angel script in the first place I've had a blast using it recently.  If however you are, hopefully this can help out anyone else who wants/needs this in future.

Share this post


Link to post
Share on other sites
Advertisement

I have very little time at the moment, but I'm very interested in seeing iOS 64bit native calling convention support (as well as Android 64bit).

It's not really necessary to have a lot of assembly skills. I don't have it either. Most of the assembler code to support native calling convention on other platforms was written by doing disassembly of C++ functions, and then piecing together the related code. 

I can certainly help you point out the direction on how to proceed. 

  1. Download the latest code revision from the SVN to get the regression test suite not included in the SDK
  2. Compile the test_feature app for iOS 64bit. There is a rather old xcode project included. You can try to upgrade it to the latest xcode version, or just start from scratch. (I'd like to get the updated xcode projects to check them into the SVN later)
  3. Take a look at the as_config.h file, and update it to enable native calling convention on iOS 64bit. You probably need to change the condition for #if defined(__GNUC__) => #if defined(__APPLE__) => #if defined(__arm64__) to remove #define AS_MAX_PORTABILITY and include AS_ARM64 (AS_ARM64 is not used yet, we'll use it to tell the compiler to include the code needed for arm64 native calling convention)
  4. Create a new as_callfunc_arm64.cpp (you can use as_callfunc_arm.cpp as the base to begin with).
  5. Change the #ifdef AS_ARM to #ifdef_AS_ARM64 so it will only be compiled on arm64
  6. You will probably need a as_callfunc_arm64_xcode.S assembly file too (similar to as_callfunc_arm_xcode.S)
  7. Change the main.cpp in the test_feature app to comment out all the test cases before main() => TestExecute() which is the first test case designed specifically for testing the native calling convention. 
  8. Make the necessary changes to allow you to compile and debug the test_feature app on iOS 64bit. 

At the end of these steps you'll have what is needed to get started on adding the support for iOS 64bit. Next up is an iteration of compile, debug, disassembly, etc to understand the underlying ABI used by Apple on iOS and creating the necessary code to support the native calling convention.

The test_feature test cases are ordered by the complexity of the native calls, so the first TestExecute() scenario just calls a C function without any arguments, just to see the call being made. The next scenario add an integer argument, then more, then more. After functions with integer arguments is working, it goes on to float and double arguments, that usually work differently. After that it goes on to class methods and passing/returning objects. Only when all the scenarios that are designed for testing the native calling convention are working, should you uncomment the rest of the test suite to do the full regression test.

If you share your progress here on the forum, others may also be able to join in and help progress even faster.

Share this post


Link to post
Share on other sites

You might also find some useful information in the source code for dyncall. It seems to support arm64 as well.

Sidenote - would it be interesting to implement dyncall into Angelscript directly so that Angelscript itself doesn't need to maintain architecture calling code? I don't know exactly if there are any massive differences.

Share this post


Link to post
Share on other sites

@WitchLord : Thanks for the steps, I'll give it a try and post back any results or issues.  Hopefully I can get somewhere useful without taking up to much of anybodies time.

@Miss : Thanks for the link - I'll definitely check that out.

Share this post


Link to post
Share on other sites
21 hours ago, Miss said:

Sidenote - would it be interesting to implement dyncall into Angelscript directly so that Angelscript itself doesn't need to maintain architecture calling code?

While dyncall is an interesting library, it is out of the question to add any dependency to thirdparty libraries from AngelScript. It is one of the main principles that I follow.

It can still be an additional source for gaining understanding on the arm64 ABI though.

Share this post


Link to post
Share on other sites
Just now, WitchLord said:

While dyncall is an interesting library, it is out of the question to add any dependency to thirdparty libraries from AngelScript. It is one of the main principles that I follow.

Ah yes, that is indeed the impression I've always had and one that I really appreciate a lot. :)

Share this post


Link to post
Share on other sites

Sadly I'm still not up to native calling, I'm just trying to get the whole thing working with AS_MAX_PORTABILITY to ensure I'm starting from a solid base.  I've got the 64bit iOS app setup, it's building and running on device and all but one of the tests pass.  Annoyingly though TestExecuteString() fails on an assert:

       assert(*reinterpret_cast<void**>(ref) != 0);

on line 193 of scripthelper.cpp.  The assert is not even part of the test - just part of the Script Helper add-on.  'ref' is a pointer to a std::string so I'm not sure what this assert is even doing here.  Casting to a double pointer then de-referencing back to it's original single pointer to check if it's null?  The code works if I remove this, so not sure why the assert is triggering, but I'm clearly not understanding something.  For now I'm just going to move on to native calling next week, but if that assert is in some way important let me know.

Share this post


Link to post
Share on other sites

line 193 seems to be for when the execution return type is not a handle (pointer).
You can see that the handle version has the opposite assert.
I guess it just assumes that the first 64bits of the return type should not be all 0 and tries to catch instances where people incorrectly used return values by handle.
I think the return address will be treated as a fully constructed object and some form of assignment will be used on it.
Make sure that having the first 64bits of 0 in your object instance is valid before removing that assert.
 

Share this post


Link to post
Share on other sites
On 4/13/2019 at 9:08 AM, Pto said:

       assert(*reinterpret_cast<void**>(ref) != 0);

This assert may very well be invalid and should be removed. What it does is that it checks if the first PWORD of the object referred to by ref is not null, in an attempt to validate if the object is seemingly a valid object.

Interestingly it doesn't trigger on any other platform though that I've tested on.

Which test is triggering this assert? 

On 4/13/2019 at 9:08 AM, Pto said:

I've got the 64bit iOS app setup, it's building and running on device and all but one of the tests pass

Which test doesn't pass?

 

 

Share this post


Link to post
Share on other sites
On 4/15/2019 at 11:20 PM, WitchLord said:

Which test is triggering this assert?

Which test doesn't pass?

Sorry I wasn't clear in my initial post.  TestExecuteString() is the test that trigger the assert.  The assert triggering inside TestExecuteString() is the only issue I had when AS_MAX_PORTABILITY defined.  I'm not sure if triggering an assert is technically a failure or not but that's what I meant when I said a test failed.  As I mentioned if I simply comment out the assert it all worked and everything passed including TestExecuteString().

 

After Easter break I got back to it and I removed AS_MAX_PORTABILITY and set up the two Arm64 files ('as_callfunc_x64_arm.cpp' and 'as_callfunc_x64_arm_xcode.S') as instructed.  In the .cpp I was able to get it compiling based on what I saw in the other x64 files, and fixing a few other minor compiler issues (mostly just changing any asDWORD types to asQWORD ).  So the .cpp now compiles and I think it's doing what it's meant to do.

I'm left with a whole heap of assembly errors for the .S.  Currently it's just a cut+paste of the original ARM native call without any changes for 64bit.  This is where my programming knowledge ends.  I don't know any arm assembly and certainly not enough to re-write the .S.

I've attached my two new files and the compiler errors generated by the assembly.  This is kind of as far as I can go on my own.  Any help appreciated and if anyone wants I try to zip up my test project for someone else to look at (but to get it working I had to change a few things so it's not a simple as just getting a new version of the xcode project sadly).

 

 

as_callfunc_x64_arm_xcode.S

as_callfunc_x64_arm.cpp

compile_errors.txt

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

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!