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
set_te32(&file_image[user_init_off], word); // set the hook
unsigned off = fo->st_size();
Elf32_Phdr *phdr = (Elf32_Phdr *)lowmem.subref(
"bad e_phoff", e_phoff, e_phnum * sizeof(Elf32_Phdr));
unsigned off = fo->st_size();
so_slide = 0;
for (unsigned j = 0; j < e_phnum; ++j, ++phdr) {
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) {
// Rotate to highest position, so it can be lopped
// by decrementing e_phnum.
memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr));
memmove(phdr, 1+phdr, j * sizeof(*phdr)); // overlapping
memcpy(&phdr[j], (unsigned char *)ibuf, sizeof(*phdr));
memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); // extract
memmove(phdr, 1+phdr, (e_phnum - (1+ j))*sizeof(*phdr)); // overlapping
memcpy(&phdr[-1+ e_phnum], (unsigned char *)ibuf, sizeof(*phdr)); // to top
--phdr;
set_te16(&ehdri.e_phnum, --e_phnum);
continue;
}
if (PT_LOAD32==type) {
if (PT_LOAD32 == type) {
if (xct_off < ioff) { // Slide up non-first PT_LOAD.
if ((1u<<12) < align) {
align = 1u<<12;
@@ -441,9 +441,9 @@ off_t PackLinuxElf32::pack3(OutputFile *fo, Filter &ft)
so_slide = off - ioff;
set_te32(&phdr->p_offset, so_slide + ioff);
}
else { // Change length of first PT_LOAD.
set_te32(&phdr->p_filesz, sz_pack2 + lsize);
set_te32(&phdr->p_memsz, sz_pack2 + lsize);
else if ((ioff - xct_off) < len) { // Change length of compressed PT_LOAD.
set_te32(&phdr->p_filesz, sz_pack2 + lsize - ioff);
set_te32(&phdr->p_memsz, sz_pack2 + lsize - ioff);
}
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)) {
unsigned offset = get_te32(&shdr->sh_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->seek(0, SEEK_END);
}
@@ -546,9 +546,9 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
if (Elf64_Phdr::PT_INTERP==type) {
// Rotate to highest position, so it can be lopped
// by decrementing e_phnum.
memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr));
memmove(phdr, 1+phdr, j * sizeof(*phdr)); // overlapping
memcpy(&phdr[j], (unsigned char *)ibuf, sizeof(*phdr));
memcpy((unsigned char *)ibuf, phdr, sizeof(*phdr)); // extract
memmove(phdr, 1+phdr, (e_phnum - (1+ j))*sizeof(*phdr)); // overlapping
memcpy(&phdr[-1+ e_phnum], (unsigned char *)ibuf, sizeof(*phdr)); // to top
--phdr;
set_te16(&ehdri.e_phnum, --e_phnum);
continue;
@@ -570,9 +570,9 @@ off_t PackLinuxElf64::pack3(OutputFile *fo, Filter &ft)
so_slide = off - ioff;
set_te64(&phdr->p_offset, so_slide + ioff);
}
else { // Change length of first PT_LOAD.
set_te64(&phdr->p_filesz, sz_pack2 + lsize);
set_te64(&phdr->p_memsz, sz_pack2 + lsize);
else if ((ioff - xct_off) < len) { // Change length of compressed PT_LOAD.
set_te64(&phdr->p_filesz, sz_pack2 + lsize - ioff);
set_te64(&phdr->p_memsz, sz_pack2 + lsize - ioff);
}
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
// 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_out = xct_off;
unsigned total_in = (is_shlib ? 0 : xct_off);
unsigned total_out = (is_shlib ? sz_elf_hdrs : xct_off);
uip->ui_pass = 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;
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) {
// FIXME: ?? ft.addvalue = phdri[k].p_vaddr;
}
x.offset = get_te32(&phdri[k].p_offset);
x.size = get_te32(&phdri[k].p_filesz);
if (0 == nx) { // 1st PT_LOAD32 must cover Ehdr at 0==p_offset
unsigned const delta = !is_shlib
? (sizeof(Elf32_Ehdr) + sz_phdrs) // main executable
: xct_off; // shared library
if (ft.id < 0x40) {
// FIXME: ?? ft.addvalue += asl_delta;
if (!is_shlib || hdr_u_len < x.size) {
if (0 == nx) { // 1st PT_LOAD32 must cover Ehdr at 0==p_offset
unsigned const delta = hdr_u_len;
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
// throw NotCompressible for small .data Extents, which PowerPC
// 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;
else {
total_in += x.size;
}
hdr_u_len = 0;
++nx;
}
@@ -3526,6 +3541,16 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
uip->ui_pass = 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;
for (k = 0; k < e_phnum; ++k)
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.size = get_te64(&phdri[k].p_filesz);
if (0 == nx) { // 1st PT_LOAD64 must cover Ehdr at 0==p_offset
unsigned const delta = hdr_u_len;
if (ft.id < 0x40) {
// FIXME: ?? ft.addvalue += asl_delta;
if (!is_shlib || hdr_u_len < x.size) {
if (0 == nx) { // 1st PT_LOAD64 must cover Ehdr at 0==p_offset
unsigned const delta = hdr_u_len;
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
// throw NotCompressible for small .data Extents, which PowerPC
// 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;
else {
total_in += x.size;
}
hdr_u_len = 0;
++nx;
}
sz_pack2a = fpad4(fo); // MATCH01
// 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);
}