+// file on disk has been reprebound, but we are still mapped to old file
+void ImageLoaderMachO::prebindUnmap(const LinkContext& context)
+{
+ // this removes all mappings to the old file, so the kernel will unlink (delete) it.
+ // We need to leave the load commands and __LINKEDIT in place
+ for (std::vector<class Segment*>::iterator it=fSegments.begin(); it != fSegments.end(); ++it) {
+ void* segmentAddress = (void*)((*it)->getActualLoadAddress());
+ uintptr_t segmentSize = (*it)->getSize();
+ //fprintf(stderr, "unmapping segment %s at %p for %s\n", (*it)->getName(), segmentAddress, this->getPath());
+ // save load commands at beginning of __TEXT segment
+ if ( segmentAddress == fMachOData ) {
+ // typically load commands are one or two pages in size, so ok to alloc on stack
+ uint32_t loadCmdSize = sizeof(macho_header) + ((macho_header*)fMachOData)->sizeofcmds;
+ uint32_t loadCmdPages = (loadCmdSize+4095) & (-4096);
+ uint8_t loadcommands[loadCmdPages];
+ memcpy(loadcommands, fMachOData, loadCmdPages);
+ // unmap whole __TEXT segment
+ munmap((void*)(fMachOData), segmentSize);
+ // allocate and copy back mach_header and load commands
+ vm_address_t addr = (vm_address_t)fMachOData;
+ int r2 = vm_allocate(mach_task_self(), &addr, loadCmdPages, false /*at this address*/);
+ if ( r2 != 0 )
+ fprintf(stderr, "prebindUnmap() vm_allocate for __TEXT %d failed\n", loadCmdPages);
+ memcpy((void*)fMachOData, loadcommands, loadCmdPages);
+ //fprintf(stderr, "copying back load commands to %p size=%u for %s\n", segmentAddress, loadCmdPages, this->getPath());
+ }
+ else if ( strcmp((*it)->getName(), "__LINKEDIT") == 0 ) {
+ uint32_t linkEditSize = segmentSize;
+ uint32_t linkEditPages = (linkEditSize+4095) & (-4096);
+ void* linkEditTmp = malloc(linkEditPages);
+ memcpy(linkEditTmp, segmentAddress, linkEditPages);
+ // unmap whole __LINKEDIT segment
+ munmap(segmentAddress, segmentSize);
+ vm_address_t addr = (vm_address_t)segmentAddress;
+ int r2 = vm_allocate(mach_task_self(), &addr, linkEditPages, false /*at this address*/);
+ if ( r2 != 0 )
+ fprintf(stderr, "prebindUnmap() vm_allocate for __LINKEDIT %d failed\n", linkEditPages);
+ memcpy(segmentAddress, linkEditTmp, linkEditPages);
+ //fprintf(stderr, "copying back __LINKEDIT to %p size=%u for %s\n", segmentAddress, linkEditPages, this->getPath());
+ free(linkEditTmp);
+ }
+ else {
+ // unmap any other segment
+ munmap((void*)(segmentAddress), (*it)->getSize());
+ }
+ }