C 尝试在Visual Studio中运行程序集时出现问题
我试图在VisualStudio2012中运行一些汇编代码,并在C中调用它,仅用于测试目的。由于我没有编写汇编代码的经验,我不知道出了什么问题,所以我非常感谢您的帮助 我在编译代码时遇到以下错误:C 尝试在Visual Studio中运行程序集时出现问题,c,visual-studio,assembly,visual-studio-2012,C,Visual Studio,Assembly,Visual Studio 2012,我试图在VisualStudio2012中运行一些汇编代码,并在C中调用它,仅用于测试目的。由于我没有编写汇编代码的经验,我不知道出了什么问题,所以我非常感谢您的帮助 我在编译代码时遇到以下错误: Error 5 error MSB3721: The command "ml.exe /c /nologo /Zi /Fo"Debug\callee.obj" /W3 /errorReport:prompt /Tacallee.asm" exited
Error 5 error MSB3721: The command "ml.exe /c /nologo /Zi /Fo"Debug\callee.obj" /W3 /errorReport:prompt /Tacallee.asm" exited with code 1. C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\V110\BuildCustomizations\masm.targets 49 5 ProjetoASM
Error 2 error A2206: missing operator in expression C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 18 1 ProjetoASM
Error 3 error A2206: missing operator in expression C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 21 1 ProjetoASM
Error 4 error A2206: missing operator in expression C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 8 1 ProjetoASM
Error 1 error A2022: instruction operands must be the same size C:\Users\Suporte\Desktop\ASM\ProjetoASM\ProjetoASM\callee.asm 15 1 ProjetoASM
和汇编代码:
PUBLIC hello_from_asm
EXTERN puts:PROC
.model flat
.data
msg db 'Hello, world!',0xa
len equ $ - msg
.code
hello_from_asm PROC
mov edx,len
mov ecx,msg
mov ebx,1
mov eax,4
int 0x80
mov eax,1
int 0x80
hello_from_asm ENDP
END
这应该输出一个“你好,世界!”,所以任何其他可能有效的想法都是受欢迎的
C完整性代码:
#include <stdio.h>
extern void hello_from_asm();
int main(){
printf("Hello from C");
hello_from_asm();
return 0;
}
#包括
extern void hello_from_asm();
int main(){
printf(“来自C的你好”);
你好,我是_asm();
返回0;
}
这些详细的MASM错误消息说明了一切
您需要使用MASM样式。上述指令尝试在32位寄存器中加载msg的第一个字节。这就是“大小不匹配”错误。您需要的是在
ECX
中加载msg的地址。使用
mov ecx, offset msg
其他错误可能是无法识别0x
十六进制前缀。尝试改用h
十六进制后缀。(0Ah
,80h
)
以上内容很容易更改,您的代码将很好地组装。但是不要运行它,因为
int 80h
指令是一个Linux系统调用,在Visual Studio 2012(Windows)上不起作用。打印“Hello World”的32位Visual Studio | Masm程序示例。我包括了最常见的指令。“legacy_stdio_definitions.lib”用于VS2015及更高版本,因为printf和scanf已更改为与C编译器的输出内联。VS2012可能不需要它
.686p ;enable instructions
.xmm ;enable instructions
.model flat,c ;use C naming convention (stdcall is default)
; include C libraries
includelib msvcrtd
includelib oldnames
includelib legacy_stdio_definitions.lib ;for scanf, printf, ...
.data ;initialized data
pfstr db "Hello world!",0dh,0ah,0
.data? ;uinitialized data
.stack 4096 ;stack (optional, linker will default)
.code ;code
extrn printf:near
public main
main proc
push offset pfstr ; 32-bit mode uses stack args
call printf
add esp,4 ; cdecl is caller-pops
xor eax,eax ; return 0
ret
main endp
end
int 0x80
是32位Linux系统cal ABI。作为本机Windows程序的一部分,这永远不会起作用。您从一些NASM示例复制的部分仍然使用NASM语法,这似乎是MASM所抱怨的。e、 g.我认为MASM不允许0xa
,只允许0aH
用于十六进制数字文本。在MASM中,mov-ecx,msg
表示mov-ecx,[msg]
。这并不重要,因为在Windows下,int0x80
只会出错,所以在ECX中是否有指针或4字节的ASCII数据并不重要。我认为重要的是,一旦你将其组装起来,它只会在int80h
上出错,因为这是Windows,而不是Linux。和mov ecx,msg
同样可以描述为试图加载msg
的前4个字节(基于表示操作数大小的寄存器),这就是为什么MASM会抱怨操作数大小不匹配的原因,因为symbol:db
还意味着引用该符号的操作数大小。printf
永远不是stdcall;它需要可变数量的参数。您上次的更改使评论错误/误导。是stdcall
也使用堆栈参数,但用于在32位模式下调用printf的调用约定是cdecl
stdcall
不会在通话后使用addesp,4
。@PeterCordes-我编辑了我的答案。我的困惑是由于64位模式调用约定,在这种情况下,printf的前两个参数在rcx和rdx中。我想可能会有一个32位的快速调用版本的printf,它可以在ecx和edx中使用它的前两个参数,尽管它可能会导致稍微慢一些的代码,因为在32位模式中没有那么多寄存器。哦,是的,不幸的是32位fastcall
被调用,所以它不能用于printf。(ISO C要求printf忽略格式字符串没有告诉它的额外未使用的参数)。64位调用约定是调用方pops,因此它可以用于可变函数,并且可以传递RCX、RDX、R8、R9中的前4个参数(如果它们是整数/指针)。@PeterCordes-更令人困惑的是VS2015和更高版本现在在C/C++编译代码中内联printf和scanf(如果输出C/C++生成的汇编代码,您可以看到这一点)。幸运的是,至少通过VS2019,遗留库仍然存在。
.686p ;enable instructions
.xmm ;enable instructions
.model flat,c ;use C naming convention (stdcall is default)
; include C libraries
includelib msvcrtd
includelib oldnames
includelib legacy_stdio_definitions.lib ;for scanf, printf, ...
.data ;initialized data
pfstr db "Hello world!",0dh,0ah,0
.data? ;uinitialized data
.stack 4096 ;stack (optional, linker will default)
.code ;code
extrn printf:near
public main
main proc
push offset pfstr ; 32-bit mode uses stack args
call printf
add esp,4 ; cdecl is caller-pops
xor eax,eax ; return 0
ret
main endp
end