Merge "linker: add experimental support for SHT_RELR sections."

This commit is contained in:
Elliott Hughes 2018-01-23 00:24:26 +00:00 committed by Gerrit Code Review
commit d00d38b36b
3 changed files with 85 additions and 6 deletions

View File

@ -194,6 +194,14 @@ typedef struct {
Elf64_Word vna_next;
} Elf64_Vernaux;
/* Relocation table entry for relative (in section of type SHT_RELR). */
typedef Elf32_Word Elf32_Relr;
typedef Elf64_Xword Elf64_Relr;
#define ELF32_R_JUMP(val) ((val) >> 24)
#define ELF32_R_BITS(val) ((val) & 0xffffff)
#define ELF64_R_JUMP(val) ((val) >> 56)
#define ELF64_R_BITS(val) ((val) & 0xffffffffffffff)
/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html */
#define DF_ORIGIN 0x00000001
#define DF_SYMBOLIC 0x00000002
@ -242,6 +250,13 @@ typedef struct {
#define DT_PREINIT_ARRAY 32
#define DT_PREINIT_ARRAYSZ 33
/* Experimental support for SHT_RELR sections. For details, see proposal
at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */
#define DT_RELR 0x6fffe000
#define DT_RELRSZ 0x6fffe001
#define DT_RELRENT 0x6fffe003
#define DT_RELRCOUNT 0x6fffe005
/* Android compressed rel/rela sections */
#define DT_ANDROID_REL (DT_LOOS + 2)
#define DT_ANDROID_RELSZ (DT_LOOS + 3)
@ -494,6 +509,10 @@ typedef struct {
#define SHT_LOOS 0x60000000
#define SHT_HIOS 0x6fffffff
/* Experimental support for SHT_RELR sections. For details, see proposal
at https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg */
#define SHT_RELR 0x6fffff00
/* http://www.sco.com/developers/gabi/latest/ch4.symtab.html */
#define STN_UNDEF 0

View File

@ -2595,6 +2595,35 @@ bool soinfo::lookup_version_info(const VersionTracker& version_tracker, ElfW(Wor
return true;
}
// Process relocations in SHT_RELR section (experimental).
// See the original proposal for details of the encoding:
// - https://groups.google.com/forum/#!topic/generic-abi/bX460iggiKg
bool soinfo::relocate_relr() {
ElfW(Relr)* begin = relr_;
ElfW(Relr)* end = relr_ + relr_count_;
ElfW(Addr) offset = 0;
for (ElfW(Relr)* current = begin; current < end; ++current) {
ElfW(Addr) jump = ELFW(R_JUMP)(*current);
ElfW(Addr) bits = ELFW(R_BITS)(*current);
offset += jump * sizeof(ElfW(Addr));
if (jump == 0) {
++current;
offset = *current;
}
ElfW(Addr) r_offset = offset;
for (; bits != 0; bits >>= 1) {
if ((bits&1) != 0) {
ElfW(Addr) reloc = static_cast<ElfW(Addr)>(r_offset + load_bias);
ElfW(Addr) addend = *reinterpret_cast<ElfW(Addr)*>(reloc);
*reinterpret_cast<ElfW(Addr)*>(reloc) = (load_bias + addend);
}
r_offset += sizeof(ElfW(Addr));
}
}
return true;
}
#if !defined(__mips__)
#if defined(USE_RELA)
static ElfW(Addr) get_addend(ElfW(Rela)* rela, ElfW(Addr) reloc_addr __unused) {
@ -3151,7 +3180,7 @@ bool soinfo::prelink_image() {
}
break;
// ignored (see DT_RELCOUNT comments for details)
// Ignored (see DT_RELCOUNT comments for details).
case DT_RELACOUNT:
break;
@ -3212,6 +3241,25 @@ bool soinfo::prelink_image() {
return false;
#endif
case DT_RELR:
relr_ = reinterpret_cast<ElfW(Relr)*>(load_bias + d->d_un.d_ptr);
break;
case DT_RELRSZ:
relr_count_ = d->d_un.d_val / sizeof(ElfW(Relr));
break;
case DT_RELRENT:
if (d->d_un.d_val != sizeof(ElfW(Relr))) {
DL_ERR("invalid DT_RELRENT: %zd", static_cast<size_t>(d->d_un.d_val));
return false;
}
break;
// Ignored (see DT_RELCOUNT comments for details).
case DT_RELRCOUNT:
break;
case DT_INIT:
init_func_ = reinterpret_cast<linker_ctor_function_t>(load_bias + d->d_un.d_ptr);
DEBUG("%s constructors (DT_INIT) found at %p", get_realpath(), init_func_);
@ -3504,16 +3552,23 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
}
}
if (relr_ != nullptr) {
DEBUG("[ relocating %s relr ]", get_realpath());
if (!relocate_relr()) {
return false;
}
}
#if defined(USE_RELA)
if (rela_ != nullptr) {
DEBUG("[ relocating %s ]", get_realpath());
DEBUG("[ relocating %s rela ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(rela_, rela_count_), global_group, local_group)) {
return false;
}
}
if (plt_rela_ != nullptr) {
DEBUG("[ relocating %s plt ]", get_realpath());
DEBUG("[ relocating %s plt rela ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(plt_rela_, plt_rela_count_), global_group, local_group)) {
return false;
@ -3521,14 +3576,14 @@ bool soinfo::link_image(const soinfo_list_t& global_group, const soinfo_list_t&
}
#else
if (rel_ != nullptr) {
DEBUG("[ relocating %s ]", get_realpath());
DEBUG("[ relocating %s rel ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(rel_, rel_count_), global_group, local_group)) {
return false;
}
}
if (plt_rel_ != nullptr) {
DEBUG("[ relocating %s plt ]", get_realpath());
DEBUG("[ relocating %s plt rel ]", get_realpath());
if (!relocate(version_tracker,
plain_reloc_iterator(plt_rel_, plt_rel_count_), global_group, local_group)) {
return false;

View File

@ -62,7 +62,7 @@
// unset.
#define FLAG_NEW_SOINFO 0x40000000 // new soinfo format
#define SOINFO_VERSION 3
#define SOINFO_VERSION 4
typedef void (*linker_dtor_function_t)();
typedef void (*linker_ctor_function_t)(int, char**, char**);
@ -309,6 +309,7 @@ struct soinfo {
template<typename ElfRelIteratorT>
bool relocate(const VersionTracker& version_tracker, ElfRelIteratorT&& rel_iterator,
const soinfo_list_t& global_group, const soinfo_list_t& local_group);
bool relocate_relr();
private:
// This part of the structure is only available
@ -365,6 +366,10 @@ struct soinfo {
friend soinfo* get_libdl_info(const char* linker_path,
const soinfo& linker_si,
const link_map& linker_map);
// version >= 4
ElfW(Relr)* relr_;
size_t relr_count_;
};
// This function is used by dlvsym() to calculate hash of sym_ver