Sunday, October 20, 2013

How To Cross Compile A Binary For iDevices

How To Cross Compile A Binary For iDevices

by cawan (cawan[at]ieee.org or chuiyewleong[at]hotmail.com)

on 20/10/2013

The gcc that comes with OSX without Xcode being installed does not include cross
compilation toolchain in generating software for idevices. Let's verify.

awans-MacBook-Pro:~ cawan$ gcc
i686-apple-darwin11-llvm-gcc-4.2: no input files
cawans-MacBook-Pro:~ cawan$ which gcc
/usr/bin/gcc
cawans-MacBook-Pro:~ cawan$ ls -l /usr/bin/gcc
lrwxr-xr-x  1 root  wheel  12 Sep 26  2012 /usr/bin/gcc -> llvm-gcc-4.2
cawans-MacBook-Pro:~ cawan$ ls -l /usr/bin/llvm-gcc-4.2
lrwxr-xr-x  1 root  wheel  32 Sep 26  2012 /usr/bin/llvm-gcc-4.2 ->
../llvm-gcc-4.2/bin/llvm-gcc-4.2
cawans-MacBook-Pro:~ cawan$ ls -l /usr/llvm-gcc-4.2/bin/llvm-gcc-4.2
-rwxr-xr-x  1 root  wheel  117168 Sep 26  2012 /usr/llvm-gcc-4.2/bin/llvm-gcc-4.2

So, the gcc is just a symbolic link to llvm-gcc-4.2. Let's check the llvm-gcc-4.2.

awans-MacBook-Pro:~ cawan$ /usr/llvm-gcc-4.2/bin/llvm-gcc-4.2
i686-apple-darwin11-llvm-gcc-4.2: no input files
cawans-MacBook-Pro:~ cawan$ /usr/llvm-gcc-4.2/bin/llvm-gcc-4.2 -arch armv7
llvm-gcc-4.2: error trying to exec '/usr/llvm-gcc-4.2/bin/arm-apple-darwin11-llvm-gcc-4.2':
execvp: No such file or directory
cawans-MacBook-Pro:~ cawan$ /usr/llvm-gcc-4.2/bin/llvm-gcc-4.2 -arch i686
i686-apple-darwin11-llvm-gcc-4.2: no input files

Well, the llvm-gcc-4.2 is just a forwarder to an appropriate compiler, either
i686-apple-darwin11-llvm-gcc-4.2 or arm-apple-darwin11-llvm-gcc-4.2, which is
decided by "-arch" parameter. When "-arch" is not specified, the default is
i686-apple-darwin11-llvm-gcc-4.2. Now, let us install a copy of Xcode (I am using
Xcode 4.5 here). After the installation is completed, the llvm-gcc-4.2 can be
found in 2 locations.

cawans-MacBook-Pro:bin cawan$ pwd
/Applications/Xcode.app/Contents/Developer/usr/llvm-gcc-4.2/bin
cawans-MacBook-Pro:bin cawan$ ls -l
total 1464
-rwxr-xr-x@ 1 cawan  admin  127776 Sep  8  2012 gcov-4.2
-rwxr-xr-x@ 1 cawan  admin  544416 Sep  8  2012 i686-apple-darwin11-llvm-g++-4.2
-rwxr-xr-x@ 1 cawan  admin  544416 Sep  8  2012 i686-apple-darwin11-llvm-gcc-4.2
-rwxr-xr-x@ 1 cawan  admin  117168 Aug  5  2012 llvm-c++-4.2
-rwxr-xr-x@ 1 cawan  admin  257552 Sep  8  2012 llvm-cpp-4.2
-rwxr-xr-x@ 1 cawan  admin  117168 Sep  8  2012 llvm-g++-4.2
-rwxr-xr-x@ 1 cawan  admin  117168 Sep  8  2012 llvm-gcc-4.2
cawans-MacBook-Pro:bin cawan$

