NDK1

  • 来看看强大的NDK吧

NDK直译为“安卓原声开发套件”。它可以将原生的C、C++代码的强大功能和Android应用的图形界面结合在一起 //这是否意味着实际上很多功能都是C或者C++来完成的呢?

使用gcc编译器手动编译

1
2
3
4
5
6
7
//hello.c文件
#include <stdio.h>
int main(int argc, int ** argv[])
{
printf("Hello World\n")
return 0;
}

原生程序的生成过程分为两个步骤:第一步将hello.c编译成hello.o目标文件,第二部将hello.o目标文件与特定的原生程序启动代码及依赖库进行链接最终生成可执行文件

其余还有ndk-build和Eclipse编译,就不列举了。

大体上是gcc编译的进阶版。


原生程序的启动流程

很多人认为main函数是程序的入口函数,其实不然,在程序启动过程中,main函数开始之前,需要做一些初始化工作,如动态库的加载、程序的参数argc、argv的初始化等

入口函数

原生程序有静态链接与动态链接两种,其中动态链接又分为动态链接程序和动态链接库

静态链接会链接crtbegin_static.ocrtend_android.o目标文件

crtend_static.o文件中定义了静态链接程序启动函数_start,这个函数在程序启动时执行第一个函数。静态链接程序在启动时不需要加载其他的动态库,目前已知的有Android系统中的init、adbd、linker等程序。

动态链接需要在gcc编译器的命令行参数中指定-bdynamic,在生成可执行程序时会链接cerbegin_dynamic.o与cretend_android.o目标文件

在生成可执行文件中,每个程序都会包含一个”.interp” 段来存入程序的加载器。

静态链接和动态链接有着相同的启动函数


结合书上代码分析发现,静态链接的程序包括大致分为5个部分的东西

1、声明了_start函数以及代码对齐方式

2、调用了_libc_init函数,传递了4个参数。分别是堆栈指针、数值0、执行main函数的指针与4个段数组的指针

3、保存了4个数组段地址

4、生命了4个数组段,每个数据段声明了一个全局标符符,并都只有一个Long类型值为-1

5、包含了其他两个汇编文件

以上是静态链接的启动函数


下面是动态链接

动态链接的程序在运行前需要做一些初始化工作,如程序运行所依赖的动态库需要先被载入内存。

看书发现,动态链接的程序会先解析这个ELF文件,然后执行linker,最后由linker调用真正可执行程序的代码

linker调用_linker_init函数来进行初始化工作,初始化完毕后悔返回原生程序的入口到r0,最后将r0赋值给pc跳转到真正的程序入口去执行

总结一下,静态链接和动态链接的启动函数相同,动态链接的程序在执行入口函数前需要通过Linker进行额外的初始化


那么问题来了,main函数是在何时被执行的呢

静态链接的_libc_init 程序在运行时,自己初始化c运行库环境及调用静态狗仔函数,最后调用了slingshot函数,也就是程序的main函数,最后调用exit()

动态链接的初始化已经由Linker完成了,接下来就和静态链接一样

文章目录
  1. 1. 来看看强大的NDK吧