Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to iOS / Mac ARM64 #9699

Merged
merged 18 commits into from
Jul 28, 2020
Merged

Add support to iOS / Mac ARM64 #9699

merged 18 commits into from
Jul 28, 2020

Conversation

EduardoRFS
Copy link
Contributor

@EduardoRFS EduardoRFS commented Jun 22, 2020

Requirements

Apple / Darwin ARM64 assembler:

  • global label should be prefixed with _
  • local label should be prefixed with L
  • use assembly macros instead of C macros
  • remove .type and .size

Runtime requirements:

  • stop using x18 as the kernel sets it to 0 at anytime
  • only x0 to x9 are saved between calls when the linker stub is added

About this PR

This PR was based on the #1084 but it diverges on some details and it also addresses some problems, namely, shared libraries on iOS and ./configure support.

I tried to keep the ABI as close as possible to Linux ARM64, they're identical if we keep x15 as the ADDITIONAL_ARG and when the OCaml code is in the main binary.
After some changes, now both ARM64 platforms uses x8 as ADDITIONAL_ARG, so the only remaining difference in the ABI is #9752 and that we do only x0-x7 for ARGS.

But for iOS if the OCaml code is in a shared library it mess with every register except x0-x9 when making function calls, even to symbols in the same shared library. The ABI is x0-x7 for ARGS, x8 seems to be used for syscalls so it is also saved and x9 is saved in the same package as x8.

And to support iOS in a shared library this ABI needs to be followed, so x0-x7 was used for ARGS and x8 was used as the additional ARG.

Changes to Linux ARM64

It is a requirement to not use x18, by moving some registers it was possible to stop using it without any visible(to me) performance impact as the data dependency and the instructions was kept 1:1.

But as x18 is still safe to use, and x15 is also used as a temporary register, it seems like a good idea to use x18 as the ADDITIONAL ARG instead of x15.

That can easily be reverted if it isn't desired.

Current state + Tests

Currently I can compile it using a cross compiler and inside an iPhone with jailbreak is also possible to run the testsuite if you patch the iPhoneOS.sdk to support system(). Currently the best way to run the tests is exactly like that, an iPhone up to iPhone X with jailbreak on an ssh, but maybe Apple will release a Mac ARM.

The test suite is almost entirely green, I'm looking on how to solve all of them, but overall the support is great

https://gist.githubusercontent.com/EduardoRFS/d067cff0aebec4df0fe55539669fff05/raw/10e071ba62a094c37e2f140835ed33a2cacc3211/test-result-ocaml+ios.txt

Known causes:

statmemprof/internal.ml fails because iOS supports only 1008 on the stack size, so it doesn't fit in the stack

@EduardoRFS
Copy link
Contributor Author

as you may be interested: @shindere

runtime/sys.c Outdated Show resolved Hide resolved
@shindere
Copy link
Contributor

shindere commented Jun 22, 2020 via email

@EduardoRFS
Copy link
Contributor Author

Also backported to 4.10, same state as the trunk

https://github.com/EduardoRFS/ocaml/tree/4.10+ios

@xavierleroy
Copy link
Contributor

I haven't fully reviewed yet, and hope to do it soon, but this looks very good, and extremely timely! Thank you @EduardoRFS .

It would be very nice to add references to the iOS ABI (and the soon-to-be-revealed macOS one too!) in file asmcomp/arm64/NOTES.md. Is this the reference document you worked from? https://developer.apple.com/library/archive/documentation/Xcode/Conceptual/iPhoneOSABIReference/Articles/ARM64FunctionCallingConventions.html

@EduardoRFS
Copy link
Contributor Author

Added that, but it's not the full story, like x8 and x9 being safe across calls, it's in the linker code, as you can see the stub mentioning it. Couldn't found any reference for that as most details of that. Maybe mentioning that in the code?

dyld_stub_binder

@m-schmidt
Copy link
Contributor

m-schmidt commented Jun 29, 2020

