前言

本文在Ubuntu 64位系统上对qemu项目进行交叉编译,并且只编译与qemu user mode有关的代码。

下文中的”NDK”若无特殊说明均指”Android NDK”。

下文中”$NDK”表示的是NDK的根目录。

步骤

1. 下载并安装Android NDK

下载并安装Android NDK的过程在这里不做介绍。

2. 下载qemu

3. 设置NDK工具的环境变量

为交叉编译设置Android NDK环境变量:NDK、SYSROOT

4. 编译依赖库

glib

编译可在Android上运行的glib库

编译参考资料:编译可在Android上运行的glib库

libpng12

下载地址:https://sourceforge.net/projects/libpng/files/libpng12/

编译参考资料:编译可在Android上运行的libffi库

5. 创建pkg-config的软链接

ln命令中的源路径是pkg-config工具的源路径。

如果不创建这个软链接,当执行configure脚本时会报下面的错误:

6. 修改configure

添加arm的PIE支持

找到下面的代码:

将”i386-Linux|x86_64-Linux|x32-Linux|i386-OpenBSD|x86_64-OpenBSD”更改为”i386-Linux|x86_64-Linux|x32-Linux|i386-OpenBSD|x86_64-OpenBSD|arm-Linux”。

如果不这么做的后果,使用”readelf -S qemu-arm”查看编译出来的qemu-arm可执行文件的段,可以发现所有在运行时可加载段的地址均以0x60000000为基址。

在configure中有这么一段代码:

如果

如果qemu-arm可加载段的基址为0x60000000,当qemu-arm在Android设备上运行时将会发生”Segmentation fault”,详情请参考Android上可执行ELF文件中的段不能有基址。

7. 运行configure

命令行解析

configure脚本会在终端输出一些关键的信息,如:用什么编译器,flags等。

 

PKG_CONFIG_PATH

上面命令中的PKG_CONFIG_PATH="$SYSROOT/usr/lib/pkgconfig"是必要的,如果不设置这个宏,configure脚本输出”CFLAGS”的内容见下:

关注”-I”后的路径,首先说一下这个路径是怎么来的,configure脚本中有下面的代码:

“glib_cflags=$pkg_config --cflags $i“语句会获得glib的包含目录,看这篇文章的人如果电脑上安装有glib2.0可以通过这个命令进行查看输出内容:pkg-config –cflags glib-2.0。然而这个路径并不是我想要的,因为我现在是交叉编译,目标是ARM,所以我在这里将一个新的pkgconfig目录路径设置到PKG_CONFIG_PATH宏,输入下面的命令查看输出内容:

输出内容:

会发现此时”-I”后的路径有了改变。

注意:pkgconfig是一个目录,在这个目录中包含了步骤5中安装的依赖库的信息。

–target-list –cpu

–target-list arm-linux-user 意味着编译出来的qemu程序用于user mode,可以执行arm指令,并且这个arm指令的可执行程序的执行环境基于linux系统。 
–cpu=arm 意味着编译出的qemu程序只能在arm机器上执行。

–disable-system –disable-bsd-user

–disable-system:不编译system mode的代码。 
–disable-bsd-user:不编译bsd user mode的代码。

–cross-prefix

交叉编译工具的前缀,在当前命令行中它的值为”arm-linux-androideabi-“,那么configure脚本会去查找名为arm-linux-androideabi-gcc、arm-linux-androideabi-g++等工具。

–disable-tools

当命令行中有–disable-tools选项时,脚本中的禁用want_tools宏将被设置为”no”,这个宏默认为”yes”。当want_tools宏为”yes”时,会对tools宏进行设置,下面是与want_tools有关的设置tools宏的代码:

configure脚本会将tools宏的内容写入config-host.mak文件。

–disable-guest-agent

当没有这个选项时,编译会报下面的错误:

为PC编译qemu项目没有这个命令选项时不会报这个错误,然而lockf函数在Android上并不存在,所以为Android编译qemu项目时会报这个错误。

编译错误排除

ld: error: cannot find -lutil

将根目录下的Makefile文件中下面的内容注释:

ifaddrs.h: No such file or directory

错误信息

修复办法:将这个链接中的源文件都下载下来:android-ifaddrs,将下载下来的文件拷贝到qga/目录下。然后找到qga/Makefile.objs文件,将”ifaddrs.o”插入”qga-obj-$(CONFIG_POSIX)”宏中。

mqueue.h: No such file or directory

错误信息

修复办法:将”#include <mqueue.h>”更改为”#include <linux/mqueue.h>”。

char __unused[128 - sizeof(target_sigset_t)];

错误信息

修复办法:将__unused更改为_unused。

syscall.c:4108:9: error: dereferencing pointer to incomplete type

错误信息

修复办法

改为

disas/arm-a64.cc:67: error: undefined reference to ‘__cxa_end_cleanup’

错误信息

解决办法 :在configure中找到下面的代码:

将这些代码注释掉:

原因分析 :目前在Android NDK中没有64位版本的object。

syscall.c中找不到符号

错误信息

解决办法:在syscall.c文件中写下面的内容

编译清理命令

执行下面两个命令:

make clean

make distclean

 

编译debug版

调用configure脚本的命令行中添加”–enable-debug”命令选项。

