这次来分享的是用masm32编写一个很简单的汇编程序来入门一下masm32,打算使用斐波拉切数列这个简单的小程序来作为例子讲述。自己学习masm32原因是,编译原理告诉我们编译器通过一系列骚操作把我们的代码翻译成机器识别的机器码,这一波操作中有一步是翻译成了汇编代码,为了了解编译器的骚操作,我们当然得先懂得手工翻译,所以来回忆一下大一暑假学的汇编,讲道理masm32写起来还是很方便的。吐槽一下,感觉写masm32遇到的问题在度娘上很难找到很切合你所需要的答案,更多的要靠自己去翻官方的教程以及安装的masm32包里给你的一些demo来探索。

可能很多人开始学汇编用的是在dos虚拟机编写的,然而我们选用masm32就是为了借助MASM32包对很多动态链接库支持的特点,使用的时候可以对库函数直接调用,免去自己与硬件/操作系统底层打交道实现的麻烦。我第一次看到masm32给的示例那一堆include、while、invoke的反应是:这TMD什么鬼的汇编程序,你觉得我会信吗!后来看了教程才慢慢入门,可以说如果你对汇编语言和高级语言都有所了解的话,使用起来至少思路上还是很畅通的,至于说遇到问题很难在各大论坛找到针对性的答案,还希望有经验的大佬们分享一些好的方式或资源。

言归正传,fibonacci的高级语言的程序我想大家闭着眼睛倒叙着都能写出来,以C++的为例:

main()
{
int a, b, i, t, n;
a = 0;
b = 1;
i = 1;
cin >> n;
cout << a << endl;
cout << b << endl;
while (i < n)
{
t = b;
b = a + b;
cout << b << endl;
a = t;
i = i + 1;
}
}

它的masm32下的汇编代码是什么样的呢,我是这样写的(文章在会最后给出详细的注释版本):

.486
.model flat, stdcalloption casemap:noneincludelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\masm32.libinclude \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\gdi32.inc
include \masm32\include\windows.inc
include \masm32\include\msvcrt.inc
include \masm32\include\masm32.inc
include \masm32\macros\macros.asm.datan dd 0a dd 0b dd 1i dd 1t dd 0
.code
start:mov eax, sval(input("Enter a number : "))mov n,eaxprint chr$("Fibonacci_number")print str$(1)print chr$(" is ")print str$(b)print chr$(" ",13,10)mov ecx,nmov i,ecxdec i.while imov eax,bmov t,eaxmov eax,badd eax,amov b,eaxprint chr$("Fibonacci_number")mov ecx,nsub ecx,iinc ecxprint str$(ecx)print chr$(" is ")print str$(b)print chr$(" ",13,10)mov eax,tmov a,eaxdec i.endwret
end start

这是使用input和print输入输出的汇编代码,一开始没找到他两,所以我先使用了百度查到的crt_scanf和crt_printf写出的代码(用crt_scanf输入数字还有一些问题没有解决,暂时用输入字符串然后减去0的ascii码的方式完成):

.486
.model flat, stdcall
option casemap:none
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\gdi32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\masm32.libinclude \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\gdi32.inc
include \masm32\include\windows.inc
include \masm32\include\msvcrt.inc
include \masm32\include\masm32.inc.dataszFmt db 'fibonacci_number=%d',13,10n dw 5a dw 0b dw 1i dw 1t dw 0szFmtIn db '%s',0szText  db ' ',0
.code
start:invoke crt_scanf, addr szFmtIn,addr szTextmov al,szTextsub al,48mov ah,0mov n,axinvoke crt_printf, addr szFmt,bmov cx,nmov i,cxdec i.while imov ax,bmov t,axmov ax,badd ax,amov b,axinvoke crt_printf, addr szFmt,bmov ax,tmov a,axdec i.endwinvoke ExitProcess, 0
end start

可以看到这段代码和以前我们编写的汇编程序主要区别在于
1.框架
2. Masm有一些伪高阶的语法来简便地创建条件和循环结构
3. Invoke简化了过程和call的使用
4.这里是输入输出调用现成的,可以预见很多在写汇编时常用的操作都被封装好了

当然还有一些像宏方面的优点我暂时还没用到就不说了。

现在具体来说说(参考masm32教程)

1.框架

开门见山,有屁快放道理我懂的

