bool
ElfSoinfo::relocate(hook_info
*
info) {
if
(my_soinfo_
-
>rela_ !
=
nullptr) {
LOGD(
"[ relocating %s ]"
, get_realpath());
relocate(plain_reloc_iterator(my_soinfo_
-
>rela_,
my_soinfo_
-
>rela_count_), info);
}
if
(my_soinfo_
-
>plt_rela_ !
=
nullptr) {
LOGD(
"[ relocating %s plt ]"
, get_realpath());
relocate(plain_reloc_iterator(my_soinfo_
-
>plt_rela_,
my_soinfo_
-
>plt_rela_count_), info);
}
if
(my_soinfo_
-
>rel_ !
=
nullptr) {
LOGD(
"[ relocating %s ]"
, get_realpath());
relocate(plain_reloc_iterator(my_soinfo_
-
>rel_,
my_soinfo_
-
>rel_count_), info, exported);
}
if
(my_soinfo_
-
>plt_rel_ !
=
nullptr) {
LOGD(
"[ relocating %s plt ]"
, get_realpath());
relocate(plain_reloc_iterator(my_soinfo_
-
>plt_rel_,
my_soinfo_
-
>plt_rel_count_), info, exported);
}
return
false;
}
bool
ElfSoinfo::relocate(plain_reloc_iterator&& rel_iterator, hook_info
*
info) {
for
(size_t idx
=
0
; rel_iterator.has_next();
+
+
idx) {
const auto rel
=
rel_iterator.
next
();
if
(rel
=
=
nullptr) {
return
false;
}
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
+
my_soinfo_
-
>load_bias);
ElfW(Addr) sym_addr
=
0
;
const char
*
sym_name
=
nullptr;
ElfW(Addr) addend
=
get_addend(rel, reloc);
LOGD(
"Processing \"%s\" relocation at index %zd addend: %16p"
, get_realpath(), idx, addend);
if
(
type
=
=
R_GENERIC_NONE) {
continue
;
}
const ElfW(Sym)
*
s
=
nullptr;
if
(sym !
=
0
) {
sym_name
=
get_string(my_soinfo_
-
>symtab_[sym].st_name);
s
=
&my_soinfo_
-
>symtab_[sym];
LOGD(
"func(%s@%p)"
, sym_name, (void
*
) reloc);
if
(s
-
>st_shndx
=
=
SHN_UNDEF && sym_name && strcmp(sym_name, info
-
>symbol)
=
=
0
) {
switch (
type
) {
case R_GENERIC_JUMP_SLOT: {
ElfW(Addr) page_start
=
PAGE_START(reloc);
mprotect((ElfW(Addr)
*
) page_start, PAGE_SIZE, PROT_WRITE | PROT_READ);
LOGD(
"RELO JMP_SLOT %16p <- %16p %s"
, reinterpret_cast<void
*
>(reloc),
info
-
>hook_sym, sym_name);
if
(info
-
>orig_sym) {
*
info
-
>orig_sym
=
(ElfW(Addr)
*
) reloc;
}
*
((ElfW(Addr)
*
) reloc)
=
(ElfW(Addr)) info
-
>hook_sym
+
addend;
mprotect((ElfW(Addr)
*
) page_start, PAGE_SIZE, PROT_READ);
__clear_cache((void
*
) page_start, (void
*
)PAGE_END(reloc));
break
;
}
default:
LOGE(
"currently only support arch64 got hook!"
);
break
;
}
}
}
switch (
type
) {
case R_GENERIC_JUMP_SLOT:
LOGD(
"RELO JMP_SLOT %16p <- %16p %s\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(sym_addr
+
addend), sym_name);
break
;
case R_GENERIC_GLOB_DAT:
LOGD(
"RELO GLOB_DAT %16p <- %16p %s\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(sym_addr
+
addend), sym_name);
break
;
case R_GENERIC_RELATIVE:
LOGD(
"RELO RELATIVE %16p <- %16p\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(my_soinfo_
-
>load_bias
+
addend));
break
;
case R_GENERIC_IRELATIVE:
LOGD(
"RELO IRELATIVE %16p <- %16p\n"
,
reinterpret_cast<void
*
>(reloc),
reinterpret_cast<void
*
>(my_soinfo_
-
>load_bias
+
addend));
break
;
case R_AARCH64_ABS64:
LOGD(
"RELO ABS64 %16llx <- %16llx %s\n"
,
reloc, sym_addr
+
addend, sym_name);
break
;
case R_AARCH64_ABS32:
LOGD(
"RELO ABS32 %16llx <- %16llx %s\n"
,
reloc, sym_addr
+
addend, sym_name);
break
;
case R_AARCH64_ABS16:
LOGD(
"RELO ABS16 %16llx <- %16llx %s\n"
,
reloc, sym_addr
+
addend, sym_name);
break
;
case R_AARCH64_PREL64:
LOGD(
"RELO REL64 %16llx <- %16llx - %16llx %s\n"
,
reloc, sym_addr
+
addend, rel
-
>r_offset, sym_name);
break
;
case R_AARCH64_PREL32:
LOGD(
"RELO REL32 %16llx <- %16llx - %16llx %s\n"
,
reloc, sym_addr
+
addend, rel
-
>r_offset, sym_name);
break
;
case R_AARCH64_PREL16:
LOGD(
"RELO REL16 %16llx <- %16llx - %16llx %s\n"
,
reloc, sym_addr
+
addend, rel
-
>r_offset, sym_name);
break
;
case R_AARCH64_COPY:
LOGE(
"%s R_AARCH64_COPY relocations are not supported"
, get_realpath());
case R_AARCH64_TLS_TPREL64:
LOGD(
"RELO TLS_TPREL64 *** %16llx <- %16llx - %16llx\n"
,
reloc, (sym_addr
+
addend), rel
-
>r_offset);
break
;
case R_AARCH64_TLS_DTPREL32:
LOGD(
"RELO TLS_DTPREL32 *** %16llx <- %16llx - %16llx\n"
,
reloc, (sym_addr
+
addend), rel
-
>r_offset);
break
;
default:
LOGE(
"unknown reloc type %d @ %p (%zu)"
,
type
, rel, idx);
return
false;
}
}
return
true;
}