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:
+61
-30
@@ -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,9 +422,9 @@ 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;
|
||||||
@@ -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,25 +3409,35 @@ 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 (!is_shlib || hdr_u_len < x.size) {
|
||||||
if (0 == nx) { // 1st PT_LOAD32 must cover Ehdr at 0==p_offset
|
if (0 == nx) { // 1st PT_LOAD32 must cover Ehdr at 0==p_offset
|
||||||
unsigned const delta = !is_shlib
|
unsigned const delta = hdr_u_len;
|
||||||
? (sizeof(Elf32_Ehdr) + sz_phdrs) // main executable
|
|
||||||
: xct_off; // shared library
|
|
||||||
if (ft.id < 0x40) {
|
if (ft.id < 0x40) {
|
||||||
// FIXME: ?? ft.addvalue += asl_delta;
|
// FIXME: ?? ft.addvalue += asl_delta;
|
||||||
}
|
}
|
||||||
@@ -3437,12 +3447,17 @@ int PackLinuxElf32::pack2(OutputFile *fo, Filter &ft)
|
|||||||
// compressWithFilters() always assumes a "loader", so would
|
// compressWithFilters() always assumes a "loader", so would
|
||||||
// throw NotCompressible for small .data Extents, which PowerPC
|
// throw NotCompressible for small .data Extents, which PowerPC
|
||||||
// sometimes marks as PF_X anyway. So filter only first segment.
|
// sometimes marks as PF_X anyway. So filter only first segment.
|
||||||
if (0==nx || !is_shlib)
|
if (k == nk_f || !is_shlib) {
|
||||||
packExtent(x, total_in, total_out,
|
packExtent(x, total_in, total_out,
|
||||||
((0==nx && (Elf32_Phdr::PF_X & get_te32(&phdri[k].p_flags)))
|
(k==nk_f ? &ft : 0 ), fo, hdr_u_len);
|
||||||
? &ft : 0 ), fo, hdr_u_len);
|
}
|
||||||
else
|
else {
|
||||||
total_in += x.size;
|
total_in += x.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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,6 +3559,7 @@ 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 (!is_shlib || hdr_u_len < x.size) {
|
||||||
if (0 == nx) { // 1st PT_LOAD64 must cover Ehdr at 0==p_offset
|
if (0 == nx) { // 1st PT_LOAD64 must cover Ehdr at 0==p_offset
|
||||||
unsigned const delta = hdr_u_len;
|
unsigned const delta = hdr_u_len;
|
||||||
if (ft.id < 0x40) {
|
if (ft.id < 0x40) {
|
||||||
@@ -3545,19 +3571,24 @@ int PackLinuxElf64::pack2(OutputFile *fo, Filter &ft)
|
|||||||
// compressWithFilters() always assumes a "loader", so would
|
// compressWithFilters() always assumes a "loader", so would
|
||||||
// throw NotCompressible for small .data Extents, which PowerPC
|
// throw NotCompressible for small .data Extents, which PowerPC
|
||||||
// sometimes marks as PF_X anyway. So filter only first segment.
|
// sometimes marks as PF_X anyway. So filter only first segment.
|
||||||
if (0==nx || !is_shlib)
|
if (k == nk_f || !is_shlib) {
|
||||||
packExtent(x, total_in, total_out,
|
packExtent(x, total_in, total_out,
|
||||||
((0==nx && (Elf64_Phdr::PF_X & get_te64(&phdri[k].p_flags)))
|
(k==nk_f ? &ft : 0 ), fo, hdr_u_len);
|
||||||
? &ft : 0 ), fo, hdr_u_len);
|
}
|
||||||
else
|
else {
|
||||||
total_in += x.size;
|
total_in += x.size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user