From 95cedb6640245ac669cb234980ceaf59e15ed652 Mon Sep 17 00:00:00 2001 From: John Reiser Date: Fri, 2 Feb 2018 14:50:56 -0800 Subject: [PATCH] upgrade ::unpack for --android-shlib modified: p_elf_enum.h modified: p_lx_elf.cpp modified: p_lx_elf.h modified: stub/src/arm64-linux.shlib-init.S modified: stub/src/arm.v4t-linux.shlib-init.S --- src/p_elf_enum.h | 3 + src/p_lx_elf.cpp | 324 +++++++++++++++++++++++++++++++---------------- src/p_lx_elf.h | 2 + 3 files changed, 221 insertions(+), 108 deletions(-) diff --git a/src/p_elf_enum.h b/src/p_elf_enum.h index 2707b962..a47dc064 100644 --- a/src/p_elf_enum.h +++ b/src/p_elf_enum.h @@ -166,7 +166,10 @@ DT_JMPREL = 23, /* Address of PLT relocs */ DT_INIT_ARRAY = 25, /* Array with addresses of init fct */ DT_FINI_ARRAY = 26, /* Array with addresses of fini fct */ + DT_INIT_ARRAYSZ= 27, /* size in bytes */ + DT_FINI_ARRAYSZ= 28, /* size in bytes */ DT_PREINIT_ARRAY = 32, /* Array with addresses of preinit fct*/ + DT_PREINIT_ARRAYSZ= 33, /* size in bytes */ DT_CHECKSUM = 0x6ffffdf8, /* Only for prelink? */ DT_GNU_HASH = 0x6ffffef5, /* GNU-style hash table */ DT_VERSYM = 0x6ffffff0, /* version[] for each symbol */ diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index e03295bc..02c8edb9 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -3685,6 +3685,50 @@ void PackLinuxElf64::pack4(OutputFile *fo, Filter &ft) } } +void +PackLinuxElf32::unRel32( + unsigned dt_rel, + Elf32_Rel *rel0, + unsigned relsz, + MemBuffer &ptload1, + unsigned const load_off, + OutputFile *fo +) +{ + Elf32_Rel *rel = rel0; + for (int k = relsz / sizeof(Elf32_Rel); --k >= 0; ++rel) { + unsigned r_offset = get_te32(&rel->r_offset); + unsigned r_info = get_te32(&rel->r_info); + unsigned r_type = ELF32_R_TYPE(r_info); + if (xct_off <= r_offset) { + set_te32(&rel->r_offset, r_offset - asl_delta); + } + if (Elf32_Ehdr::EM_ARM == e_machine) { + if (R_ARM_RELATIVE == r_type) { + unsigned d = r_offset - load_off - asl_delta; + unsigned w = get_te32(&ptload1[d]); + if (xct_off <= w) { + set_te32(&ptload1[d], w - asl_delta); + } + } + if (R_ARM_JUMP_SLOT == r_type) { + ++n_jmp_slot; + // .rel.plt contains offset of the "first time" target + unsigned d = r_offset - load_off - asl_delta; + if (plt_off > d) { + plt_off = d; + } + unsigned w = get_te32(&ptload1[d]); + if (xct_off <= w) { + set_te32(&ptload1[d], w - asl_delta); + } + } + } + } + fo->seek(dt_rel, SEEK_SET); + fo->rewrite(rel0, relsz); +} + void PackLinuxElf64::unRela64( upx_uint64_t dt_rela, @@ -3737,6 +3781,7 @@ void PackLinuxElf64::unpack(OutputFile *fo) upx_uint64_t old_data_off = 0; upx_uint64_t old_data_len = 0; upx_uint64_t old_dtinit = 0; + unsigned is_asl = 0; // is Android Shared Library unsigned szb_info = sizeof(b_info); { @@ -3750,6 +3795,9 @@ void PackLinuxElf64::unpack(OutputFile *fo) fi->seek(overlay_offset - sizeof(l_info), SEEK_SET); fi->readx(&linfo, sizeof(linfo)); lsize = get_te16(&linfo.l_lsize); + if (UPX_MAGIC_LE32 != get_le32(&linfo.l_magic)) { + throwCantUnpack("l_info corrupted"); + } p_info hbuf; fi->readx(&hbuf, sizeof(hbuf)); unsigned orig_file_size = get_te32(&hbuf.p_filesize); blocksize = get_te32(&hbuf.p_blocksize); @@ -3821,6 +3869,21 @@ void PackLinuxElf64::unpack(OutputFile *fo) if (e_shoff == xct_off2) { xct_off = e_shoff; } + // un-Relocate dynsym (DT_SYMTAB) which is below xct_off + upx_uint64_t const off_dynsym = get_te64(&sec_dynsym->sh_offset); + upx_uint64_t const sz_dynsym = get_te64(&sec_dynsym->sh_size); + Elf64_Sym *const sym0 = (Elf64_Sym *)ibuf.subref( + "bad dynsym", off_dynsym, sz_dynsym); + Elf64_Sym *sym = sym0; + for (int j = sz_dynsym / sizeof(Elf64_Sym); --j>=0; ++sym) { + 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 + && xct_off <= symval) { + set_te64(&sym->st_value, symval - asl_delta); + } + } } if (fo) { fo->write(ibuf + ph.u_len, xct_off - ph.u_len); @@ -3890,6 +3953,7 @@ void PackLinuxElf64::unpack(OutputFile *fo) unsigned d_info[6]; fi->readx(d_info, sizeof(d_info)); if (0==old_dtinit) { old_dtinit = d_info[2 + (0==d_info[0])]; + is_asl = 1u& d_info[1]; } fi->seek(lsize - sizeof(d_info), SEEK_CUR); } @@ -3929,9 +3993,11 @@ void PackLinuxElf64::unpack(OutputFile *fo) throwCompressedDataViolation(); } - if (is_shlib) { // the non-first PT_LOAD + if (is_shlib) { + // DT_INIT must be restored. + // If android_shlib, then the asl_delta relocations must be un-done. int n_ptload = 0; - unsigned load_off = 0; + upx_uint64_t load_off = 0; phdr = (Elf64_Phdr *)&u[sizeof(*ehdr)]; for (unsigned j= 0; j < u_phnum; ++j, ++phdr) { if (PT_LOAD64==get_te32(&phdr->p_type) && 0!=n_ptload++) { @@ -3941,76 +4007,61 @@ void PackLinuxElf64::unpack(OutputFile *fo) fi->readx(ibuf, old_data_len); total_in += old_data_len; total_out += old_data_len; + + Elf64_Phdr *dynhdr = (Elf64_Phdr *)&u[sizeof(*ehdr)]; + for (unsigned j3= 0; j3 < u_phnum; ++j3, ++dynhdr) + if (Elf64_Phdr::PT_DYNAMIC==get_te32(&dynhdr->p_type)) { + upx_uint64_t dt_pltrelsz(0), dt_jmprel(0); + upx_uint64_t dt_relasz(0), dt_rela(0); + upx_uint64_t const dyn_off = get_te64(&dynhdr->p_offset); + upx_uint64_t const dyn_len = get_te64(&dynhdr->p_filesz); + Elf64_Dyn *dyn = (Elf64_Dyn *)((unsigned char *)ibuf + + (dyn_off - load_off)); + for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { + upx_uint64_t const tag = get_te64(&dyn->d_tag); + upx_uint64_t val = get_te64(&dyn->d_val); + if (Elf64_Dyn::DT_INIT == tag) { + set_te64(&dyn->d_val, old_dtinit); + } + if (is_asl) switch (tag) { + case Elf64_Dyn::DT_RELASZ: { dt_relasz = val; } break; + case Elf64_Dyn::DT_RELA: { dt_rela = val; } break; + case Elf64_Dyn::DT_PLTRELSZ: { dt_pltrelsz = val; } break; + case Elf64_Dyn::DT_JMPREL: { dt_jmprel = val; } break; + + case Elf64_Dyn::DT_PLTGOT: + case Elf64_Dyn::DT_PREINIT_ARRAY: + case Elf64_Dyn::DT_INIT_ARRAY: + case Elf64_Dyn::DT_FINI_ARRAY: + case Elf64_Dyn::DT_FINI: { + set_te64(&dyn->d_val, val - asl_delta); + }; break; + } // end switch() + // Modified DT_*.d_val are re-written later from ibuf[] + } + if (is_asl) { + lowmem.alloc(xct_off); + fi->seek(0, SEEK_SET); + fi->read(lowmem, xct_off); // contains relocation tables + if (dt_relasz && dt_rela) { + Elf64_Rela *const rela0 = (Elf64_Rela *)lowmem.subref( + "bad Rela offset", dt_rela, dt_relasz); + unRela64(dt_rela, rela0, dt_relasz, ibuf, load_va, fo); + } + if (dt_pltrelsz && dt_jmprel) { // FIXME: overlap w/ DT_REL ? + Elf64_Rela *const jmp0 = (Elf64_Rela *)lowmem.subref( + "bad Jmprel offset", dt_jmprel, dt_pltrelsz); + unRela64(dt_jmprel, jmp0, dt_pltrelsz, ibuf, load_va, fo); + } + // Modified relocation tables are re-written by unRela64 + } + } if (fo) { fo->seek(get_te64(&phdr->p_offset), SEEK_SET); fo->rewrite(ibuf, old_data_len); } } } - // Restore DT_INIT.d_val - phdr = (Elf64_Phdr *)&u[sizeof(*ehdr)]; - if (fo) - for (unsigned j= 0; j < u_phnum; ++j, ++phdr) { - if (Elf64_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { - upx_uint64_t dt_pltrelsz(0), dt_jmprel(0); - upx_uint64_t dt_relasz(0), dt_rela(0); - unsigned const dyn_off = get_te64(&phdr->p_offset); - unsigned const dyn_len = get_te64(&phdr->p_filesz); - Elf64_Dyn *dyn = (Elf64_Dyn *)((unsigned char *)ibuf + - (dyn_off - load_off)); - for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { - upx_uint64_t const tag = get_te64(&dyn->d_tag); - upx_uint64_t val = get_te64(&dyn->d_val); - switch (tag) { - case Elf64_Dyn::DT_INIT: { - fo->seek(sizeof(upx_uint64_t) + j2 + dyn_off, SEEK_SET); - fo->rewrite(&old_dtinit, sizeof(old_dtinit)); - } break; - case Elf64_Dyn::DT_PREINIT_ARRAY: - case Elf64_Dyn::DT_INIT_ARRAY: - case Elf64_Dyn::DT_FINI_ARRAY: - case Elf64_Dyn::DT_FINI: - case Elf64_Dyn::DT_PLTGOT: { - fo->seek(sizeof(upx_uint64_t) + j2 + dyn_off, SEEK_SET); - val -= asl_delta; - fo->rewrite(&val, sizeof(val)); - } break; - case Elf64_Dyn::DT_PLTRELSZ: { // Size in bytes of PLT relocs - dt_pltrelsz = val; (void)dt_pltrelsz; - } break; - case Elf64_Dyn::DT_JMPREL: { // Address of PLT relocs - dt_jmprel = val; (void)dt_jmprel; - } break; - case Elf64_Dyn::DT_RELASZ: { // Total size of Rela relocs - dt_relasz = val; - } break; - case Elf64_Dyn::DT_RELA: { // Address of Rela relocs - dt_rela = val; - } break; - } // end switch() - } - - lowmem.alloc(xct_off); - fi->seek(0, SEEK_SET); - fi->read(lowmem, xct_off); // contains relocation tables - if (dt_relasz) { - Elf64_Rela *const rela0 = (Elf64_Rela *)lowmem.subref( - "bad Rela offset", dt_rela, dt_relasz); - unRela64(dt_rela, rela0, dt_relasz, ibuf, load_va, fo); - } - if (dt_pltrelsz) { - Elf64_Rela *const jmp0 = (Elf64_Rela *)lowmem.subref( - "bad Jmprel offset", dt_jmprel, dt_pltrelsz); - plt_off = ~0ull; n_jmp_slot = 0; - unRela64(dt_jmprel, jmp0, dt_pltrelsz, ibuf, load_va, fo); - if (~0ull != plt_off) { - fo->seek(plt_off + load_off, SEEK_SET); - fo->rewrite(&ibuf[plt_off], n_jmp_slot * sizeof(void *)); - } - } - } - } - if (fo) fo->seek(0, SEEK_END); } // update header with totals @@ -4453,6 +4504,7 @@ void PackLinuxElf32::unpack(OutputFile *fo) unsigned old_data_off = 0; unsigned old_data_len = 0; unsigned old_dtinit = 0; + unsigned is_asl = 0; // is Android Shared Library unsigned szb_info = sizeof(b_info); { @@ -4468,6 +4520,9 @@ void PackLinuxElf32::unpack(OutputFile *fo) fi->seek(overlay_offset - sizeof(l_info), SEEK_SET); fi->readx(&linfo, sizeof(linfo)); lsize = get_te16(&linfo.l_lsize); + if (UPX_MAGIC_LE32 != get_le32(&linfo.l_magic)) { + throwCantUnpack("l_info corrupted"); + } p_info hbuf; fi->readx(&hbuf, sizeof(hbuf)); unsigned orig_file_size = get_te32(&hbuf.p_filesize); blocksize = get_te32(&hbuf.p_blocksize); @@ -4475,29 +4530,24 @@ void PackLinuxElf32::unpack(OutputFile *fo) || !mem_size_valid(1, blocksize, OVERHEAD)) throwCantUnpack("p_info corrupted"); -#define MAX_ELF_HDR 512 - union { - unsigned char buf[MAX_ELF_HDR]; - struct { Elf32_Ehdr ehdr; Elf32_Phdr phdr; } e; - } u; - COMPILE_TIME_ASSERT(sizeof(u) == MAX_ELF_HDR) - Elf32_Ehdr *const ehdr = (Elf32_Ehdr *) u.buf; - Elf32_Phdr const *phdr = 0; - ibuf.alloc(blocksize + OVERHEAD); b_info bhdr; memset(&bhdr, 0, sizeof(bhdr)); fi->readx(&bhdr, szb_info); ph.u_len = get_te32(&bhdr.sz_unc); ph.c_len = get_te32(&bhdr.sz_cpr); if (ph.c_len > (unsigned)file_size || ph.c_len == 0 || ph.u_len == 0 - || ph.u_len > sizeof(u)) + || ph.u_len > orig_file_size) throwCantUnpack("b_info corrupted"); ph.filter_cto = bhdr.b_cto8; - // Peek at resulting Ehdr and Phdrs for use in controlling unpacking. - // Uncompress an extra time, and don't verify or update checksums. - if (ibuf.getSize() < ph.c_len || sizeof(u) < ph.u_len) + MemBuffer u(ph.u_len); + Elf32_Ehdr *const ehdr = (Elf32_Ehdr *)&u[0]; + Elf32_Phdr const *phdr = 0; + + // Uncompress Ehdr and Phdrs. + if (ibuf.getSize() < ph.c_len) { throwCompressedDataViolation(); + } fi->readx(ibuf, ph.c_len); decompress(ibuf, (upx_byte *)ehdr, false); if (ehdr->e_type !=ehdri.e_type @@ -4506,8 +4556,9 @@ void PackLinuxElf32::unpack(OutputFile *fo) || ehdr->e_flags !=ehdri.e_flags || ehdr->e_ehsize !=ehdri.e_ehsize // check EI_MAG[0-3], EI_CLASS, EI_DATA, EI_VERSION - || memcmp(ehdr->e_ident, ehdri.e_ident, Elf32_Ehdr::EI_OSABI)) + || memcmp(ehdr->e_ident, ehdri.e_ident, Elf32_Ehdr::EI_OSABI)) { throwCantUnpack("ElfXX_Ehdr corrupted"); + } fi->seek(- (off_t) (szb_info + ph.c_len), SEEK_CUR); unsigned const u_phnum = get_te16(&ehdr->e_phnum); @@ -4515,9 +4566,11 @@ void PackLinuxElf32::unpack(OutputFile *fo) unsigned total_out = 0; unsigned c_adler = upx_adler32(NULL, 0); unsigned u_adler = upx_adler32(NULL, 0); +#define MAX_ELF_HDR 512 if ((MAX_ELF_HDR - sizeof(Elf32_Ehdr))/sizeof(Elf32_Phdr) < u_phnum) { throwCantUnpack("bad compressed e_phnum"); } +#undef MAX_ELF_HDR // Packed ET_EXE has no PT_DYNAMIC. // Packed ET_DYN has original PT_DYNAMIC for info needed by rtld. @@ -4533,8 +4586,31 @@ void PackLinuxElf32::unpack(OutputFile *fo) fi->seek(0, SEEK_SET); fi->readx(ibuf, overlay_offset + sizeof(hbuf) + szb_info + ph.c_len); overlay_offset -= sizeof(linfo); + xct_off = overlay_offset; + e_shoff = get_te32(&ehdri.e_shoff); + if (e_shoff && shdri) { // --android-shlib + unsigned xct_off2 = get_te32(&shdri->sh_offset); + if (e_shoff == xct_off2) { + xct_off = e_shoff; + } + // un-Relocate dynsym (DT_SYMTAB) which is below xct_off + unsigned const off_dynsym = get_te32(&sec_dynsym->sh_offset); + unsigned const sz_dynsym = get_te32(&sec_dynsym->sh_size); + Elf32_Sym *const sym0 = (Elf32_Sym *)ibuf.subref( + "bad dynsym", off_dynsym, sz_dynsym); + Elf32_Sym *sym = sym0; + for (int j = sz_dynsym / sizeof(Elf32_Sym); --j>=0; ++sym) { + unsigned symval = get_te32(&sym->st_value); + unsigned symsec = get_te16(&sym->st_shndx); + if (Elf32_Sym::SHN_UNDEF != symsec + && Elf32_Sym::SHN_ABS != symsec + && xct_off <= symval) { + set_te32(&sym->st_value, symval - asl_delta); + } + } + } if (fo) { - fo->write(ibuf + ph.u_len, overlay_offset - ph.u_len); + fo->write(ibuf + ph.u_len, xct_off - ph.u_len); } // Search the Phdrs of compressed int n_ptload = 0; @@ -4547,15 +4623,15 @@ void PackLinuxElf32::unpack(OutputFile *fo) } } - total_in = overlay_offset; - total_out = overlay_offset; + total_in = xct_off; + total_out = xct_off; ph.u_len = 0; // Decompress and unfilter the tail of first PT_LOAD. phdr = (Elf32_Phdr *) (void *) (1+ ehdr); for (unsigned j=0; j < u_phnum; ++phdr, ++j) { if (PT_LOAD32==get_te32(&phdr->p_type)) { - ph.u_len = get_te32(&phdr->p_filesz) - overlay_offset; + ph.u_len = get_te32(&phdr->p_filesz) - xct_off; break; } } @@ -4601,12 +4677,13 @@ void PackLinuxElf32::unpack(OutputFile *fo) unsigned d_info[4]; fi->readx(d_info, sizeof(d_info)); if (0==old_dtinit) { old_dtinit = d_info[2 + (0==d_info[0])]; + is_asl = 1u& d_info[1]; } fi->seek(lsize - sizeof(d_info), SEEK_CUR); } // The gaps between PT_LOAD and after last PT_LOAD - phdr = (Elf32_Phdr *) (u.buf + sizeof(*ehdr)); + phdr = (Elf32_Phdr *)&u[sizeof(*ehdr)]; unsigned hi_offset(0); for (unsigned j = 0; j < u_phnum; ++j) { if (PT_LOAD32==phdr[j].p_type @@ -4640,43 +4717,75 @@ void PackLinuxElf32::unpack(OutputFile *fo) throwCompressedDataViolation(); } - if (is_shlib) { // the non-first PT_LOAD + if (is_shlib) { + // DT_INIT must be restored. + // If android_shlib, then the asl_delta relocations must be un-done. int n_ptload = 0; unsigned load_off = 0; - phdr = (Elf32_Phdr *) (u.buf + sizeof(*ehdr)); + phdr = (Elf32_Phdr *)&u[sizeof(*ehdr)]; for (unsigned j= 0; j < u_phnum; ++j, ++phdr) { if (PT_LOAD32==get_te32(&phdr->p_type) && 0!=n_ptload++) { load_off = get_te32(&phdr->p_offset); + load_va = get_te32(&phdr->p_vaddr); fi->seek(old_data_off, SEEK_SET); fi->readx(ibuf, old_data_len); total_in += old_data_len; total_out += old_data_len; + + Elf32_Phdr *dynhdr = (Elf32_Phdr *)&u[sizeof(*ehdr)]; + for (unsigned j3= 0; j3 < u_phnum; ++j3, ++dynhdr) + if (Elf32_Phdr::PT_DYNAMIC==get_te32(&dynhdr->p_type)) { + unsigned dt_pltrelsz(0), dt_jmprel(0); + unsigned dt_relsz(0), dt_rel(0); + unsigned const dyn_off = get_te32(&dynhdr->p_offset); + unsigned const dyn_len = get_te32(&dynhdr->p_filesz); + Elf32_Dyn *dyn = (Elf32_Dyn *)((unsigned char *)ibuf + + (dyn_off - load_off)); + for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { + unsigned const tag = get_te32(&dyn->d_tag); + unsigned val = get_te32(&dyn->d_val); + if (Elf32_Dyn::DT_INIT == tag) { + set_te32(&dyn->d_val, old_dtinit); + } + if (is_asl) switch (tag) { + case Elf32_Dyn::DT_RELSZ: { dt_relsz = val; } break; + case Elf32_Dyn::DT_REL: { dt_rel = val; } break; + case Elf32_Dyn::DT_PLTRELSZ: { dt_pltrelsz = val; } break; + case Elf32_Dyn::DT_JMPREL: { dt_jmprel = val; } break; + + case Elf32_Dyn::DT_PLTGOT: + case Elf32_Dyn::DT_PREINIT_ARRAY: + case Elf32_Dyn::DT_INIT_ARRAY: + case Elf32_Dyn::DT_FINI_ARRAY: + case Elf32_Dyn::DT_FINI: { + set_te32(&dyn->d_val, val - asl_delta); + }; break; + } // end switch() + // Modified DT_*.d_val are re-written later from ibuf[] + } + if (is_asl) { + lowmem.alloc(xct_off); + fi->seek(0, SEEK_SET); + fi->read(lowmem, xct_off); // contains relocation tables + if (dt_relsz && dt_rel) { + Elf32_Rel *const rel0 = (Elf32_Rel *)lowmem.subref( + "bad Rel offset", dt_rel, dt_relsz); + unRel32(dt_rel, rel0, dt_relsz, ibuf, load_va, fo); + } + if (dt_pltrelsz && dt_jmprel) { // FIXME: overlap w/ DT_REL ? + Elf32_Rel *const jmp0 = (Elf32_Rel *)lowmem.subref( + "bad Jmprel offset", dt_jmprel, dt_pltrelsz); + unRel32(dt_jmprel, jmp0, dt_pltrelsz, ibuf, load_va, fo); + } + // Modified relocation tables are re-written by unRel32 + } + } if (fo) { fo->seek(get_te32(&phdr->p_offset), SEEK_SET); fo->rewrite(ibuf, old_data_len); } } } - // Restore DT_INIT.d_val - phdr = (Elf32_Phdr *) (u.buf + sizeof(*ehdr)); - for (unsigned j= 0; j < u_phnum; ++j, ++phdr) { - if (Elf32_Phdr::PT_DYNAMIC==get_te32(&phdr->p_type)) { - unsigned const dyn_off = get_te32(&phdr->p_offset); - unsigned const dyn_len = get_te32(&phdr->p_filesz); - Elf32_Dyn *dyn = (Elf32_Dyn *)((unsigned char *)ibuf + - (dyn_off - load_off)); - for (unsigned j2= 0; j2 < dyn_len; ++dyn, j2 += sizeof(*dyn)) { - if (Elf32_Dyn::DT_INIT==get_te32(&dyn->d_tag)) { - if (fo) { - fo->seek(sizeof(unsigned) + j2 + dyn_off, SEEK_SET); - fo->rewrite(&old_dtinit, sizeof(old_dtinit)); - fo->seek(0, SEEK_END); - } - break; - } - } - } - } } // update header with totals @@ -4690,7 +4799,6 @@ void PackLinuxElf32::unpack(OutputFile *fo) // finally test the checksums if (ph.c_adler != c_adler || ph.u_adler != u_adler) throwChecksumError(); -#undef MAX_ELF_HDR } void PackLinuxElf::unpack(OutputFile * /*fo*/) diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index 298791a9..4f08c030 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -123,6 +123,8 @@ protected: virtual off_t pack3(OutputFile *, Filter &); // append loader virtual void pack4(OutputFile *, Filter &); // append pack header virtual void unpack(OutputFile *fo); + virtual void unRel32(unsigned dt_rel, Elf32_Rel *rel0, unsigned relsz, + MemBuffer &membuf, unsigned const load_off, OutputFile *fo); virtual void generateElfHdr( OutputFile *,