--android-shlib handles implicit relocation in PLT

modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
This commit is contained in:
John Reiser 2018-01-15 15:45:37 -08:00
parent e8ef0cf63f
commit 1fa9ff2c05
3 changed files with 58 additions and 24 deletions

View File

@ -590,7 +590,8 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
// Update {DYNAMIC}.sh_offset by so_slide.
Elf64_Shdr *shdr = shdri;
for (unsigned j = 0; j < e_shnum; ++shdr, ++j) {
if (Elf64_Shdr::SHT_DYNAMIC == get_te32(&shdr->sh_type)) {
unsigned sh_type = get_te32(&shdr->sh_type);
if (Elf64_Shdr::SHT_DYNAMIC == sh_type) {
upx_uint64_t offset = get_te64(&shdr->sh_offset);
set_te64(&shdr->sh_offset, so_slide - asl_delta + offset );
fo->seek(j * sizeof(Elf64_Shdr) - asl_delta + xct_off, SEEK_SET);
@ -598,6 +599,13 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
fo->seek(0, SEEK_END);
break;
}
if (Elf64_Shdr::SHT_RELA == sh_type
&& n_jmp_slot
&& !strcmp(".rela.plt", get_te32(&shdr->sh_name) + shstrtab)) {
upx_uint64_t f_off = elf_get_offset_from_address(plt_off);
fo->seek(f_off, SEEK_SET);
fo->rewrite(&file_image[f_off - so_slide], n_jmp_slot * sizeof(void *));
}
}
}
else { // !opt->o_unix.android_shlib)
@ -2032,11 +2040,11 @@ PackLinuxElf64::canPack()
}
}
else { // no Sections; use heuristics
uint64_t const strsz = elf_unsigned_dynamic(Elf64_Dyn::DT_STRSZ);
uint64_t const strtab = elf_unsigned_dynamic(Elf64_Dyn::DT_STRTAB);
uint64_t const relsz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELSZ);
uint64_t const rel = elf_unsigned_dynamic(Elf64_Dyn::DT_REL);
uint64_t const init = elf_unsigned_dynamic(Elf64_Dyn::DT_INIT);
upx_uint64_t const strsz = elf_unsigned_dynamic(Elf64_Dyn::DT_STRSZ);
upx_uint64_t const strtab = elf_unsigned_dynamic(Elf64_Dyn::DT_STRTAB);
upx_uint64_t const relsz = elf_unsigned_dynamic(Elf64_Dyn::DT_RELSZ);
upx_uint64_t const rel = elf_unsigned_dynamic(Elf64_Dyn::DT_REL);
upx_uint64_t const init = elf_unsigned_dynamic(Elf64_Dyn::DT_INIT);
if ((init == (relsz + rel ) && rel == (strsz + strtab))
|| (init == (strsz + strtab) && strtab == (relsz + rel ))
) {
@ -2865,23 +2873,23 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
// Relocate PT_DYNAMIC (in 2nd PT_LOAD)
Elf64_Dyn *dyn = const_cast<Elf64_Dyn *>(dynseg);
for (; dyn->d_tag; ++dyn) {
uint64_t d_tag = get_te64(&dyn->d_tag);
upx_uint64_t d_tag = get_te64(&dyn->d_tag);
if (Elf64_Dyn::DT_FINI == d_tag
|| Elf64_Dyn::DT_FINI_ARRAY == d_tag
|| Elf64_Dyn::DT_INIT_ARRAY == d_tag
|| Elf64_Dyn::DT_PREINIT_ARRAY == d_tag
|| Elf64_Dyn::DT_PLTGOT == d_tag) {
uint64_t d_val = get_te64(&dyn->d_val);
upx_uint64_t d_val = get_te64(&dyn->d_val);
set_te64(&dyn->d_val, asl_delta + d_val);
}
}
// Relocate dynsym (DT_SYMTAB) which is below xct_va
Elf64_Sym *sym = const_cast<Elf64_Sym *>(dynsym);
uint64_t off_dynsym = get_te64(&sec_dynsym->sh_offset);
uint64_t sz_dynsym = get_te64(&sec_dynsym->sh_size);
upx_uint64_t off_dynsym = get_te64(&sec_dynsym->sh_offset);
upx_uint64_t sz_dynsym = get_te64(&sec_dynsym->sh_size);
for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) {
uint64_t symval = get_te64(&sym->st_value);
upx_uint64_t symval = get_te64(&sym->st_value);
unsigned symsec = get_te16(&sym->st_shndx);
if (Elf64_Sym::SHN_UNDEF != symsec
&& Elf64_Sym::SHN_ABS != symsec
@ -2897,10 +2905,10 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
// Relocate Phdr virtual addresses, but not physical offsets and sizes
/* Elf64_Phdr * */ phdr = phdri;
for (int j = e_phnum; --j>=0; ++phdr) {
uint64_t offset = get_te64(&phdr->p_offset);
upx_uint64_t offset = get_te64(&phdr->p_offset);
if (xct_off <= offset) { // above the extra page
//set_te64(&phdr->p_offset, asl_delta + offset); // physical
uint64_t addr = get_te64(&phdr->p_paddr);
upx_uint64_t addr = get_te64(&phdr->p_paddr);
set_te64(&phdr->p_paddr, asl_delta + addr);
addr = get_te64(&phdr->p_vaddr);
set_te64(&phdr->p_vaddr, asl_delta + addr);
@ -2911,29 +2919,53 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
// Relocate Shdr; and Rela, Rel (below xct_off)
Elf64_Shdr *shdr = shdri;
uint64_t sz_shstrtab = get_te64(&sec_strndx->sh_size);
upx_uint64_t sz_shstrtab = get_te64(&sec_strndx->sh_size);
for (int j = e_shnum; --j>=0; ++shdr) {
unsigned sh_type = get_te32(&shdr->sh_type);
uint64_t sh_size = get_te64(&shdr->sh_size);
uint64_t sh_offset = get_te64(&shdr->sh_offset);
uint64_t sh_entsize = get_te64(&shdr->sh_entsize);
upx_uint64_t sh_size = get_te64(&shdr->sh_size);
upx_uint64_t sh_offset = get_te64(&shdr->sh_offset);
upx_uint64_t sh_entsize = get_te64(&shdr->sh_entsize);
if (xct_off <= sh_offset) {
set_te64(&shdr->sh_offset, asl_delta + sh_offset);
uint64_t addr = get_te64(&shdr->sh_addr);
upx_uint64_t addr = get_te64(&shdr->sh_addr);
set_te64(&shdr->sh_addr, asl_delta + addr);
}
if (Elf64_Shdr::SHT_RELA== sh_type) {
if (Elf64_Shdr::SHT_RELA == sh_type) {
if (sizeof(Elf64_Rela) != sh_entsize) {
char msg[50];
snprintf(msg, sizeof(msg), "bad Rela.sh_entsize %lu", sh_entsize);
snprintf(msg, sizeof(msg), "bad Rela.sh_entsize %lu", (long)sh_entsize);
throwCantPack(msg);
}
n_jmp_slot = 0;
plt_off = ~0ull;
Elf64_Rela *rela = (Elf64_Rela *)(sh_offset + file_image);
for (int k = sh_size / sh_entsize; --k >= 0; ++rela) {
uint64_t r_offset = get_te64(&rela->r_offset);
upx_uint64_t r_addend = get_te64(&rela->r_addend);
upx_uint64_t r_offset = get_te64(&rela->r_offset);
upx_uint64_t r_info = get_te64(&rela->r_info);
unsigned r_type = ELF64_R_TYPE(r_info);
if (xct_off <= r_offset) {
set_te64(&rela->r_offset, asl_delta + r_offset);
}
if (Elf64_Ehdr::EM_AARCH64 == e_machine) {
if (R_AARCH64_RELATIVE == r_type) {
if (xct_off <= r_addend) {
set_te64(&rela->r_addend, asl_delta + r_addend);
}
}
if (R_AARCH64_JUMP_SLOT == r_type) {
// .rela.plt contains offset of the "first time" target
if (plt_off > (asl_delta + r_offset)) {
plt_off = (asl_delta + r_offset);
}
upx_uint64_t d = elf_get_offset_from_address(asl_delta + r_offset);
upx_uint64_t w = get_te64(&file_image[d]);
if (xct_off <= w) {
set_te64(&file_image[d], asl_delta + w);
}
++n_jmp_slot;
}
}
}
fo->seek(sh_offset, SEEK_SET);
fo->rewrite(sh_offset + file_image, sh_size);
@ -2941,12 +2973,12 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/)
if (Elf64_Shdr::SHT_REL == sh_type) {
if (sizeof(Elf64_Rel) != sh_entsize) {
char msg[50];
snprintf(msg, sizeof(msg), "bad Rel.sh_entsize %lu", sh_entsize);
snprintf(msg, sizeof(msg), "bad Rel.sh_entsize %lu", (long)sh_entsize);
throwCantPack(msg);
}
Elf64_Rel *rel = (Elf64_Rel *)(sh_offset + file_image);
for (int k = sh_size / sh_entsize; --k >= 0; ++rel) {
uint64_t r_offset = get_te64(&rel->r_offset);
upx_uint64_t r_offset = get_te64(&rel->r_offset);
if (xct_off <= r_offset) {
set_te64(&rel->r_offset, asl_delta + r_offset);
}

View File

@ -291,6 +291,8 @@ protected:
upx_uint64_t so_slide;
unsigned char *note_body; // concatenated contents of PT_NOTEs, if any
unsigned note_size; // total size of PT_NOTEs
unsigned n_jmp_slot;
upx_uint64_t plt_off;
upx_uint64_t page_mask; // AND clears the offset-within-page
Elf64_Dyn const *dynseg; // from PT_DYNAMIC

View File

@ -126,7 +126,7 @@ sp_frame = 24 * NBPW
// .long offset(escape_hatch)
// .long offset(xct_off) dst of f_exp
_start: .globl _start
// brk #0 // debugging
// brk #0 // debugging
slot f_argc // 0
slot f_argv // 1