Placate Android dlopen() some more.
https://github.com/upx/upx/issues/680 modified: p_lx_elf.cpp
This commit is contained in:
parent
dc76b2af97
commit
c429859cbf
@ -2712,6 +2712,7 @@ bool PackLinuxElf32::canPack()
|
||||
// not explicitly PIE main program
|
||||
if (Elf32_Ehdr::EM_ARM == e_machine // Android is common
|
||||
&& !opt->o_unix.android_shlib // but not explicit
|
||||
&& !saved_opt_android_shlib
|
||||
) {
|
||||
opt->info_mode++;
|
||||
info("note: use --android-shlib if appropriate");
|
||||
@ -2899,7 +2900,9 @@ bad:
|
||||
throwCantPack(buf);
|
||||
goto abandon;
|
||||
}
|
||||
if (!opt->o_unix.android_shlib) {
|
||||
if (!opt->o_unix.android_shlib
|
||||
&& !saved_opt_android_shlib
|
||||
) {
|
||||
phdr = phdri;
|
||||
for (unsigned j= 0; j < e_phnum; ++phdr, ++j) {
|
||||
unsigned const vaddr = get_te32(&phdr->p_vaddr);
|
||||
@ -3135,6 +3138,7 @@ PackLinuxElf64::canPack()
|
||||
// not explicitly PIE main program
|
||||
if (Elf64_Ehdr::EM_AARCH64 == e_machine // Android is common
|
||||
&& !opt->o_unix.android_shlib // but not explicit
|
||||
&& !saved_opt_android_shlib
|
||||
) {
|
||||
opt->info_mode++;
|
||||
info("note: use --android-shlib if appropriate");
|
||||
@ -3315,7 +3319,9 @@ PackLinuxElf64::canPack()
|
||||
throwCantPack(buf);
|
||||
goto abandon;
|
||||
}
|
||||
if (!opt->o_unix.android_shlib) {
|
||||
if (!opt->o_unix.android_shlib
|
||||
&& !saved_opt_android_shlib
|
||||
) {
|
||||
phdr = phdri;
|
||||
for (unsigned j= 0; j < e_phnum; ++phdr, ++j) {
|
||||
upx_uint64_t const vaddr = get_te64(&phdr->p_vaddr);
|
||||
@ -5560,7 +5566,7 @@ void PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
||||
if (saved_opt_android_shlib) { // Forward select _Shdr
|
||||
unsigned penalty = total_out;
|
||||
// Keep _Shdr for rtld data (below xct_off).
|
||||
// Discard _Shdr for compressed regions.
|
||||
// Discard _Shdr for compressed regions, except ".text" for gdb
|
||||
// Keep _Shdr for SHF_WRITE.
|
||||
// Discard _Shdr with (0==sh_addr), except _Shdr[0]
|
||||
// Keep ARM_ATTRIBUTES
|
||||
@ -5581,6 +5587,20 @@ void PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
||||
| 1u<<(0x1f & SHT_GNU_verneed)
|
||||
| 1u<<(0x1f & SHT_GNU_verdef)
|
||||
| 1u<<(0x1f & SHT_GNU_HASH);
|
||||
|
||||
u32_t xct_off_hi = 0;
|
||||
Elf32_Phdr const *ptr = phdri, *ptr_end = &phdri[e_phnum];
|
||||
for (; ptr < ptr_end; ++ptr) {
|
||||
if (PT_LOAD32 == get_te32(&ptr->p_type)) {
|
||||
u32_t hi = get_te32(&ptr->p_filesz)
|
||||
+ get_te32(&ptr->p_offset);
|
||||
if (xct_off < hi) {
|
||||
xct_off_hi = hi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemBuffer mb_ask_for(e_shnum * sizeof(eho->e_shnum));
|
||||
memset(mb_ask_for, 0, mb_ask_for.getSize());
|
||||
unsigned short *const ask_for = (unsigned short *)mb_ask_for.getVoidPtr();
|
||||
@ -5595,11 +5615,11 @@ void PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
||||
|
||||
for (unsigned j = 1; j < e_shnum; ++j, ++sh_in) {
|
||||
unsigned sh_type = get_te32(&sh_in->sh_type);
|
||||
unsigned sh_info = get_te32(&sh_in->sh_info);
|
||||
unsigned sh_flags = get_te32(&sh_in->sh_flags);
|
||||
unsigned sh_addr = get_te32(&sh_in->sh_addr);
|
||||
unsigned sh_offset = get_te32(&sh_in->sh_offset);
|
||||
unsigned sh_size = get_te32(&sh_in->sh_size);
|
||||
unsigned sh_info = get_te32(&sh_in->sh_info);
|
||||
if (ask_for[j]) { // Some previous _Shdr requested me
|
||||
// Tell them my new index
|
||||
set_te32(&sh_out0[ask_for[j]].sh_info, n_sh_out); // sh_info vs st_shndx
|
||||
@ -5614,17 +5634,27 @@ void PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
|
||||
|| (want_types_mask & (1<<(0x1f & sh_type)))
|
||||
) {
|
||||
*sh_out = *sh_in;
|
||||
if (sh_offset > xct_off) { // default: so_slide down
|
||||
set_te32(&sh_out->sh_offset, so_slide + sh_offset);
|
||||
}
|
||||
if (sh_addr > xct_off) { // default: so_slide down
|
||||
if (!(SHF_WRITE & sh_flags)) {
|
||||
set_te32(&sh_out->sh_addr, so_slide + sh_addr);
|
||||
if (sh_offset > xct_off) { // may slide down: earlier compression
|
||||
if (sh_offset >= xct_off_hi) { // easy: so_slide down
|
||||
if (sh_out->sh_addr) // change only if non-zero
|
||||
set_te32(&sh_out->sh_addr, so_slide + sh_addr);
|
||||
set_te32(&sh_out->sh_offset, so_slide + sh_offset);
|
||||
}
|
||||
else { // somewhere in compressed; try proportional (aligned)
|
||||
u32_t const slice = xct_off + (~0xFu & (unsigned)(
|
||||
(sh_offset - xct_off) *
|
||||
((sh_offset - xct_off) / (float)(xct_off_hi - xct_off))));
|
||||
set_te32(&sh_out->sh_addr, slice);
|
||||
set_te32(&sh_out->sh_offset, slice);
|
||||
}
|
||||
u32_t const max_sz = total_out - get_te32(&sh_out->sh_offset);
|
||||
if (sh_size > max_sz) { // avoid complaint "extends beyond EOF"
|
||||
set_te32(&sh_out->sh_size, max_sz);
|
||||
}
|
||||
// BEWARE: .p_vaddr does not slide
|
||||
}
|
||||
if (j == e_shstrndx) { // changes Elf32_Ehdr itself
|
||||
set_te16(&eho->e_shstrndx, sh_out - (Elf32_Shdr *)mb_shdro.getVoidPtr());
|
||||
set_te16(&eho->e_shstrndx, sh_out -
|
||||
(Elf32_Shdr *)mb_shdro.getVoidPtr());
|
||||
}
|
||||
if (j == e_shstrndx
|
||||
|| sec_arm_attr == sh_in
|
||||
@ -5704,7 +5734,7 @@ void PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|
||||
if (saved_opt_android_shlib) { // Forward select _Shdr
|
||||
unsigned penalty = total_out;
|
||||
// Keep _Shdr for rtld data (below xct_off).
|
||||
// Discard _Shdr for compressed regions.
|
||||
// Discard _Shdr for compressed regions, except ".text" for gdb.
|
||||
// Keep _Shdr for SHF_WRITE.
|
||||
// Discard _Shdr with (0==sh_addr), except _Shdr[0]
|
||||
// Keep ARM_ATTRIBUTES
|
||||
@ -5725,6 +5755,20 @@ void PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|
||||
| 1u<<(0x1f & SHT_GNU_verneed)
|
||||
| 1u<<(0x1f & SHT_GNU_verdef)
|
||||
| 1u<<(0x1f & SHT_GNU_HASH);
|
||||
|
||||
upx_uint64_t xct_off_hi = 0;
|
||||
Elf64_Phdr const *ptr = phdri, *ptr_end = &phdri[e_phnum];
|
||||
for (; ptr < ptr_end; ++ptr) {
|
||||
if (PT_LOAD64 == get_te32(&ptr->p_type)) {
|
||||
upx_uint64_t hi = get_te64(&ptr->p_filesz)
|
||||
+ get_te64(&ptr->p_offset);
|
||||
if (xct_off < hi) {
|
||||
xct_off_hi = hi;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MemBuffer mb_ask_for(e_shnum * sizeof(eho->e_shnum));
|
||||
memset(mb_ask_for, 0, mb_ask_for.getSize());
|
||||
unsigned short *const ask_for = (unsigned short *)mb_ask_for.getVoidPtr();
|
||||
@ -5758,17 +5802,27 @@ void PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|
||||
|| (want_types_mask & (1<<(0x1f & sh_type)))
|
||||
) {
|
||||
*sh_out = *sh_in;
|
||||
if (sh_offset > xct_off) { // default: so_slide down
|
||||
set_te64(&sh_out->sh_offset, so_slide + sh_offset);
|
||||
}
|
||||
if (sh_addr > xct_off) { // default: so_slide down
|
||||
if (!(SHF_WRITE & sh_flags)) {
|
||||
set_te64(&sh_out->sh_addr, so_slide + sh_addr);
|
||||
if (sh_offset > xct_off) { // may slide down: earlier compression
|
||||
if (sh_offset >= xct_off_hi) { // easy: so_slide down
|
||||
if (sh_out->sh_addr) // change only if non-zero
|
||||
set_te64(&sh_out->sh_addr, so_slide + sh_addr);
|
||||
set_te64(&sh_out->sh_offset, so_slide + sh_offset);
|
||||
}
|
||||
else { // somewhere in compressed; try proportional (aligned)
|
||||
u64_t const slice = xct_off + (~0xFu & (unsigned)(
|
||||
(sh_offset - xct_off) *
|
||||
((sh_offset - xct_off) / (float)(xct_off_hi - xct_off))));
|
||||
set_te64(&sh_out->sh_addr, slice);
|
||||
set_te64(&sh_out->sh_offset, slice);
|
||||
}
|
||||
u64_t const max_sz = total_out - get_te64(&sh_out->sh_offset);
|
||||
if (sh_size > max_sz) { // avoid complaint "extends beyond EOF"
|
||||
set_te64(&sh_out->sh_size, max_sz);
|
||||
}
|
||||
// BEWARE: .p_vaddr does not slide
|
||||
}
|
||||
if (j == e_shstrndx) { // changes Elf64_Ehdr itself
|
||||
set_te16(&eho->e_shstrndx, sh_out - (Elf64_Shdr *)mb_shdro.getVoidPtr());
|
||||
set_te16(&eho->e_shstrndx, sh_out -
|
||||
(Elf64_Shdr *)mb_shdro.getVoidPtr());
|
||||
}
|
||||
if (j == e_shstrndx
|
||||
|| sec_arm_attr == sh_in
|
||||
|
||||
Loading…
Reference in New Issue
Block a user