cawans-MacBook-Pro:bin cawan$ pwd
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/llvm-gcc-4.2/bin
cawans-MacBook-Pro:bin cawan$ ls -l
total 2344
-rwxr-xr-x@ 1 cawan  admin  555104 Sep  8  2012 arm-apple-darwin10-llvm-g++-4.2
-rwxr-xr-x@ 1 cawan  admin  546896 Sep  8  2012 arm-apple-darwin10-llvm-gcc-4.2
-rwxr-xr-x@ 1 cawan  admin  130816 Sep  8  2012 gcov-4.2
-rwxr-xr-x@ 1 cawan  admin  551008 Sep  8  2012 i686-apple-darwin10-llvm-g++-4.2
-rwxr-xr-x@ 1 cawan  admin  546896 Sep  8  2012 i686-apple-darwin10-llvm-gcc-4.2
-rwxr-xr-x@ 1 cawan  admin  106112 Sep  8  2012 llvm-c++-4.2
-rwxr-xr-x@ 1 cawan  admin  255728 Sep  8  2012 llvm-cpp-4.2
-rwxr-xr-x@ 1 cawan  admin  106112 Sep  8  2012 llvm-g++-4.2
-rwxr-xr-x@ 1 cawan  admin  106112 Sep  8  2012 llvm-gcc-4.2
cawans-MacBook-Pro:bin cawan$

So, the cross compiler is only available in Platforms/iPhoneOS.platform/Developer/.
Now, let us try to build a simple binary to run in idevice.

cawans-MacBook-Pro:bin cawan$ ./llvm-gcc-4.2
i686-apple-darwin10-llvm-gcc-4.2: no input files
cawans-MacBook-Pro:bin cawan$ ./llvm-gcc-4.2 -arch armv7
arm-apple-darwin10-llvm-gcc-4.2: no input files
cawans-MacBook-Pro:bin cawan$ cat cawan_hello.c
#include
main()
{
  printf("\nhello cawan\n");
}
cawans-MacBook-Pro:bin cawan$ ./llvm-gcc-4.2 -arch armv7 cawan_hello.c -o cawan_hello
In file included from /usr/include/sys/_types.h:33,
                 from /usr/include/_types.h:27,
                 from /usr/include/stdio.h:67,
                 from cawan_hello.c:1:
/usr/include/machine/_types.h:34:24: error: arm/_types.h: No such file or directory
In file included from /usr/include/_types.h:27,
                 from /usr/include/stdio.h:67,
                 from cawan_hello.c:1:
...
...
...
cawans-MacBook-Pro:bin cawan$

Well, the headers and libraries of idevice should be specified for the cross compilation
process. It is located in the directory of iphone SDK being installed together with Xcode.

cawans-MacBook-Pro:bin cawan$ ls -l /Applications/Xcode.app/Contents/Developer/Platforms/
iPhoneOS.platform/Developer/SDKs/
total 0
drwxr-xr-x@  8 cawan  admin  272 Oct 17 09:28 iPhoneOS5.1.sdk
drwxr-xr-x@ 10 cawan  admin  340 Oct 15 23:47 iPhoneOS6.0.sdk
cawans-MacBook-Pro:bin cawan$

I have 2 versions of SDKs installed, 5.1 and 6.0. Now, I am going to use version 6.0.

cawans-MacBook-Pro:bin cawan$ ./llvm-gcc-4.2 -arch armv7 -o cawan_hello -isysroot
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
iPhoneOS6.0.sdk cawan_hello.c
cawans-MacBook-Pro:bin cawan$ ls -l cawan_hello
-rwxr-xr-x  1 cawan  admin  12604 Oct 20 15:13 cawan_hello
cawans-MacBook-Pro:bin cawan$ file cawan_hello
cawan_hello: Mach-O executable arm
cawans-MacBook-Pro:bin cawan$ lipo -info cawan_hello
Non-fat file: cawan_hello is architecture: armv7
cawans-MacBook-Pro:bin cawan$

Fine, it seems the binary is ready. Let's run it in iphone environment. Turn on the ssh
server in iphone and use tcprelay to connect into the iphone.

cawans-MacBook-Pro:python-client cawan$ python tcprelay.py 22:2222
Forwarding local port 2222 to remote port 22

Now, it is ready to copy the cawan_hello into the iphone via port 2222.

