Bump soinfo version
This includes: 1. Placing has_ifunc after fields with version = 0 2. Switch to has_min_version(v) function. 3. Minor soinfo initialization refactoring (placement new + ctor) Change-Id: I1bf5fde4d930914012ce5f3ad5acb48217da9b2d
This commit is contained in:
parent
2e6c5fc4e9
commit
0d15094287
@ -232,17 +232,12 @@ static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0 };
|
|||||||
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
|
static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Defined as global because we do not yet have access
|
static soinfo __libdl_info("libdl.so", nullptr);
|
||||||
// to synchronization functions __cxa_guard_* needed
|
|
||||||
// to define statics inside functions.
|
|
||||||
static soinfo __libdl_info;
|
|
||||||
|
|
||||||
// This is used by the dynamic linker. Every process gets these symbols for free.
|
// This is used by the dynamic linker. Every process gets these symbols for free.
|
||||||
soinfo* get_libdl_info() {
|
soinfo* get_libdl_info() {
|
||||||
if (__libdl_info.name[0] == '\0') {
|
if ((__libdl_info.flags & FLAG_LINKED) == 0) {
|
||||||
// initialize
|
__libdl_info.flags |= FLAG_LINKED;
|
||||||
strncpy(__libdl_info.name, "libdl.so", sizeof(__libdl_info.name));
|
|
||||||
__libdl_info.flags = FLAG_LINKED | FLAG_NEW_SOINFO;
|
|
||||||
__libdl_info.strtab = ANDROID_LIBDL_STRTAB;
|
__libdl_info.strtab = ANDROID_LIBDL_STRTAB;
|
||||||
__libdl_info.symtab = g_libdl_symtab;
|
__libdl_info.symtab = g_libdl_symtab;
|
||||||
__libdl_info.nbucket = sizeof(g_libdl_buckets)/sizeof(unsigned);
|
__libdl_info.nbucket = sizeof(g_libdl_buckets)/sizeof(unsigned);
|
||||||
|
@ -35,9 +35,10 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
// Private C library headers.
|
// Private C library headers.
|
||||||
#include "private/bionic_tls.h"
|
#include "private/bionic_tls.h"
|
||||||
#include "private/KernelArgumentBlock.h"
|
#include "private/KernelArgumentBlock.h"
|
||||||
@ -290,17 +291,7 @@ static soinfo* soinfo_alloc(const char* name, struct stat* file_stat) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
soinfo* si = g_soinfo_allocator.alloc();
|
soinfo* si = new (g_soinfo_allocator.alloc()) soinfo(name, file_stat);
|
||||||
|
|
||||||
// Initialize the new element.
|
|
||||||
memset(si, 0, sizeof(soinfo));
|
|
||||||
strlcpy(si->name, name, sizeof(si->name));
|
|
||||||
si->flags = FLAG_NEW_SOINFO;
|
|
||||||
|
|
||||||
if (file_stat != NULL) {
|
|
||||||
si->set_st_dev(file_stat->st_dev);
|
|
||||||
si->set_st_ino(file_stat->st_ino);
|
|
||||||
}
|
|
||||||
|
|
||||||
sonext->next = si;
|
sonext->next = si;
|
||||||
sonext = si;
|
sonext = si;
|
||||||
@ -466,6 +457,19 @@ static ElfW(Sym)* soinfo_elf_lookup(soinfo* si, unsigned hash, const char* name)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
soinfo::soinfo(const char* name, const struct stat* file_stat) {
|
||||||
|
memset(this, 0, sizeof(*this));
|
||||||
|
|
||||||
|
strlcpy(this->name, name, sizeof(this->name));
|
||||||
|
flags = FLAG_NEW_SOINFO;
|
||||||
|
version = SOINFO_VERSION;
|
||||||
|
|
||||||
|
if (file_stat != NULL) {
|
||||||
|
set_st_dev(file_stat->st_dev);
|
||||||
|
set_st_ino(file_stat->st_ino);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void soinfo::resolve_ifunc_symbols() {
|
void soinfo::resolve_ifunc_symbols() {
|
||||||
if (!get_has_ifuncs()) {
|
if (!get_has_ifuncs()) {
|
||||||
return;
|
return;
|
||||||
@ -860,7 +864,7 @@ static void soinfo_unload(soinfo* si) {
|
|||||||
TRACE("unloading '%s'", si->name);
|
TRACE("unloading '%s'", si->name);
|
||||||
si->CallDestructors();
|
si->CallDestructors();
|
||||||
|
|
||||||
if ((si->flags | FLAG_NEW_SOINFO) != 0) {
|
if (si->has_min_version(0)) {
|
||||||
si->get_children().for_each([&] (soinfo* child) {
|
si->get_children().for_each([&] (soinfo* child) {
|
||||||
TRACE("%s needs to unload %s", si->name, child->name);
|
TRACE("%s needs to unload %s", si->name, child->name);
|
||||||
soinfo_unload(child);
|
soinfo_unload(child);
|
||||||
@ -1585,16 +1589,14 @@ void soinfo::CallDestructors() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void soinfo::add_child(soinfo* child) {
|
void soinfo::add_child(soinfo* child) {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(0)) {
|
||||||
return;
|
this->children.push_front(child);
|
||||||
|
child->parents.push_front(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->children.push_front(child);
|
|
||||||
child->parents.push_front(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void soinfo::remove_all_links() {
|
void soinfo::remove_all_links() {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (!has_min_version(0)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1617,51 +1619,45 @@ void soinfo::remove_all_links() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void soinfo::set_st_dev(dev_t dev) {
|
void soinfo::set_st_dev(dev_t dev) {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(0)) {
|
||||||
return;
|
st_dev = dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
st_dev = dev;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void soinfo::set_st_ino(ino_t ino) {
|
void soinfo::set_st_ino(ino_t ino) {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(0)) {
|
||||||
return;
|
st_ino = ino;
|
||||||
}
|
}
|
||||||
|
|
||||||
st_ino = ino;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void soinfo::set_has_ifuncs(bool ifuncs) {
|
void soinfo::set_has_ifuncs(bool ifuncs) {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(1)) {
|
||||||
return;
|
has_ifuncs = ifuncs;
|
||||||
}
|
}
|
||||||
|
|
||||||
has_ifuncs = ifuncs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dev_t soinfo::get_st_dev() {
|
dev_t soinfo::get_st_dev() {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(0)) {
|
||||||
return 0;
|
return st_dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
return st_dev;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
ino_t soinfo::get_st_ino() {
|
ino_t soinfo::get_st_ino() {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(0)) {
|
||||||
return 0;
|
return st_ino;
|
||||||
}
|
}
|
||||||
|
|
||||||
return st_ino;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool soinfo::get_has_ifuncs() {
|
bool soinfo::get_has_ifuncs() {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(1)) {
|
||||||
return false;
|
return has_ifuncs;
|
||||||
}
|
}
|
||||||
|
|
||||||
return has_ifuncs;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is a return on get_children() in case
|
// This is a return on get_children() in case
|
||||||
@ -1669,11 +1665,11 @@ bool soinfo::get_has_ifuncs() {
|
|||||||
static soinfo::soinfo_list_t g_empty_list;
|
static soinfo::soinfo_list_t g_empty_list;
|
||||||
|
|
||||||
soinfo::soinfo_list_t& soinfo::get_children() {
|
soinfo::soinfo_list_t& soinfo::get_children() {
|
||||||
if ((this->flags & FLAG_NEW_SOINFO) == 0) {
|
if (has_min_version(0)) {
|
||||||
return g_empty_list;
|
return this->children;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this->children;
|
return g_empty_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force any of the closed stdin, stdout and stderr to be associated with
|
/* Force any of the closed stdin, stdout and stderr to be associated with
|
||||||
@ -2135,7 +2131,12 @@ static void add_vdso(KernelArgumentBlock& args __unused) {
|
|||||||
/*
|
/*
|
||||||
* This is linker soinfo for GDB. See details below.
|
* This is linker soinfo for GDB. See details below.
|
||||||
*/
|
*/
|
||||||
static soinfo linker_soinfo_for_gdb;
|
#if defined(__LP64__)
|
||||||
|
#define LINKER_PATH "/system/bin/linker64"
|
||||||
|
#else
|
||||||
|
#define LINKER_PATH "/system/bin/linker"
|
||||||
|
#endif
|
||||||
|
static soinfo linker_soinfo_for_gdb(LINKER_PATH, nullptr);
|
||||||
|
|
||||||
/* gdb expects the linker to be in the debug shared object list.
|
/* gdb expects the linker to be in the debug shared object list.
|
||||||
* Without this, gdb has trouble locating the linker's ".text"
|
* Without this, gdb has trouble locating the linker's ".text"
|
||||||
@ -2145,12 +2146,6 @@ static soinfo linker_soinfo_for_gdb;
|
|||||||
* be on the soinfo list.
|
* be on the soinfo list.
|
||||||
*/
|
*/
|
||||||
static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
|
static void init_linker_info_for_gdb(ElfW(Addr) linker_base) {
|
||||||
#if defined(__LP64__)
|
|
||||||
strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker64", sizeof(linker_soinfo_for_gdb.name));
|
|
||||||
#else
|
|
||||||
strlcpy(linker_soinfo_for_gdb.name, "/system/bin/linker", sizeof(linker_soinfo_for_gdb.name));
|
|
||||||
#endif
|
|
||||||
linker_soinfo_for_gdb.flags = FLAG_NEW_SOINFO;
|
|
||||||
linker_soinfo_for_gdb.base = linker_base;
|
linker_soinfo_for_gdb.base = linker_base;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2369,10 +2364,6 @@ extern "C" void _start();
|
|||||||
* function, or other GOT reference will generate a segfault.
|
* function, or other GOT reference will generate a segfault.
|
||||||
*/
|
*/
|
||||||
extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
||||||
// Initialize static variables.
|
|
||||||
solist = get_libdl_info();
|
|
||||||
sonext = get_libdl_info();
|
|
||||||
|
|
||||||
KernelArgumentBlock args(raw_args);
|
KernelArgumentBlock args(raw_args);
|
||||||
|
|
||||||
ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
|
ElfW(Addr) linker_addr = args.getauxval(AT_BASE);
|
||||||
@ -2380,8 +2371,7 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
|||||||
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
|
ElfW(Ehdr)* elf_hdr = reinterpret_cast<ElfW(Ehdr)*>(linker_addr);
|
||||||
ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
|
ElfW(Phdr)* phdr = reinterpret_cast<ElfW(Phdr)*>(linker_addr + elf_hdr->e_phoff);
|
||||||
|
|
||||||
soinfo linker_so;
|
soinfo linker_so("[dynamic linker]", nullptr);
|
||||||
memset(&linker_so, 0, sizeof(soinfo));
|
|
||||||
|
|
||||||
// If the linker is not acting as PT_INTERP entry_point is equal to
|
// If the linker is not acting as PT_INTERP entry_point is equal to
|
||||||
// _start. Which means that the linker is running as an executable and
|
// _start. Which means that the linker is running as an executable and
|
||||||
@ -2393,7 +2383,6 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
|||||||
__libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
|
__libc_fatal("This is %s, the helper program for shared library executables.\n", args.argv[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
strcpy(linker_so.name, "[dynamic linker]");
|
|
||||||
linker_so.base = linker_addr;
|
linker_so.base = linker_addr;
|
||||||
linker_so.size = phdr_table_get_load_size(phdr, elf_hdr->e_phnum);
|
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.load_bias = get_elf_exec_load_bias(elf_hdr);
|
||||||
@ -2417,6 +2406,13 @@ extern "C" ElfW(Addr) __linker_init(void* raw_args) {
|
|||||||
// Initialize the linker's own global variables
|
// Initialize the linker's own global variables
|
||||||
linker_so.CallConstructors();
|
linker_so.CallConstructors();
|
||||||
|
|
||||||
|
// Initialize static variables. Note that in order to
|
||||||
|
// get correct libdl_info we need to call constructors
|
||||||
|
// before get_libdl_info().
|
||||||
|
solist = get_libdl_info();
|
||||||
|
sonext = get_libdl_info();
|
||||||
|
|
||||||
|
|
||||||
// We have successfully fixed our own relocations. It's safe to run
|
// We have successfully fixed our own relocations. It's safe to run
|
||||||
// the main part of the linker now.
|
// the main part of the linker now.
|
||||||
args.abort_message_ptr = &g_abort_message;
|
args.abort_message_ptr = &g_abort_message;
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
#define _LINKER_H_
|
#define _LINKER_H_
|
||||||
|
|
||||||
#include <elf.h>
|
#include <elf.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <link.h>
|
#include <link.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <android/dlext.h>
|
#include <android/dlext.h>
|
||||||
@ -88,6 +89,8 @@
|
|||||||
#define FLAG_LINKER 0x00000010 // The linker itself
|
#define FLAG_LINKER 0x00000010 // The linker itself
|
||||||
#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
|
#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
|
||||||
|
|
||||||
|
#define SOINFO_VERSION 1
|
||||||
|
|
||||||
#define SOINFO_NAME_LEN 128
|
#define SOINFO_NAME_LEN 128
|
||||||
|
|
||||||
typedef void (*linker_function_t)();
|
typedef void (*linker_function_t)();
|
||||||
@ -195,6 +198,9 @@ struct soinfo {
|
|||||||
bool has_text_relocations;
|
bool has_text_relocations;
|
||||||
#endif
|
#endif
|
||||||
bool has_DT_SYMBOLIC;
|
bool has_DT_SYMBOLIC;
|
||||||
|
|
||||||
|
soinfo(const char* name, const struct stat* file_stat);
|
||||||
|
|
||||||
void CallConstructors();
|
void CallConstructors();
|
||||||
void CallDestructors();
|
void CallDestructors();
|
||||||
void CallPreInitConstructors();
|
void CallPreInitConstructors();
|
||||||
@ -209,10 +215,11 @@ struct soinfo {
|
|||||||
dev_t get_st_dev();
|
dev_t get_st_dev();
|
||||||
bool get_has_ifuncs();
|
bool get_has_ifuncs();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
soinfo_list_t& get_children();
|
soinfo_list_t& get_children();
|
||||||
|
|
||||||
|
bool inline has_min_version(uint32_t min_version) {
|
||||||
|
return (flags & FLAG_NEW_SOINFO) != 0 && version >= min_version;
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
|
void CallArray(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
|
||||||
void CallFunction(const char* function_name, linker_function_t function);
|
void CallFunction(const char* function_name, linker_function_t function);
|
||||||
@ -221,10 +228,9 @@ struct soinfo {
|
|||||||
private:
|
private:
|
||||||
// This part of the structure is only available
|
// This part of the structure is only available
|
||||||
// when FLAG_NEW_SOINFO is set in this->flags.
|
// when FLAG_NEW_SOINFO is set in this->flags.
|
||||||
unsigned int version;
|
uint32_t version;
|
||||||
|
|
||||||
bool has_ifuncs;
|
|
||||||
|
|
||||||
|
// version >= 0
|
||||||
dev_t st_dev;
|
dev_t st_dev;
|
||||||
ino_t st_ino;
|
ino_t st_ino;
|
||||||
|
|
||||||
@ -232,6 +238,8 @@ struct soinfo {
|
|||||||
soinfo_list_t children;
|
soinfo_list_t children;
|
||||||
soinfo_list_t parents;
|
soinfo_list_t parents;
|
||||||
|
|
||||||
|
// version >= 1
|
||||||
|
bool has_ifuncs;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern soinfo* get_libdl_info();
|
extern soinfo* get_libdl_info();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user