如何让我用 SysV 调用约定编译的 C 程序在 MinGW 下运行

Posted

技术标签:

【中文标题】如何让我用 SysV 调用约定编译的 C 程序在 MinGW 下运行【英文标题】:How to make my C program compiled with SysV calling convention run under MinGW 【发布时间】:2021-03-23 02:20:05 【问题描述】:

我的平台是 x86_64 + Windows 10 + Cygwin。我的编译器是x86_64-w64-mingw32-gcc

出于某种原因,我不得不使用-mabi=sysv 选项编译我的程序,如果可能的话,我想避免使用默认的-mabi=ms 选项。

程序编译成功。但是当它调用像printf 这样的库函数时,它segfaults。原因是库函数驻留在msvcrt.dll 中,这可能是使用-mabi=sysv 以外的调用约定预构建的。

那么,有没有办法在 Cygwin 中安装使用-mabi=sysv 编译的库?

【问题讨论】:

我认为这是不可能的。为什么需要这个? @ssbssa 我正在处理的项目中有手写的 x86 程序集。手写汇编代码使用sysv 调用约定。现在我们将它移植到一个 mingw 环境,它的默认值为ms,我们认为只安装sysv 库而不重写汇编部分会很好。但由于我们没有找到方法,我们已经重写了程序集。 【参考方案1】:

根据您对手写汇编的评论,您似乎亲身体验了汇编实际上是如何不那么可移植的,以及为什么在历史上需要像 C 这样更可移植的高级语言。

您出现崩溃的原因很可能是由于两个 ABI 之间的寄存器使用情况不同。调用函数时,ABI 定义与每个参数关联的寄存器。因此,当您使用一个 ABI 调用一个库函数时,该库之前是为另一个 ABI 编译的,该库代码将查看其指定的寄存器并可能访问导致未定义行为的内存。

我认为虽然获取库会解决您的问题,但存在误解。想一想你得到了你想要的东西,即针对 System V ABI 编译的 windows C 运行时库。现在,当您的程序调用printf(...) 时,您至少会将您的参数放在正确的寄存器中。但是文本必须打印到控制台,因此必须要求内核介入并使其发生。为了进行该系统调用,将使用 Windows API 库,并且会发生另一个 ABI 不匹配。所以你可以看到这个困境是如何上升到顶部的。您基本上需要一个针对 System V ABI 编译的完整 Windows 操作系统,或某种其他形式的兼容层,例如 WINE 的工作原理。

您在这里可能有两个选择。重写程序集以匹配本机 Windows ABI,或研究使用提供完整(但虚拟化)Linux 环境的 WSL。

【讨论】:

以上是关于如何让我用 SysV 调用约定编译的 C 程序在 MinGW 下运行的主要内容,如果未能解决你的问题,请参考以下文章

__stdcall的名字修饰约定

c语言函数调用规则

CentOS 7 巨大变动之 systemd 取代 SysV的Init

CentOS 7 巨大变动之 systemd 取代 SysV的Init

C/C++函数的调用约定详解

C语言函数调用约定