我构建了一个虚拟USB总线(通过网络与linux盒通信)作为OSX的kext。 主类派生自IOUSBControllerV3。
它工作在10.6 32Bit,10.7.5 64bit,10.8 64bit,但无法加载 因为(a?)纯虚函数而在10.7.5 32bit之下。 kextutil告诉我这个。
我在同一系统下编译了(Xcode 4.6)kext,尝试了很多变化 哪个目标系统或SDK版本,但问题仍然存在?
我知道在标题中有一些#ifdef LP64 差异 基类,特别是在纯虚函数的上下文中。
但经过两天的比较和比较的过载 纯虚函数我不知道为什么只有32bit会出错?
相同的代码在其他系统下工作,但Lion 32bit不能。
非常感谢每一个提示,
问候 马库斯
===========终端输出:
MacProTest:Developer ms$ sudo kextutil -t -v 2 MaCute.kext
Password:
Notice: MaCute.kext has debug properties set.
MaCute.kext appears to be loadable (not including linkage for on-disk libraries).
Loading MaCute.kext.
Reading load info for 13 kexts.
Created mkext for architecture i386 containing 1 kexts.
Loading MaCute.kext.
(kernel) Received request from user space to load kext de.seh.utn.MaCute.
(kernel) Loading kext de.seh.utn.MaCute.
(kernel) Allocated link buffer for kext de.seh.utn.MaCute at 0x1507000 (200704 bytes).
(kernel) kxld[de.seh.utn.MaCute]: This kext calls a pure virtual function. Make sure your kext's OSObject-derived classes implement all pure virtual functions.
(kernel) Can't load kext de.seh.utn.MaCute - link failed.
(kernel) Failed to load executable for kext de.seh.utn.MaCute.
(kernel) Kext de.seh.utn.MaCute failed to load (0xdc008016).
(kernel) Failed to load kext de.seh.utn.MaCute (error 0xdc008016).
Failed to load MaCute.kext - (libkern/kext) link error.
Failed to load MaCute.kext - (libkern/kext) link error.
Check library declarations for your kext with kextlibs(8).
答案 0 :(得分:1)
由于我在IOUSBControllerV3.h
头文件中找不到任何明显的罪魁祸首,因此我决定向Google发送错误消息,以尝试查找相关的源代码。我已将其追溯到kxld_reloc.c中的函数check_for_direct_pure_virtual_call()
:
entry = kxld_vtable_get_entry_for_offset(relocator->current_vtable,
offset, relocator->is_32_bit);
require_action(!entry || !entry->patched.name ||
!kxld_sym_name_is_pure_virtual(entry->patched.name),
finish, rval=KERN_FAILURE;
kxld_log(kKxldLogLinking, kKxldLogErr,
kKxldLogDirectPureVirtualCall));
kKxldLogDirectPureVirtualCall
#define
为该错误。
如果我是你,我会下载该osx版本的xnu源包(1699.32.7)并使用on this site指令构建自己的内核二进制文件。然后,如果断言条件失败,则修改上述函数以输出entry->patched.name
,因此在require_action()
行之前插入此函数:
if (entry && entry->patched.name && kxld_sym_name_is_pure_virtual(entry->patched.name))
printf("pure virtual function called by kext: %s\n", entry->patched.name);
然后重建并启动新内核。我认为这应该将函数的(受损)名称打印到内核日志中。这是相当多的努力,但我认为它会让你到那里!
<强>更新强>
从评论中可以清楚地知道我们还没有完成。在i386上,从check_for_direct_pure_virtual_call()
调用generic_process_reloc()
,如果纯虚拟检查失败,将报告失败:
rval = check_for_direct_pure_virtual_call(relocator, instr_data);
require_noerr(rval, finish);
在这个函数中对我们没有任何帮助,但它又从2个函数调用:kxld_relocator_process_sect_reloc()
和kxld_relocator_process_table_reloc()
。在这种情况下我不知道哪一个适用,但两者中的代码看起来非常相似,所以我们可以用调试输出以相同的方式修改它们:
rval = relocator->process_reloc(relocator, instruction, reloc->length,
reloc->pcrel, base_pc, link_pc, link_disp, reloc->reloc_type, target,
pair_target, relocator->swap);
require_noerr(rval, finish);
我们想在这两个语句之间插入代码:第一个是失败的重定位调用,第二个是函数失效。我们希望捕获故障并为它们生成一些调试输出。所以,像这样:
rval = relocator->process_reloc(relocator, instruction, reloc->length,
reloc->pcrel, base_pc, link_pc, link_disp, reloc->reloc_type, target,
pair_target, relocator->swap);
if (rval)
{
// try to find the symbol corresponding to this relocation entry
KXLDSym* sym = kxld_reloc_get_symbol(relocator, reloc, NULL);
const char* symname = (sym && sym->name) ? sym->name : "[NULL]";
const char* symalias = (sym && sym->alias) ? sym->alias : "[NULL]";
printf("Relocation failed for relocation %p, symbol %p: name = '%s', alias = '%s'\n",
reloc, sym, symname, symalias);
}
require_noerr(rval, finish);
修改两个函数,构建内核,启动它,并尝试加载kext。我希望这会让你有所帮助。让我们知道你是怎么过的!
请注意,我还没有测试上面的代码,因为我目前无法再现这个问题。