第4章汇编语言程序设计_第1页
第4章汇编语言程序设计_第2页
第4章汇编语言程序设计_第3页
第4章汇编语言程序设计_第4页
第4章汇编语言程序设计_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第4章汇编语言程序设计4.1分支程序结构4.2循环程序结构 4.3子程序结构4.4Windows应用程序编程4.5与C++语言的混合编程本章内容4.1分支程序结构4.2循环程序结构 4.3子程序结构4.4Windows应用程序编程4.5与C++语言的混合编程本章内容4.1分支程序结构改变程序执行顺序、形成分支、循环、调用等程序结构是很常见的程序设计问题高级语言采用IF等语句表达条件,并根据条件是否成立转向不同的程序分支汇编语言需要首先利用比较CMP、测试TEST、加减运算、逻辑运算等影响状态标志的指令形成条件然后利用条件转移指令判断由标志表达的条件,并根据标志状态控制程序转移到不同的程序段4.1.1无条件转移指令程序代码在代码段CS:指明代码段在主存中的段基地址EIP:给出将要执行指令的偏移地址当程序顺序执行,处理器根据被执行指令的字节长度自动增加EIP当程序控制转移,EIP随之改变当程序转移到另外的代码段,EIP和CS都改变控制转移类指令:改变EIP(有些也改变CS),即改变程序执行顺序(实现程序控制转移)的指令1.转移范围段内转移在当前代码段范围内的程序转移不需更改CS,只要改变EIP(偏移地址)近转移(Near):32位近转移NEAR32,16位近转移NEAR16短转移(Short):转移范围在127~-128字节段间转移从当前代码段跳转到另一个代码段需要更改CS(段地址)和EIP(偏移地址)远转移(Far):48位远转移FAR32,32位远转移FAR162.指令寻址方式相对寻址方式指令代码提供目标地址相对于当前指令指针EIP的位移量目标地址(转移后的EIP)=当前EIP+位移量相对寻址都是段内转移,最常用、最灵活直接寻址方式指令代码直接提供目标地址目标地址(转移后的CS和EIP)=指令操作数间接寻址方式指令代码指示寄存器或存储单元目标地址来自寄存器或存储单元、间接获得寄存器间接寻址:用寄存器保存目标地址存储器间接寻址:用存储单元保存目标地址目标地址=目的地址=转移地址3.JMP指令无条件转移:无任何先决条件就能使程序改变执行顺序JMP指令相当于高级语言的goto语句

JMPlabel ;程序转向label标号指定的地址

;段内相对寻址,段间直接寻址

JMPreg32/reg16 ;程序转向寄存器指定的地址

;寄存器间接寻址

JMPmem48/mem32/mem16 ;程序转向存储单元指定的地址

;存储器间接寻址JMP指令的4种类型1.段内转移、相对寻址标号指明目标地址,指令代码包含位移量2.段内转移、间接寻址通用寄存器或主存单元包含目标指令偏移地址3.段间转移、直接寻址标号包含目标指令的段地址和偏移地址4.段间转移、间接寻址32位段用3字存储单元包含目标地址16位段用双字存储单元包含目标地址MASM会根据存储模式等信息自动识别〔例4-1〕无条件转移程序-1

;数据段00000000 00000000nvar dword?

;代码段00000000 EB01 jmplabl1 ;相对寻址00000002 90

nop00000003 E900000001labl1: jmpnearptrlabl2 ;相对近转移00000008 90

nop00000009 B800000011Rlabl2: moveax,offsetlabl3

〔例4-1〕无条件转移程序-20000000E FFE0

jmpeax ;寄存器间接寻址00000010 90

nop00000011 B800000022Rlabl3: moveax,offsetlabl400000016 A300000000R

movnvar,eax0000001B FF2500000000R

jmpnvar ;存储器间接寻址00000021 90

noplabl4:

movebx,offsetnvarjmpnearptr[ebx];数据的寄存器间接寻址数据的存储器直接寻址4.1.2条件转移指令根据指定的条件确定程序是否发生转移