.486
.model flat, stdcalloption casemap:noneincludelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\gdi32.libinclude \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include \masm32\include\gdi32.inc
include \masm32\include\windows.inc.datayaoyaoyaoyao.codestart:zongzongzongzonghaihaihaihaiend start

这是Windows汇编源文件(.asm)的基本框架,逐个解释一下

.486
告诉汇编器应该生成486处理器(或更高)的伪代码。你可以使用.386,但大多数情况下用.486

.model flat, stdcall
使用平坦内存模式并使用stdcall调用习惯(stdcall的意思是函数的参数从右往左压入,即最后的参数最先压入,而且函数在结束时自己清栈),这对于几乎所有的Windows API函数和dll是标准

插嘴解释一下平坦内存模式,知道汇编语言的人一定知道段的概念,在16位编程中,段是必不可少的,但对段的各自操作都很乏味。这个问题已经在32位Windows(95及以上)中得到解决。你仍然有段,但不用管他们了,因为它们不再是64kb,而是4GB。你如果尝试着改变段寄存器中的一个,windows甚至会崩溃。这称为平坦(flat)内存模式。只有offset,而且是32位的,因而范围从0到4,294,967,295。内存中的每一个地址都是用offset表示的。这真是32位胜于16位的最大优点。所以,你现在可以忘了段寄存器并把精神集中在其他的寄存器上。

option casemap:none
控制字符的映射为大写。为了Windows.inc文件能正常工作,这个应该为”none”

includelib include
为了使用来自WindowsAPI的函数,你需要导入dll。这是由导入库(.lib)来完成的。这些库是必需的。因为它们使系统(Windows)能在内存的动态基地址处动态的载入dll。在Win32asm包中(win32asm.cjb.net)提供了大多数标准dll的库。你可以用masm的includelib语句装载一个库:

Includelib C:\masm32\lib\kernel32.lib

但你不只是需要包含库。包含文件(.inc)也是必须的。这些可以用l2inc工具由库文件自动生成。包含文件这样装载:

include \masm32\include\kernel32.inc 

这里有一个特别的包含文件。大多数的时候统称为Windows.inc,其中包含了用于Windows API的所有常量和结构的定义。

.data
定义各种变量
.code
写代码的地方

start:
end start
表示一个程序的开始的标签。它不是非得叫“start”。你可以使用任何和“end”语句后相同的标签。

2.条件和循环结构

是的,你可以像在C语言里if while的语句一样来在masm里用条件和循环语句,这会使你的汇编代码更加可读易懂。Masm为我们提供了许多的伪高阶的语法来简便地创建条件和循环结构:
.IF, .ELSE, .ELSEIF, .ENDIF
.REPEAT, .UNTIL
.WHILE, .ENDW, .BREAK
.CONTINUE

If语句
你不需要和一对跳转搅在一起了,只要一个.IF语句

.IF eax==1
;eax等于1
.ELSEIF eax==3
; eax等于3
.ELSE
; eax既不是1也不是3
.ENDIF 

你一定发现了美丽的==符号,是的在masm下一堆美丽的操作符也能使用了,==,!=,>,<,>=,<=,&,!,&&,||,而他们的作用想必大家也都知道。

Repeat语句
这个语句执行直到条件为真为止:

.REPEAT
;代码在此
.UNTIL eax==1 

这块代码反复执行repeat和until之间的代码,直到eax=1。

While语句
While是repeat语句的反转。它在条件为真时执行代码块:

.WHILE eax==1
;代码在此
.ENDW 

你可以使用.BREAK语句来跳出循环

.WHILE edx==1
inc eax
.IF eax==7
.BREAK
.ENDIF
.ENDW 

如果Eax==7,while循环将停止
continue指令使repeat或While跳过下面的代码块,重新执行循环。

3.Invoke语句

Invoke简化了过程和call的使用。

在汇编语言中一般的格式:

push parameter3
push parameter2
push parameter1
call procedure 

Invoke 格式:

invoke procedure, parameter1, parameter2, parameter3 

汇编后的代码是一模一样的,但invoke格式更简单而且更可靠。对一个过程使用invoke,你要这样定义prototype:

PROTO STDCALL testproc:DWORD, :DWORD, :DWORD 

声明了名为testproc,需三个DWORD大小的参数的过程。现在,如果你这么做

