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