Three remarks to this pull request:

  • the target triple for the new ARM based Macs seems to be not aarch64-*-darwin* but e.g. arm-apple-darmin20.0.0

  • with a patched target triple make world.opt works

  • make tests reports 4 failures:

    List of failed tests:
    tests/unwind/'driver.ml' with 1.1.1.1.1.1 (run)
    tests/unboxed-primitive-args/'test.ml' with 1.1.1.1.1.1 (check-program-output)
    tests/link-test/'test.ml' with 2.1.1.1.1.1.1.1.1.1.1.1.1 (check-ocamlopt.byte-output)
    tests/required-external/'main.ml' with 2.1.1.1.1 (check-ocamlopt.byte-output)

Edit: attached log files of testsuite: log.txt

@xavierleroy
Copy link
Contributor

@m-schmidt: thanks a lot for the early testing, the results are extremely encouraging!

tests/unwind is a macos-specific thing for Spacetime profiling; possibly Spacetime needs to be turned off on macOS/ARM64.
tests/unboxed-primitive-args may point to a mismatch in calling conventions.
tests/link-test and tests/required-external both complain about a .o being put in a .a and having size <> 0 mod 8; should be easy to track down.

Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit fdcfe0d must be removed before merging because it breaks the bootstrap. I understand why it is useful in a cross-compilation setting, but cross-compilation will have to be handled differently and in separate future work.

Makefile Outdated
@@ -1014,7 +1014,7 @@ toplevel/opttoploop.cmx: otherlibs/dynlink/dynlink.cmxa
make_opcodes := tools/make_opcodes$(EXE)

bytecomp/opcodes.ml: runtime/caml/instruct.h $(make_opcodes)
runtime/ocamlrun$(EXE) $(make_opcodes) -opcodes < $< > $@
$(CAMLRUN) $(make_opcodes) -opcodes < $< > $@
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make_opcodes is generated by boot/ocamlc -use-prims runtime/primitives, so it must be run with runtime/camlrun$(EXE).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will address it, thanks and also open a cross compilation PR.

If anyone is interested on why I made that, I got a native cross compiler to work(ocamlopt.opt), and this was a requirement.
https://github.com/EduardoRFS/reason-mobile/blob/master/patches/ocaml/files/make.cross.sh

Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(I'm trying to review commit-by-commit and Github doesn't make this easy.)

Commit 2c84349: I agree the use of x18 was wrong. The original ARM64/Linux port did not use x18 at all.

ARG_DOMAIN_STATE_PTR could be any register used for parameter passing beyond r0...r3, which are used to pass up to 4 arguments to the OCaml code being called from C.

The proposed change is OK as long as we don't need a second temporary register in addition to x16. If we ever need a second temp, we'll go back to using r17 and could use r4, say, as ARG_DOMAIN_STATE_PTR.

Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 02dd612 is fine. Well spotted!

However the commit message should be made more informative:

"Avoid implicit conversion from integer to FP

This is flagged (rightly so) by clang -Wimplicit-int-float-conversion."

Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 0c718d3 is OK.
Commit cf8cc86 is OK.
Commit 7654d56: I'm not sure about it. The prudent thing to do would be to keep the .size and .type declarations for ARM64/Linux code.

runtime/arm64.S Show resolved Hide resolved
Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 7db8f62 looks good to me.

Commit 51769c0 is OK, but it's a real pain that the macOS assembler doesn't support multiline C preprocessor macros like the GNU and LLVM assemblers.

Commit 7f6681b is misguided in my opinion. The compiled code should never use x18 for any purpose. But I'm pretty sure you can use x8 for the "ARG" register, see below why.

asmcomp/arm64/emit.mlp Outdated Show resolved Hide resolved
asmcomp/arm64/emit.mlp Outdated Show resolved Hide resolved
asmcomp/arm64/emit.mlp Outdated Show resolved Hide resolved
asmcomp/arm64/proc.ml Outdated Show resolved Hide resolved
asmcomp/arm64/proc.ml Outdated Show resolved Hide resolved
runtime/arm64.S Outdated Show resolved Hide resolved
Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last commit 2f1c175, looks good to me. A small suggestion below.

Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the style comment I promised.

Comment on lines 30 to 31
let is_macosx =
Config.system = "macosx"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could move this definition to asmcomp/arm64/arch.ml, so that you don't have to repeat it in selection.ml.

