用汇编语言编写一个小程序(比如hello,word!)请懂的人帮忙提供源码

用汇编语言编写一个小程序(比如hello,word!)请懂的人帮忙提供源码,第1张

您正在看的汇编语言是:hello,world!win32汇编小程序

首先我们看一个“复杂”的Win32汇编程序

程序用来显示一个消息框

--------------------------------------------------

文件名:3.asm

.386

.model flat ,stdcall

NULLequ 0

MB_OK equ 0

ExitProcess PROTO :Dword

MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:Dword

includelib kernel32.lib

includelib user32.lib

.data

szTextdb "Hello, world!",0

szCaption db "Win32Asm",0

.code

start:

push MB_OK

lea eax,szCaption

push eax

lea eax,szText

push eax

push NULL

call messageboxa

xor eax,eax

push eax

call exitprocess

end start

--------------------------------------------------

编译链接:

分下面两步进行:

ml /c /coff 3.asm

link /subsystem:Windows /libpath:d:\masm7\lib 3.obj

第一步编译生成3.obj文件

/c 表示只编译,不链接

/coff 表示生成COFF格式的目标文件

第二步链接生成3.exe文件

/subsystem:windows 表示生成Windows文件

/libpath:d:\masm7\lib 表示引入库的路径为:d:\masm7\lib。

在安装Masm32后,引入库位于Masm32\Lib目录下。

也可设置环境变量Lib的值:在dos提示符下键入Set Lib=d:\masm7\lib,这样“链接”就可简单写成:

link /subsystem:Windows 3.obj,试想一下,在程序调试过程中,修改源程序是常用的事啦,每次编译链接都要带/libpath:...那该有多烦人呢。当然,我们也可在源程序中直接给出引入库的位置,这样,链接时就方便啦,如下:

includelib d:\masm7\lib\kernel32.lib

includelib d:\masm7\lib\user32.lib

--------------------------------------------------

执行:在dos提示符下键入3,回车,出现一个消息框,哈哈,真正的Win32程序!

--------------------------------------------------

深入分析:

看一下源程序,有这么两行:call messageboxa\call exitprocess。大家一看都知道,这是子程序调用,但是我们并没写这样的子程序,事实上,这些是API函数。作为函数,我们在调用时可能需要传送给函数一些参数,程序怎么知道传送的参数有哪些,类型是什么呢?就是通过函数原型定义,如下所示:

ExitProcess PROTO :Dword

MessageBoxA PROTO :DWORD,:DWORD,:DWORD,:Dword

可以看出,ExitProcess有一个参数,MessageBoxA有四个参数,这些参数都是Dword类型。

在Win32中,参数的传递都是通过堆栈来完成的。象MessageBoxA这个函数有四个参数,究竟是左边的先压入堆栈还是右边的先入栈呢?.model flat,stdcall给出了答案。stdcall 指定参数是从右到左压入堆栈的,且调整堆栈是在子程序返回时完成的。在源程序中不需要用“add sp,值”来保持堆栈平衡。对MessageBox,在API手册中是这样定义的:

int MessageBox(

HWND hWnd, // handle of owner window

LPCTSTR lpText, // address of text in message box

LPCTSTR lpCaption, // address of title of message box

UINT uType&n

您正在看的汇编语言是:hello,world!win32汇编小程序。

bsp// style of message box

)

所以会有我们的程序段:

push MB_OK

lea eax,szCaption

push eax

lea eax,szText

push eax

push NULL

call messageboxa

看看上面的程序,不难想到,假如在写程序时,少往堆栈里压入一个数据,那将是一个致命的错误。能不能将这种检查参数个数是否匹配的工作交给计算机来完成呢?这是可以的,INVOKE指令可以帮助我们完成这样的工作。假如你的参数个数不正确,连接器将给出错误提示。所以,极力建议你使用invoke代替call来调用子程序,当然,这不是绝对的。使用invoke上面的指令就可简写成下面的样子,看起来简炼多啦,查错也方便啦!

invoke messageboxa, NULL,addr szText,addr szCaption,MB_OK

另外,像NULL,MB_OK都是一些常量,这样的常量有很多,还有很多的结构,如果在我们的程序中一开始都写这么多的东西,可能一下子就把你吓怕啦,也容易出错,更不便于看程序的主要部分。hutch整理的Windows.inc包含了WIN32编程所需要的常量和结构体的定义,我们可简单的用一个include指令将这些常量和结构的定义插入到我们的文件中:

include d:\masm32\include\Windows.inc

但是Windows.inc中并不包含函数原型的声明,还要从其他的头文件中得到函数原型的声明,比如:messageboxa的原型声明在user32.inc文件中,exitprocess在kernel32.inc文件中。这些头文件都放在 \masm32\include文件夹下。

