在 iOS 设备上编译原生 lc3tools
这次寒假回家的时候,给已经慢得要死的 iPad mini 降级到了 iOS 8.4.1,然后用 CoolBooter 装上了 iOS 6.1.3(因为 iOS 8 还是很慢)——反正设备里面已经没有任何有用的数据了,怎么搞都可以。既然如此,在安装上 OpenSSH 之后就可以 ssh
到我们的设备上搞事啦。
(base) ➜ ~ ssh [email protected]
[email protected]'s password: # password is 'alpine' by default
Kud:~ root# uname -a
Darwin Kud 13.0.0 Darwin Kernel Version 13.0.0: Wed Feb 13 21:37:47 PST 2013; root:xnu-2107.7.55.2.2~1/RELEASE_ARM_S5L8942X iPad2,5 arm P105AP Darwin
但是系统内置的命令很少,基本干不了什么事情(当然要想 rm -rf /
删光文件跑路还是可以的)。我们知道,Cydia 实际上是使用的 Debian 的那一套来管理软件包的,但是找不到 apt-get
——所以我们在 Cydia 中安装 APT 0.6 Transitional
或者 APT 0.7 Strict
1,然后就可以抛弃掉这个缓慢的前端界面了。
默认的 APT 源(在 /etc/apt/sources.list.d/
里面)的命令行工具比我原先想象的要多不少。要是能够装个编译器来编译我们自己写的程序就好了。
当然,这是可以做到的。至于为什么选择 lc3tools
作为我们的目标?那是因为这个程序足够小,同时舍友 @iBug 也成功在 Android 上编译了这个工具。
有什么用吗?emmmmmm,其实没什么用,至少我相信不会有人去拿这玩意去完成自己的 ICS 作业。
准备工具链
默认源里可以找到 gcc
和 clang
。
Kud:~ root# apt-cache search gcc
iphone-gcc - a native c compiler _on_ the phone
com.macciti.sliderkoenigseggccxorange - Nice Slider of a orange Koenigsegg CCX. If you want your Car as a Slider on your iPhone, email me! I will make Sliders of all your Cars!! ;)
com.bigboss.20toolchain - Full *compatibility* toolchain with one click! Use this to compile your 1.1.x apps for 2.0 with some limitations. BigBoss' headers for 1.1.1 from working Cygwin toolchain. Also depends on all other necessary packages. Copies to /var/include and symlinks /usr/local/include to /var/include if possible. Also links gcc to arm-apple-darwin-gcc.
# 以下省略
Kud:~ root# apt-cache search clang
org.coolstar.iostoolchain - LLVM+Clang, ld64, CC tools, Make, ldid
org.coolstar.llvm-clang - LLVM, Clang, and Compiler for 32/64Bit devices
org.coolstar.llvm-clang32 - LLVM, Clang, and Compiler-RT 3.4 SVN
org.coolstar.llvm-clang64 - LLVM, Clang, and LLD 5.0.1 for iOS/arm64
# 以下省略
但如果你去尝试安装 gcc
,会发现缺少 libgcc
的依赖。所以还是去安装 org.coolstar.iostoolchain
吧(据说2 gcc
的版本比 LLVM+Clang
工具链要老得多)。
好,安装完这一套工具链,写个 Hello, world! 编译看看。
Kud:~ root# cat helloworld.c
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}
Kud:~ root# clang helloworld.c
helloworld.c:1:10: fatal error: 'stdio.h' file not found
#include <stdio.h>
^
1 error generated.
最后你会绝望得发现,就算去掉 include
,自己动手声明函数,也会在链接的时候遇到问题。
Kud:~ root# cat test.c
int printf(const char * restrict format, ...);
int main(void) {
printf("Hello, world!\n");
return 0;
}
Kud:~ root# clang test.c
ld: library not found for -lcrt1.3.1.o
clang-3.7: error: linker command failed with exit code 1 (use -v to see invocation)
关于 SDK
为了解决这个问题,我们需要 iOS 对应的 SDK。在下载3对应版本的 SDK 之后,我们可以看看里面有什么东西。
我们看到了熟悉的 usr/lib
和 usr/include
。
(base) ➜ iPhoneOS6.1.sdk ls usr/include/stdio.h
usr/include/stdio.h
(base) ➜ iPhoneOS6.1.sdk ls usr/lib/crt1.3.1.o
usr/lib/crt1.3.1.o
缺少的文件都在这里。
可以理解为什么 iOS 不自带这些文件,作为移动端的操作系统,头文件和运行库的目标文件对于终端用户而言没有任何意义。
用 scp
传过去,然后怎么让 clang
知道 SDK 的位置呢?clang
有一个参数 -isysroot
,可以指定系统根目录的位置。正常情况下,这个目录就是 /
,但是很明显 /usr/
下面没有我们想要的东西。
所以我们来试一下:
Kud:~ root# clang helloworld.c -isysroot ~/sdk # ~/sdk is where you store your iOS SDK
Kud:~ root# ./a.out
Hello, world!
可以了。
如果手头有一台 Linux 机器,那么也可以看到类似于 crt1.3.1.o
的文件。
taoky@linux-cloud:/usr/lib/x86_64-linux-gnu$ ls *.o # on a Ubuntu 18.04.2 machine
Mcrt1.o crt1.o crtn.o grcrt1.o rcrt1.o
Scrt1.o crti.o gcrt1.o libtsan_preinit.o
crt
是 C Runtime 的缩写。我们知道 Linux 一般而言 C 运行库是 glibc
,那么 macOS/iOS 下是什么?
Kud:~ root# otool -L a.out
a.out:
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 173.8.0)
dylib
格式是 macOS/iOS 的动态库格式,类似于 Linux 下的 *.so
。而 libSystem
库提供了 libc
的功能4。
开始编译
下载一份 lc3tools
源代码,丢过去。(这里的 OpenSSL 版本太老了,连 GitHub 都连不上,所以只能电脑上下载好之后传过去)
在 ./configure
中缺失的 flex
依赖(用于汇编器的词法分析)可以在源里找到。但 wish
是什么?
wish
是 Tcl/Tk 的解释器,可以用来创建 GUI 界面。显然我们这里不需要 GUI(也显示不了),所以可以直接删掉。
另外会报告找不到 gcc
,一个简单粗暴的解决方法是创建软链接。
Kud:~/lc3tools root# ln -s /usr/bin/clang /usr/bin/gcc
由于我们先前提到的原因,我们还要修改 Makefile.def
,以使 configure
生成正确的 Makefile
。
将
CFLAGS = -g -Wall # 编译时选项
LDFLAGS = -g # 链接时选项
修改为
CFLAGS = -g -Wall -isysroot ~/sdk
LDFLAGS = -g -isysroot ~/sdk
再运行 ./configure
,之后就可以顺利编译了。
成功~
Comments