OCaml 4.00.0 on iOS: Progress Report
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