关于dlopen的疑惑

为什么用dlopen动态加载私有库/System/Library/PrivateFrameworks/FrontBoard.framework/FrontBoard会报错:out of adress space,而加载其他的私有库例如 /System/Library/PrivateFrameworks/StoreServices.framework/StoreServices却又可以加载成功呢?如果确实没办法打算把不能加载的bin转成dylib来加载,不知是否可行

进程确实有/System/Library/Frameworks/Healthkit.framework/healthd,我用dlopen动态加载始终还是error:
dlopen(/System/Library/Frameworks/Healthkit.framework/healthd,1):no suitable image found . Did find :/System/Library/Frameworks/Healthkit.framework/healthd: out of address space
有大神给点提示信息吗

dlopen是用来加载dylib, 不是加载bin的

为什么有些bin可以用dlopen加载成功呢,这是什么情况

系统的bin 32位的可以, 64位基本不行, 只要有PAGEZERO就不行

输出错误信息是在dyld.cpp,

ImageLoader* loadPhase5open(const char* path, const LoadContext& context, const struct stat& stat_buf, std::vector<const char*>* exceptions)

抛出是在 ImageLoaderMachO.cpp

uintptr_t ImageLoaderMachO::reserveAnAddressRange(size_t length, const ImageLoader::LinkContext& context)
{
	vm_address_t addr = 0;
	vm_size_t size = length;
	// in PIE programs, load initial dylibs after main executable so they don't have fixed addresses either
	if ( fgNextPIEDylibAddress != 0 ) {
		 // add small (0-3 pages) random padding between dylibs
		addr = fgNextPIEDylibAddress + (__stack_chk_guard/fgNextPIEDylibAddress & (sizeof(long)-1))*dyld_page_size;
		//dyld::log("padding 0x%08llX, guard=0x%08llX\n", (long long)(addr - fgNextPIEDylibAddress), (long long)(__stack_chk_guard));
		kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_FIXED | VM_MAKE_TAG(VM_MEMORY_DYLIB));
		if ( r == KERN_SUCCESS ) {
			fgNextPIEDylibAddress = addr + size;
			return addr;
		}
		fgNextPIEDylibAddress = 0;
	}
	kern_return_t r = vm_alloc(&addr, size, VM_FLAGS_ANYWHERE | VM_MAKE_TAG(VM_MEMORY_DYLIB));
	if ( r != KERN_SUCCESS ) 
		throw "out of address space";
	
	return addr;
}

调用时

reserveAnAddressRange(highAddr-lowAddr, context);

highAddr 和 lowAddr 的计算

		uintptr_t lowAddr = (unsigned long)(-1);
		uintptr_t highAddr = 0;
		for(unsigned int i=0, e=segmentCount(); i < e; ++i) {
			const uintptr_t segLow = segPreferredLoadAddress(i);
			const uintptr_t segHigh = dyld_page_round(segLow + segSize(i));
			if ( segLow < highAddr ) {
				if ( dyld_page_size > 4096 )
					dyld::throwf("can't map segments into 16KB pages");
				else
					dyld::throwf("overlapping segments");
			}
			if ( segLow < lowAddr )
				lowAddr = segLow;
			if ( segHigh > highAddr )
				highAddr = segHigh;
				
			if ( needsToSlide || !imageHasPreferredLoadAddress || inPIE || !reserveAddressRange(segPreferredLoadAddress(i), segSize(i)) )
				needsToSlide = true;
		}

所以有PAGEZERO的就爆炸了

1 个赞

Thanks!刚学着去啃了下dyld开源代码(虽然不怎么看得懂

有现成工具去掉pagezero实现你的需求

1 个赞

请问后来这个问题解决了吗。。我现在也遇到了这个问题

前面的回复不是给解决方法了吗

具体看大神文章详细解答:黑科技:把第三方 iOS 应用转成动态库 - Jun's Blog