cawans-MacBook-Pro:bin cawan$ scp -P 2222 cawan_hello root@127.0.0.1:/Applications/
root@127.0.0.1's password:
cawan_hello                                   100%   12KB  12.3KB/s   00:00  
cawans-MacBook-Pro:bin cawan$

The cawan_hello is copied into /Applications/ of the iphone. So, it is ready to connect
into the iphone and run the cawan_hello.

cawans-MacBook-Pro:bin cawan$ ssh -p 2222 root@127.0.0.1
root@127.0.0.1's password:
snows-iPhone:~ root# cd /Applications
snows-iPhone:/Applications root# ls cawan_hello
cawan_hello*
snows-iPhone:/Applications root# ./cawan_hello
-sh: ./cawan_hello: Bad CPU type in executable
snows-iPhone:/Applications root#

Unfortunately, it seems the processor architecture of my iphone is not armv7. From the
back cover of my iphone, I can see its model number is A1241. Well, it is iphone 3G and
its processor architecture is armv6, not armv7. Let's recompile the binary again.

cawans-MacBook-Pro:bin cawan$ ./llvm-gcc-4.2 -arch armv6 -o cawan_hello -isysroot
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
iPhoneOS6.0.sdk cawan_hello.c
ld: file is universal (4 slices) but does not contain a(n) armv6 slice:
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/
iPhoneOS6.0.sdk/usr/lib/crt1.o for architecture armv6
collect2: ld returned 1 exit status
cawans-MacBook-Pro:bin cawan$

Well, it seems iphone sdk 6.0 is not compatible with armv6 architecture. Let's use
iphone sdk 5.1 instead.

cawans-MacBook-Pro:bin cawan$ ./llvm-gcc-4.2 -arch armv6 -o cawan_hello -isysroot
/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/
SDKs/iPhoneOS5.1.sdk cawan_hello.c
cawans-MacBook-Pro:bin cawan$

Copy the new cawan_hello into the iphone and run it again.

cawans-MacBook-Pro:bin cawan$ scp -P 2222 cawan_hello root@127.0.0.1:/Applications/
root@127.0.0.1's password:
cawan_hello                                   100%   12KB  12.3KB/s   00:00  
cawans-MacBook-Pro:bin cawan$ ssh -p 2222 root@127.0.0.1
root@127.0.0.1's password:
snows-iPhone:~ root# cd /Applications
snows-iPhone:/Applications root# ls cawan_hello
cawan_hello*
snows-iPhone:/Applications root# ./cawan_hello
Killed
snows-iPhone:/Applications root#

Good, the cawan_hello is capable to run in my iphone but it is killed by the iOS.
This is because the iOS will verify the signature of a binary first before allowing
it to run. If the signiture verification check is failed, then the iOS will kill
the binary which attempting to run. Anyway, since I know my iphone is jailbroken,
so I can simply use ldid to perform pseudo-signing to my cawan_hello. Let's try again.

cawans-MacBook-Pro:bin cawan$ ldid -S cawan_hello
cawans-MacBook-Pro:bin cawan$ scp -P 2222 cawan_hello root@127.0.0.1:/Applications/
root@127.0.0.1's password:
cawan_hello                                   100%   13KB  12.5KB/s   00:00  
cawans-MacBook-Pro:bin cawan$ ssh -p 2222 root@127.0.0.1
root@127.0.0.1's password:
snows-iPhone:~ root# cd /Applications
snows-iPhone:/Applications root# ls cawan_hello
cawan_hello*
snows-iPhone:/Applications root# ./cawan_hello

hello cawan
snows-iPhone:/Applications root#

Excellent, the cawan_hello can run properly in my iphone now. There are some arguments
about is it possible for Xcode 4.5 in generating binary for armv6 based idevices such
as iphone 3G or iPod touch 2G. From this exercise, it is proven the Xcode 4.5 is able
to generate armv6 binary by specifiying the base sdk as 5.1 and target architecture as
armv6.

pdf version:

http://www.scribd.com/doc/177494010/How-to-Cross-Compile-a-Binary-for-iDevices

1 comment:

  1. Hello,
    The Article on How To Cross Compile A Binary For iDevices is nice it give detail information about it.Thanks for sharing the article. Xamarin Consulting Services

    ReplyDelete