作者:寻禹@阿里聚安全,更多技术文章,请访问阿里聚安全博客

编译可在Android上运行的qemu user mode的更多相关文章

  1. 系列篇|编译可在Android上运行的依赖库(一):glib库

    前言 这是系列文章,它们由<编译可在Android上运行的glib库>及其他4篇文章组成,这4篇文章在“编译依赖库”一节中列出.由于glib库依赖于其他第三方库,所以需要先将依赖的第三方库 ...

  2. 编译可在Nexus5上运行的CyanogenMod13.0 ROM(基于Android6.0)

    编译可在Nexus5上运行的CyanogenMod13.0 ROM (基于Android6.0) 作者:寻禹@阿里聚安全 前言 下文中无特殊说明时CM代表CyanogenMod的缩写. 下文中说的“设 ...

  3. 在Android上运行Java和C程序

    在linux上运行java程序,直接用javac编译,再用java启动虚拟机运行就行了.但是在Android上,由于虚拟机和pc端的不同,所以操作方法也是不一样的.下面介绍Android上运行Hell ...

  4. 在 android 上运行 python 的方法

    在android上运行python脚本,或者在android上使用python交互界面,对熟悉python的研究或开发人员来说,是一件很有吸引力的事情,因为python脚本真是非常高效,另外,有很多非 ...

  5. react native-调用react-native-fs插件时,如果数据的接口是需要验证信息的,在android上运行报错

    调用react-native-fs插件时,如果数据的接口是需要验证信息的,在android上运行报错,而在iOS上运行没问题.原因是因为接口是有验证信息的,而调用这个插件时没有传入,在iOS上会自动加 ...

  6. NDK编译可执行文件在Android 中运行显示error: only position independent executables (PIE) are supported.失败问题解决办法。

    由于使用了NDK编译的可执行文件在应用中调用,在Android 7.0上的运行情况发现,当运行该可执行文件时,报如下错误: error: only position independent execu ...

  7. Spark源码编译并在YARN上运行WordCount实例

    在学习一门新语言时,想必我们都是"Hello World"程序开始,类似地,分布式计算框架的一个典型实例就是WordCount程序,接触过Hadoop的人肯定都知道用MapRedu ...

  8. Unity3D之AssetBundle学习:Android上运行笔记

    路径统一 在Android上加载StreamingAssets文件夹下的AssetBundle文件,首先需要对加载地址进行处理,注意PC.Android和IOS的地址不一致需要针对不同的平台不同的处理 ...

  9. Android上运行本地c

    在android代码中编译一个可执行文件,主要功能是对文件的读写, 简单贴出来: #include <errno.h> #include <stdio.h> #include  ...

随机推荐

  1. SQL Server架构 -- 数据库文件和文件组

    在SQL SERVER中,数据库在硬盘上的存储方式和普通文件在Windows中的存储方式没有什么不同,也是在特定文件夹下创建不同的文件,然后经过文件存储系统去抓取数据信息.理解文件和文件组的概念可以帮 ...

  2. Project Euler欧拉计划

    1 If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. Th ...

  3. java中的throw与throws的区别

    什么时运行时异常?什么是非运行时异常? 通俗的讲: 运行时异常:就是编译通过,运行时就崩了,比如数组越界. 非运行时异常:就是编译不通过,这时就得必须去处理了.不然就没法运行了. 全面的讲: Thro ...

  4. 设置CentOS不启用图形界面

    由于linux服务器放在机房长时间运行,或者只是在后台运行,一般通过secureCRT连接服务器: 所以在虚拟机上都不需要图形界面,而且图形界面占用内存. 所以,我们可以通过简单的设置,让linux只 ...

  5. iphone 尺寸and字体

    iPhone的APP界面一般由四个元素组成,分别是:状态栏.导航栏.主菜单栏以及中间的内容区域 这里取用 640×960 的尺寸设计,那我们就说说在这个尺寸下这些元素的尺寸: 状态栏:就是我们经常说的 ...

  6. JS(去掉前后空格或去掉所有空格)的用法

    1.  去掉字符串前后所有空格: 代码如下: function Trim(str) { return str.replace(/(^\s*)|(\s*$)/g, ""); } 说明 ...

  7. ci框架登陆之后每隔几分钟就需要重新登录的问题

    一个简单的登陆写好之后,发现每次进入需要登陆之后才能进入的页面都会跳转到登录页面,猜测应该是session被清了,打印出来,果然为空,但是我没有设置session的生存周期,按照默认的应该是24小时, ...

  8. Linux学习笔记(11)-kill函数

    明天开始学习kill函数的用法. ---------------------------------------------- kill函数可以用来向指定的进程发送一个指定的信号,在我的理解的来看,就 ...

  9. iOS之转场动画

    CodeApp地址CATransition_Demo:https://github.com/Wheat-Qin/CATransition_Demo iOS中比较全的翻转过渡动画(不只是苹果提供的).包 ...

  10. 大神的Blog挂了,从Bing快照里复制过来的备份

    UWidget封装SWidget到UMG 2015年8月30日0 为了使用UMG中的一些高级或便利特性,需要将制作好的Slate控件封装到UWidget中去. 当前UE4版本4.8.3. 将Slate ...