Adapt to 4 PT_LOAD in binutils-2.31 and gcc-8.2.1 (Fedora 29)

0:        PF_R: .gnu.hash .dynsym .dynstr
1: PF_X | PF_R: .plt .plt.sec .text
2:        PF_R: .rodata .hash
3: PF_W | PF_R: .data.rel.ro .dynamic .got .got.plt .data .bss
	modified:   p_lx_elf.cpp

https://github.com/upx/upx/issues/212 (partial, Fedora 29)
This commit is contained in:
John Reiser
2018-08-11 17:40:05 -07:00
parent 95fcbcb4f2
commit 90eb68b3b9
+83 -52
View File
@@ -410,9 +410,9 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
unsigned word = (Elf32_Ehdr::EM_ARM==e_machine) + load_va + sz_pack2; // Thumb mode unsigned word = (Elf32_Ehdr::EM_ARM==e_machine) + load_va + sz_pack2; // Thumb mode
set_te32(&file_image[user_init_off], word); // set the hook set_te32(&file_image[user_init_off], word); // set the hook
unsigned off = fo->st_size();
Elf32_Phdr *phdr = (Elf32_Phdr *)lowmem.subref( Elf32_Phdr *phdr = (Elf32_Phdr *)lowmem.subref(
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf32_Phdr)); "bad e_phoff", e_phoff, e_phnum * sizeof(Elf32_Phdr));
unsigned off = fo->st_size();
so_slide = 0; so_slide = 0;
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) { for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
unsigned const len = get_te32(&phdr->p_filesz); unsigned const len = get_te32(&phdr->p_filesz);
@@ -422,14 +422,14 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
if (Elf32_Phdr::PT_INTERP==type) { if (Elf32_Phdr::PT_INTERP==type) {
// Rotate to highest position, so it can be lopped // Rotate to highest position, so it can be lopped
// by decrementing e_phnum. // by decrementing e_phnum.
memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); // extract
memmove(phdr, 1+phdr, j * sizeof(*phdr)); // overlapping memmove(phdr, 1+phdr, (e_phnum - (1+ j))*sizeof(*phdr)); // overlapping
memcpy(&phdr[j], (unsigned char *)ibuf, sizeof(*phdr)); memcpy(&phdr[-1+ e_phnum], (unsigned char *)ibuf, sizeof(*phdr)); // to top
--phdr; --phdr;
set_te16(&ehdri.e_phnum, --e_phnum); set_te16(&ehdri.e_phnum, --e_phnum);
continue; continue;
} }
if (PT_LOAD32==type) { if (PT_LOAD32 == type) {
if (xct_off < ioff) { // Slide up non-first PT_LOAD. if (xct_off < ioff) { // Slide up non-first PT_LOAD.
if ((1u<<12) < align) { if ((1u<<12) < align) {
align = 1u<<12; align = 1u<<12;
@@ -441,9 +441,9 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
so_slide = off - ioff; so_slide = off - ioff;
set_te32(&phdr->p_offset, so_slide + ioff); set_te32(&phdr->p_offset, so_slide + ioff);
} }
else { // Change length of first PT_LOAD. else if ((ioff - xct_off) < len) { // Change length of compressed PT_LOAD.
set_te32(&phdr->p_filesz, sz_pack2 + lsize); set_te32(&phdr->p_filesz, sz_pack2 + lsize - ioff);
set_te32(&phdr->p_memsz, sz_pack2 + lsize); set_te32(&phdr->p_memsz, sz_pack2 + lsize - ioff);
} }
continue; // all done with this PT_LOAD continue; // all done with this PT_LOAD
} }
@@ -460,7 +460,7 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
if (Elf32_Shdr::SHT_DYNAMIC == get_te32(&shdr->sh_type)) { if (Elf32_Shdr::SHT_DYNAMIC == get_te32(&shdr->sh_type)) {
unsigned offset = get_te32(&shdr->sh_offset); unsigned offset = get_te32(&shdr->sh_offset);
set_te32(&shdr->sh_offset, so_slide + offset ); set_te32(&shdr->sh_offset, so_slide + offset );
fo->seek(j * sizeof(Elf32_Shdr) + xct_off - asl_delta, SEEK_SET); fo->seek((j * sizeof(Elf32_Shdr)) + xct_off - asl_delta, SEEK_SET);
fo->rewrite(shdr, sizeof(*shdr)); fo->rewrite(shdr, sizeof(*shdr));
fo->seek(0, SEEK_END); fo->seek(0, SEEK_END);
} }
@@ -546,9 +546,9 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
if (Elf64_Phdr::PT_INTERP==type) { if (Elf64_Phdr::PT_INTERP==type) {
// Rotate to highest position, so it can be lopped // Rotate to highest position, so it can be lopped
// by decrementing e_phnum. // by decrementing e_phnum.
memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); // extract
memmove(phdr, 1+phdr, j * sizeof(*phdr)); // overlapping memmove(phdr, 1+phdr, (e_phnum - (1+ j))*sizeof(*phdr)); // overlapping
memcpy(&phdr[j], (unsigned char *)ibuf, sizeof(*phdr)); memcpy(&phdr[-1+ e_phnum], (unsigned char *)ibuf, sizeof(*phdr)); // to top
--phdr; --phdr;
set_te16(&ehdri.e_phnum, --e_phnum); set_te16(&ehdri.e_phnum, --e_phnum);
continue; continue;
@@ -570,9 +570,9 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
so_slide = off - ioff; so_slide = off - ioff;
set_te64(&phdr->p_offset, so_slide + ioff); set_te64(&phdr->p_offset, so_slide + ioff);
} }
else { // Change length of first PT_LOAD. else if ((ioff - xct_off) < len) { // Change length of compressed PT_LOAD.
set_te64(&phdr->p_filesz, sz_pack2 + lsize); set_te64(&phdr->p_filesz, sz_pack2 + lsize - ioff);
set_te64(&phdr->p_memsz, sz_pack2 + lsize); set_te64(&phdr->p_memsz, sz_pack2 + lsize - ioff);
} }
continue; // all done with this PT_LOAD continue; // all done with this PT_LOAD
} }
@@ -3409,40 +3409,55 @@ int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
uip->ui_total_passes -= !!is_shlib; // not .data of shlib uip->ui_total_passes -= !!is_shlib; // not .data of shlib
// compress extents // compress extents
unsigned hdr_u_len = sizeof(Elf32_Ehdr) + sz_phdrs; unsigned hdr_u_len = (is_shlib ? xct_off : (sizeof(Elf32_Ehdr) + sz_phdrs));
unsigned total_in = xct_off - (is_shlib ? hdr_u_len : 0); unsigned total_in = (is_shlib ? 0 : xct_off);
unsigned total_out = xct_off; unsigned total_out = (is_shlib ? sz_elf_hdrs : xct_off);
uip->ui_pass = 0; uip->ui_pass = 0;
ft.addvalue = 0; ft.addvalue = 0;
unsigned nk_f = 0; unsigned xsz_f = 0;
for (k = 0; k < e_phnum; ++k)
if (PT_LOAD32==get_te32(&phdri[k].p_type)
&& Elf32_Phdr::PF_X & get_te32(&phdri[k].p_flags)) {
unsigned xsz = get_te32(&phdri[k].p_filesz);
if (xsz_f < xsz) {
xsz_f = xsz;
nk_f = k;
}
}
int nx = 0; int nx = 0;
for (k = 0; k < e_phnum; ++k) if (PT_LOAD32==get_te32(&phdri[k].p_type)) { for (k = 0; k < e_phnum; ++k)
if (PT_LOAD32==get_te32(&phdri[k].p_type)) {
if (ft.id < 0x40) { if (ft.id < 0x40) {
// FIXME: ?? ft.addvalue = phdri[k].p_vaddr; // FIXME: ?? ft.addvalue = phdri[k].p_vaddr;
} }
x.offset = get_te32(&phdri[k].p_offset); x.offset = get_te32(&phdri[k].p_offset);
x.size = get_te32(&phdri[k].p_filesz); x.size = get_te32(&phdri[k].p_filesz);
if (0 == nx) { // 1st PT_LOAD32 must cover Ehdr at 0==p_offset if (!is_shlib || hdr_u_len < x.size) {
unsigned const delta = !is_shlib if (0 == nx) { // 1st PT_LOAD32 must cover Ehdr at 0==p_offset
? (sizeof(Elf32_Ehdr) + sz_phdrs) // main executable unsigned const delta = hdr_u_len;
: xct_off; // shared library if (ft.id < 0x40) {
if (ft.id < 0x40) { // FIXME: ?? ft.addvalue += asl_delta;
// FIXME: ?? ft.addvalue += asl_delta; }
x.offset += delta;
x.size -= delta;
}
// compressWithFilters() always assumes a "loader", so would
// throw NotCompressible for small .data Extents, which PowerPC
// sometimes marks as PF_X anyway. So filter only first segment.
if (k == nk_f || !is_shlib) {
packExtent(x, total_in, total_out,
(k==nk_f ? &ft : 0 ), fo, hdr_u_len);
}
else {
total_in += x.size;
} }
x.offset += delta;
x.size -= delta;
} }
// compressWithFilters() always assumes a "loader", so would else {
// throw NotCompressible for small .data Extents, which PowerPC total_in += x.size;
// sometimes marks as PF_X anyway. So filter only first segment. }
if (0==nx || !is_shlib)
packExtent(x, total_in, total_out,
((0==nx && (Elf32_Phdr::PF_X & get_te32(&phdri[k].p_flags)))
? &ft : 0 ), fo, hdr_u_len);
else
total_in += x.size;
hdr_u_len = 0; hdr_u_len = 0;
++nx; ++nx;
} }
@@ -3526,6 +3541,16 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
uip->ui_pass = 0; uip->ui_pass = 0;
ft.addvalue = 0; ft.addvalue = 0;
unsigned nk_f = 0; upx_uint64_t xsz_f = 0;
for (k = 0; k < e_phnum; ++k)
if (PT_LOAD64==get_te32(&phdri[k].p_type)
&& Elf64_Phdr::PF_X & get_te64(&phdri[k].p_flags)) {
upx_uint64_t xsz = get_te64(&phdri[k].p_filesz);
if (xsz_f < xsz) {
xsz_f = xsz;
nk_f = k;
}
}
int nx = 0; int nx = 0;
for (k = 0; k < e_phnum; ++k) for (k = 0; k < e_phnum; ++k)
if (PT_LOAD64==get_te32(&phdri[k].p_type)) { if (PT_LOAD64==get_te32(&phdri[k].p_type)) {
@@ -3534,30 +3559,36 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
} }
x.offset = get_te64(&phdri[k].p_offset); x.offset = get_te64(&phdri[k].p_offset);
x.size = get_te64(&phdri[k].p_filesz); x.size = get_te64(&phdri[k].p_filesz);
if (0 == nx) { // 1st PT_LOAD64 must cover Ehdr at 0==p_offset if (!is_shlib || hdr_u_len < x.size) {
unsigned const delta = hdr_u_len; if (0 == nx) { // 1st PT_LOAD64 must cover Ehdr at 0==p_offset
if (ft.id < 0x40) { unsigned const delta = hdr_u_len;
// FIXME: ?? ft.addvalue += asl_delta; if (ft.id < 0x40) {
// FIXME: ?? ft.addvalue += asl_delta;
}
x.offset += delta;
x.size -= delta;
}
// compressWithFilters() always assumes a "loader", so would
// throw NotCompressible for small .data Extents, which PowerPC
// sometimes marks as PF_X anyway. So filter only first segment.
if (k == nk_f || !is_shlib) {
packExtent(x, total_in, total_out,
(k==nk_f ? &ft : 0 ), fo, hdr_u_len);
}
else {
total_in += x.size;
} }
x.offset += delta;
x.size -= delta;
} }
// compressWithFilters() always assumes a "loader", so would else {
// throw NotCompressible for small .data Extents, which PowerPC total_in += x.size;
// sometimes marks as PF_X anyway. So filter only first segment. }
if (0==nx || !is_shlib)
packExtent(x, total_in, total_out,
((0==nx && (Elf64_Phdr::PF_X & get_te64(&phdri[k].p_flags)))
? &ft : 0 ), fo, hdr_u_len);
else
total_in += x.size;
hdr_u_len = 0; hdr_u_len = 0;
++nx; ++nx;
} }
sz_pack2a = fpad4(fo); // MATCH01 sz_pack2a = fpad4(fo); // MATCH01
// Accounting only; ::pack3 will do the compression and output // Accounting only; ::pack3 will do the compression and output
for (k = 0; k < e_phnum; ++k) { // for (k = 0; k < e_phnum; ++k) {
total_in += find_LOAD_gap(phdri, k, e_phnum); total_in += find_LOAD_gap(phdri, k, e_phnum);
} }