安卓linker源码阅读01
2015-08-08 22:50
357 查看
---恢复内容开始---
感觉想看源码还是得先了解安卓的makefile,这样知道是怎么编译的
参考
Android编译系统参考手册
http://android.cloudchou.com/build/core/main.php
深入浅出Android makefile
http://blog.csdn.net/lizzywu/article/details/12842031
参考:看雪 linker阅读笔记一
\bionic\linker\arch\arm\begin.s
ENTRY(_start)
mov r0, sp
bl __linker_init
/* linker init returns the _entry address in the main image */
mov pc, r0
END(_start)
调用 __linker_init函数,返回值为main函数入口地址
__linker_init 在\bionic\linker\linker.cpp
第一行就用了一个类,跟过去
bionic\libc\private\KernelArgumentBlock.h
从内核解析出来argc,argv,envp(程序环境变量),auxv(辅助向量,key:value的形式,类似python的字典)
unsigned long getauxval(unsigned long type, bool* found_match = NULL)
给key(参数type),查value(参数found_match),注意看注释:Similar to ::getauxval but doesn't require the libc global variables
去看看man手册,http://www.man7.org/linux/man-pages/man3/getauxval.3.html,一会儿能用到
ElfW(auxv_t)* v = auxv
ElfW(auxv_t) 就是下面这个结构,在elf.h
typedef struct {
__u32 a_type;
union {
__u32 a_val;
} a_un;
} Elf32_auxv_t;
ElfW()宏在link.h里:
继续__linker_init
ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr);
ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff);
看man手册,就知道是什么意思了。获取镜像基址,可执行文件的入口点,获取header指针,程序头执指针
继续__linker_init
soinfo linker_so("[dynamic linker]", nullptr);
linker_so.base = linker_addr;
linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
linker_so.dynamic = nullptr;
linker_so.phdr = phdr;
linker_so.phnum = elf_hdr->e_phnum;
linker_so.flags |= FLAG_LINKER;
======================================================================================
/* Returns the size of the extent of all the possibly non-contiguous
loadable segments in an ELF program header table. This corresponds
to the page-aligned size in bytes that needs to be reserved in the
process' address space. If there are no loadable segments, 0 is
returned.
If out_min_vaddr or out_max_vaddr are not null, they will be
set to the minimum and maximum addresses of pages to be reserved,
or 0 if there is nothing to load.
*/
/
从ELF program header table中读取,返回不连续的可以被加载的segment
要在内存中保留的内存范围大小
/
size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr)* out_min_vaddr,
ElfW(Addr)* out_max_vaddr) {
/
实际上只用到了2个参数:
phdr_table
phdr_count
/
ElfW(Addr) min_vaddr = UINTPTR_MAX;
ElfW(Addr) max_vaddr = 0;
bool found_pt_load = false;
//遍历所有的phdr,找到PT_LOAD标志的segment
for (size_t i = 0; i < phdr_count; ++i) {
const ElfW(Phdr)* phdr = &phdr_table[i];
//phdr->p_vaddr 段的第一个字节将被放到内存中的虚拟地址
if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
max_vaddr = phdr->p_vaddr + phdr->p_memsz;
}
}
if (!found_pt_load) {
min_vaddr = 0;
}
//PAGE_START PAGE_END 页对齐的宏
min_vaddr = PAGE_START(min_vaddr);
max_vaddr = PAGE_END(max_vaddr);
if (out_min_vaddr != nullptr) {
out_min_vaddr = min_vaddr;
}
if (out_max_vaddr != nullptr) {
out_max_vaddr = max_vaddr;
}
return max_vaddr - min_vaddr;
}
===========================================
/* Compute the load-bias of an existing executable. This shall only
be used to compute the load bias of an executable or shared library
that was loaded by the kernel itself.
Input:
elf -> address of ELF header, assumed to be at the start of the file.
Return:
load bias, i.e. add the value of any p_vaddr in the file to get
the corresponding address in memory.
bias 偏移,此函数计算load的偏移。
/
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr) elf) {
ElfW(Addr) offset = elf->e_phoff;
//phdr_table 第一个phdr phdr_end 最后一个phdr
const ElfW(Phdr)* phdr_table = reinterpret_cast(reinterpret_cast(elf) + offset);
const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
if (phdr->p_type == PT_LOAD) {
return reinterpret_cast(elf) + phdr->p_offset - phdr->p_vaddr;
}
}
return 0;
}
// return reinterpret_cast(elf) + phdr->p_offset - phdr->p_vaddr;
//这句没看懂,elf文件基地址+程序头的文件偏移 - 程序头的内存偏移这是个啥
//这个就是计算一个文件头和虚拟内存偏移的差值,后面用的时候再加上这个虚拟内存值
===========================================
继续__linker_init
if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr)))
===========================================
/* Return the address and size of the ELF file's .dynamic section in memory,
or null if missing.
Input:
phdr_table -> program header table
phdr_count -> number of entries in tables
load_bias -> load bias
Output:
dynamic -> address of table in memory (null on failure).
Return:
void
/
void phdr_table_get_dynamic_section(const ElfW(Phdr) phdr_table, size_t phdr_count,
ElfW(Addr) load_bias, ElfW(Dyn)** dynamic) {
dynamic = nullptr;
for (const ElfW(Phdr) phdr = phdr_table, phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) {
if (phdr->p_type == PT_DYNAMIC) {
dynamic = reinterpret_cast(load_bias + phdr->p_vaddr);
return;
}
}
}
//靠,这里又不懂了,原来返回的是一个PT_LOAD的segment的偏移(文件地址-内存地址),
//到了这儿,和一个PT_DYNAMIC的segmet加在一起,这是在干啥
===========================================
bool soinfo::LinkImage(const android_dlextinfo* extinfo)函数中,重要的是
2184这几行的代码
if (plt_rel != nullptr) {
DEBUG("[ relocating %s plt ]", name);
if (Relocate(plt_rel, plt_rel_count)) { //这里1
return false;
}
}
if (rel != nullptr) {
DEBUG("[ relocating %s ]", name);
if (Relocate(rel, rel_count)) { //这里2
return false;
}
ifuncs不造是什么
然后到2229行
===========================================
===========================================
感觉想看源码还是得先了解安卓的makefile,这样知道是怎么编译的
参考
Android编译系统参考手册
http://android.cloudchou.com/build/core/main.php
深入浅出Android makefile
http://blog.csdn.net/lizzywu/article/details/12842031
看雪:linker阅读笔记一
感觉想看源码还是得先了解安卓的makefile,这样知道是怎么编译的
参考
Android编译系统参考手册
http://android.cloudchou.com/build/core/main.php
深入浅出Android makefile
http://blog.csdn.net/lizzywu/article/details/12842031
参考:看雪 linker阅读笔记一
\bionic\linker\arch\arm\begin.s
ENTRY(_start)
mov r0, sp
bl __linker_init
/* linker init returns the _entry address in the main image */
mov pc, r0
END(_start)
调用 __linker_init函数,返回值为main函数入口地址
__linker_init 在\bionic\linker\linker.cpp
第一行就用了一个类,跟过去
bionic\libc\private\KernelArgumentBlock.h
从内核解析出来argc,argv,envp(程序环境变量),auxv(辅助向量,key:value的形式,类似python的字典)
unsigned long getauxval(unsigned long type, bool* found_match = NULL)
给key(参数type),查value(参数found_match),注意看注释:Similar to ::getauxval but doesn't require the libc global variables
去看看man手册,http://www.man7.org/linux/man-pages/man3/getauxval.3.html,一会儿能用到
ElfW(auxv_t)* v = auxv
ElfW(auxv_t) 就是下面这个结构,在elf.h
typedef struct {
__u32 a_type;
union {
__u32 a_val;
} a_un;
} Elf32_auxv_t;
ElfW()宏在link.h里:
define ElfW(type) Elf32_ ## type
加起来就是Elf32_auxv_t了继续__linker_init
ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
ElfW(Addr) entry_point = args.getauxval(AT_ENTRY);
ElfW(Ehdr)* elf_hdr = reinterpret_cast(linker_addr);
ElfW(Phdr)* phdr = reinterpret_cast(linker_addr + elf_hdr->e_phoff);
看man手册,就知道是什么意思了。获取镜像基址,可执行文件的入口点,获取header指针,程序头执指针
继续__linker_init
soinfo linker_so("[dynamic linker]", nullptr);
linker_so.base = linker_addr;
linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
linker_so.load_bias = get_elf_exec_load_bias(elf_hdr);
linker_so.dynamic = nullptr;
linker_so.phdr = phdr;
linker_so.phnum = elf_hdr->e_phnum;
linker_so.flags |= FLAG_LINKER;
======================================================================================
/* Returns the size of the extent of all the possibly non-contiguous
loadable segments in an ELF program header table. This corresponds
to the page-aligned size in bytes that needs to be reserved in the
process' address space. If there are no loadable segments, 0 is
returned.
If out_min_vaddr or out_max_vaddr are not null, they will be
set to the minimum and maximum addresses of pages to be reserved,
or 0 if there is nothing to load.
*/
/
从ELF program header table中读取,返回不连续的可以被加载的segment
要在内存中保留的内存范围大小
/
size_t phdr_table_get_load_size(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr)* out_min_vaddr,
ElfW(Addr)* out_max_vaddr) {
/
实际上只用到了2个参数:
phdr_table
phdr_count
/
ElfW(Addr) min_vaddr = UINTPTR_MAX;
ElfW(Addr) max_vaddr = 0;
bool found_pt_load = false;
//遍历所有的phdr,找到PT_LOAD标志的segment
for (size_t i = 0; i < phdr_count; ++i) {
const ElfW(Phdr)* phdr = &phdr_table[i];
if (phdr->p_type != PT_LOAD) { continue; } found_pt_load = true; if (phdr->p_vaddr < min_vaddr) { min_vaddr = phdr->p_vaddr; }
//phdr->p_vaddr 段的第一个字节将被放到内存中的虚拟地址
if (phdr->p_vaddr + phdr->p_memsz > max_vaddr) {
max_vaddr = phdr->p_vaddr + phdr->p_memsz;
}
}
if (!found_pt_load) {
min_vaddr = 0;
}
//PAGE_START PAGE_END 页对齐的宏
min_vaddr = PAGE_START(min_vaddr);
max_vaddr = PAGE_END(max_vaddr);
if (out_min_vaddr != nullptr) {
out_min_vaddr = min_vaddr;
}
if (out_max_vaddr != nullptr) {
out_max_vaddr = max_vaddr;
}
return max_vaddr - min_vaddr;
}
===========================================
/* Compute the load-bias of an existing executable. This shall only
be used to compute the load bias of an executable or shared library
that was loaded by the kernel itself.
Input:
elf -> address of ELF header, assumed to be at the start of the file.
Return:
load bias, i.e. add the value of any p_vaddr in the file to get
the corresponding address in memory.
bias 偏移,此函数计算load的偏移。
/
static ElfW(Addr) get_elf_exec_load_bias(const ElfW(Ehdr) elf) {
ElfW(Addr) offset = elf->e_phoff;
//phdr_table 第一个phdr phdr_end 最后一个phdr
const ElfW(Phdr)* phdr_table = reinterpret_cast(reinterpret_cast(elf) + offset);
const ElfW(Phdr)* phdr_end = phdr_table + elf->e_phnum;
for (const ElfW(Phdr)* phdr = phdr_table; phdr < phdr_end; phdr++) {
if (phdr->p_type == PT_LOAD) {
return reinterpret_cast(elf) + phdr->p_offset - phdr->p_vaddr;
}
}
return 0;
}
// return reinterpret_cast(elf) + phdr->p_offset - phdr->p_vaddr;
//这句没看懂,elf文件基地址+程序头的文件偏移 - 程序头的内存偏移这是个啥
//这个就是计算一个文件头和虚拟内存偏移的差值,后面用的时候再加上这个虚拟内存值
===========================================
继续__linker_init
if (!(linker_so.PrelinkImage() && linker_so.LinkImage(nullptr)))
===========================================
/* Return the address and size of the ELF file's .dynamic section in memory,
or null if missing.
Input:
phdr_table -> program header table
phdr_count -> number of entries in tables
load_bias -> load bias
Output:
dynamic -> address of table in memory (null on failure).
Return:
void
/
void phdr_table_get_dynamic_section(const ElfW(Phdr) phdr_table, size_t phdr_count,
ElfW(Addr) load_bias, ElfW(Dyn)** dynamic) {
dynamic = nullptr;
for (const ElfW(Phdr) phdr = phdr_table, phdr_limit = phdr + phdr_count; phdr < phdr_limit; phdr++) {
if (phdr->p_type == PT_DYNAMIC) {
dynamic = reinterpret_cast(load_bias + phdr->p_vaddr);
return;
}
}
}
//靠,这里又不懂了,原来返回的是一个PT_LOAD的segment的偏移(文件地址-内存地址),
//到了这儿,和一个PT_DYNAMIC的segmet加在一起,这是在干啥
===========================================
bool soinfo::LinkImage(const android_dlextinfo* extinfo)函数中,重要的是
2184这几行的代码
if (plt_rel != nullptr) {
DEBUG("[ relocating %s plt ]", name);
if (Relocate(plt_rel, plt_rel_count)) { //这里1
return false;
}
}
if (rel != nullptr) {
DEBUG("[ relocating %s ]", name);
if (Relocate(rel, rel_count)) { //这里2
return false;
}
ifuncs不造是什么
然后到2229行
===========================================
===========================================
===========================================
===========================================---恢复内容结束---感觉想看源码还是得先了解安卓的makefile,这样知道是怎么编译的
参考
Android编译系统参考手册
http://android.cloudchou.com/build/core/main.php
深入浅出Android makefile
http://blog.csdn.net/lizzywu/article/details/12842031
看雪:linker阅读笔记一
相关文章推荐
- 乱评赢在中国之蓝天碧水间系列 分类: 业余 2015-08-08 22:50 3人阅读 评论(0) 收藏
- Studio第三方类库导包
- swift -- Tuple 元组 Dictionary
- 访问网站提示An error occurred on the server when processing the URL的解决方法
- 8.8 LeetCode 222 Count Complete Tree Nodes
- Material Design调色板
- 利用python获取指定url在ATS中缓存对象的信息
- hdu 5364 Distribution money
- 545B. Equidistant String
- 12、C语言和设计模式(解释器模式)
- 加密的操作类,包含判断是否加密
- LCIS
- 数据库mysql 分库备份脚本
- Android Studio快捷键
- 使用原生JavaScript实现的EventEmitter
- The mook jong-dp
- 数据结构之斐波那契查找
- 关于Wireshark "The NPF driver isn’t running……"解决办法
- 防守阵地1_推公式
- 11、C语言和设计模式(备忘录模式)