【发布时间】:2019-08-06 13:39:32
【问题描述】:
我想以混合 C++/Assembly 的方式开始使用 MASM。 我目前正在尝试从程序集中的 PROC 调用标准库函数(例如 printf),然后在 C++ 中调用。
在我的 cpp 文件中声明 printf 的签名后,我的代码就可以工作了。但我不明白为什么我必须这样做以及是否可以避免。
我的 cpp 文件:
#include <stdio.h>
extern "C" {
extern int __stdcall foo(int, int);
}
extern int __stdcall printf(const char*, ...); // When I remove this line I get Linker-Error "LNK2019: unresolved external symbol"
int main()
{
foo(5, 5);
}
我的 asm 文件:
.model flat, stdcall
EXTERN printf :PROC ; declare printf
.data
tstStr db "Mult: %i",0Ah,"Add: %i",0 ; 0Ah is the backslash - escapes are not supported
.code
foo PROC x:DWORD, y:DWORD
mov eax, x
mov ebx, y
add eax, ebx
push eax
mov eax, x
mul ebx
push eax
push OFFSET tstStr
call printf
ret
foo ENDP
END
一些更新
为了响应 cmets,我尝试重新编写代码以符合 cdecl 调用约定。不幸的是,这并没有解决问题(代码在 extern 声明下运行良好,但在没有声明的情况下会引发错误)。
但经过反复试验,我发现extern 似乎强制外部链接,即使不需要关键字,因为外部链接应该是函数声明的default。
我可以通过在我的 cpp 代码中使用该函数来省略声明(即,如果在源文件的某处添加 printf("\0");,则链接器可以使用它并且一切正常。
新的(但不是更好的)cpp 文件:
#include <stdio.h>
extern "C" {
extern int __cdecl foo(int, int);
}
extern int __cdecl printf(const char*, ...); // omiting the extern results in a linker error
int main()
{
//printf("\0"); // this would replace the declaration
foo(5, 5);
return 0;
}
asm 文件:
.model flat, c
EXTERN printf :PROC
.data
tstStr db "Mult: %i",0Ah,"Add: %i",0Ah,0 ; 0Ah is the backslash - escapes are not supported
.code
foo PROC
push ebp
mov ebp, esp
mov eax, [ebp+8]
mov ebx, [ebp+12]
add eax, ebx
push eax
mov eax, [ebp+8]
mul ebx
push eax
push OFFSET tstStr
call printf
add esp, 12
pop ebp
ret
foo ENDP
END
【问题讨论】:
-
extern在函数声明前面可能不会像你想的那样做,因为它没有效果。 -
@KonradRudolph:it has no effect 是一个相当强的声明,因为代码使用该声明进行编译并且没有该声明就无法编译。对于纯(标准)C++ 程序,您的评论可能是正确的,但这是 C++ 和汇编的混合。显然,此编译器、此汇编器和此链接器之间的交互以
extern必须完成某事的方式进行。 -
@MSalters 删除
extern关键字不会改变任何东西(这里是一个红鲱鱼),因为函数声明总是隐含的外部。所以,是的,它没有效果。 -
@MSalters Konrad 谈论的是
extern,而不是整个声明。 -
我自己确实有点困惑。由于包含
<stdio.h>,因此已经有::std::printf或::printf的声明,视情况而定。不过弄明白确实是件好事。 @AnonymousAnonymous,如果您删除 justextern,它仍然有效?
标签: c++ visual-studio assembly x86 masm