Lion 32bit kext无法加载纯虚函数,但64bit工作

时间:2013-02-27 12:21:57

标签: usb osx-lion 32-bit kernel-extension

我构建了一个虚拟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).

1 个答案:

答案 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。我希望这会让你有所帮助。让我们知道你是怎么过的!

请注意,我还没有测试上面的代码,因为我目前无法再现这个问题。