WINE是否在MSVCRT中实现“ _printf”和类似功能?

时间:2019-06-21 17:21:00

标签: wine msvcrt

这是一个说明我的问题的示例程序,可以使用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中实现。但是,我不确定这是问题所在,如果是问题,那就是唯一的问题。

2 个答案:

答案 0 :(得分: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(或任何其他运行时环境)提供具有相同签名的功能,则可能起作用。

我想我应该进一步澄清一下,因为将 standard C运行时库函数称为“不可移植”可能会引起一些注意。这些功能可以在源代码级别移植,但不能在 binary 级别移植。即使没有增加Wine的复杂性,C运行时库函数也是不可移植的,因为Microsoft的CRT是版本的-您必须链接到适当的版本,并在运行时或应用程序中使用该DLL将无法正常工作。

这个确切的问题就是为什么Windows将这些标准功能的包装器作为通用平台API的基本平台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)打开该句柄。

答案 1 :(得分:0)

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

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才能正常工作。