invoke testproc, 1, 2, 3, 4 ;这是错误的

masm会给你一个testproc过程需要三个参数而不是四个的错误。Masm还会做类型检查。它检查参数是否为正确的类型(即大小)
在一个invoke语句中,你可以用ADDR代替offset。这会使地址在汇编时是正确的。
过程这样定义:

testproc PROTO STDCALL :DWORD, :DWORD, :DWORD
.code
testproc proc param1:DWORD, param2:DWORD, param3:DWORD
ret
testproc endp 

这会创建一个名为testproc,带三个参数的过程。Prototype是用来调用过程的。

testproc PROTO STDCALL :DWORD, :DWORD, :DWORD
.code
testproc proc param1:DWORD, param2:DWORD, param3:DWORD
mov ecx, param1
mov edx, param2
mov eax, param3
add edx, eax
mul eax, ecx
ret
testproc endp 

现在,过程做了一下计算,(param1, param2, param3) = param1 * (param2 + param3).结果(返回值)存放在eax中,局部变量这样定义:

testproc proc param1:DWORD, param2:DWORD, param3:DWORD
LOCAL var1:DWORD
LOCAL var2:BYTE
mov ecx, param1
mov var2, cl
mov edx, param2
mov eax, param3
mov var1, eax
add edx, eax
mul eax, ecx
mov ebx, var1
.IF bl==var2
xor eax, eax
.ENDIF
ret
testproc endp 

你不可以在过程外使用这些变量。它们储存在栈中而且当过程返回时移出。

4.一堆封装好的库函数

就很优秀,没啥好说的具体要用什么函数百度一下或者查查手册吧


最后再解释一蛤

最后再针对自己写的fibonacci代码解释一波吧

data段没啥好说的,简洁明了赋初值,dd即dword是为了和后边eax的大小匹配
code段我们一句句分析

mov eax, sval(input("Enter a number : "))

应该很好看出格式,控制台输出引号中的话等待你输入,然后你键入的值被赋给eax寄存器

mov n,eax

从寄存器再给n(注意汇编里面不存在mov memory,memory这一操作,所以两变量赋值要经过寄存器)

print chr$("Fibonacci_number1")
print chr$(" is ")
print str$(b)
print chr$(" ",13,10)

输出第一个斐波拉切数,写的麻烦了点但大家应该都能读懂输出Fibonacci_number1 is 1换行(最后那个print是换行,相信知道汇编的都知道13,10的含义)

mov ecx,n
mov i,ecx
dec i

经过寄存器给循环计数的参数赋值

.while imov eax,bmov t,eaxmov eax,badd eax,amov b,eaxprint chr$("Fibonacci_number")mov ecx,nsub ecx,iinc ecxprint str$(ecx)print chr$(" is ")print str$(b)print chr$(" ",13,10)mov eax,tmov a,eaxdec i
.endw

这段循环语句也很简单,参照C++的代码翻译的,那么多print只是print用的不熟,不知道按这种格式输出的print怎么写在一句里,其他的mov add操作大家对照C++的代码就能明白了

Ret

没有这句话会让让你调试的

所以最后结果也很完美,用cmd运行masm生成的exe文件(如果直接双击exe文件输入后就会闪退,所以大家用cmd进入文件夹运行exe比较好):

什么?你问我怎么生成exe文件,那我就大发慈悲再告诉你一下:
打开masm32 editor,菜单栏点fileopen你的asm文件,然后菜单栏找到project下的console assemble&link,之后就能在asm文件所在目录找到同名exe文件啦

That’s all thank you

