Psellos
Life So Short, the Craft So Long to Learn

OCaml 4.00.0 on iOS: Progress Report

August 25, 2012

After finding and resolving some problems, two of which were very interesting, I’m getting close to releasing a version of OCaml 4.00.0 that cross-compiles for iOS devices. I’ve tested it with all the OCaml iOS apps I can, and my colleagues at SEAiq have tested with their iOS apps also.

Update: OCamlXARM 3.1, based on OCaml 4.00.0, has been released! Read my blog post OCaml 4.00.0 on iOS Is Released. The OCaml-on-iOS page Compile OCaml for iOS has been updated for OCamlXARM 3.1.

I call the compiler OCamlXARM because it runs on a Mac, and cross-compiles for ARM-based iOS devices. You can read about the current release of OCamlXARM in Compile OCaml for iOS.

Initially the new version will compile only for armv7/Thumb, which means the generated apps will only run on moderately recent iOS devices (including all iPads). I’ll release an update that compiles for armv6/ARM, which will be able to create apps for all the historical iOS devices.

If you’re interested in trying a prerelease of the OCaml 4.00.0 cross compiler, send me an email. I recommend this for the adventurous only, but it’s extremely useful to me to get feedback on what works and doesn’t. The less adventurous can try the current release, linked above. The current release is based on OCaml 3.10.2 (a pretty old version admittedly), and has been used to create production iOS apps for a few years now.

For those interested in the ups and downs of doing the port, I wrote about earlier development stages in OCaml 4.00.0 Working on iOS. Here are the two interesting problems that came up recently.

While running a test version of our Cassino app I uncovered a code generation bug in the OCaml 4.00.0 compiler. It turned out to be in the scheduling pass, which reorders instructions to make them execute faster. This has been fixed by the experts at OCaml HQ—you can read about it as Mantis issue 5731. The fix will appear in the next bugfix release of OCaml (scheduled to be 4.00.1), but I’ve also merged the fix into OCamlXARM. Many thanks to (the illustrious) Xavier Leroy for looking at and fixing the problem.

I also had the pleasure to discover what I consider a bug in Apple’s iOS assembler (or possibly it’s a problem with the link editor). You can see the problem in this simple example, using the cross-development versions of the assembler and the link editor—as and ld—from the Xcode 4.3.3 iOS toolchain:

$ cat diffplus.s
        .data
        .word Lsym - . + 0x80000000
        .word 0x1966
Lsym:
        .word 0x1967
$ as -arch armv7 -o diffplus.o diffplus.s
$ otool -d diffplus.o
diffplus.o:
(__DATA,__data) section
00000000        80000008 00001966 00001967 
$ otool -rv diffplus.o
diffplus.o:
Relocation information (__DATA,__data) 2 entries
address  pcrel length extern type    scattered symbolnum/value
00000000 False long   n/a    SECTDIFFTrue      0x00000008
         False long   n/a    PAIR    True      0x00000000

What the otool output shows is that the three generated 32-bit values have the proper values. However, the first of the values is marked as a (somewhat strange) relocatable value. This is incorrect—all of the values are assembly-time constants, and no relocation is required. This error seems to prevent some types of linking of the generated object file:

$ ld -r -o ldr1.o diffplus.o
$ ld -r -o ldr2.o ldr1.o
ld: in ldr1.o, in section __DATA,__data reloc 0: sectionForAddress(0x80000000) address not in any section for inferred architecture armv7
$

The purpose of ld -r is to do incremental linking, that is, to combine several object files (.o files) into one. For files like diffplus.o, however, ld generates an invalid object file as output. If you try to process the file with a later run of ld, you get the error shown.

Unfortunately, the OCaml compiler creates output that looks exactly like diffplus.s above. Lines like this are used in the frame tables that describe OCaml function call sites, used by the garbage collector to avoid collecting values that will still be live when the call returns. Furthermore, ld -r is used internally to implement the OCaml compiler’s -output-obj flag.

After some experimentation I found a workaround. The following assembly code avoids the (seeming) bug in as:

$ cat diffplusok.s
        .data
offset001 = Lsym - . + 0x80000000
        .word offset001
        .word 0x1966
Lsym:
        .word 0x1967
$ as -arch armv7 -o diffplusok.o diffplusok.s
$ otool -d diffplusok.o
diffplusok.o:
(__DATA,__data) section
00000000        80000008 00001966 00001967 
$ otool -rv diffplusok.o
diffplusok.o:
$
$ ld -r -o ldrok1.o diffplusok.o
$ ld -r -o ldrok2.o ldrok1.o
$

This transformed version convinces the assembler that the value is constant at assembly time, so there are no relocation markings in the generated file. This doesn’t present any problems for ld, and so incremental linking works OK.

If no other big problems appear, the new release will be available shortly. The new version will be OCamlXARM 3.1. I’m looking forward to trying out some of the more modern OCaml features in my iOS programming, and I’d also like to do some timing tests. I wonder whether armv7/Thumb code is faster than the armv6/ARM code generated by the previous OCamlXARM release. I’ve also started to be curious how much the scheduling pass (where the recent bug was fixed) improves the speed of my code.

If you have comments or questions, please leave them below, or email me at jeffsco@psellos.com.

Posted by: Jeffrey

Comments

blog comments powered by Disqus