Jcclabel ;条件满足,发生转移;否则,顺序执行下条指令LABEL表示目标地址,采用段内相对寻址32位IA-32处理器:达到32位的全偏移量16位80x86处理器:-128~+127间的短转移条件转移指令不影响标志,但要利用标志cc表示利用标志判断的条件,16种、两类单个标志状态作为条件两数大小关系作为条件转移条件cc:单个标志状态JZ/JE

ZF=1 JumpifZero/EqualJNZ/JNE

ZF=0 JumpifNotZero/NotEqualJS

SF=1 JumpifSignJNS

SF=0 JumpifNotSignJP/JPE

PF=1 JumpifParity/ParityEvenJNP/JPO

PF=0 JumpifNotParity/ParityOddJO

OF=1 JumpifOverflowJNO

OF=0 JumpifNotOverflowJC

CF=1 JumpifCarryJNC

CF=0 JumpifNotCarry多个助记符方便记忆转移条件cc:两数大小关系JB/JNAE

CF=1 JumpifBelow/NotAboveorEqualJNB/JAE

CF=0 JumpifNotBelow/AboveorEqualJBE/JNA

CF=1或ZF=1 JumpifBelow/NotAboveJNBE/JA

CF=0且ZF=0 JumpifNotBeloworEqual/AboveJL/JNGE

SF≠OF JumpifLess/NotGreaterorEqualJNL/JGE

SF=OF JumpifNotLess/GreaterorEqualJLE/JNG

SF≠OF或ZF=1 JumpifLessorEqual/NotGreaterJNLE/JG

SF=OF且ZF=0 JumpifNotLessorEqual/Greater1.单个标志状态作为条件的条件转移指令JZ(JE)和JNZ(JNE):利用零位标志ZF判断结果是零(相等)还是非零(不等)JS和JNS:利用符号标志SF判断结果是负还是正JO和JNO:利用溢出标志OF判断结果是溢出还是没有溢出JP(JPE)和JNP(JPO):利用奇偶标志PF判断结果低字节“1”的个数是偶数还是奇数JC和JNC:利用进位标志CF判断结果是有进位(为1)还是无进位(为0)〔例4-2〕个数折半程序-1

moveax,885 ;假设一个数据

shreax,1 ;数据右移进行折半

jncgoeven ;余数为0,即CF=0条件成立,转移

addeax,1 ;否则余数为1,即CF=1,进行加1操作goeven: calldispuid ;显示结果

443运行结果〔例4-2〕个数折半程序-2

moveax,886 ;假设一个数据

shreax,1 ;数据右移进行折半

jcgoodd ;余数为1,即CF=1条件成立,转移到分支体,进行加1操作

jmpgoeven ;余数为0,即CF=0,不需要处理,转移到显示!goodd: addeax,1 ;进行加1操作goeven: calldispuid ;显示结果jncgoeven何不合二为一?〔例4-2〕个数折半程序-3

moveax,887 ;假设一个数据

shreax,1 ;数据右移进行折半

adceax,0 ;余数=CF=1,进行加1操作 ;余数=CF=0,没有加1

calldispuid ;显示结果

moveax,888 ;假设一个数据

addeax,1 ;个数加1

rcreax,1 ;数据右移进行折半

calldispuid ;显示结果改进算法消除分支〔例4-3〕位测试程序-1

;数据段no_msg byte'NotReady!',0yes_msg byte'ReadytoGo!',0 ;代码段

moveax,56h ;假设一个数据

testeax,02h ;测试D1位(D1=1,其他位为0)

jznom ;D1=0条件成立,转移

moveax,offsetyes_msg ;D1=1,显示准备好

jmpdone ;跳转过另一个分支体!nom: moveax,offsetno_msg ;显示没有准备好done: calldispmsg〔例4-3〕位测试程序-2

;数据段no_msg byte'NotReady!',0yes_msg byte'ReadytoGo!',0 ;代码段

moveax,56h ;假设一个数据

testeax,02h ;测试D1位(D1=1,其他位为0)

jnzyesm ;D1=1条件成立,转移

moveax,offsetno_msg ;D1=0,显示没有准备好