Also, the house style would omit is_ and call this variable macosx. For example in asmcomp/amd64/arch.ml, we have a win64 Boolean, not is_win64.

Also, the new brand name is macOS, so macOS or macos would work too.

Copy link
Contributor Author

@EduardoRFS EduardoRFS Jun 29, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm trying to keep it coherently with every other mention where it is macosx, if we want to rename, it should be in a future PR. But fully agreed on removing the is_ and moving to arch.ml

@EduardoRFS
Copy link
Contributor Author

EduardoRFS commented Jun 29, 2020

@xavierleroy thanks for the review, it's funny I had even implemented x8 instead of x18 for every platform, but I was thinking "it will slightly increase the spill rate, but if you agree on that, this is nice.

Also it will makes a lot more easier to check the overall code because we will not have any branching except by the calling convention.

Thx for the review, will address the points maded in the following days and fix the buggy tests.

@EduardoRFS
Copy link
Contributor Author

EduardoRFS commented Jun 29, 2020

@m-schmidt seriously, thanks, are you sure about the triplet? Like is that what clang -dumpmachine get's you? If so I can fix it. It was the same for iOS where the triplet is arm64-apple-ios13.5.0. So I was doing ./configure --host=aarch64-apple-darwin19.5.0 --build=aarch64-apple-darwin19.5.0.

Also if you can or know someone who can lend me an ssh I have time to address it, I'm doing this fulltime. And would love to address esy(and opam if needed).

@m-schmidt
Copy link
Contributor

I get the following output:

$ clang -dumpmachine
arm64-apple-darwin20.0.0

But the configure script of OCaml prints:

configure: Configuring OCaml version 4.12.0+dev0-2020-04-22
checking build system type... arm-apple-darwin20.0.0
checking host system type... arm-apple-darwin20.0.0
checking target system type... arm-apple-darwin20.0.0

@EduardoRFS
Copy link
Contributor Author

@m-schmidt thx, is exactly what I was expecting, the configure script doesn't know arm64 it's not an option, so I'm going to fix for both of them arm64-apple-darwin19.5.0 = Darwin ARM64. Which is the same problem as previously where x86_64-apple-darwin19.5.0 could be iOS x86_64 or mac x86_64.

Simple to fix, thanks for your help

@xavierleroy
Copy link
Contributor