入门masm32编写简单汇编程序并做具体分析相关推荐

  1. 嵌入式入门实践——编写简单STM32程序

    嵌入式入门--编写简单STM32程序 目录 嵌入式入门--编写简单STM32程序 一.环境配置 1.安装前准备 2.安装流程 2.1安装keil 2.2破解keil5 2.3安装STM32pack 3 ...

  2. ubuntu系统下c语言helloworld入门以及编写简单程序

    文章目录 一.c语言helloworld入门 二.分别在ubuntu和windows系统下编写简单程序 (一)ubuntu系统下的简单主/子程序 (二)在windows系统下编写简单主/子程序 (三) ...

  3. ubuntu系统下c语言入门以及编写简单程序

    目录 一,hello world入门 二,在windows系统中编写简单程序 三,在ubuntu系统下用makefile方式编写程序 一,hello world入门 在linux操作系统中打开终端 1 ...

  4. 用python写一个彩票过滤器_python入门教程NO.6 用python做个简单的彩票号码统计分析工具...

    python入门教程 python入门教程NO.6 用python做个简单的彩票号码统计分析工具 本文涉及的python基础语法是:字典.集合及for循环 字典的定义 字典也是一种可变的容器,它可以存 ...

  5. 网络编程入门从未如此简单(一):假如你来设计网络,会怎么做?

    本文原题"如果让你来设计网络",有修订和改动,收录已征得作者同意,转载请联系作者.本文已同步发布于52im社区:http://www.52im.net/thread-3330-1- ...

  6. python写彩票预测软件_python入门教程NO.6 用python做个简单的彩票号码统计分析工具...

    python入门教程NO.6 用python做个简单的彩票号码统计分析工具-1.jpg (37.04 KB, 下载次数: 0) 2020-11-27 14:29 上传 python入门教程 pytho ...

  7. python做好的程序如何变成小程序-使用python编写简单的小程序编译成exe跑在win10上...

    每天的工作其实很无聊,早知道应该去IT公司闯荡的.最近的工作内容是每逢一个整点,从早7点到晚11点,去查一次客流数据,整理到表格中,上交给素未蒙面的上线,由他呈交领导查阅. 人的精力毕竟是有限的,所以 ...

  8. 如何:从Spring 4.0快速入门以构建简单的REST-Like API(演练)

    如何:从Spring 4.0快速入门以构建简单的REST-Like API(演练) 关于使用Spring MVC创建Web API的另一篇教程. 不太复杂. 只是一个演练. 生成的应用程序将提供简单的 ...

  9. 用Visual Studio 2008编写Win32汇编程序

    用Visual Studio 2008编写Win32汇编程序 Binhua Liu 本文分为以下三个部分: 1)用Visual Studio2008建立一个汇编控制台工程 2)汇编程序模板 3)汇编编 ...

  10. python程序-30分钟学会用Python编写简单程序

    原标题:30分钟学会用Python编写简单程序 参与文末每日话题讨论,赠送异步新书 异步图书君 学习目标 知道有序的软件开发过程的步骤. 了解遵循输入.处理.输出(IPO)模式的程序,并能够以简单的方 ...

最新文章

  1. 清空Python Shell 窗口的方法 - ClearWindow
  2. 【行为型模式】《大话设计模式》——读后感 (10)无尽加班何时休?——状态模式...
  3. EA(Enterprise Architect)UML修改字体大小
  4. Win10 UAP 绑定
  5. centos安装禅道的步骤
  6. 0622 - 如何坚守自己的价值观?
  7. 单例模式到Java内存模型
  8. Kafka 设计与原理详解(二)
  9. 微信修改步数 Android,安卓微信怎么改步数
  10. 深度学习检测视频马赛克
  11. python解压带密码的rar文件_Python实现加密的RAR文件解压的方法(密码已知)
  12. e4a 安卓获取ROOT权限的方法思路 转载
  13. 【TCP-IP详解卷1-协议】第一章 概述
  14. K_A11_008 基于STM32等单片机驱动SHT30和SHT31 串口与OLED0.96双显示
  15. u盘启动盘恢复计算机,U盘启动盘怎么恢复正常普通U盘?
  16. 后台缓存收回进程无法释放上下文[/BUSINESS的缓存的[10]%-请考虑增加缓存的最大大小
  17. Hutool-crypto加密工具
  18. 内涵段子爬取及re匹配
  19. 如何把一个整数转换成二进制
  20. Java学习-SpringBoot

热门文章

  1. bt 与 ed2k 区别
  2. word参考文献的引用
  3. tp5 点击刷新验证码
  4. caffe c++实战:通过训练好的模型对人脸图像进行特征提取(单张图像)
  5. python数据分析之朴素贝叶斯实践
  6. 推荐好轮子【Echarts数据可视化】图表插件 兼容ie6、7、8
  7. 贝叶斯(Bayes)决策理论
  8. 5G通信演进和常见名词释义
  9. 宽带波形测试软件,适用于5G时代的波形测试分析系统是怎样的? - 全文
  10. 【渝粤题库】陕西师范大学201821 宋词研究 作业(专升本)