13

我有一个用 LLVM 编写的编译器,我正在寻找我的 ABI 合规性。例如,我发现实际上很难在 Windows x86 或 Linux 上找到 C ABI 的规范文档。我发现的那些是用 RAX/EAX/etc 来解释的,而不是我可以使用的 IR 术语。

到目前为止,我想我已经发现 LLVM 以不可见的方式处理聚合——也就是说,它将它们的成员各自视为一个不同的参数。因此,例如,在 Windows x64 上,如果我想处理文档所说的聚合,我需要强制转换为该大小的单个整数,如果是 8、16、32 或 64 位。否则,按指针传递。

对于 Windows x86,似乎 __cdecl 和 __stdcall 不需要我的任何操作,因为所有参数都在堆栈上传递。__fastcall 表示前两个 32 位或更小的参数是寄存器传递的,所以我需要强制该大小或更小的聚合。__thiscall 在寄存器中传递这个,其余的在堆栈中,所以看起来我不需要在这里执行任何调整。

对于 __vectorcall,通过整数强制传递不超过 sizeof(void*) 的聚合。对于其他聚合,如果它们是 HVA,则按值传递;否则在 x86 上按值传递或在 x64 上按指针传递。

这看起来很简单(好吧,相对而言),但 LLVM 文档sext明确指出“这向代码生成器表明参数或返回值应符号扩展至目标 ABI 所需的范围(通常为 32 位)由调用者(对于参数)或被调用者(对于返回值)。”。x86 调用约定的 Microsoft 页面没有提到将任何内容扩展到任何宽度。

而且我观察到 Clang 生成的 LLVM IRbyval在 Windows 上生成属性。我从上面收集到的理解从来不需要byval' 的用法。

如何将各种平台 C ABI 降低到 LLVM IR?

4

2 回答 2

6

我不能说我 100% 理解你的问题,但值得注意的是,LLVM IR 根本无法代表平台 ABI 的所有细节。因此,在 Clang 工具链中,前端负责执行 ABI 降低,例如正确地将对象按值传递给函数等。

查看lib/Basic/Targets.cppClang 源代码树中的定义。血淋淋的细节在进一步lib/CodeGen/TargetInfo.cpp

于 2014-08-05T17:19:01.360 回答
4

我最终破解了 Clang 的 CodeGen 内部结构来执行 C ABI 调用(C++ ABI 支持已经完成)。因此,我不必重新实现(和重新测试)他们的代码,而是简单地重新使用他们的工作。CodeGen API 正式不公开,也不打算供任何人使用,但在这种情况下,我设法使它工作。事实证明,它并没有看起来那么可怕——许多像 LValue/RValue/ReturnValueSlot 这样的类只是 llvm::Value* 上的包装器,并附加了一些额外的可选语义。

更多的问题是创建从 C ABI 到我自己的 ABI 的蹦床。CodeGenFunction 接口似乎不太适合这种情况。但我想我可以让它发挥作用。

于 2014-08-07T22:35:34.983 回答