【问题标题】:Does WINE implement "_printf" and similar functions in MSVCRT?WINE 是否在 MSVCRT 中实现“_printf”和类似功能?
【发布时间】:2019-11-04 13:42:48
【问题描述】:

这是一个说明我的问题的示例程序,它可以使用 FlatAssembler 编译而不使用链接器:

format PE console
entry start

include 'win32a.inc'

section '.text' code executable
start:

mov dword [esp],_output1
call [printf]
mov dword [esp+4],first
mov dword [esp],_input
call [scanf]

mov dword [esp],_output2
call [printf]
mov dword [esp+4],second
mov dword [esp],_input
call [scanf]

finit
fld dword [first]
fabs
fld dword [second]
fxch
fld1
fxch
fyl2x
fldl2e
fdivp st1,st0
fmulp st1,st0
fldl2e
fmulp st1,st0
fld1
fscale
fxch
fld1
fxch
fprem
f2xm1
faddp st1,st0
fmulp st1,st0
fstp dword [result]

fld dword [result]
fst qword [esp+4]
mov dword [esp],_output
call [printf]
invoke system,_pause
invoke exit,0

_output1 db "Enter the first number: ",0
_output2 db "Enter the second number: ",0
_input db "%f",0
_pause db "PAUSE",0
_output db "The first number to the power of the second number is: %f.",10,0

section '.rdata' readable writable
result dd ?
first dd ?
second dd ?

section '.idata' data readable import
library msvcrt,'msvcrt.dll'
import msvcrt,printf,'printf',system,'system',exit,'exit',scanf,'scanf'

所以,预期的输出当然是这样的:

Enter the first number: -2.5
Enter the second number: -2
The first number to the power of the second number is: 0.16

如果我在 Windows 10 上运行该程序,我确实得到了输出。但是,如果我尝试在 Oracle Linux 上的 WINE 上运行该程序,我得到的输出是:

000f:fixme:service:scmdatabase_autostart_services Auto-start service L"MountMgr" failed to start: 2
000f:fixme:service:scmdatabase_autostart_services Auto-start service L"WineBus" failed to start: 2
wine: Bad EXE format for Z:\home\teo.samarzija\Documents\Assembly\debug.exe.

知道发生了什么吗?

我做了一些研究,但我找不到任何参考资料来确认 _printf_scanf 甚至在 WINE 的 MSVCRT 中实现。但是,我不确定这是不是问题,如果是问题,那就是唯一的问题。

【问题讨论】:

    标签: wine msvcrt


    【解决方案1】:

    但是,如果我尝试在 Oracle Linux 上的 WINE 上运行该程序, 我得到的输出是:

    000f:fixme:service:scmdatabase_autostart_services Auto-start service L"MountMgr" failed to start: 2
    000f:fixme:service:scmdatabase_autostart_services Auto-start service L"WineBus" failed to start: 2
    wine: Bad EXE format for Z:\home\teo.samarzija\Documents\Assembly\debug.exe.
    

    “错误的 EXE 格式”错误完全不同。这并不意味着问题是缺少导入的函数。装载机从来没有走那么远。它甚至无法读取您的二进制文件。这很可能是由位不匹配引起的。例如,尝试在 32 位系统上运行 64 位应用程序。

    除了这个问题,值得指出的是,您尝试使用 C 运行时库函数本质上是不可移植的。如果 Wine(或任何其他运行时环境)提供具有相同签名的函数,它可能工作,但很可能不会。

    我想我应该进一步澄清,因为调用 标准 C 运行时库函数“不可移植”可能会引起一些人的注意。这些函数在 source-code 级别是可移植的,但在 binary 级别是不可移植的。即使没有增加 Wine 的复杂性,C 运行时库函数也是不可移植的,因为 Microsoft 的 CRT 是版本化的——您必须链接到适当的版本并在运行时提供该 DLL,或者您的应用程序不会工作。

    这个确切的问题就是为什么 Windows 将这些标准函数的包装器作为普遍可用的基本平台 API 的一部分提供。如果您想完全移植到 Win32 环境的所有实现,并且您没有在自己的 C 运行时库副本中进行链接,那么您应该调用这些函数。

    sprintf 函数的 Win32 版本是wsprintf。它具有与sprintf 相同的接口,因此您可以以相同的方式调用它,作为直接替换。实际上,尽管您不应该依赖它,但它是由 Windows 实现的,作为 C 运行时库的本地副本提供的 sprintf 版本的简单包装器。

    如果您想要一个可以向其传递参数列表的版本(例如vsprintf),那么您可以调用wvsprintf

    请注意,与大多数 Windows API 函数不同,这些函数使用 __cdecl 调用约定,而不是 __stdcall 调用约定。确保您在汇编代码中遵守这一点。简而言之,这意味着从右到左传递参数并在调用站点清理堆栈。

    但是,Microsoft 已弃用这些函数,因为它们并不完全安全(可能存在缓冲区溢出等)。作为替代品,它们提供StrSafe.h 标头中的功能。这些函数有两种变体:一种是字节数(Cb),另一种是字符数(Cch)。与本次讨论相关的是StringCbPrintfAStringCchPrintfA。然而,这些在汇编语言中使用起来更棘手,因为它们旨在通过简单地包含 StrSafe.h 头文件来内联使用。您可以以库形式使用它们,但是您需要将相应的StrSafe.lib 存根传递给链接器。请注意,链接到此库意味着您的应用程序只能在带有 SP2 或更高版本的 Windows XP 上运行。

    这让你成功了一半。您实际上是在尝试调用printf,而不是sprintf。当然,差距是将格式化的字符串写入控制台。一旦你有了格式化的字符串(由wsprintfStringCchPrintfA 或其他生成),就可以通过调用WriteConsole 函数来完成,这是用于将输出写入控制台窗口的Win32 API。如果你想要 STDOUT,那么你需要先用GetStdHandle(STD_OUTPUT_HANDLE) 打开那个句柄。

    【讨论】:

    • 好的,谢谢,这是一个信息丰富的答案。不过,您是否尝试过在配置良好的 WINE 中运行我的程序?它在那里工作吗?
    • 我没试过。我没有这样一个配置良好的 WINE 环境。 Meta讨论引起了我的注意。我认为它应该在您的编辑后重新打开和投票,然后我投入了两分钱作为答案。如果您仍然希望 WINE 专家回答,那很好;不要因为接受我的回答而感到压力。
    【解决方案2】:

    无论如何,我得到了答案:

    https://www.linuxquestions.org/questions/linux-general-1/can%27t-install-wine-on-64-bit-oracle-linux-4175655895/page2.html#post6012838

    简而言之,在 64 位 Oracle Linux 上,WINE 需要从源代码编译才能正常工作。

    【讨论】:

      猜你喜欢
      • 2013-07-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      • 2014-04-27
      • 2011-01-31
      • 2016-11-20
      • 1970-01-01
      相关资源
      最近更新 更多