在Windows平台中,应用程序通常引用其IAT(导入访问表)以获取所需API的地址,然后对其进行调用。然后完成了一些机制,如此处演示的很好。我认为ELF文件中没有IAT。有人能告诉我在汇编级别的android上的API调用是如何工作的吗? />
 mov r4, 0x2000  ; address of mylooper
 bl 0x7777fff0      ;address of ALooper_acauire
 ... after ALooper_acquire()


然后进入ALooper_acquire(&mylooper)

Blah blah happens to call system api, ...



#1 楼

要回答您的问题,让我们首先在实体和定义方面打下坚实的基础。

ELF代表“可执行和可链接格式”。
即,它定义了两种类型的文件的结构和形状:


可执行文件(共享对象* .so和独立可执行文件)
可链接文件(目标文件* .o)

让我们关注可执行文件。

可执行文件的依赖关系解析

ELF定义了一种描述方法

依赖项

简单地说,依赖项是必需的外部符号。
符号被命名为(已标识的)内存块。
其中一些块是数据块(全局变量),而另一些是代码数据块(全局函数)。
由于符号是模块(也称为共享对象)的一部分,所以任何必需的符号都将与模块耦合。
请注意,作为OS API一部分的函数可以是并且通常是外部符号。但是,情况并非总是如此。

依赖项描述

ELF定义了一个称为动态段的结构,该结构用于存储加载程序(也称为动态链接器)在加载过程中所需的信息。
可执行文件的依赖项描述存储在其动态分段中。

所需符号在动态分段所引用的称为动态符号表的表中进行组织: br />
引用Loader指令下的符号表-https://elfy.io/KYze4
动态符号表是符号描述符的连续数组:


.dynsym在Symbols下-https://elfy.io/KYze4

另一方面,需要的模块直接用DT_NEEDED条目描述:


在Loader指令下需要的模块-https://elfy.io/KYze4

动态链接

现在,我们准备讨论连接机制,该机制将使可执行文件在加载程序解析后即可达到其依赖关系。让我们以调用__android_log_print为例(ARM 32位)作为示例。 />但实际上,blx指令会分支到称为过程链接表(PLT)的特殊区域中的特定代码存根。
每个所需的外部函数在PLT中都有一个代码存根。

这是__android_log_print的存根: >
全局偏移表(GOT)是一个指针表。
每个外部函数在GOT中都有一个单元。
每个外部函数在GOT中都有自己的单元。 。
加载后完成后,函数X的单元格包含函数X的内存地址。


由于
编码,GOT中右单元格的地址计算被分成3个局限性。例如:大的偏移量不能用
单个指令编码。 />
PLT和GOT是ELF规范的一部分。

评论


非常感谢!!听起来像这样适用于所有Linux可执行文件,对不对?

– KYHSGeekCode
18/12/12在16:15

@KYHSGeekCode我还没有看到使用非ELF格式格式化的Linux可执行文件。因此可以安全地假设Linux可执行文件是ELF文件,在这种情况下,是的,其机制是相同的。


18/12/12在17:17

ELF不是Linux最初的动态可执行文件格式。并且今天有一些静态二进制格式在使用。但是Android真正值得注意的是它使用了唯一的libc。一些嵌入式系统也使用备用libc。

–克里斯·斯特拉顿(Chris Stratton)
18/12/24在13:25