is_asl handles per-file opt->o_unix.android_shlib

Also slide_sh_offset() handles so_slide.
TODO: if asl_delta, then relocate sh_offset that is above xct_off.
PT_DYNAMIC.p_offset and {.dynamic}.sh_offset must match; etc.

	modified:   p_lx_elf.cpp
	modified:   p_lx_elf.h
	modified:   p_unix.cpp
This commit is contained in:
John Reiser 2024-12-17 17:17:24 -08:00 committed by Markus F.X.J. Oberhumer
parent d00ba4b465
commit 7d907d9d65
3 changed files with 57 additions and 33 deletions

View File

@ -397,7 +397,7 @@ off_t PackLinuxElf::pack3(OutputFile *fo, Filter &ft) // return length of output
}
set_te32(&disp, sz_elf_hdrs + usizeof(p_info) + usizeof(l_info) +
(!!xct_off & !!opt->o_unix.android_shlib)); // |1 iff android shlib
(!!xct_off & !!is_asl)); // |1 iff android shlib
fo->write(&disp, sizeof(disp)); // offset(b_info)
// FIXME: If is_shlib then that is useful only for the is_asl bit.
// Better info is the word below with (overlay_offset - sizeof(linfo)).
@ -419,7 +419,7 @@ off_t PackLinuxElf::pack3(OutputFile *fo, Filter &ft) // return length of output
fo->write(&disp, sizeof(disp)); // offset(lowest_executable_instr)
len += sizeof(disp);
if (opt->o_unix.android_shlib) {
if (is_asl) {
xct_off += asl_delta; // the extra page
}
set_te32(&disp, overlay_offset - sizeof(linfo));
@ -479,6 +479,23 @@ PackLinuxElf64::elf_find_Phdr_for_va(upx_uint64_t addr, Elf64_Phdr const *phdr,
return nullptr;
}
unsigned
PackLinuxElf32::slide_sh_offset(Elf32_Shdr *shdr)
{
unsigned offset = get_te32(&shdr->sh_offset);
if (Elf32_Shdr::SHF_WRITE & get_te32(&shdr->sh_flags)
|| (offset && !get_te32(&shdr->sh_addr)))
{
unsigned newoff = so_slide + offset;
if ((unsigned)this->file_size < newoff) {
throwInternalError("bad slide %p %#x", shdr, (unsigned)so_slide);
}
set_te32(&shdr->sh_offset, newoff);
return newoff;
}
return offset;
}
void
PackLinuxElf32::asl_slide_Shdrs()
{
@ -486,7 +503,7 @@ PackLinuxElf32::asl_slide_Shdrs()
for (unsigned j = 0; j < e_shnum; ++shdr, ++j) {
unsigned sh_offset = get_te32(&shdr->sh_offset);
if (xct_off < sh_offset) {
set_te32(&shdr->sh_offset, so_slide + sh_offset);
slide_sh_offset(shdr);
}
}
}
@ -680,7 +697,7 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
// So don't do it unless appending plain text of shstrtab.
unsigned sh_off = get_te32(&shdr->sh_offset);
if (xct_off < sh_off) {
set_te32(&shdr->sh_offset, sh_off + so_slide);
slide_sh_offset(shdr);
}
}
}
@ -925,7 +942,7 @@ PackLinuxElf::addStubEntrySections(Filter const *, unsigned m_decompr)
}
addLoader("+40,ELFMAINZ", nullptr);
if (hasLoaderSection("ANDMAJNZ")) { // Android trouble with args to DT_INIT
if (opt->o_unix.android_shlib) {
if (is_asl) {
addLoader("ANDMAJNZ", nullptr); // constant PAGE_SIZE
}
else {
@ -1488,7 +1505,7 @@ PackLinuxElf32::buildLinuxLoader(
// End of daisy-chain fall-through.
len += snprintf(&sec[len], sizeof(sec) - len, ",%s",
(sec_arm_attr || is_asl || opt->o_unix.android_shlib)
(sec_arm_attr || is_asl)
? "HUMF_A,UMF_ANDROID"
: "HUMF_L,UMF_LINUX");
if (hasLoaderSection("STRCON")) {
@ -1535,7 +1552,7 @@ PackLinuxElf32::buildLinuxLoader(
// $ARCH-linux.elf-main2.c calls upx_mmap_and_fd, not direct memfd_create
len += snprintf(&sec[len], sizeof(sec) - len, ",%s",
(sec_arm_attr || is_asl || opt->o_unix.android_shlib)
(sec_arm_attr || is_asl)
? "HUMF_A,UMF_ANDROID"
: "HUMF_L,UMF_LINUX");
if (hasLoaderSection("SYSCALLS")) {
@ -1599,7 +1616,7 @@ PackLinuxElf32::buildLinuxLoader(
)
) { // shlib with ELF2 de-compressor
addLoader("ELFMAINX");
addLoader((sec_arm_attr || is_asl || opt->o_unix.android_shlib)
addLoader((sec_arm_attr || is_asl)
? "HUMF_A,UMF_ANDROID"
: "HUMF_L,UMF_LINUX");
addLoader("ELFMAINZ,FOLDEXEC,IDENTSTR");
@ -1615,7 +1632,7 @@ PackLinuxElf32::buildLinuxLoader(
// Only if $ARCH-linux.elf-entry.S calls upx_mmap_and_fd instead of memfd_create
if (this->e_machine != Elf32_Ehdr::EM_PPC
&& this->e_machine != Elf32_Ehdr::EM_MIPS)
addLoader((sec_arm_attr || is_asl || opt->o_unix.android_shlib)
addLoader((sec_arm_attr || is_asl)
? "HUMF_A,UMF_ANDROID"
: "HUMF_L,UMF_LINUX");
addLoader("ELFMAINZ,FOLDEXEC,IDENTSTR");
@ -2819,7 +2836,7 @@ bad:
unsigned const p_filesz = get_te32(&pload_x0->p_filesz);
if (!((user_init_va - xct_va) < p_filesz)) {
// Not in executable portion of first executable PT_LOAD.
if (0==user_init_va && opt->o_unix.android_shlib) {
if (0==user_init_va && is_asl) {
// Android allows (0 ==> skip) ?
upx_dt_init = 0; // force steal of 'extra' DT_NULL
// XXX: FIXME: depends on SHT_DYNAMIC coming later
@ -2964,7 +2981,7 @@ upx_uint64_t PackLinuxElf64::canPack_Shdr(Elf64_Phdr const *pload_x0)
unsigned const p_filesz = get_te64(&pload_x0->p_filesz);
if (!((user_init_va - xct_va) < p_filesz)) {
// Not in executable portion of first executable PT_LOAD.
if (0==user_init_va && opt->o_unix.android_shlib) {
if (0==user_init_va && is_asl) {
// Android allows (0 ==> skip) ?
upx_dt_init = 0; // force steal of 'extra' DT_NULL
// XXX: FIXME: depends on SHT_DYNAMIC coming later
@ -3210,6 +3227,13 @@ tribool PackLinuxElf32::canPack()
goto proceed; // calls C library init for main program
}
if (Elf32_Ehdr::EM_ARM==get_te16(&ehdri.e_machine)) {
sec_arm_attr = elf_find_section_type(Elf32_Shdr::SHT_ARM_ATTRIBUTES);
if (Elf32_Ehdr::ET_DYN == e_type) {
is_asl = (!!saved_opt_android_shlib) << 1; // bit 1; see is_shlib
}
}
// Heuristic HACK for shared libraries (compare Darwin (MacOS) Dylib.)
// If there is an existing DT_INIT, and if everything that the dynamic
// linker ld-linux needs to perform relocations before calling DT_INIT
@ -3239,8 +3263,7 @@ tribool PackLinuxElf32::canPack()
if (!(Elf32_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf32_Dyn::DT_FLAGS_1))) {
// 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
&& !is_asl // but not explicit
) {
opt->info_mode++;
info("note: use --android-shlib if appropriate");
@ -3531,8 +3554,7 @@ tribool PackLinuxElf64::canPack()
if (!(Elf64_Dyn::DF_1_PIE & elf_unsigned_dynamic(Elf64_Dyn::DT_FLAGS_1))) {
// 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
&& !is_asl // but not explicit
) {
opt->info_mode++;
info("note: use --android-shlib if appropriate");
@ -5480,13 +5502,9 @@ int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
{
Extent x;
unsigned k;
is_asl = (!!opt->o_unix.android_shlib) << 1; // bit 1; see is_shlib
unsigned const is_shlib = (0!=xct_off) | is_asl;
unsigned pre_xct_top = 0; // offset of end of PT_LOAD _before_ xct_off
if (Elf32_Ehdr::EM_ARM==get_te16(&ehdri.e_machine)) {
sec_arm_attr = elf_find_section_type(Elf32_Shdr::SHT_ARM_ATTRIBUTES);
}
// count passes, set ptload vars
uip->ui_total_passes = 0;
for (k = 0; k < e_phnum; ++k) {
@ -5759,7 +5777,7 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
{
Extent x;
unsigned k;
is_asl = (!!opt->o_unix.android_shlib) << 1; // bit 1; see is_shlib
is_asl = (!!saved_opt_android_shlib) << 1; // bit 1; see is_shlib
unsigned const is_shlib = (0!=xct_off) | is_asl;
unsigned pre_xct_top = 0; // offset of end of PT_LOAD _before_ xct_off
@ -6018,7 +6036,7 @@ unsigned PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
return 0;
}
unsigned penalty = total_out;
if (saved_opt_android_shlib) { // Forward select _Shdr
if (sec_arm_attr) { // Forward select _Shdr
// Keep _Shdr for rtld data (below xct_off).
// Discard _Shdr for compressed regions, except ".text" for gdb.
// Keep _Shdr for SHF_WRITE.
@ -6091,17 +6109,18 @@ unsigned PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
ask_for[sh_info] = j; // Enter my request, if any
}
if ( (sh_offset && sh_offset < xct_off)
|| (Elf32_Shdr::SHF_WRITE & sh_flags)
|| (j == e_shstrndx)
|| (sec_arm_attr == sh_in)
|| (want_types_mask & (1<<(0x1f & sh_type)))
|| (Elf32_Shdr::SHF_WRITE & sh_flags)
|| (sh_type < Elf32_Shdr::SHT_LOPROC
&& want_types_mask & (1<<(0x1f & sh_type)))
|| (Elf32_Shdr::SHT_ARM_ATTRIBUTES == sh_type)
) {
*sh_out = *sh_in; // *sh_in is a candidate for fowarding
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);
if (Elf32_Shdr::SHT_ARM_ATTRIBUTES != sh_type) {
slide_sh_offset(sh_out);
}
}
else { // somewhere in compressed; try proportional (aligned)
// But note that PROGBITS without SHF_ALLOC
@ -6121,7 +6140,7 @@ unsigned PackLinuxElf32::forward_Shdrs(OutputFile *fo, Elf32_Ehdr *const eho)
set_te16(&eho->e_shstrndx, sh_out -
(Elf32_Shdr *)mb_shdro.getVoidPtr());
}
if (sec_arm_attr == sh_in
if (Elf32_Shdr::SHT_ARM_ATTRIBUTES == sh_type
|| (SHT_NOTE == sh_type && xct_off < sh_offset)
) { // append a copy
set_te32(&sh_out->sh_offset, total_out);
@ -6247,12 +6266,12 @@ unsigned PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
return 0;
}
unsigned penalty = total_out;
if (saved_opt_android_shlib) { // Forward select _Shdr
if (sec_arm_attr) { // Forward select _Shdr
// Keep _Shdr for rtld data (below xct_off).
// Discard _Shdr for compressed regions, except ".text" for gdb.
// Keep _Shdr for SHF_WRITE.
// Discard _Shdr with (0==sh_addr), except _Shdr[0]
// Keep _Shdr with SHF_WRITE.
// Keep ARM_ATTRIBUTES
// Discard _Shdr with (0==sh_addr), except _Shdr[0]
unsigned const want_types_mask =
1u<<SHT_SYMTAB
| 1u<<SHT_RELA
@ -6318,6 +6337,7 @@ unsigned PackLinuxElf64::forward_Shdrs(OutputFile *fo, Elf64_Ehdr *const eho)
|| (j == e_shstrndx)
|| (sec_arm_attr == sh_in)
|| (want_types_mask & (1<<(0x1f & sh_type)))
|| (Elf32_Shdr::SHT_ARM_ATTRIBUTES == sh_type)
) {
*sh_out = *sh_in;
if (sh_offset > xct_off) { // may slide down: earlier compression

View File

@ -159,6 +159,7 @@ protected:
virtual void pack1(OutputFile *, Filter &) override; // generate executable header
virtual void asl_pack2_Shdrs(OutputFile *, unsigned pre_xct_top); // AndroidSharedLibrary processes Shdrs
virtual void asl_slide_Shdrs(); // by so_slide if above xct_off
virtual unsigned slide_sh_offset(Elf32_Shdr *shdr);
virtual int pack2(OutputFile *, Filter &) override; // append compressed data
virtual int pack2_shlib(OutputFile *fo, Filter &ft, unsigned pre_xct_top);
virtual off_t pack3(OutputFile *, Filter &) override; // append loader

View File

@ -56,9 +56,12 @@ PackUnix::PackUnix(InputFile *f) :
COMPILE_TIME_ASSERT(sizeof(l_info) == 12)
COMPILE_TIME_ASSERT(sizeof(p_info) == 12)
// Disable --android-shlib, file-by-file; undecided how to fix.
// opt->o_unix.android_shlib is global, but must be hint
// that applies only when an actual ET_DYN on EM_ARM or EM_ARM64.
// User might say "--android-shlib" but give mulitple files
// where some are ET_EXEC.
saved_opt_android_shlib = opt->o_unix.android_shlib;
opt->o_unix.android_shlib = 0;
opt->o_unix.android_shlib = 0; // Must apply selectively
}
PackUnix::~PackUnix()