//
// linker.cpp
// ArmVM
//
// Created by denghui on 19/6/21.
// Copyright © 2019年 denghui. All rights reserved.
//
#include "linker.h"
#include "dlfcn.h"
#include "linker_phdr.h"
#include <errno.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#define LDPATH_BUFSIZE 512
#define LDPATH_MAX 8
#define LDPRELOAD_BUFSIZE 512
#define LDPRELOAD_MAX 8
static bool soinfo_link_image(soinfo* si);
#define SOINFO_PER_POOL ((PAGE_SIZE - sizeof(soinfo_pool_t*)) / sizeof(soinfo))
struct soinfo_pool_t {
soinfo_pool_t* next;
soinfo info[SOINFO_PER_POOL];
};
static struct soinfo_pool_t* gSoInfoPools = NULL;
static soinfo* gSoInfoFreeList = NULL;
static soinfo* solist = &libdl_info;
static soinfo* sonext = &libdl_info;
static soinfo* somain; /* main process, always the one after libdl_info */
static const char* const gSoPaths[] = {
"/vendor/lib",
"/system/lib",
NULL
};
static char gLdPathsBuffer[LDPATH_BUFSIZE];
static const char* gLdPaths[LDPATH_MAX + 1];
static char gLdPreloadsBuffer[LDPRELOAD_BUFSIZE];
static const char* gLdPreloadNames[LDPRELOAD_MAX + 1];
static soinfo* gLdPreloads[LDPRELOAD_MAX + 1];
soinfo libdl_info;
enum RelocationKind {
kRelocAbsolute = 0,
kRelocRelative,
kRelocCopy,
kRelocSymbol,
kRelocMax
};
#if STATS
struct linker_stats_t {
int count[kRelocMax];
};
static linker_stats_t linker_stats;
static void count_relocation(RelocationKind kind) {
++linker_stats.count[kind];
}
#else
static void count_relocation(RelocationKind) {
}
#endif
#if COUNT_PAGES
static unsigned bitmask[4096];
#define MARK(offset) \
do { \
bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
} while(0)
#else
#define MARK(x) do {} while (0)
#endif
static bool ensure_free_list_non_empty() {
if (gSoInfoFreeList != NULL) {
return true;
}
// Allocate a new pool.
soinfo_pool_t* pool = reinterpret_cast<soinfo_pool_t*>(mmap(NULL, sizeof(*pool),
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0));
if (pool == MAP_FAILED) {
return false;
}
// Add the pool to our list of pools.
pool->next = gSoInfoPools;
gSoInfoPools = pool;
// Chain the entries in the new pool onto the free list.
gSoInfoFreeList = &pool->info[0];
soinfo* next = NULL;
for (int i = SOINFO_PER_POOL - 1; i >= 0; --i) {
pool->info[i].next = next;
next = &pool->info[i];
}
return true;
}
static void set_soinfo_pool_protection(int protection) {
for (soinfo_pool_t* p = gSoInfoPools; p != NULL; p = p->next) {
if (mprotect(p, sizeof(*p), protection) == -1) {
DL_ERR("mprotect fail: %s",strerror(errno));
abort(); // Can't happen.
}
}
}
static soinfo* soinfo_alloc(const char* name) {
if (strlen(name) >= SOINFO_NAME_LEN) {
DL_ERR("library name \"%s\" too long\n", name);
return NULL;
}
if (!ensure_free_list_non_empty()) {
DL_ERR("out of memory when loading \"%s\"\n", name);
return NULL;
}
// Take the head element off the free list.
soinfo* si = gSoInfoFreeList;
gSoInfoFreeList = gSoInfoFreeList->next;
// Initialize the new element.
memset(si, 0, sizeof(soinfo));
strlcpy(si->name, name, sizeof(si->name));
sonext->next = si;
sonext = si;
TRACE("name %s: allocated soinfo @ %p\n", name, si);
return si;
}
static void soinfo_free(soinfo* si)
{
if (si == NULL) {
return;
}
soinfo *prev = NULL, *trav;
TRACE("name %s: freeing soinfo @ %p", si->name, si);
for (trav = solist; trav != NULL; trav = trav->next) {
if (trav == si)
break;
prev = trav;
}
if (trav == NULL) {
/* si was not in solist */
DL_ERR("name \"%s\" is not in solist!", si->name);
return;
}
/* prev will never be NULL, because the first entry in solist is
always the static libdl_info.
*/
prev->next = si->next;
if (si == sonext) {
sonext = prev;
}
si->next = gSoInfoFreeList;
gSoInfoFreeList = si;
}
static void parse_path(const char* path, const char* delimiters,
const char** array, char* buf, size_t buf_size, size_t max_count) {
if (path == NULL) {
return;
}
size_t len = strlcpy(buf, path, buf_size);
size_t i = 0;
char* buf_p = buf;
while (i < max_count && (array[i] = strsep(&buf_p, delimiters))) {
if (*array[i] != '\0') {
++i;
}
}
// Forget the last path if we had to truncate; this occurs if the 2nd to
// last char isn't '\0' (i.e. wasn't originally a delimiter).
if (i > 0 && len >= buf_size && buf[buf_size - 2] != '\0') {
array[i - 1] = NULL;
} else {
array[i] = NULL;
}
}
static void parse_LD_LIBRARY_PATH(const char* path) {
parse_path(path, ":", gLdPaths,
gLdPathsBuffer, sizeof(gLdPathsBuffer), LDPATH_MAX);
}
static void parse_LD_PRELOAD(const char* path) {
// We have historically supported ':' as well as ' ' in LD_PRELOAD.
parse_path(path, " :", gLdPreloadNames,
gLdPreloadsBuffer, sizeof(gLdPreloadsBuffer), LDPRELOAD_MAX);
}
static soinfo *find_loaded_library(const char *name)
{
soinfo *si;
const char *bname;
// TODO: don't use basename only for determining libraries
// http://code.google.com/p/android/issues/detail?id=6670
bname = strrchr(name, '/');
bname = bname ? bname + 1 : name;
for (si = solist; si != NULL; si = si->next) {
if (!strcmp(bname, si->name)) {
return si;
}
}
return NULL;
}
static int open_library_on_path(const char* name, const char* const paths[]) {
char buf[512];
for (size_t i = 0; paths[i] != NULL; ++i) {
int n = snprintf(buf, sizeof(buf), "%s/%s", paths[i], name);
if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
TRACE("Warning: ignoring very long library path: %s/%s\n", paths[i], name);
continue;
}
int fd = (open(buf, O_RDONLY | O_CLOEXEC));
if (fd != -1) {
return fd;
}
}
return -1;
}
static int open_library(const char* name) {
TRACE("[ opening %s ]\n", name);
// If the name contains a slash, we should attempt to open it directly and not search the paths.
if (strchr(name, '/') != NULL) {
int fd = open(name, O_RDONLY | O_CLOEXEC);
if (fd != -1) {
return fd;
}
// ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now.
}
// Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
int fd = open_library_on_path(name, gLdPaths);
if (fd == -1) {
fd = open_library_on_path(name, gSoPaths);
}
return fd;
}
static soinfo* load_library(const char* name) {
// Open the file.
DL_DEBUG("load_library: %s", name);
int fd = open_library(name);
if (fd == -1) {
DL_ERR("library \"%s\" not found\n", name);
return NULL;
}
// Read the ELF header and load the segments.
ElfReader elf_reader(name, fd);
if (!elf_reader.Load()) {
return NULL;
}
const char* bname = strrchr(name, '/');
soinfo* si = soinfo_alloc(bname ? bname + 1 : name);
if (si == NULL) {
return NULL;
}
si->base = elf_reader.load_start();
si->size = elf_reader.load_size();
si->load_bias = elf_reader.load_bias();
si->flags = 0;
si->entry = 0;
si->dynamic = NULL;
si->phnum = elf_reader.phdr_count();
si->phdr = elf_reader.loaded_phdr(
没有合适的资源?快使用搜索试试~ 我知道了~
安卓Linker源码(可修改编译).zip
共17个文件
d:5个
cpp:4个
h:4个
1星 需积分: 11 13 下载量 196 浏览量
2020-06-19
11:14:19
上传
评论
收藏 1.37MB ZIP 举报
温馨提示
将Android Linker部分源码单独提取出来,可用ndk-build编译修改,用于学习ELF格式,及Linker加载链接过程
资源推荐
资源详情
资源评论
收起资源包目录
linker.zip (17个子文件)
linker
obj
local
armeabi
objs
xlinker
linker_phdr.o.d 530B
__
__
util
Logger.o.d 548B
dlfcn.o.d 477B
main.o.d 478B
linker.o.d 520B
xlinker 3.72MB
jni
main.cpp 338B
main.h 142B
Application.mk 263B
Android.mk 335B
linker_phdr.h 4KB
linker.h 5KB
linker_phdr.cpp 20KB
linker.cpp 41KB
dlfcn.h 2KB
dlfcn.cpp 3KB
libs
armeabi
xlinker 222KB
共 17 条
- 1
资源评论
- notEBfast2020-11-17这是个屁的linker,楼主你是出来搞笑的么,骗积分sm
大塘坡牛哥
- 粉丝: 17
- 资源: 16
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功