jmpdone ;跳转过另一个分支体!yesm: moveax,offsetyes_msg ;显示准备好done: calldispmsg〔例4-4〕奇校验程序

callreadc ;键盘输入,AL=返回值

calldispcrlf ;回车换行(用于分隔)

calldispbb ;以二进制形式显示数据

calldispcrlf ;回车换行(用于分隔)

andal,7fh ;最高位置“0”、其他位不变

;同时标志PF反映“1”的个数

jnpnext ;个数为奇数,不需处理,转移

oral,80h ;个数为偶数,最高位置“1”、其他位不变next: calldispbb ;显示含校验位的数据2.两数大小关系作为条件的条件转移指令无符号数用高(Above)、低(Below)低于(不高于等于):JB(JNAE)不低于(高于等于):JNB(JAE)低于等于(不高于):JBE(JNA)不低于等于(高于):JNBE(JA)有符号数用大(Greater)、小(Less)小于(不大于等于):JL(JNGE)不小于(大于等于):JNL(JGE)小于等于(不大于):JLE(JNG)不小于等于(大于):JNLE(JG)〔例4-5〕数据比较程序-1

;数据段in_msg1 byte'Enteranumber:',0in_msg2 byte'Enteranothernumber:',0out_msg1 byte'Twonumbersareequal:',0out_msg2 byte'Thelessnumberis:',0out_msg3 byte13,10,'Thegreaternumberis:',0

;代码段

moveax,offsetin_msg1 ;提示输入

calldispmsg callreadsid ;输入第一个数据

movebx,eax ;保存到EBX

moveax,offsetin_msg2 ;提示输入

calldispmsg callreadsid ;输入第二个数据

movecx,eax ;保存到ECX〔例4-5〕数据比较程序-2

cmpebx,ecx ;二个数据进行比较

jnenequal ;两数不相等,转移

moveax,offsetout_msg1

calldispmsg ;显示两数相等

moveax,ebx calldispsid ;显示相等的数据

jmpdone ;转移到结束nequal: jlfirst ;EBX较小,不需要交换,转移

xchgebx,ecx ;EBX保存较小数,ECX保存较大数〔例4-5〕数据比较程序-3first: moveax,offsetout_msg2 ;显示较小数

calldispmsg moveax,ebx ;较小数在EBX中

calldispsid moveax,offsetout_msg3 ;显示较大数

calldispmsg

moveax,ecx ;较大数在ECX中

calldispsiddone:4.1.3单分支结构单分支程序结构只有一个分支的程序类似高级语言的IF-THEN语句结构注意采用正确的条件转移指令当条件满足(成立),发生转移,跳过分支体条件不满足,顺序向下执行分支体条件转移指令与高级语言的IF语句正好相反IF语句是条件成立,执行分支体〔例4-6〕求绝对值程序

;代码段

callreadsid ;输入一个有符号数,从EAX返回值

cmpeax,0 ;比较EAX与0

jgenonneg ;条件满足:EAX≥0,转移

negeax ;条件不满足:EAX<0,为负数

;需求补得正值nonneg: calldispuid ;分支结束,显示结果单分支结构的流程图negeax〔例4-7〕字母判断程序

callreadc ;输入一个字符,从AL返回值

cmpal,'A’ ;与大写字母A比较

jbdone ;比大写字母A小,不是大写字母,转移

cmpal,'Z’ ;与大写字母Z比较

jadone ;比大写字母Z大,不是大写字母,转移

oral,20h ;转换为小写

calldispcrlf ;回车换行

calldispc ;显示小写字母done:

4.1.4双分支结构双分支程序结构有两个分支,条件为真执行一个分支;条件为假,执行另一个分支相当于高级语言的IF-THEN-ELSE语句顺序执行的分支体1最后一定要有一条JMP指令跳过分支体2JMP指令必不可少,实现结束前一个分支回到共同的出口作用双分支结构有时可以改变为单分支结构事先执行其中一个分支(选择出现概率较高的分支)〔例4-8〕显示数据最高位程序-1

