am c16eafd5: am fcc6fd35: Merge "Refactoring: move mips reloc to separate method"
* commit 'c16eafd5ff06845606fa24ed83794104c7f995e6': Refactoring: move mips reloc to separate method
This commit is contained in:
commit
9a0641a0f3
@ -16,8 +16,8 @@ LOCAL_SRC_FILES_arm := arch/arm/begin.S
|
|||||||
LOCAL_SRC_FILES_arm64 := arch/arm64/begin.S
|
LOCAL_SRC_FILES_arm64 := arch/arm64/begin.S
|
||||||
LOCAL_SRC_FILES_x86 := arch/x86/begin.c
|
LOCAL_SRC_FILES_x86 := arch/x86/begin.c
|
||||||
LOCAL_SRC_FILES_x86_64 := arch/x86_64/begin.S
|
LOCAL_SRC_FILES_x86_64 := arch/x86_64/begin.S
|
||||||
LOCAL_SRC_FILES_mips := arch/mips/begin.S
|
LOCAL_SRC_FILES_mips := arch/mips/begin.S linker_mips.cpp
|
||||||
LOCAL_SRC_FILES_mips64 := arch/mips64/begin.S
|
LOCAL_SRC_FILES_mips64 := arch/mips64/begin.S linker_mips.cpp
|
||||||
|
|
||||||
LOCAL_LDFLAGS := \
|
LOCAL_LDFLAGS := \
|
||||||
-shared \
|
-shared \
|
||||||
|
@ -122,14 +122,6 @@ __LIBC_HIDDEN__ int g_ld_debug_verbosity;
|
|||||||
|
|
||||||
__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
|
__LIBC_HIDDEN__ abort_msg_t* g_abort_message = nullptr; // For debuggerd.
|
||||||
|
|
||||||
enum RelocationKind {
|
|
||||||
kRelocAbsolute = 0,
|
|
||||||
kRelocRelative,
|
|
||||||
kRelocCopy,
|
|
||||||
kRelocSymbol,
|
|
||||||
kRelocMax
|
|
||||||
};
|
|
||||||
|
|
||||||
#if STATS
|
#if STATS
|
||||||
struct linker_stats_t {
|
struct linker_stats_t {
|
||||||
int count[kRelocMax];
|
int count[kRelocMax];
|
||||||
@ -137,30 +129,16 @@ struct linker_stats_t {
|
|||||||
|
|
||||||
static linker_stats_t linker_stats;
|
static linker_stats_t linker_stats;
|
||||||
|
|
||||||
static void count_relocation(RelocationKind kind) {
|
void count_relocation(RelocationKind kind) {
|
||||||
++linker_stats.count[kind];
|
++linker_stats.count[kind];
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static void count_relocation(RelocationKind) {
|
void count_relocation(RelocationKind) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if COUNT_PAGES
|
#if COUNT_PAGES
|
||||||
static unsigned bitmask[4096];
|
uint32_t bitmask[4096];
|
||||||
#if defined(__LP64__)
|
|
||||||
#define MARK(offset) \
|
|
||||||
do { \
|
|
||||||
if ((((offset) >> 12) >> 5) < 4096) \
|
|
||||||
bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \
|
|
||||||
} while (0)
|
|
||||||
#else
|
|
||||||
#define MARK(offset) \
|
|
||||||
do { \
|
|
||||||
bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
#define MARK(x) do {} while (0)
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// You shouldn't try to call memory-allocating functions in the dynamic linker.
|
// You shouldn't try to call memory-allocating functions in the dynamic linker.
|
||||||
@ -539,7 +517,7 @@ uint32_t SymbolName::gnu_hash() {
|
|||||||
return gnu_hash_;
|
return gnu_hash_;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in,
|
ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in,
|
||||||
const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) {
|
const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group) {
|
||||||
SymbolName symbol_name(name);
|
SymbolName symbol_name(name);
|
||||||
ElfW(Sym)* s = nullptr;
|
ElfW(Sym)* s = nullptr;
|
||||||
@ -1292,10 +1270,9 @@ static ElfW(Addr) get_addend(ElfW(Rel)* rel, ElfW(Addr) reloc_addr) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
||||||
template<typename ElfRelT>
|
template<typename ElfRelT>
|
||||||
int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
|
bool soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
|
||||||
for (size_t idx = 0; idx < count; ++idx, ++rel) {
|
for (size_t idx = 0; idx < count; ++idx, ++rel) {
|
||||||
ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
|
ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
|
||||||
ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
|
ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
|
||||||
@ -1303,11 +1280,9 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
|
ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
|
||||||
ElfW(Addr) sym_addr = 0;
|
ElfW(Addr) sym_addr = 0;
|
||||||
const char* sym_name = nullptr;
|
const char* sym_name = nullptr;
|
||||||
#if !defined(__mips__)
|
|
||||||
ElfW(Addr) addend = get_addend(rel, reloc);
|
ElfW(Addr) addend = get_addend(rel, reloc);
|
||||||
#endif
|
|
||||||
|
|
||||||
DEBUG("Processing '%s' relocation at index %zd", name, idx);
|
DEBUG("Processing '%s' relocation at index %zd", this->name, idx);
|
||||||
if (type == R_GENERIC_NONE) {
|
if (type == R_GENERIC_NONE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1323,7 +1298,7 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
s = &symtab_[sym];
|
s = &symtab_[sym];
|
||||||
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
|
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
|
||||||
DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
|
DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IHI0044C AAELF 4.5.1.1:
|
/* IHI0044C AAELF 4.5.1.1:
|
||||||
@ -1339,7 +1314,6 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
#if !defined(__mips__)
|
|
||||||
case R_GENERIC_JUMP_SLOT:
|
case R_GENERIC_JUMP_SLOT:
|
||||||
case R_GENERIC_GLOB_DAT:
|
case R_GENERIC_GLOB_DAT:
|
||||||
case R_GENERIC_RELATIVE:
|
case R_GENERIC_RELATIVE:
|
||||||
@ -1370,11 +1344,10 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
case R_386_PC32:
|
case R_386_PC32:
|
||||||
sym_addr = reloc;
|
sym_addr = reloc;
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
|
DL_ERR("unknown weak reloc type %d @ %p (%zu)", type, rel, idx);
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We got a definition.
|
// We got a definition.
|
||||||
@ -1384,7 +1357,6 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
#if !defined(__mips__)
|
|
||||||
case R_GENERIC_JUMP_SLOT:
|
case R_GENERIC_JUMP_SLOT:
|
||||||
count_relocation(kRelocAbsolute);
|
count_relocation(kRelocAbsolute);
|
||||||
MARK(rel->r_offset);
|
MARK(rel->r_offset);
|
||||||
@ -1418,7 +1390,6 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
reinterpret_cast<void*>(base + addend));
|
reinterpret_cast<void*>(base + addend));
|
||||||
*reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + addend);
|
*reinterpret_cast<ElfW(Addr)*>(reloc) = call_ifunc_resolver(base + addend);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__aarch64__)
|
#if defined(__aarch64__)
|
||||||
case R_AARCH64_ABS64:
|
case R_AARCH64_ABS64:
|
||||||
@ -1441,7 +1412,7 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
(*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)),
|
(*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)),
|
||||||
static_cast<ElfW(Addr)>(INT32_MIN),
|
static_cast<ElfW(Addr)>(INT32_MIN),
|
||||||
static_cast<ElfW(Addr)>(UINT32_MAX));
|
static_cast<ElfW(Addr)>(UINT32_MAX));
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R_AARCH64_ABS16:
|
case R_AARCH64_ABS16:
|
||||||
@ -1457,7 +1428,7 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
(*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)),
|
(*reinterpret_cast<ElfW(Addr)*>(reloc) + (sym_addr + addend)),
|
||||||
static_cast<ElfW(Addr)>(INT16_MIN),
|
static_cast<ElfW(Addr)>(INT16_MIN),
|
||||||
static_cast<ElfW(Addr)>(UINT16_MAX));
|
static_cast<ElfW(Addr)>(UINT16_MAX));
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R_AARCH64_PREL64:
|
case R_AARCH64_PREL64:
|
||||||
@ -1480,7 +1451,7 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
(*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)),
|
(*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)),
|
||||||
static_cast<ElfW(Addr)>(INT32_MIN),
|
static_cast<ElfW(Addr)>(INT32_MIN),
|
||||||
static_cast<ElfW(Addr)>(UINT32_MAX));
|
static_cast<ElfW(Addr)>(UINT32_MAX));
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R_AARCH64_PREL16:
|
case R_AARCH64_PREL16:
|
||||||
@ -1496,7 +1467,7 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
(*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)),
|
(*reinterpret_cast<ElfW(Addr)*>(reloc) + ((sym_addr + addend) - rel->r_offset)),
|
||||||
static_cast<ElfW(Addr)>(INT16_MIN),
|
static_cast<ElfW(Addr)>(INT16_MIN),
|
||||||
static_cast<ElfW(Addr)>(UINT16_MAX));
|
static_cast<ElfW(Addr)>(UINT16_MAX));
|
||||||
return -1;
|
return false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -1511,7 +1482,7 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
* set to ET_EXEC.
|
* set to ET_EXEC.
|
||||||
*/
|
*/
|
||||||
DL_ERR("%s R_AARCH64_COPY relocations are not supported", name);
|
DL_ERR("%s R_AARCH64_COPY relocations are not supported", name);
|
||||||
return -1;
|
return false;
|
||||||
case R_AARCH64_TLS_TPREL64:
|
case R_AARCH64_TLS_TPREL64:
|
||||||
TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
|
TRACE_TYPE(RELO, "RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n",
|
||||||
reloc, (sym_addr + addend), rel->r_offset);
|
reloc, (sym_addr + addend), rel->r_offset);
|
||||||
@ -1568,7 +1539,7 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
* set to ET_EXEC.
|
* set to ET_EXEC.
|
||||||
*/
|
*/
|
||||||
DL_ERR("%s R_ARM_COPY relocations are not supported", name);
|
DL_ERR("%s R_ARM_COPY relocations are not supported", name);
|
||||||
return -1;
|
return false;
|
||||||
#elif defined(__i386__)
|
#elif defined(__i386__)
|
||||||
case R_386_32:
|
case R_386_32:
|
||||||
count_relocation(kRelocRelative);
|
count_relocation(kRelocRelative);
|
||||||
@ -1583,87 +1554,15 @@ int soinfo::relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_g
|
|||||||
reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
|
reloc, (sym_addr - reloc), sym_addr, reloc, sym_name);
|
||||||
*reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
|
*reinterpret_cast<ElfW(Addr)*>(reloc) += (sym_addr - reloc);
|
||||||
break;
|
break;
|
||||||
#elif defined(__mips__)
|
|
||||||
case R_MIPS_REL32:
|
|
||||||
#if defined(__LP64__)
|
|
||||||
// MIPS Elf64_Rel entries contain compound relocations
|
|
||||||
// We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case
|
|
||||||
if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 ||
|
|
||||||
ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) {
|
|
||||||
DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)",
|
|
||||||
type, (unsigned)ELF64_R_TYPE2(rel->r_info),
|
|
||||||
(unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
count_relocation(kRelocAbsolute);
|
|
||||||
MARK(rel->r_offset);
|
|
||||||
TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc),
|
|
||||||
static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*");
|
|
||||||
if (s) {
|
|
||||||
*reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
|
|
||||||
} else {
|
|
||||||
*reinterpret_cast<ElfW(Addr)*>(reloc) += base;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
|
DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__mips__)
|
|
||||||
bool soinfo::mips_relocate_got(const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
|
|
||||||
ElfW(Addr)** got = plt_got_;
|
|
||||||
if (got == nullptr) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// got[0] is the address of the lazy resolver function.
|
|
||||||
// got[1] may be used for a GNU extension.
|
|
||||||
// Set it to a recognizable address in case someone calls it (should be _rtld_bind_start).
|
|
||||||
// FIXME: maybe this should be in a separate routine?
|
|
||||||
if ((flags_ & FLAG_LINKER) == 0) {
|
|
||||||
size_t g = 0;
|
|
||||||
got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadbeef);
|
|
||||||
if (reinterpret_cast<intptr_t>(got[g]) < 0) {
|
|
||||||
got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadfeed);
|
|
||||||
}
|
|
||||||
// Relocate the local GOT entries.
|
|
||||||
for (; g < mips_local_gotno_; g++) {
|
|
||||||
got[g] = reinterpret_cast<ElfW(Addr)*>(reinterpret_cast<uintptr_t>(got[g]) + load_bias);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now for the global GOT entries...
|
|
||||||
ElfW(Sym)* sym = symtab_ + mips_gotsym_;
|
|
||||||
got = plt_got_ + mips_local_gotno_;
|
|
||||||
for (size_t g = mips_gotsym_; g < mips_symtabno_; g++, sym++, got++) {
|
|
||||||
// This is an undefined reference... try to locate it.
|
|
||||||
const char* sym_name = get_string(sym->st_name);
|
|
||||||
soinfo* lsi = nullptr;
|
|
||||||
ElfW(Sym)* s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group);
|
|
||||||
if (s == nullptr) {
|
|
||||||
// We only allow an undefined symbol if this is a weak reference.
|
|
||||||
s = &symtab_[g];
|
|
||||||
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
|
|
||||||
DL_ERR("cannot locate \"%s\"...", sym_name);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
*got = 0;
|
|
||||||
} else {
|
|
||||||
// FIXME: is this sufficient?
|
|
||||||
// For reference see NetBSD link loader
|
|
||||||
// http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/arch/mips/mips_reloc.c?rev=1.53&content-type=text/x-cvsweb-markup
|
|
||||||
*got = reinterpret_cast<ElfW(Addr)*>(lsi->resolve_symbol_address(s));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
#endif
|
#endif // !defined(__mips__)
|
||||||
|
|
||||||
void soinfo::call_array(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) {
|
void soinfo::call_array(const char* array_name __unused, linker_function_t* functions, size_t count, bool reverse) {
|
||||||
if (functions == nullptr) {
|
if (functions == nullptr) {
|
||||||
@ -2352,26 +2251,26 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
|
|||||||
#if defined(USE_RELA)
|
#if defined(USE_RELA)
|
||||||
if (rela_ != nullptr) {
|
if (rela_ != nullptr) {
|
||||||
DEBUG("[ relocating %s ]", name);
|
DEBUG("[ relocating %s ]", name);
|
||||||
if (relocate(rela_, rela_count_, global_group, local_group)) {
|
if (!relocate(rela_, rela_count_, global_group, local_group)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (plt_rela_ != nullptr) {
|
if (plt_rela_ != nullptr) {
|
||||||
DEBUG("[ relocating %s plt ]", name);
|
DEBUG("[ relocating %s plt ]", name);
|
||||||
if (relocate(plt_rela_, plt_rela_count_, global_group, local_group)) {
|
if (!relocate(plt_rela_, plt_rela_count_, global_group, local_group)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (rel_ != nullptr) {
|
if (rel_ != nullptr) {
|
||||||
DEBUG("[ relocating %s ]", name);
|
DEBUG("[ relocating %s ]", name);
|
||||||
if (relocate(rel_, rel_count_, global_group, local_group)) {
|
if (!relocate(rel_, rel_count_, global_group, local_group)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (plt_rel_ != nullptr) {
|
if (plt_rel_ != nullptr) {
|
||||||
DEBUG("[ relocating %s plt ]", name);
|
DEBUG("[ relocating %s plt ]", name);
|
||||||
if (relocate(plt_rel_, plt_rel_count_, global_group, local_group)) {
|
if (!relocate(plt_rel_, plt_rel_count_, global_group, local_group)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,7 +287,7 @@ struct soinfo {
|
|||||||
void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
|
void call_array(const char* array_name, linker_function_t* functions, size_t count, bool reverse);
|
||||||
void call_function(const char* function_name, linker_function_t function);
|
void call_function(const char* function_name, linker_function_t function);
|
||||||
template<typename ElfRelT>
|
template<typename ElfRelT>
|
||||||
int relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group);
|
bool relocate(ElfRelT* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// This part of the structure is only available
|
// This part of the structure is only available
|
||||||
@ -318,6 +318,19 @@ struct soinfo {
|
|||||||
friend soinfo* get_libdl_info();
|
friend soinfo* get_libdl_info();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ElfW(Sym)* soinfo_do_lookup(soinfo* si_from, const char* name, soinfo** si_found_in,
|
||||||
|
const soinfo::soinfo_list_t& global_group, const soinfo::soinfo_list_t& local_group);
|
||||||
|
|
||||||
|
enum RelocationKind {
|
||||||
|
kRelocAbsolute = 0,
|
||||||
|
kRelocRelative,
|
||||||
|
kRelocCopy,
|
||||||
|
kRelocSymbol,
|
||||||
|
kRelocMax
|
||||||
|
};
|
||||||
|
|
||||||
|
void count_relocation(RelocationKind kind);
|
||||||
|
|
||||||
soinfo* get_libdl_info();
|
soinfo* get_libdl_info();
|
||||||
|
|
||||||
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
|
void do_android_get_LD_LIBRARY_PATH(char*, size_t);
|
||||||
|
@ -82,4 +82,23 @@ __LIBC_HIDDEN__ extern int g_ld_debug_verbosity;
|
|||||||
|
|
||||||
#define TRACE_TYPE(t, x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0)
|
#define TRACE_TYPE(t, x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0)
|
||||||
|
|
||||||
|
#if COUNT_PAGES
|
||||||
|
extern uint32_t bitmask[];
|
||||||
|
#if defined(__LP64__)
|
||||||
|
#define MARK(offset) \
|
||||||
|
do { \
|
||||||
|
if ((((offset) >> 12) >> 5) < 4096) \
|
||||||
|
bitmask[((offset) >> 12) >> 5] |= (1 << (((offset) >> 12) & 31)); \
|
||||||
|
} while (0)
|
||||||
|
#else
|
||||||
|
#define MARK(offset) \
|
||||||
|
do { \
|
||||||
|
bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#define MARK(x) do {} while (0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _LINKER_DEBUG_H_ */
|
#endif /* _LINKER_DEBUG_H_ */
|
||||||
|
143
linker/linker_mips.cpp
Normal file
143
linker/linker_mips.cpp
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "linker.h"
|
||||||
|
#include "linker_debug.h"
|
||||||
|
#include "linker_relocs.h"
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool soinfo::relocate(ElfW(Rel)* rel, unsigned count, const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
|
||||||
|
for (size_t idx = 0; idx < count; ++idx, ++rel) {
|
||||||
|
ElfW(Word) type = ELFW(R_TYPE)(rel->r_info);
|
||||||
|
ElfW(Word) sym = ELFW(R_SYM)(rel->r_info);
|
||||||
|
|
||||||
|
ElfW(Addr) reloc = static_cast<ElfW(Addr)>(rel->r_offset + load_bias);
|
||||||
|
ElfW(Addr) sym_addr = 0;
|
||||||
|
const char* sym_name = nullptr;
|
||||||
|
|
||||||
|
DEBUG("Processing '%s' relocation at index %zd", this->name, idx);
|
||||||
|
if (type == R_GENERIC_NONE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ElfW(Sym)* s = nullptr;
|
||||||
|
soinfo* lsi = nullptr;
|
||||||
|
|
||||||
|
if (sym != 0) {
|
||||||
|
sym_name = get_string(symtab_[sym].st_name);
|
||||||
|
s = soinfo_do_lookup(this, sym_name, &lsi, global_group,local_group);
|
||||||
|
if (s == nullptr) {
|
||||||
|
// mips does not support relocation with weak-undefined symbols
|
||||||
|
DL_ERR("cannot locate symbol \"%s\" referenced by \"%s\"...", sym_name, name);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// We got a definition.
|
||||||
|
sym_addr = lsi->resolve_symbol_address(s);
|
||||||
|
}
|
||||||
|
count_relocation(kRelocSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case R_MIPS_REL32:
|
||||||
|
#if defined(__LP64__)
|
||||||
|
// MIPS Elf64_Rel entries contain compound relocations
|
||||||
|
// We only handle the R_MIPS_NONE|R_MIPS_64|R_MIPS_REL32 case
|
||||||
|
if (ELF64_R_TYPE2(rel->r_info) != R_MIPS_64 ||
|
||||||
|
ELF64_R_TYPE3(rel->r_info) != R_MIPS_NONE) {
|
||||||
|
DL_ERR("Unexpected compound relocation type:%d type2:%d type3:%d @ %p (%zu)",
|
||||||
|
type, (unsigned)ELF64_R_TYPE2(rel->r_info),
|
||||||
|
(unsigned)ELF64_R_TYPE3(rel->r_info), rel, idx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
count_relocation(s == nullptr ? kRelocAbsolute : kRelocRelative);
|
||||||
|
MARK(rel->r_offset);
|
||||||
|
TRACE_TYPE(RELO, "RELO REL32 %08zx <- %08zx %s", static_cast<size_t>(reloc),
|
||||||
|
static_cast<size_t>(sym_addr), sym_name ? sym_name : "*SECTIONHDR*");
|
||||||
|
if (s != nullptr) {
|
||||||
|
*reinterpret_cast<ElfW(Addr)*>(reloc) += sym_addr;
|
||||||
|
} else {
|
||||||
|
*reinterpret_cast<ElfW(Addr)*>(reloc) += base;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
DL_ERR("unknown reloc type %d @ %p (%zu)", type, rel, idx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool soinfo::mips_relocate_got(const soinfo_list_t& global_group, const soinfo_list_t& local_group) {
|
||||||
|
ElfW(Addr)** got = plt_got_;
|
||||||
|
if (got == nullptr) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// got[0] is the address of the lazy resolver function.
|
||||||
|
// got[1] may be used for a GNU extension.
|
||||||
|
// Set it to a recognizable address in case someone calls it (should be _rtld_bind_start).
|
||||||
|
// FIXME: maybe this should be in a separate routine?
|
||||||
|
if ((flags_ & FLAG_LINKER) == 0) {
|
||||||
|
size_t g = 0;
|
||||||
|
got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadbeef);
|
||||||
|
if (reinterpret_cast<intptr_t>(got[g]) < 0) {
|
||||||
|
got[g++] = reinterpret_cast<ElfW(Addr)*>(0xdeadfeed);
|
||||||
|
}
|
||||||
|
// Relocate the local GOT entries.
|
||||||
|
for (; g < mips_local_gotno_; g++) {
|
||||||
|
got[g] = reinterpret_cast<ElfW(Addr)*>(reinterpret_cast<uintptr_t>(got[g]) + load_bias);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now for the global GOT entries...
|
||||||
|
ElfW(Sym)* sym = symtab_ + mips_gotsym_;
|
||||||
|
got = plt_got_ + mips_local_gotno_;
|
||||||
|
for (size_t g = mips_gotsym_; g < mips_symtabno_; g++, sym++, got++) {
|
||||||
|
// This is an undefined reference... try to locate it.
|
||||||
|
const char* sym_name = get_string(sym->st_name);
|
||||||
|
soinfo* lsi = nullptr;
|
||||||
|
ElfW(Sym)* s = soinfo_do_lookup(this, sym_name, &lsi, global_group, local_group);
|
||||||
|
if (s == nullptr) {
|
||||||
|
// We only allow an undefined symbol if this is a weak reference.
|
||||||
|
s = &symtab_[g];
|
||||||
|
if (ELF_ST_BIND(s->st_info) != STB_WEAK) {
|
||||||
|
DL_ERR("cannot locate \"%s\"...", sym_name);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*got = 0;
|
||||||
|
} else {
|
||||||
|
// FIXME: is this sufficient?
|
||||||
|
// For reference see NetBSD link loader
|
||||||
|
// http://cvsweb.netbsd.org/bsdweb.cgi/src/libexec/ld.elf_so/arch/mips/mips_reloc.c?rev=1.53&content-type=text/x-cvsweb-markup
|
||||||
|
*got = reinterpret_cast<ElfW(Addr)*>(lsi->resolve_symbol_address(s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user