diff --git a/src/p_lx_elf.cpp b/src/p_lx_elf.cpp index 2d1fb5c2..08626511 100644 --- a/src/p_lx_elf.cpp +++ b/src/p_lx_elf.cpp @@ -85,6 +85,52 @@ fpad4(OutputFile *fo) return d + len; } +void +PackLinuxElf32::hemfix(Elf32_Phdr *phdr, unsigned n_phdr) +{ + unsigned j; + for (j=0; j < n_phdr; ++phdr, ++j) { + unsigned const mask = -phdr->p_align; + if (PT_LOAD32==phdr->p_type) { /* first PT_LOAD */ + if (~mask & phdr->p_vaddr + && 0==(~mask & (phdr->p_vaddr - phdr->p_offset))) { + unsigned const hem = ~mask & phdr->p_offset; + phdr->p_offset -= hem; + phdr->p_vaddr -= hem; + if (phdr->p_paddr) + phdr->p_paddr -= hem; + phdr->p_filesz += hem; + phdr->p_memsz += hem; + } + break; + } + } + return; +} + +void +PackLinuxElf64::hemfix(Elf64_Phdr *phdr, unsigned n_phdr) +{ + unsigned j; + for (j=0; j < n_phdr; ++phdr, ++j) { + unsigned const mask = -phdr->p_align; + if (PT_LOAD64==phdr->p_type) { /* first PT_LOAD */ + if (~mask & phdr->p_vaddr + && 0==(~mask & (phdr->p_vaddr - phdr->p_offset))) { + unsigned const hem = ~mask & phdr->p_offset; + phdr->p_offset -= hem; + phdr->p_vaddr -= hem; + if (phdr->p_paddr) + phdr->p_paddr -= hem; + phdr->p_filesz += hem; + phdr->p_memsz += hem; + } + break; + } + } + return; +} + int PackLinuxElf32::checkEhdr(Elf32_Ehdr const *ehdr) const { @@ -1240,7 +1286,8 @@ bool PackLinuxElf32::canPack() unsigned osabi0 = u.buf[Elf32_Ehdr::EI_OSABI]; // The first PT_LOAD32 must cover the beginning of the file (0==p_offset). - Elf32_Phdr const *phdr = (Elf32_Phdr const *)(u.buf + e_phoff); + Elf32_Phdr *phdr = (Elf32_Phdr *)(u.buf + e_phoff); + hemfix(phdr, umin(14, e_phnum)); note_size = 0; for (unsigned j=0; j < e_phnum; ++phdr, ++j) { if (j >= 14) { @@ -1476,16 +1523,16 @@ PackLinuxElf64amd::canPack() } // The first PT_LOAD64 must cover the beginning of the file (0==p_offset). - Elf64_Phdr const *phdr = (Elf64_Phdr const *)(u.buf + (unsigned) e_phoff); + Elf64_Phdr *phdr = (Elf64_Phdr *)(u.buf + e_phoff); + hemfix(phdr, umin(14, e_phnum)); for (unsigned j=0; j < e_phnum; ++phdr, ++j) { if (j >= 14) return false; if (phdr->PT_LOAD64 == get_te32(&phdr->p_type)) { - // Just avoid the "rewind" when unpacking? - //if (phdr->p_offset != 0) { - // throwCantPack("invalid Phdr p_offset; try '--force-execve'"); - // return false; - //} + if (phdr->p_offset != 0) { + throwCantPack("invalid Phdr p_offset; try '--force-execve'"); + return false; + } load_va = get_te64(&phdr->p_vaddr); exetype = 1; break; @@ -1974,6 +2021,7 @@ void PackLinuxElf32::pack1(OutputFile *fo, Filter & /*ft*/) phdri = new Elf32_Phdr[e_phnum]; fi->seek(e_phoff, SEEK_SET); fi->readx(phdri, sz_phdrs); + hemfix(phdri, e_phnum); // Remember all PT_NOTE, and find lg2_page from PT_LOAD. Elf32_Phdr const *phdr = phdri; @@ -2163,6 +2211,7 @@ void PackLinuxElf64::pack1(OutputFile *fo, Filter & /*ft*/) phdri = new Elf64_Phdr[e_phnum]; fi->seek(e_phoff, SEEK_SET); fi->readx(phdri, sz_phdrs); + hemfix(phdri, e_phnum); Elf64_Phdr const *phdr = phdri; note_size = 0; diff --git a/src/p_lx_elf.h b/src/p_lx_elf.h index fd3040cd..1d384c9d 100644 --- a/src/p_lx_elf.h +++ b/src/p_lx_elf.h @@ -101,6 +101,7 @@ public: PackLinuxElf32(InputFile *f); virtual ~PackLinuxElf32(); protected: + void hemfix(Elf32_Phdr *phdr, unsigned n_phdr); virtual int checkEhdr(Elf32_Ehdr const *ehdr) const; virtual bool canPack(); @@ -225,6 +226,7 @@ public: /*virtual void buildLoader(const Filter *);*/ protected: + void hemfix(Elf64_Phdr *phdr, unsigned n_phdr); virtual int checkEhdr(Elf64_Ehdr const *ehdr) const; virtual void pack1(OutputFile *, Filter &); // generate executable header diff --git a/src/p_mach.cpp b/src/p_mach.cpp index d33c8f52..12f47b8f 100644 --- a/src/p_mach.cpp +++ b/src/p_mach.cpp @@ -1376,7 +1376,7 @@ bool PackMachBase::canPack() // Put LC_SEGMENT together at the beginning, ascending by .vmaddr. qsort(msegcmd, ncmds, sizeof(*msegcmd), compare_segment_command); - // Check that LC_SEGMENTs form one contiguous chunk of the file. + // Check alignment of non-null LC_SEGMENT. for (unsigned j= 0; j < ncmds; ++j) { if (lc_seg==msegcmd[j].cmd) { if (~PAGE_MASK & (msegcmd[j].fileoff | msegcmd[j].vmaddr)) { @@ -1384,13 +1384,11 @@ bool PackMachBase::canPack() } if (msegcmd[j].vmsize==0) break; // was sorted last - if (0 < j) { - unsigned const sz = PAGE_MASK - & (~PAGE_MASK + msegcmd[j-1].filesize); - if ((sz + msegcmd[j-1].fileoff)!=msegcmd[j].fileoff) { - return false; - } - } + + // We used to check that LC_SEGMENTS were contiguous, + // but apparently that is not needed anymore, + // and Google compilers generate strange layouts. + ++n_segment; sz_segment = msegcmd[j].filesize + msegcmd[j].fileoff - msegcmd[0].fileoff; }