ART虚拟机,通过dex2oat将dex预编译成机器码的oat文件,是基于linux中的可执行文件格式ELF所做的扩展。
ELF(Executable and Linkable Format)的处理流程:
它至少支持三种文件形态:可重定向文件(Relocatable File),可执行文件(Executable File),可共享的对象文件(Shared Object File)。
Relocatable File的一个具体范例是.o 文件,是编译过程中产生的中间文件,通过file 命令查看这类.o文件,可看到他们属于 ELF relocatable文件。
ELF的另一种文件形态是shared object file(动态链接库),通常以.so为后缀:
ELF文件格式的内部构成,可以从Linking,Execution两个视角分析,可以参考:
可以利用readelf命令读取elf的文件头信息,命令行:
readelf -h ***.o
readelf是linux系统分析ELF文件的一个工具。
elf header对应的数据结构:
art/runtime/elf.h
struct Elf32_Ehdr {
unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes
Elf32_Half e_type; // Type of file (see ET_* below)
Elf32_Half e_machine; // Required architecture for this file (see EM_*)
Elf32_Word e_version; // Must be equal to 1
Elf32_Addr e_entry; // Address to jump to in order to start program
Elf32_Off e_phoff; // Program header table's file offset, in bytes
Elf32_Off e_shoff; // Section header table's file offset, in bytes
Elf32_Word e_flags; // Processor-specific flags
Elf32_Half e_ehsize; // Size of ELF header, in bytes
Elf32_Half e_phentsize; // Size of an entry in the program header table
Elf32_Half e_phnum; // Number of entries in the program header table
Elf32_Half e_shentsize; // Size of an entry in the section header table
Elf32_Half e_shnum; // Number of entries in the section header table
Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table
bool checkMagic() const {
return (memcmp(e_ident, ElfMagic, strlen(ElfMagic))) == 0;
}
unsigned char getFileClass() const { return e_ident[EI_CLASS]; }
unsigned char getDataEncoding() const { return e_ident[EI_DATA]; }
};
ELF文件的加载和动态链接过程
示例程序:
#include "stdio.h"
int add(int v1,int v2){
return v1+v2;
}
int main(){
add(1,2);
printf("it is test.");
return 0;
}
在这个程序中,add函数是定义在当前程序的,它的地址已知,但是printf函数是由C库提供的外部函数,在编译时不会被打包到这个程序中,而是等到这个程序真正运行起来,系统把它需要的动态链接库加载到内存,然后解析出它引用的外部函数的真实地
址,并保证可执行程序可以正确指向这些外部函数。
编译这个小程序,
gcc -c Main.cpp
然后执行链接操作,使其成为真正的可执行程序:
gcc -o Main Main.cpp
使用readelf -S 命令查看section信息:
在Linux平台下,elf格式可执行程序提供了一个名为.interp字段,用于记录程序运行时所使用的动态连接器,这个程序使用的连接器是/lib64/ld-linux-x86-64.so.2,这实际是个可执行程序,类似于Android平台下的system/bin/Linker。
转载:可执行文件的加载函数
Android系统的配置文件,定义了相关的动态连接器
build/core/definitions.mk
###########################################################
## Commands for running gcc to link an executable
###########################################################
define transform-o-to-executable-inner
$(hide) $(PRIVATE_CXX) -pie \
-nostdlib -Bdynamic \
-Wl,-dynamic-linker,$(PRIVATE_LINKER) \
-Wl,--gc-sections \
其中的-dynamic-linker指定了所需的动态链接其,由后面的变量值决定(system/bin/linker64 or linker32).
对应的源码目录:/bionic/linker,这个linker是处理的动态链接库的隐式调用,Android中对动态库的显示调用方法有:
1)Java层,System.loadLibary(String libname)和System.load(String pathname),这两个函数的区别是前者要指出动态链接库的名称,系统在预先设置的路径查找并加载.so库;后者允许将动态库放在程序有权限访问的地方,给出完整的加载路径。
2)native层,dlopen标准接口