还有,要用Windows.inc,必须使用option casemap:none,它的意思是告诉 MASM 要区分符号的大小写,譬如:start和START是不一样的。否则,一个小小的程序,可能会出成百上千的错误呀!

其他的,就不再细说啦,到此,上面的程序可重新修改如下:

-----------------------------------------------------------------

最终的结果

.386表示要用到386指令

.model flat,stdcall 32位程序,要用flat啦!stadcall,标准调用

option casemap:none 区别大小写

includeWindows.inc 包括常量及结构定义

includekernel32.inc 函数原型声明

includeuser32.inc

includelib kernel32.lib 用到的引入库

includelib user32.lib

.data数据区,定义2个字符串

szTextdb "Hello, world!",0

szCaption db "Win32Asm",0

.code 代码开始执行处

start:

invoke MessageBox,NULL,addr szText,addr szCaption,MB_OK

调用MessageBoxAPI函数

invoke ExitProcess,NULL 程序退出

end start结束

------------------------------------

编译链接:

ml /c /coff /I d:\masm7\include 3.asm 注意开关符识别大小写

link /subsystem:Windows /libpath:d:\masm7\lib 3.obj

/I d:\masm7\include 表示*.inc文件的位置,也可设置环境变量Set include=d:\masm7\include来简化 *** 作,也可在程序中明确指出*.inc的位置。

前面讲的都是用两条指令来完成编译链接,实际上用一条指令也可完成,如下:

ml /coff /I d:\masm7\include 3.asm /link /subsystem:Windows /libpath:lib

若*.inc及引入库在源程序中都明确指出其位置,则可简化为:

ml /coff 3.asm /link /subsystem:

这个还不简单#include<stdio.h>void main(){ float a,b,c,s/*定义数据类型,数据初始化*/s=(a*b+c)/a/*计算并把计算结果赋值给s*/printf("s=%f\n",s)/*输出计算结果*/}

本程序在MASMPlus 1.2集成环境下通过编译,经过调试,运行正确。

Data Segment

Buffer db 20,23,-69,-89,35,-46,57,-68,79,-51,-81,98,-43,56,-67,123,-98,102,-87,165,156

posAmount db ? 正数个数

negAmount db ? 负数个数

Pos_Prompt db 'The positive numbers: $'

Neg_Prompt db 13,10,'The negative numbers: $'

Press_Key db13,10,13,10,'The complated. Press any key to exit...$'

Data ends

Code Segment

Assume CS:Code,DS:Data

-------------------------------------

功能:显示指定地址(Str_Addr)的字符串

入口:

Str_Addr=字符串地址(要求在数据段)

用法: Output Str_Addr

用法举例:Output PromptStr

Output MACRO Str_Addr

lea dx,Str_Addr

mov ah,9

int 21h

EndM

-------------------------------------

功能:把AX中的二进制无符号数转换成显式的十进制ASCII码,并送显示屏显示

入口:AX=二进制数

出口:在当前光标位置显示转换后的ASCII码数字

Dec_ASCII Proc Near

push ds

push cs

pop ds

push cs

pop es

push dx

push bx

push di

mov bx,10

lea di,@@Temp_Save[6]

mov BYTE ptr [di],'$'

dec di

cld

@@Divide: xor dx,dx

div bx

or dl,30h

mov [di],dl

dec di

test ax,0ffffh

jnz @@Divide

inc di

push di

pop dx

mov ah,9

int 21h

pop di

pop bx

pop dx

pop ds

ret

@@Temp_Save db 7 dup(?)

Dec_ASCII EndP

-------------------------------------

Start:mov ax,Data

mov ds,ax

lea si,Buffer 取数组变量地址

cld

lodsb 读入数组元素个数

xor ah,ah

mov cx,ax 元素个数

Statics: lodsb 读入一个元素

test al,80h 是否正数?

jnz Neg_Count 不是

inc posAmount 是,正数计数

jmp Next_One

Neg_Count: inc negAmount 负数计数

Next_One: loop Statics

Output Pos_Prompt 提示显示正数个数

mov al,posAmount

xor ah,ah

call Dec_ASCII 把AX中的二进制无符号数转换成显式的十进制ASCII码,并送显示屏显示

Output Neg_Prompt 提示显示负数个数

mov al,negAmount

xor ah,ah

call Dec_ASCII

Exit_Proc: Output Press_Key 提示 *** 作完成,按任意键结束程序

mov ah,1

int 21h

mov ah,4ch 结束程序

int 21h

Code ENDS

END Start 编译到此结束


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/11479960.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-16
下一篇 2023-05-16

发表评论

登录后才能评论

评论列表(0条)

保存