Preserve Mach_segment_header.flags; fix non-PIE main programs on MacOS.

https://github.com/upx/upx/issues/222
	modified:   p_mach.cpp
	modified:   p_mach.h
	modified:   stub/src/amd64-darwin.macho-entry.S
	also *.macho-*.h, *.macho-fold.map, amd64-darwin.macho-entry.bin.dump
This commit is contained in:
John Reiser
2018-09-22 18:45:44 -07:00
parent c1cfde21d7
commit 4d1c754af9
11 changed files with 737 additions and 700 deletions
+21 -20
View File
@@ -583,8 +583,7 @@ void PackMachBase<T>::pack4(OutputFile *fo, Filter &ft) // append PackHeader
segLINK.fileoff = len; // must be in the file
segLINK.vmaddr = len + segTEXT.vmaddr;
fo->write(page, blankLINK); len += blankLINK;
// reserve convex hull of input segments
segLINK.vmsize -= (segLINK.vmaddr - segTEXT.vmaddr);
segLINK.vmsize = PAGE_SIZE;
segLINK.filesize = blankLINK;
// Get a writeable copy of the stub to make editing easier.
@@ -593,6 +592,7 @@ void PackMachBase<T>::pack4(OutputFile *fo, Filter &ft) // append PackHeader
Mach_header *const mhp = (Mach_header *)upxstub;
mhp->cpusubtype = my_cpusubtype;
mhp->flags = mhdro.flags;
char *tail = (char *)(1+ mhp);
Mach_section_command *sectxt = 0; // in temp for output
unsigned txt_addr = 0;
@@ -1243,9 +1243,8 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
mhdro = mhdri;
if (my_filetype==Mach_header::MH_EXECUTE) {
memcpy(&mhdro, stub_main, sizeof(mhdro));
mhdro.flags = mhdri.flags;
COMPILE_TIME_ASSERT(sizeof(mhdro.flags) == sizeof(unsigned))
mhdro.flags &= ~ (unsigned) Mach_header::MH_PIE; // we require fixed address
mhdro.flags |= Mach_header::MH_BINDATLOAD; // DT_BIND_NOW
}
unsigned pos = sizeof(mhdro);
fo->write(&mhdro, sizeof(mhdro));
@@ -1270,12 +1269,16 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
segTEXT.cmdsize = sizeof(segTEXT) + sizeof(secTEXT);
strncpy((char *)segTEXT.segname, "__TEXT", sizeof(segTEXT.segname));
if (my_filetype==Mach_header::MH_EXECUTE) {
int k; // must ignore zero-length segments, which sort last
for (k=1 /*n_segment*/; --k>=0; )
if (msegcmd[k].vmsize!=0)
break;
segTEXT.vmaddr = PAGE_MASK64 & (~PAGE_MASK64 +
msegcmd[k].vmsize + msegcmd[k].vmaddr );
if (Mach_header::MH_PIE & mhdri.flags) {
segTEXT.vmaddr = segZERO.vmsize; // contiguous
}
else { // not MH_PIE
// Start above all eventual mappings.
// Cannot enlarge segZERO.vmsize because MacOS 10.13 (HighSierra)
// won't permit re-map of PAGEZERO.
// Stub will fill with PROT_NONE first.
segTEXT.vmaddr = vma_max;
}
}
if (my_filetype==Mach_header::MH_DYLIB) {
segTEXT.vmaddr = 0;
@@ -1319,18 +1322,10 @@ void PackMachBase<T>::pack1(OutputFile *const fo, Filter &/*ft*/) // generate e
segLINK = segTEXT;
segLINK.cmdsize = sizeof(segLINK);
strncpy((char *)segLINK.segname, "__LINKEDIT", sizeof(segLINK.segname));
segLINK.nsects = 0;
segLINK.initprot = Mach_command::VM_PROT_READ;
segLINK.nsects = 0;
segLINK.vmsize = 0;
// Adjust later: .vmaddr .vmsize .fileoff .filesize
upx_uint64_t up(0);
unsigned const ncmds = mhdri.ncmds;
for (unsigned j= 0; j < ncmds; ++j) if (lc_seg == msegcmd[j].cmd) {
upx_uint64_t sup = msegcmd[j].vmsize + msegcmd[j].vmaddr;
if (up < sup) {
up = sup;
segLINK.vmsize = sup - segLINK.vmaddr;
}
}
unsigned gap = 0;
if (my_filetype == Mach_header::MH_EXECUTE) {
@@ -1899,6 +1894,7 @@ bool PackMachBase<T>::canPack()
}
// Check alignment of non-null LC_SEGMENT.
vma_max = 0;
for (unsigned j= 0; j < ncmds; ++j) {
if (lc_seg==msegcmd[j].cmd) {
if (msegcmd[j].vmsize==0)
@@ -1906,6 +1902,10 @@ bool PackMachBase<T>::canPack()
if (~PAGE_MASK & (msegcmd[j].fileoff | msegcmd[j].vmaddr)) {
return false;
}
upx_uint64_t t = msegcmd[j].vmsize + msegcmd[j].vmaddr;
if (vma_max < t) {
vma_max = t;
}
// We used to check that LC_SEGMENTS were contiguous,
// but apparently that is not needed anymore,
@@ -1915,6 +1915,7 @@ bool PackMachBase<T>::canPack()
sz_segment = msegcmd[j].filesize + msegcmd[j].fileoff - msegcmd[0].fileoff;
}
}
vma_max = PAGE_MASK & (~PAGE_MASK + vma_max);
// info: currently the header is 36 (32+4) bytes before EOF
unsigned char buf[256];