1

我构建了一个虚拟 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差异,尤其是在纯虚函数的上下文中。

但是经过两天的比较和比较纯虚函数的重载,我不知道为什么只有32位会出问题?

相同的代码在其他系统下工作,但 Lion 32 位不能。

非常感谢您的每一个提示,

关于马库斯

=========== 终端输出:

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).
4

1 回答 1

1

由于我在头文件中找不到任何明显的罪魁祸首IOUSBControllerV3.h,我决定谷歌搜索错误信息,试图找到相关的源代码。我已经将其追溯到kxld_reloc.ccheck_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#defined 作为那个错误。

如果我是你,我会下载那个 osx 版本 (1699.32.7) 的 xnu 源代码包,并使用这个站点上的说明构建你自己的内核二进制文件。然后,修改上面的函数,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);

这个函数对我们没有什么太大的帮助,但它又是从两个函数调用的: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。我希望这能让你有所收获。让我们知道您的身体情况如何!

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

于 2013-02-28T21:13:20.523 回答