再次将 C/Rust 交叉编译为 win32

这是关于 retrowin32 的系列文章的一部分。之前写过关于将 Rust 交叉编译到 win32 的内容,但因缺少编译器内在函数而未跟进,这里有两个密切相关的探索。

  • 交叉编译 C 到 win32:Clang 支持交叉编译包括针对 Windows,但作者常出错,经 Nico 指点后知道 Clang 的clang-cl二进制可作为 Visual Studio 的cl.exe的替代品,需正确配置编译器设置以生成 Windows 输出,如包含 Windows 头文件时需正确配置。交叉编译 C++代码到 Windows 示例为$ clang-cl -fuse-ld=lld -target i686-pc-windows-msvc -vctoolsdir $xwin_path/crt -winsdkdir $xwin_path/sdk foo.cc /link /subsystem:console,完整工作示例在这里
  • xwin:上述调用需要特定文件系统布局的 Windows 头文件和库,可从 Microsoft 获得但为安装程序.exe文件,winetricks可下载并解压这些文件,还有一个叫xwin的工具可直接下载并解压.exe文件,这是一个微妙的过程,如处理 VSIX 或 CAB 文件等,调用示例为$ xwin --accept-license --arch x86 splat --output redist --disable-symlinks--disable-symlinks仅在不区分大小写的文件系统上需要)。
  • 回到 Rust 及调用约定:之前帖子中的问题多因使用 Rust 的no_std,切换 Rust 目标从i686-pc-windows-msvci585-pc-windows-msvc可避免,然后可在 retrowin32 中运行带有std的 Rust“hello world”程序,需添加更多函数存根,其中 tricky 的是需要vcruntime140.dll中的memcpy,实现memcpy较易但要意识到其使用cdecl调用约定,Windows 有stdcallcdecl两种主要调用约定,stdcall在被调用者处弹出参数,cdecl在调用者处弹出,作者不清楚两者都存在的原因,retrowin32 之前实现的数百个 Windows 函数都是stdcall,通过两层实现,第一层用带注释的 Rust 函数实现,第二层代码生成器收集dllexport函数并生成代码,为支持cdecl只需调整dllexport代码生成以控制弹出的栈大小,这样 retrowin32 至少可运行一个简单的带有println!("hello, world");的 Rust 程序。
  • 内联汇编:作者研究这些是为在 x86 操作码实现上编写测试套件并在原生 x86 上运行以验证模拟器行为,因要测试特定操作码的调用所以写内联汇编,Clang 遵循 gcc 内联汇编语法,语法较繁琐,如写多条指令需嵌入'\n'%为转义字符且寄存器需双写%%,指定输入/输出/破坏时需在块后写,块内语法类似 printf 格式字符串等,作者不知这些语法为何如此设计,clang-cl配置为像 Windows 编译器可支持 Microsoft 内联汇编语法,看起来更简单,Rust 有自己的内联汇编语法感觉很合理,因基于 LLVM 语义上接近 Clang,且在 Rust asm 模板中格式化代码对应寄存器名,综合考虑作者倾向使用 Rust (主要抱怨是 Rust 自动格式化器跳过 asm 块),二进制文件较大,可能会研究最小化 Rust
阅读 14
0 条评论