;数据段dvar dword0bd630422h ;假设一个数据

;代码段

movebx,dvar shlebx,1 ;EBX最高位移入CF标志

jcone ;CF=1,即最高位为1,转移

moval,'0' ;CF=0,即最高位为0:AL←'0'

jmptwo ;一定要跳过另一个分支one: moval,'1' ;AL←'1'two: calldispc ;显示

双分支结构双分支结构的流程图〔例4-8〕显示数据最高位程序-2

movebx,dvar moval,'0' ;假设最高位为0:AL←'0'

shlebx,1 ;EBX最高位移入CF标志

jnctwo ;CF=0,即最高位为0,转移

moval,'1' ;CF=1,即最高位为1,AL←'1'two: calldispc ;显示单分支结构〔例4-9〕有符号数运算溢出程序

;数据段dvar1 dword1234567890 ;假设两个数据dvar2 dword-999999999dvar3 dword?okmsg byte'Correct!',0 ;正确信息errmsg byte'ERROR!Overflow!',0 ;错误信息

;代码段

moveax,dvar1 subeax,dvar2 ;求差

joerror ;有溢出,转移

movdvar3,eax ;无溢出,保存差值

moveax,offsetokmsg ;显示正确

jmpdisperror: moveax,offseterrmsg ;显示错误disp: calldispmsg

4.1分支程序结构4.2循环程序结构

4.3子程序结构4.4Windows应用程序编程4.5与C++语言的混合编程本章内容4.2循环程序结构三个部分组成:循环初始——为开始循环准备必要的条件,如循环次数、循环体需要的初始值等;循环体——重复执行的程序代码,其中包括对循环条件的修改等;循环控制——判断循环条件是否成立,决定是否继续循环“先判断、后循环”的循环程序结构对应高级语言的WHILE语句“先循环、后判断”的循环程序结构对应高级语言的DO语句循环程序结构的流程图4.2.1循环指令

LOOPlabel;ECX←ECX-1;若ECX≠0,循环到LABEL;否则,顺序执行

JECXZlabel;ECX=0,转移;否则顺序执行目标地址采用相对短转移实地址存储模型使用CX作为计数器DECECXJNZlabelCMPECX,0JZlabel〔例4-10〕数组求和程序

movecx,lengthofarray ;ECX=数组元素个数

xoreax,eax ;求和初值为0

movebx,eax ;数组指针为0again: addeax,array[ebx*(typearray)];求和

incebx ;指向下一个数组元素

loopagain movsum,eax ;保存结果

calldispsid ;显示结果循环体循环控制循环初始4.2.2计数控制循环通过次数控制循环利用LOOP指令属于计数控制常见是“先循环、后判断”循环结构计数可以减量进行,即减到0结束计数可以增量进行,即达到规定值结束循环程序结构的关键是如何控制循环〔例4-11〕简单加密解密程序4.2.3条件控制循环复杂的循环程序结构需要利用条件转移指令,根据条件决定是否进行循环,这就是所谓的条件循环控制。计数控制循环往往至少执行一次循环体之后,才判断次数是否为0,即所谓的“先循环,后判断”循环结构。条件控制循环更多见的是“先判断,后循环”结构〔例4-12〕字符个数统计程序 ;数据段string byte‘DoyouhavefunwithAssembly?’,0 ;以0结尾的字符串 ;代码段

xorebx,ebx ;EBX用于记录字符个数,也用于指向字符的指针again: moval,string[ebx] cmpal,0;用指令“testal,al”更好

jzdone incebx ;个数加1

jmpagain ;继续循环done: moveax,ebx ;显示个数

calldispuid字符剔除程序课后练习4.1分支程序结构4.2循环程序结构 4.3子程序结构4.4Windows应用程序编程4.5与C++语言的混合编程本章内容4.3子程序结构经常用到的应用问题编写成一个通用子程序大型处理过程分解成能够解决的模块使用子程序可以使程序的结构更为清楚程序的维护更为方便有利于大程序开发时的多个程序员分工合作子程序(Subroutine)=函数(Function)=过程(Procedure)4.3.1子程序指令子程序:与主程序分开的、完成特定功能的一段程序当主程序(调用程序)执行调用指令CALL调用子程序子程序(被调用程序)执行返回指令RET返回主程序CALLlabel主程序RET子程序回到CALL指令后的指令处1.子程序调用指令CALLCALL指令用在主程序中,实现子程序的调用分成段内调用(近调用)和段间调用(远调用)目标地址采用相对寻址、直接寻址或间接寻址入栈返回地址:将CALL下条指令的地址压入堆栈

CALLlabel ;调用标号指定的子程序

CALLreg16/reg32

;调用寄存器指定地址的子程序

CALLmem16/mem32/mem48 ;调用存储单元指定地址的子程序2.子程序返回指令RETRET指令用在子程序结束,实现返回主程序

RET

;无参数返回:出栈返回地址

RETi16 ;有参数返回:出栈返回地址

;ESP←ESP+i16MASM会根据存储模型等信息确定子程序的远近调用,并相应产生返回指令3.过程定义伪指令MASM利用过程定义伪指令获得子程序信息

过程名 PROC

…… ;过程体

过程名 ENDP

;过程名为符合语法的标识符PROC后面可加参数:NEAR或FAR简化段定义源程序格式中,通常不需指定过程属性,采用默认属性即可〔例4-14〕子程序调用程序-1

;代码段,主程序00000000 B800000001 moveax,100000005 BD00000005 movebp,50000000A E800000016 callsubp ;子程序调用0000000F B900000003

retp1: movecx,300000014 BA00000004retp2: movedx,400000019 E800000000E

calldisprd〔例4-14〕子程序调用程序-2 ;子程序subp proc ;过程定义,过程名为subp

pushebp movebp,esp movesi,[ebp+4] ;ESI=CALL下条指令(标号RETP1)偏移地址

movedi,offsetretp2 ;EDI=标号RETP2的偏移地址

movebx,2 popebp ;弹出堆栈,保持堆栈平衡

ret ;子程序返回subp endp ;过程结束MOV[EBP+4],EDI?子程序调用的堆栈4.3.2子程序设计子程序的编写方法与主程序一样但需要留意几个问题:利用过程定义,获得子程序名和调用属性RET指令返回主程序,CALL指令调用子程序压入和弹出操作要成对使用,保持堆栈平衡开始保护寄存器,返回前相应恢复安排在代码段的主程序之外子程序允许嵌套和递归最好有完整的注释难点是参数传递回车换行子程序DPCRLFdpcrlf proc ;回车换行子程序

pusheax ;保护寄存器

moval,0dh ;输出回车字符

calldispc ;子程序中调用子程序,实现子程序嵌套

moval,0ah ;输出换行字符

calldispc ;子程序中调用子程序,实现子程序嵌套

popeax ;恢复寄存器

ret ;子程序返回dpcrlf endp4.3.3参数传递主程序与子程序间通过参数传递建立联系入口参数(输入参数):主程序→子程序出口参数(输出参数):子程序→主程序传递参数的多少反映程序模块间的耦合程度参数的具体内容数据本身(传递数值)数据的存储地址(传递地址,传递引用)参数传递方法寄存器变量堆栈1.寄存器传递参数最简单和常用的参数传递方法把参数存于约定的寄存器少量数据直接传递数值大量数据只能传递地址带有出口参数的寄存器不能保护和恢复带有入口参数的寄存器可以保护、也可以不保护,但最好能够保持一致〔例4-15〕十六进制显示程序-1

moveax,1234abcdh ;假设一个数据

xorebx,ebx movecx,8 ;8位十六进制数again: roleax,4 ;高4位循环移位进入低4位

pusheax ;movedx,eax callhtoasc ;调用子程序

movregd+4[ebx],al ;保存转换后的ASCII码

popeax ;moveax,edx incebx dececx jnzagain moveax,offsetregd calldispmsg ;显示regdbyte'EAX=',8dup(0),'H',0〔例4-15〕十六进制显示程序-2

;子程序htoasc proc;将AL低4位表达的一位十六进制数转换为ASCII码

andal,0fh ;只取AL的低4位

oral,30h ;AL高4位变成3

cmpal,39h ;是0~9,还是A~F

jbehtoend addal,7 ;是A~F,ASCII码再加上7htoend: ret ;子程序返回htoasc endp2.共享变量传递参数子程序和主程序使用同一个变量名存取数据就是利用共享变量(全局变量)进行参数传递如果变量定义和使用不在同一个程序模块中,需要利用PUBLIC、EXTREN声明利用共享变量传递参数,子程序的通用性较差特点:特别适合在多个程序段间、尤其在不同的程序模块间传递数据〔例4-17〕二进制输入程序3.堆栈传递参数传递传输还可以通过堆栈这个临时存储区主程序将入口参数压入堆栈,子程序从堆栈中取出参数出口参数通常不使用堆栈传递高级语言堆栈高级语言进行函数调用时提供的参数,实质也利用堆栈传递的,高级语言还利用堆栈创建局部变量。采用堆栈传递参数是程式化的,它是编译程序处理参数传递、以及汇编语言与高级语言混合编程时的常规方法保存参数和局部变量的堆栈区域称为堆栈帧(StackFrame),他在函数调用时建立,返回后消失。〔例4-19〕计算有符号数平均值程序利用堆栈传递参数返回4.3.4程序模块程序分段、子程序等是进行程序模块化开发大型程序时采用的方法子程序模块子程序库库文件包含宏汇编源文件包含4.1分支程序结构4.2循环程序结构 4.3子程序结构4.4Windows应用程序编程(自学)4.5与C++语言的混合编程(自学)本章内容4.1分支程序结构4.2循环程序结构 4.3子程序结构4.4Windows应用程序编程4.5与C++语言的混合编程本章内容4.4Windows应用程序编程汇编语言可以编写32位Windows应用程序调用Windows的应用程序接口API运行于Windows操作系统平台可以利用Windows的高级特性,生成的可执行文件相对较小、性能更高从更深层次理解Windows运行机制及程序设计思想4.4.1操作系统函数调用操作系统以其提供的系统函数(系统功能Systemfunction)支持程序员进行编程Windows的系统函数(功能)以动态连接库DLL(Dynamic-LinkLibrary)形式提供,利用其应用程序接口API(ApplicationProgramInterface)调用DDL库中的函数API是一些类型、常量和函数的集合,提供了编程中使用库函数的途径Win16:16位Windows的APIWin32:32位Windows的API1.动态连接库静态连接:连接程序从库文件中抽取需要的子程序插入到最终的可执行代码中动态连接:程序运行时才将代码加载到主存动态连接库:保存程序运行时需要重复使用的代码的文件3个最重要的Windows动态连接库KERNEL32.DLL:主要处理内存管理和进程调度USER32.DLL:主要控制用户界面GDI32.DLL:负责图形方面的操作导入库(ImportLibrary):程序开发的连接阶段使用,与一个动态连接库DLL对应2.MASM的高级语言特性条件控制伪指令:.IF.ELSEIF.ELSE.ENDIF流程控制伪指令:.WHILE.ENDW.REPEAT.UNTIL.REPEAT.UNTILCXZ.BREAK.CONTINUE过程声明伪指令PROTO:事先声明过程的结构 (包括操作系统API函数、高级语言的函数) 过程名 PROTO [调用距离][语言类型] [,参数∶[类型]]...过程调用伪指令INVOKE:实现过程调用

INVOKE 过程名[,参数,...]3.程序退出函数Win32程序员参考手册VOIDExitProcess(UINTuExitCode //exitcodeforallthreads);汇编语言声明ExitProcessPROTO,:DWORD汇编语言调用invoke

ExitProcess,0将函数调用定义成宏exit MACROdwexitcode

invokeExitProcess,dwexitcode

ENDM宏调用exit 04.4.2控制台应用程序Windows应用程序开始运行创建控制台(Console)窗口或创建图形界面窗口32位Windows控制台程序像增强版的MS-DOS程序使用标准控制台

标准输入设备(键盘)

标准输出设备(显示器)32位控制台程序运行在保护方式通过API使用Windows的动态链接库函数1.处理器识别指令CPUID返回处理器特征信息的指令当EAX=0时执行CPUID指令EAX返回CPUID指令中能够赋给EAX的最大值EBX、EDX和ECX返回生产厂商的标识串GenuineIntel利用这个厂商标识串,确认是Intel公司处理器当EAX=1或2等值时执行CPUID指令返回处理器更详细的识别信息例如处理器型号、支持的指令集等〔例4-21〕处理器识别程序-1

.686 .modelflat,stdcall optioncasemap:none

includelibbin\kernel32.libExitProcess proto,:DWORDGetStdHandle proto,:DWORDWriteConsoleA\proto,:DWORD,:DWORD,:DWORD,:DWORD,:DWORDWriteConsole equ<WriteConsoleA>STD_OUTPUT_HANDLE=-11 .dataouthandle dword?outbuffer byte'TheprocessorvendorIDis' byte12dup(0)outbufsize =sizeofoutbufferoutsize dword?控制台句柄控制台输出〔例4-21〕处理器识别程序-2 .codestart: moveax,0 cpuid ;执行处理器识别指令

movdwordptroutbuffer+outbufsize-12,ebx movdwordptroutbuffer+outbufsize-8,edx movdwordptroutbuffer+outbufsize-4,ecx ;获得输出句柄

invokeGetStdHandle,STD_OUTPUT_HANDLE

movouthandle,eax ;显示信息

invokeWriteConsole,outhandle,\ addroutbuffer,outbufsize,addroutsize,0 ;退出

invokeExitProcess,0

endstartTheprocessorvendorIDisGenuineIntel运行结果2.控制台句柄句柄(Handle)是一个32位无符号整数用来唯一确定一个对象例如某个输入设备、输出设备或者一个图形标准输入句柄

STD_INPUT_HANDLE

=-10标准输出句柄

STD_OUTPUT_HANDLE

=-11标准错误句柄

STD_ERROR_HANDLE

=-12GetStdHandle函数获取控制台输入或输出的句柄实例用于控制台程序的输入输出操作返回3.控制台输出函数显示器输出API函数WriteConsole将一个字符串输出到屏幕上支持标准的ASCII控制字符,例如回车、换行等Win32API中可以使用两种字符集8位ASCII字符集,函数名以字母A结尾16位Unicode字符集,函数名以字母W结尾WriteConsole参数第一个:控制台输出句柄实例第二个:指向字符串的指针、即缓冲区地址第三个:指明字符串长度,是一个32位整数第四个:指向一个整数变量,返回实际输出的字符数第五个:保留,设置为0返回4.控制台输入函数键盘输入API函数ReadConsole将键盘输入的文本保存到一个缓冲区第一个:控制台输入句柄实例第二个:输入缓冲区指针第三个:要读取字符的最大数量第四个:实际输入字符数量的指针第五个:未使用,设置为0调用ReadConsole函数时系统等待用户输入、并回车确认(例如用户输入了3个字符,依次是123)第4个参数的变量保存用户输入字符个数再加2的结果(例如本例是5)(内容用十六进制数表达依次是3132330D0A)定义输入缓冲区要多留两个字节〔例4-22〕信息输入输出程序-1

.686 .modelflat,stdcall optioncasemap:none includelibbin\kernel32.libExitProcess proto,:DWORDexit MACROdwexitcode invokeExitProcess,dwexitcode ENDMGetStdHandle proto,:DWORDWriteConsoleAproto,:DWORD,:DWORD,:DWORD,:DWORD,:DWORDWriteConsole equ<WriteConsoleA>ReadConsoleA proto,:DWORD,:DWORD,:DWORD,:DWORD,:DWORDReadConsole equ<ReadConsoleA>STD_INPUT_HANDLE=-10STD_OUTPUT_HANDLE=-11〔例4-22〕信息输入输出程序-2 .datamsg1 byte'Pleaseenteryourname:',0msg2 byte'Welcome',0nbuf byte80dup(0)msg3 byte'toWin32Console!',0_outsize dword?_outhandle dword?_insize dword?_inbuffer byte255dup(0) ;设置输入缓冲区最大255个字符〔例4-22〕信息输入输出程序-3

.codestart: moveax,offsetmsg1 ;提示输入

calldispmsg

moveax,offsetnbuf ;输入信息

callreadmsg

moveax,offsetmsg2

calldispmsg

moveax,offsetnbuf ;显示输入信息

calldispmsg

moveax,offsetmsg3

calldispmsg

exit0〔例4-22〕信息输入输出程序-4dispmsg proc ;字符串显示子程序

pusheax ;入口参数:EAX=字符串地址

pushebx pushecx pushedx pusheax ;保存入口参数,即字符串地址

invokeGetStdHandle,STD_OUTPUT_HANDLE mov_outhandle,eax

popebx ;EBX=字符串地址

xorecx,ecx ;计算字符串长度dispm1: moval,[ebx+ecx] testal,al jzdispm2 incecx jmpdispm1〔例4-22〕信息输入输出程序-5dispm2:

invokeWriteConsole,_outhandle,\ ebx,ecx,addr_outsize,0 popedx popecx popebx popeax retdispmsg endpreadmsg proc ;字符串输入子程序

pushebx ;入口参数:EAX=缓冲区地址

pushecx

pushedx〔例4-22〕信息输入输出程序-6

pusheax ;保护输入的缓冲区地址参数

invokeGetStdHandle,STD_INPUT_HANDLE invokeReadConsole,\ eax,addr_inbuffer,255,addr_insize,0 sub_insize,2

xorecx,ecx popebx ;获得缓冲区地址readm1: moval,_inbuffer[ecx] mov[ebx+ecx],al ;将输入的字符串复制到用户缓冲区

incecx cmpecx,_insize jbreadm1〔例4-22〕信息输入输出程序-7 movbyteptr[ebx+ecx],0 ;最后填入结尾字符0 moveax,ecx popedx popecx popebx retreadmsg endp endstartPleaseenteryourname:JerryWelcomeJerrytoWin32Console!运行结果4.4.3图形窗口应用程序消息窗口是常见的Windows图形窗口显示形式使用MessageBox函数Win32程序员参考手册的定义intMessageBox(HWNDhWnd,LPCTSTRlpText,LPCTSTRlpCaption,UINTuType);hWnd:父窗口的句柄lpText:要显示字符串的地址指针,字符串的首地址lpCaption:消息窗标题的地址指针uType:指明该消息窗的类型〔例4-23〕消息窗口程序-1

.686 .modelflat,stdcall optioncasemap:none includelibbin\kernel32.lib includelibbin\user32.libExitProcess proto,:DWORDMessageBoxA PROTO:DWORD,:DWORD,:DWORD,:DWORDMessageBox equ<MessageBoxA>NULL equ0MB_OK equ0 .dataszCaption byte'消息窗口',0outbuffer byte'本机的处理器是',12dup(0),0outbufsize =sizeofoutbuffer-1〔例4-23〕消息窗口程序-2 .codestart: moveax,0 cpuid ;获得显示器信息

movdwordptroutbuffer+outbufsize-12,ebx movdwordptroutbuffer+outbufsize-8,edx movdwordptroutbuffer+outbufsize-4,ecx

invokeMessageBox,\ NULL,addroutbuffer,addrszCaption,MB_OK invokeExitProcess,NULL

endstart操作演示连接时应该使用参数/subsystem:windows消息窗口程序END4.5与C++语言的混合编程软件开发通常采用高级语言,以提高开发效率某些部分需要利用汇编语言,以提高程序的运行效率,因为汇编语言的优点:开发的程序占用存储空间小、运行速度快等汇编语言的缺点:与机器密切相关、移植性差,编程烦琐、对汇编语言程序员要求较高混合编程:汇编语言与高级语言、或高级语言间,通过相互调用、参数传递、共享数据结构和数据信息而形成程序的过程汇编语言与C和C++语言的混合编程嵌入汇编模块连接MASM6.

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论