Configuration triplets are guessed by the config.guess script, which is straight from the FSF. Please try with the newest scripts first (https://savannah.gnu.org/projects/config), before modifying our configure.ac.

@shindere
Copy link
Contributor

shindere commented Jun 30, 2020 via email

@shindere
Copy link
Contributor

shindere commented Jun 30, 2020 via email

@EduardoRFS
Copy link
Contributor Author

@shindere actually both, I use a jailbroken iPhone, quite simple to setup. But also I have an iOS emulator working (xnu-qemu-arm64), currently it doesn't support KVM so full software emulation, but I'm working on that.

@shindere
Copy link
Contributor

shindere commented Jun 30, 2020 via email

@EduardoRFS
Copy link
Contributor Author

EduardoRFS commented Jun 30, 2020

@shindere I can update my iPhone, every iPhone up to the iPhone X, has a permanent security problem into the ROM part of the bootloader and that leads to jailbreak. Look for checkra1n. So while iPhone X is supported that should still be valuable.

The emulator, you should be able to setup iOS 12 which is the same from a binary perspective as iOS 13. If you're using macOS following the tutorial on this README.md should work, for Linux you need some patches that I didn't publish to get the network to work. After having everything setup, it's just like any VM, with working SSH.

BTW I'm waiting the mac ARM, as it should be able to run almost exactly the same binaries as a normal iPhone when using the simulator. Except by some really low level features(SECURE_KERNEL).

@xavierleroy
Copy link
Contributor

xavierleroy commented Jul 1, 2020

I had even implemented x8 instead of x18 for every platform, but I was thinking "it will slightly increase the spill rate, but if you agree on that, this is nice.

Right, I'm not worried at all about extra spilling here. For Iextcall that goes through caml_c_call, all registers are destroyed anyway. For Ialloc that goes through caml_allocN, we're not in "fast code" mode, instead we're optimizing for code size, so a tiny slowdown is OK.

@EduardoRFS EduardoRFS changed the title Add support to iOS / Darwin ARM64 Add support to iOS / Mac ARM64 Jul 2, 2020
@avsm
Copy link
Member

avsm commented Jul 27, 2020

I'm seeing lots of alignment warnings from ocamlopt generated code:

/Applications/Xcode-beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ranlib:
archive member: src/state/opam_state.a(opamPackageVar.o) offset in archive not a
multiple of 8 (must be since member is an 64-bit object file)

Reading the manual page for ranlib reveals the worrying detail that the libtool(1) command (not to be confused with the GNU libtool) replaces ranlib now:

Libtool with -static is intended to replace ar(5) and ranlib

There's already a bit of a morass of workarounds for macOS-specific behaviour with ranlib/ar (especially around empty archives) in trunk, so I stopped looking there for the evening :-)

@xavierleroy
Copy link
Contributor

Reading the manual page for ranlib reveals the worrying detail that the libtool(1) command (not to be confused with the GNU libtool) replaces ranlib now

I'm seeing the glass half-full: maybe libtool -static will be less finicky than ar? Time to investigate...

@xavierleroy
Copy link
Contributor

I confirm everything works and builds without warnings if "ar" is configured to be a shell script that calls "libtool -shared" underneath. Nonetheless, it would be nice if a registered Apple developer could report the issue with "ar", as it is affecting other programs as well.

@avsm
Copy link
Member

avsm commented Jul 28, 2020

I filed radar bug FB8190988 on Apple's system with the ranlib/ar warning logs and repro instructions from this PR.

Copy link
Contributor

@xavierleroy xavierleroy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed again. Looks good to me. I see no reason to delay merging, since the remaining macOS problems ("ar" warnings and "tests/unwind" failure) are probably not our fault and can be worked around later.

@xavierleroy xavierleroy merged commit a0a1ba4 into ocaml:trunk Jul 28, 2020
xavierleroy added a commit that referenced this pull request Jul 28, 2020
@EduardoRFS EduardoRFS deleted the trunk-ios branch July 28, 2020 15:05
@shindere
Copy link
Contributor

Am I correct that the INSTALL file has not been updated and that we don't
currently have any documentation explaining how to build OCaml on iOS
in the repository?

@EduardoRFS
Copy link
Contributor Author

@shindere you would be correct, but is the same as any compiler after the fix on config.guess, if you're using jailbreak. And is the the same as any cross compiler otherwise. Just configure and make

@shindere
Copy link
Contributor

shindere commented Jul 29, 2020 via email

@m-schmidt
Copy link
Contributor

I filed radar bug FB8190988 ...

Mine is FB8207693 (which makes 16k filed bugs in under 2 days). I made a shorter example to reproduce with just plain C files. Let's hope for the best.

@m-schmidt
Copy link
Contributor

Good news! With Beta 4 the alignment warnings of ar/ranlib are gone.

EduardoRFS pushed a commit to EduardoRFS/ocaml that referenced this pull request Sep 8, 2020
Add support for iOS and macOS on ARM64
EduardoRFS pushed a commit to EduardoRFS/ocaml that referenced this pull request Sep 8, 2020
Add support for iOS and macOS on ARM64
EduardoRFS pushed a commit to EduardoRFS/ocaml that referenced this pull request Nov 16, 2020
Add support for iOS and macOS on ARM64
EduardoRFS pushed a commit to EduardoRFS/ocaml that referenced this pull request Nov 16, 2020
Add support for iOS and macOS on ARM64
EduardoRFS pushed a commit to EduardoRFS/ocaml that referenced this pull request Nov 18, 2020
Add support for iOS and macOS on ARM64
avsm pushed a commit to avsm/ocaml that referenced this pull request Nov 26, 2020
Add support for iOS and macOS on ARM64
EduardoRFS pushed a commit to EduardoRFS/ocaml that referenced this pull request Nov 30, 2020
Add support for iOS and macOS on ARM64
EduardoRFS pushed a commit to EduardoRFS/ocaml that referenced this pull request Dec 2, 2020
Add support for iOS and macOS on ARM64
@gasche gasche mentioned this pull request Nov 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants