![32位微机原理与接口技术钱晓捷课件04_第1页](http://file4.renrendoc.com/view/e694f1eee11246b3530f15867f421d7f/e694f1eee11246b3530f15867f421d7f1.gif)
![32位微机原理与接口技术钱晓捷课件04_第2页](http://file4.renrendoc.com/view/e694f1eee11246b3530f15867f421d7f/e694f1eee11246b3530f15867f421d7f2.gif)
![32位微机原理与接口技术钱晓捷课件04_第3页](http://file4.renrendoc.com/view/e694f1eee11246b3530f15867f421d7f/e694f1eee11246b3530f15867f421d7f3.gif)
![32位微机原理与接口技术钱晓捷课件04_第4页](http://file4.renrendoc.com/view/e694f1eee11246b3530f15867f421d7f/e694f1eee11246b3530f15867f421d7f4.gif)
![32位微机原理与接口技术钱晓捷课件04_第5页](http://file4.renrendoc.com/view/e694f1eee11246b3530f15867f421d7f/e694f1eee11246b3530f15867f421d7f5.gif)
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第4章
汇编语言程序设计4.1分支程序结构4.2循环程序结构 4.3子程序结构4.4Windows应用程序编程4.5与C++语言的混合编程第4章
汇编语言程序设计4.1分支程序结构4.1分支程序结构改变程序执行顺序、形成分支、循环、调用等程序结构是很常见的程序设计问题高级语言采用IF等语句表达条件,并根据条件是否成立转向不同的程序分支汇编语言需要首先利用比较CMP、测试TEST、加减运算、逻辑运算等影响状态标志的指令形成条件然后利用条件转移指令判断由标志表达的条件,并根据标志状态控制程序转移到不同的程序段4.1分支程序结构改变程序执行顺序、形成分支、循环、调用等4.1.1无条件转移指令程序代码在代码段CS:指明代码段在主存中的段基地址EIP:给出将要执行指令的偏移地址程序顺序执行,处理器自动增量EIP程序控制转移,EIP随之改变程序转移到另外的代码段,EIP和CS都改变控制转移类指令:改变EIP(有些也改变CS),即改变程序执行顺序(实现程序控制转移)的指令本章学习控制转移类指令4.1.1无条件转移指令程序代码在代码段本章学习控制转移类1.转移范围段内转移在当前代码段范围内的程序转移不需更改CS,只要改变EIP(偏移地址)近转移(Near):32位近转移NEAR32,16位近转移NEAR16短转移(Short):转移范围在127~-128字节段间转移从当前代码段跳转到另一个代码段需要更改CS(段地址)和EIP(偏移地址)远转移(Far):48位远转移FAR32,32位远转移FAR161.转移范围段内转移2.指令寻址方式相对寻址方式提供目标地址相对于当前指令指针EIP的位移量目标地址(转移后的EIP)=当前EIP+位移量相对寻址都是段内转移,最常用、最灵活直接寻址方式直接提供目标地址目标地址(转移后的CS和EIP)=指令操作数间接寻址方式指示寄存器或存储单元目标地址来自寄存器或存储单元、间接获得寄存器间接寻址:用寄存器保存目标地址存储器间接寻址:用存储单元保存目标地址目标地址=目的地址=转移地址2.指令寻址方式相对寻址方式目标地址=目的地址=转移地址3.JMP指令无条件转移:程序无条件改变执行顺序JMP指令相当于高级语言的goto语句
JMPlabel ;程序转向label标号指定的地址
;段内相对寻址,段间直接寻址
JMPreg32/reg16 ;程序转向寄存器指定的地址
;寄存器间接寻址
JMPmem48/mem32/mem16 ;程序转向存储单元指定的地址
;存储器间接寻址3.JMP指令无条件转移:程序无条件改变执行顺序JMP指令的4种类型1.段内转移、相对寻址标号指明目标地址,指令代码包含位移量2.段内转移、间接寻址通用寄存器或主存单元包含目标指令偏移地址3.段间转移、直接寻址标号包含目标指令的段地址和偏移地址4.段间转移、间接寻址32位段用3字存储单元包含目标地址16位段用双字存储单元包含目标地址MASM会根据存储模式等信息自动识别JMP指令的4种类型1.段内转移、相对寻址MASM会根据存〔例4-1〕无条件转移程序-1
;数据段00000000 00000000nvar dword?
;代码段00000000 EB01 jmplabl1 ;相对寻址00000002 90
nop00000003 E900000001labl1: jmpnearptrlabl2 ;相对近转移00000008 90
nop00000009 B800000011Rlabl2: moveax,offsetlabl3
〔例4-1〕无条件转移程序-1 ;数据段〔例4-1〕无条件转移程序-20000000E FFE0
jmpeax ;寄存器间接寻址00000010 90
nop00000011 B800000022Rlabl3: moveax,offsetlabl400000016 A300000000R
movnvar,eax0000001B FF2500000000R
jmpnvar ;存储器间接寻址00000021 90
noplabl4:
movebx,offsetnvarjmpnearptr[ebx];数据的寄存器间接寻址数据的存储器直接寻址〔例4-1〕无条件转移程序-20000000E FFE0m4.1.2条件转移指令根据指定的条件确定程序是否发生转移
Jcclabel ;条件满足,发生转移;否则,顺序执行下条指令LABEL表示目标地址,采用段内相对寻址32位IA-32处理器:达到32位的全偏移量16位80x86处理器:-128~+127间的短转移条件转移指令不影响标志,但要利用标志cc表示利用标志判断的条件,16种、两类单个标志状态作为条件两数大小关系作为条件4.1.2条件转移指令根据指定的条件确定程序是否发生转移转移条件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:单个标志状态JZ/JE ZF=1 Jumpi转移条件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/Greater转移条件cc:两数大小关系JB/JNAE CF=1 Jump1.单个标志状态作为条件的条件转移指令JZ(JE)和JNZ(JNE):利用零位标志ZF判断结果是零(相等)还是非零(不等)JS和JNS:利用符号标志SF判断结果是负还是正JO和JNO:利用溢出标志OF判断结果是溢出还是没有溢出JP(JPE)和JNP(JPO):利用奇偶标志PF判断结果低字节“1”的个数是偶数还是奇数JC和JNC:利用进位标志CF判断结果是有进位(为1)还是无进位(为0)1.单个标志状态作为条件的条件转移指令JZ(JE)和JNZ〔例4-2〕个数折半程序-1
moveax,885 ;假设一个数据
shreax,1 ;数据右移进行折半
jncgoeven ;余数为0,即CF=0条件成立,转移
addeax,1 ;否则余数为1,即CF=1,进行加1操作goeven: calldispuid ;显示结果
443运行结果〔例4-2〕个数折半程序-1 moveax,885 ;假〔例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〕个数折半程序-2 moveax,886 ;假〔例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-2〕个数折半程序-3 moveax,887 ;假〔例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〕位测试程序-1 ;数据段〔例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-3〕位测试程序-2 ;数据段〔例4-4〕奇校验程序
callreadc ;键盘输入,AL=返回值
calldispcrlf ;回车换行(用于分隔)
calldispbb ;以二进制形式显示数据
calldispcrlf ;回车换行(用于分隔)
andal,7fh ;最高位置“0”、其他位不变
;同时标志PF反映“1”的个数
jnpnext ;个数为奇数,不需处理,转移
oral,80h ;个数为偶数,最高位置“1”、其他位不变next: calldispbb ;显示含校验位的数据〔例4-4〕奇校验程序 callreadc ;键盘输入,2.两数大小关系作为条件的条件转移指令无符号数用高(Above)、低(Below)低于(不高于等于):JB(JNAE)不低于(高于等于):JNB(JAE)低于等于(不高于):JBE(JNA)不低于等于(高于):JNBE(JA)有符号数用大(Greater)、小(Less)小于(不大于等于):JL(JNGE)不小于(大于等于):JNL(JGE)小于等于(不大于):JLE(JNG)不小于等于(大于):JNLE(JG)2.两数大小关系作为条件的条件转移指令无符号数用高(Abo〔例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〕数据比较程序-1 ;数据段〔例4-5〕数据比较程序-2
cmpebx,ecx ;二个数据进行比较
jnenequal ;两数不相等,转移
moveax,offsetout_msg1
calldispmsg ;显示两数相等
moveax,ebx calldispsid ;显示相等的数据
jmpdone ;转移到结束nequal: jlfirst ;EBX较小,不需要交换,转移
xchgebx,ecx ;EBX保存较小数,ECX保存较大数〔例4-5〕数据比较程序-2 cmpebx,ecx ;二〔例4-5〕数据比较程序-3first: moveax,offsetout_msg2 ;显示较小数
calldispmsg moveax,ebx ;较小数在EBX中
calldispsid moveax,offsetout_msg3 ;显示较大数
calldispmsg
moveax,ecx ;较大数在ECX中
calldispsiddone:〔例4-5〕数据比较程序-3first: moveax,o4.1.3单分支结构只有一个分支的程序类似高级语言的IF-THEN语句结构注意采用正确的条件转移指令当条件满足(成立),发生转移,跳过分支体条件不满足,顺序向下执行分支体条件转移指令与高级语言的IF语句正好相反IF语句是条件成立,执行分支体4.1.3单分支结构只有一个分支的程序〔例4-6〕求绝对值程序
;代码段
callreadsid ;输入一个有符号数,从EAX返回值
cmpeax,0 ;比较EAX与0
jgenonneg ;条件满足:EAX≥0,转移
negeax ;条件不满足:EAX<0,为负数
;需求补得正值nonneg: calldispuid ;分支结束,显示结果示意图〔例4-6〕求绝对值程序 ;代码段示意图单分支结构的流程图返回negeax单分支结构的流程图返回negeax〔例4-7〕字母判断程序
callreadc ;输入一个字符,从AL返回值
cmpal,'A’ ;与大写字母A比较
jbdone ;比大写字母A小,不是大写字母,转移
cmpal,'Z’ ;与大写字母Z比较
jadone ;比大写字母Z大,不是大写字母,转移
oral,20h ;转换为小写
calldispcrlf ;回车换行
calldispc ;显示小写字母done:
〔例4-7〕字母判断程序 callreadc4.1.4双分支结构双分支程序结构有两个分支,条件为真执行一个分支;条件为假,执行另一个分支相当于高级语言的IF-THEN-ELSE语句顺序执行的分支体1最后一定要有一条JMP指令跳过分支体2JMP指令必不可少,实现结束前一个分支回到共同的出口作用双分支结构有时可以改变为单分支结构事先执行其中一个分支(选择出现概率较高的分支)4.1.4双分支结构双分支程序结构有两个分支,条件为真执行〔例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〕显示数据最高位程序-1 ;数据段示意图双分支结双分支结构的流程图返回双分支结构的流程图返回〔例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-8〕显示数据最高位程序-2 movebx,dvar〔例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-9〕有符号数运算溢出程序 ;数据段4.2循环程序结构三个部分组成:循环初始——为开始循环准备必要的条件,如循环次数、循环体需要的初始值等;循环体——重复执行的程序代码,其中包括对循环条件的修改等;循环控制——判断循环条件是否成立,决定是否继续循环“先判断、后循环”的循环程序结构对应高级语言的WHILE语句“先循环、后判断”的循环程序结构对应高级语言的DO语句示意图4.2循环程序结构三个部分组成:示意图循环程序结构的流程图返回循环程序结构的流程图返回4.2.1循环指令
LOOPlabel;ECX←ECX-1;若ECX≠0,循环到LABEL;否则,顺序执行
JECXZlabel;ECX=0,转移;否则顺序执行目标地址采用相对短转移实地址存储模型使用CX作为计数器DECECXJNZlabelCMPECX,0JZlabel4.2.1循环指令 LOOPlabelDECECXCM〔例4-10〕数组求和程序
movecx,lengthofarray ;ECX=数组元素个数
xoreax,eax ;求和初值为0
movebx,eax ;数组指针为0again: addeax,array[ebx*(typearray)] ;求和
incebx ;指向下一个数组元素
loopagain movsum,eax ;保存结果
calldispsid ;显示结果循环体循环控制循环初始〔例4-10〕数组求和程序 movecx,lengthof4.2.2计数控制循环通过次数控制循环利用LOOP指令属于计数控制常见是“先循环、后判断”循环结构计数可以减量进行,即减到0结束计数可以增量进行,即达到规定值结束循环程序结构的关键是如何控制循环4.2.2计数控制循环通过次数控制循环循环程序结构的关键是〔例4-11〕简单加密解密程序-1
;数据段key byte234bufnum =255buffer bytebufnum+1dup(0) ;定义键盘输入需要的缓冲区msg1 byte'Entermessge:',0msg2 byte'Encryptedmessage:',0msg3 byte13,10,'Originalmessge:',0 ;代码段
moveax,offsetmsg1 ;提示输入字符串
calldispmsg moveax,offsetbuffer ;设置入口参数EAX
callreadmsg ;调用输入字符串子程序
pusheax ;字符个数保存进入堆栈〔例4-11〕简单加密解密程序-1 ;数据段〔例4-11〕简单加密解密程序-2
movecx,eax ;ECX=实际输入的字符个数,作为循环的次数
xorebx,ebx ;EBX指向输入字符
moval,key ;AL=加密关键字encrypt: xorbuffer[ebx],al ;异或加密
incebx dececx ;等同于指令:loopencrypt
jnzencrypt ;处理下一个字符
moveax,offsetmsg2 calldispmsg moveax,offsetbuffer ;显示密文
calldispmsg〔例4-11〕简单加密解密程序-2 movecx,eax〔例4-11〕简单加密解密程序-3
popecx ;从堆栈弹出字符个数,作为循环的次数
xorebx,ebx ;EBX指向输入字符
moval,key ;AL=解密关键字decrypt: xorbuffer[ebx],al ;异或解密
incebx dececx jnzdecrypt ;处理下一个字符
moveax,offsetmsg3 calldispmsg moveax,offsetbuffer ;显示明文
calldispmsg示意图〔例4-11〕简单加密解密程序-3 popecx示意图简单加密解密程序运行实例返回简单加密解密程序运行实例返回4.2.3条件控制循环根据条件决定是否进行循环需要使用有条件转移指令实现多见“先判断、后循环”结构先行判断的条件控制循环程序很像双分支结构主要分支需要重复执行多次(JMP的目标位置是循环开始)另一个分支用于跳出这个循环先行循环的条件控制循环程序类似单分支结构,循环体就是分支体顺序执行就跳出循环4.2.3条件控制循环根据条件决定是否进行循环〔例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-12〕字符个数统计程序 ;数据段〔例4-13〕字符剔除程序-1
moveax,offsetstring
;显示处理前字符串
calldispmsg movesi,offsetstringoutlp: cmpbyteptr[esi],0 ;外循环,先判断后循环
jzdone ;为0结束again: cmpbyteptr[esi],'';是否是空格
jnznext ;不是空格继续循环
movedi,esi ;是空格,剔除空格分支inlp: incedi ;该分支是循环程序
moval,[edi] ;前移一个位置
mov[edi-1],al〔例4-13〕字符剔除程序-1 moveax,offset〔例4-13〕字符剔除程序-2
cmpbyteptr[edi],0
;内循环,先循环后判断
jnzinlp ;内循环结束处
jmpagain ;再次判断是否为空格(处理连续空格)next: incesi ;继续对后续字符进行判断处理
jmpoutlp ;外循环结束处done: moveax,offsetstring ;显示处理后字符串
calldispmsg〔例4-13〕字符剔除程序-2 cmpbyteptr[4.3子程序结构经常用到的应用问题编写成一个通用子程序大型处理过程分解成能够解决的模块使用子程序可以使程序的结构更为清楚程序的维护更为方便有利于大程序开发时的多个程序员分工合作子程序(Subroutine)=函数(Function)=过程(Procedure)4.3子程序结构经常用到的应用问题编写成一个通用子程序子程4.3.1子程序指令子程序:与主程序分开的、完成特定功能的一段程序当主程序(调用程序)执行调用指令CALL调用子程序子程序(被调用程序)执行返回指令RET返回主程序CALLlabel主程序RET子程序回到CALL指令后的指令处4.3.1子程序指令子程序:与主程序分开的、完成特定功能的1.子程序调用指令CALLCALL指令用在主程序中,实现子程序的调用分成段内调用(近调用)和段间调用(远调用)目标地址采用相对寻址、直接寻址或间接寻址入栈返回地址:将CALL下条指令的地址压入堆栈
CALLlabel ;调用标号指定的子程序
CALLreg16/reg32
;调用寄存器指定地址的子程序
CALLmem16/mem32/mem48 ;调用存储单元指定地址的子程序1.子程序调用指令CALLCALL指令用在主程序中,实现子2.子程序返回指令RETRET指令用在子程序结束,实现返回主程序
RET
;无参数返回:出栈返回地址
RETi16 ;有参数返回:出栈返回地址
;ESP←ESP+i16MASM会根据存储模型等信息确定子程序的远近调用,并相应产生返回指令2.子程序返回指令RETRET指令用在子程序结束,实现返回3.过程定义伪指令MASM利用过程定义伪指令获得子程序信息
过程名 PROC
…… ;过程体
过程名 ENDP
;过程名为符合语法的标识符PROC后面可加参数:NEAR或FAR简化段定义源程序格式中,通常不需指定3.过程定义伪指令MASM利用过程定义伪指令获得子程序信息〔例4-14〕子程序调用程序-1
;代码段,主程序00000000 B800000001 moveax,100000005 BD00000005 movebp,50000000A E800000016
callsubp ;子程序调用0000000F B900000003
retp1: movecx,300000014 BA00000004retp2: movedx,400000019 E800000000E
calldisprd〔例4-14〕子程序调用程序-1 ;代码段,主程序〔例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-14〕子程序调用程序-2 ;子程序MOV[EBP子程序调用的堆栈返回子程序调用的堆栈返回4.3.2子程序设计子程序的编写方法与主程序一样但需要留意几个问题:利用过程定义,获得子程序名和调用属性RET指令返回主程序,CALL指令调用子程序压入和弹出操作要成对使用,保持堆栈平衡开始保护寄存器,返回前相应恢复安排在代码段的主程序之外子程序允许嵌套和递归最好有完整的注释难点是参数传递4.3.2子程序设计子程序的编写方法与主程序一样最好有完整回车换行子程序DPCRLFdpcrlf proc ;回车换行子程序
pusheax ;保护寄存器
moval,0dh ;输出回车字符
calldispc ;子程序中调用子程序,实现子程序嵌套
moval,0ah ;输出换行字符
calldispc ;子程序中调用子程序,实现子程序嵌套
popeax ;恢复寄存器
ret ;子程序返回dpcrlf endp回车换行子程序DPCRLFdpcrlf proc ;回车换行4.3.3参数传递主程序与子程序间通过参数传递建立联系入口参数(输入参数):主程序→子程序出口参数(输出参数):子程序→主程序传递参数的多少反映程序模块间的耦合程度参数的具体内容数据本身(传递数值)数据的存储地址(传递地址,传递引用)参数传递方法寄存器变量堆栈4.3.3参数传递主程序与子程序间通过参数传递建立联系1.寄存器传递参数最简单和常用的参数传递方法把参数存于约定的寄存器少量数据直接传递数值大量数据只能传递地址带有出口参数的寄存器不能保护和恢复带有入口参数的寄存器可以保护、也可以不保护,但最好能够保持一致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〕十六进制显示程序-1 moveax,123〔例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 endp〔例4-15〕十六进制显示程序-2 ;子程序〔例4-15〕十六进制显示程序-3
;子程序htoasc proc andeax,0fh ;取AL低4位
moval,ASCII[eax];换码
ret ;子程序的局部数据(只读)ASCII byte'0123456789ABCDEF'htoasc endpEAX=1234ABCDH运行结果〔例4-15〕十六进制显示程序-3 ;子程序EAX=123〔例4-16〕有符号十进制数显示程序-1转换的算法如下:(1)首先判断数据是零、正数或负数,是零显示“0”退出(2)是负数,显示负号“-”,求数据的绝对值(3)接着数据除以10,余数为十进制数码,加30H转换为ASCII码保存(4)重复(3)步,直到商为0结束(5)依次从高位开始显示各位数字〔例4-16〕有符号十进制数显示程序-1转换的算法如下:〔例4-16〕有符号十进制数显示程序-2
;数据段array dword1234567890,-1234,0,1,...writebuf byte12dup(0) ;显示缓冲区
;代码段
movecx,lengthofarray movebx,0again: moveax,array[ebx*4] ;EAX=入口参数
callwrite ;调用子程序,显示一个数据
calldispcrlf ;换行以便显示下一个数据
incebx dececx jnzagain寄存器传递参数〔例4-16〕有符号十进制数显示程序-2 ;数据段寄存器传〔例4-16〕有符号十进制数显示程序-3 ;显示有符号十进制数的子程序write proc ;EAX=入口参数
pushebx ;保护寄存器
pushecx pushedx movebx,offsetwritebuf;EBX指向显示缓冲区
testeax,eax ;判断数据是零、正数或负数
jnzwrite1 ;不是零,跳转
movbyteptr[ebx],'0' ;是零,设置“0”
incebx jmpwrite5 ;转向显示write1: jnswrite2 ;是正数,跳转
movbyteptr[ebx],'-';是负数,设置负号
incebx negeax ;数据求补(绝对值)寄存器传递参数〔例4-16〕有符号十进制数显示程序-3 ;显示有符号十进〔例4-16〕有符号十进制数显示程序-4write2: movecx,10 pushecx ;10压入堆栈,作为退出标志write3: cmpeax,0 ;数据(商)为零,转向保存
jzwrite4 xoredx,edx ;零位扩展被除数为EDX.EAX
divecx ;数据除以10:EDX.EAX÷10
addedx,30h ;余数(0~9)转换为ASCII码
pushedx ;数据先低位后高位压入堆栈
jmpwrite3〔例4-16〕有符号十进制数显示程序-4write2: mo〔例4-16〕有符号十进制数显示程序-5write4: popedx ;数据先高位后低位弹出堆栈
cmpedx,ecx ;是结束标志10,转向显示
jewrite5 mov[ebx],dl ;数据保存到缓冲区
incebx jmpwrite4write5: movbyteptr[ebx],0 ;显示内容加上结尾标志
moveax,offsetwritebuf calldispmsg
popedx ;恢复寄存器
popecx popebx ret ;子程序返回write endp〔例4-16〕有符号十进制数显示程序-5write4: po2.共享变量传递参数子程序和主程序使用同一个变量名存取数据如果变量定义和使用不在同一个程序模块中,需要利用PUBLIC、EXTREN声明共享变量传递参数,子程序的通用性较差特别适合在多个程序段间、尤其在不同的程序模块间传递数据2.共享变量传递参数子程序和主程序使用同一个变量名存取数据〔例4-17〕二进制数输入程序-1输入一个字符,判断是否合法是字符“0”或“1”合法减去30H转换成数值“0”或“1”重复转换每个字符将前一次的数值左移1位并与新数值进行组合输入非法字符,或超过数据位数提示错误重新输入〔例4-17〕二进制数输入程序-1输入一个字符,判断是否合法〔例4-17〕二进制数输入程序-2
;数据段count =5array dwordcountdup(0)temp dword? ;代码段
movecx,count movebx,offsetarrayagain: callrdbd ;调用子程序,输入一个数据
moveax,temp ;获得出口参数
mov[ebx],eax ;存放到数据缓冲区
addebx,4 loopagain共享变量传递参数〔例4-17〕二进制数输入程序-2 ;数据段共享变量传递参〔例4-17〕二进制数输入程序-3 ;输入二进制数的子程序rdbd proc ;出口参数:变量TEMP=补码表示的二进制数值
pusheax ;说明:负数用“-”引导
pushebx
pushecxrdbd1: xorebx,ebx ;EBX用于存放二进制结果
movecx,32 ;限制输入字符的个数rdbd2: callreadc ;输入一个字符
cmpal,'0' ;检测键入字符是否合法
jbrderr ;不合法则返回重新输入
cmpal,'1' jarderr〔例4-17〕二进制数输入程序-3 ;输入二进制数的子程序〔例4-17〕二进制数输入程序-4
subal,'0' ;对输入的字符进行转化
shlebx,1 ;EBX的值乘以2
orbl,al ;BL和AL相加
looprdbd2 ;循环键入字符
movtemp,ebx ;把EBX的二进制结果存放TEMP返回
calldispcrlf ;分行
popecx popebx popeax ret
;子程序返回〔例4-17〕二进制数输入程序-4 subal,'0' ;〔例4-17〕二进制数输入程序-5rderr: moveax,offseterrmsg ;显示错误信息
calldispmsg jmprdbd1errmsg byte0dh,0ah,'Inputerror,enteragain:',0rdbd endp共享变量传递参数〔例4-17〕二进制数输入程序-5rderr: movea〔例4-18〕有符号十进制数输入程序-1十进制有符号整数转换为补码的算法如下:(1)判断输入了正数、还是负数,用一个寄存器记录(2)判断下一个字符是否为有效数码 字符无效,提示错误重新输入,并转向(1) 字符有效,继续(3)字符有效,减30H转换为二进制数;然后将前面输入的数值乘10,并与刚输入的数字相加得到新的数值(4)判断输入的数据是否超出有效范围超出范围,提示错误重新输入,并转向(1)没有超出范围,则继续(5)重复(2)~(4)步,输入字符都有效,一直处理完(6)是负数进行求补,转换成补码;否则直接将数值保存〔例4-18〕有符号十进制数输入程序-1十进制有符号整数转换〔例4-18〕有符号十进制数输入程序-2
;数据段count =10array dwordcountdup(0)temp dword?readbuf byte30dup(0) ;代码段
movecx,count movebx,offsetarrayagain: callread ;调用子程序,输入一个数据
moveax,temp ;获得出口参数
mov[ebx],eax ;存放到数据缓冲区
addebx,4 dececx jnzagain共享变量传递参数〔例4-18〕有符号十进制数输入程序-2 ;数据段共享变量〔例4-18〕有符号十进制数输入程序-3 ;输入有符号十进制数的子程序read proc ;出口参数:变量TEMP=补码表示的二进制数值
pusheax ;说明:负数用“-”引导
pushebx
pushecx pushedxread0: moveax,offsetreadbuf
callreadmsg ;输入一个字符串
testeax,eax jzreaderr ;没有输入数据,错误
cmpeax,12 jareaderr ;输入超过12个字符,错误〔例4-18〕有符号十进制数输入程序-3 ;输入有符号十进〔例4-18〕有符号十进制数输入程序-4
movedx,offsetreadbuf;EDX指向输入缓冲区
xorebx,ebx ;EBX保存结果
xorecx,ecx ;ECX为正负标志,0为正,-1为负
moval,[edx] ;取一个字符
cmpal,'+' ;是“+”,继续
jzread1 cmpal,'-' ;是“-”,设置-1标志
jnzread2 movecx,-1read1: incedx ;取下一个字符
moval,[edx] testal,al ;是结尾0,转向求补码
jzread3〔例4-18〕有符号十进制数输入程序-4 movedx,o〔例4-18〕有符号十进制数输入程序-5read2: cmpal,'0' ;不是0~9之间的数码,错误
jbreaderr cmpal,'9' jareaderr subal,30h ;是0~9之间的数码,转换
imulebx,10 ;原数值乘10:EBX=EBX×10
jcreaderr ;CF=1,乘积溢出,出错
movzxeax,al ;零位扩展,便于相加
addebx,eax ;原数乘10后,与新数码相加
cmpebx,80000000h ;数据超过231,出错
jberead1 ;继续转换下一个数位〔例4-18〕有符号十进制数输入程序-5read2: cmp〔例4-18〕有符号十进制数输入程序-6readerr: moveax,offseterrmsg ;显示出错信息
calldispmsg jmpread0 ;read3: testecx,ecx ;判断是正数还是负数
jzread4
negebx ;是负数,进行求补
jmpread5read4: cmpebx,7fffffffh ;正数超过231-1,出错
jareaderr〔例4-18〕有符号十进制数输入程序-6readerr: m〔例4-18〕有符号十进制数输入程序-7read5: movtemp,ebx ;设置出口参数
popedx popecx popebx popeax ret ;子程序返回errmsg byte'Inputerror,enteragain:',0read endp共享变量传递参数〔例4-18〕有符号十进制数输入程序-7read5: mov3.堆栈传递参数主程序将入口参数压入堆栈,子程序从堆栈中取出参数出口参数通常不使用堆栈传递高级语言进行函数调用时提供的参数,实质也利用堆栈传递采用堆栈传递参数是程式化的,它是编译程序处理参数传递、以及汇编语言与高级语言混合编程时的常规方法3.堆栈传递参数主程序将入口参数压入堆栈,子程序从堆栈中取〔例4-19〕计算有符号数平均值程序-1
;数据段array dword675,354,-34,... ;代码段
pushlengthofarray ;压入数据个数
pushoffsetarray ;压数组的偏移地址
callmean ;调用求平均值子程序
;出口参数:EAX=平均值(整数部分)
addesp,8 ;平衡堆栈(压入了8个字节数据)
calldispsid ;显示堆栈传递参数〔例4-19〕计算有符号数平均值程序-1 ;数据段堆栈传递〔例4-19〕计算有符号数平均值程序-2
;计算32位有符号数平均值子程序mean proc ;入口参数:顺序压入数据个数和数组偏移地址
pushebp ;出口参数:EAX=平均值
movebp,esp
pushebx ;保护寄存器
pushecx pushedx movebx,[ebp+8] ;EBX=取出的偏移地址
movecx,[ebp+12] ;ECX=取出的数据个数
xoreax,eax ;EAX保存和值
xoredx,edx ;EDX=指向数组元素堆栈传递参数〔例4-19〕计算有符号数平均值程序-2 ;计算32位有符〔例4-19〕计算有符号数平均值程序-3mean1: addeax,[ebx+edx*4] ;求和
addedx,1 ;指向下一个数据
cmpedx,ecx ;比较个数
jbmean1 ;循环
cdq ;将累加和EAX符号扩展到EDX
idivecx ;有符号数除法,EAX=平均值
popedx ;恢复寄存器
popecx popebx popebp retmean endp示意图求和溢出与个数为0的问题?〔例4-19〕计算有符号数平均值程序-3mean1: add利用堆栈传递参数返回利用堆栈传递参数返回4.3.4程序模块程序分段、子程序等是进行程序模块化开发大型程序时采用的方法子程序模块子程序库库文件包含宏汇编源文件包含4.3.4程序模块程序分段、子程序等是进行程序模块化1.子程序模块子程序单独编写,汇编形成目标模块OBJ文件连接时输入子程序模块文件名用共用伪指令PUBLIC和外部伪指令EXTERN声明PUBLIC标识符[,标识符…] ;定义标识符的模块使用EXTERN标识符:类型[,标识符:类型…] ;调用标识符的模块使用子程序在代码段,与主程序文件采用相同的存储模型,没有开始执行和结束执行点处理好子程序与主程序之间的参数传问题1.子程序模块子程序单独编写,汇编形成目标模块OBJ文件〔例4-20〕数据输入输出程序-1;eg0420s.asm(子程序文件)
includeio32.incpublic read,write,mean ;子程序共用extern temp:dword ;外部变量
.data ;定义的变量集中起来writebuf byte12dup(0) ;显示缓冲区readbuf byte30dup(0) .code ;代码段write procc ;明确采用C语言规范
…… ;输出子程序read procc …… ;输入子程序mean procc …… ;计算平均值子程序
end〔例4-20〕数据输入输出程序-1;eg0420s.asm〔例4-20〕数据输入输出程序-2;eg0420.asm(主程序文件)
includeio32.incextern
read:near,write:near,mean:near ;外部子程序public
temp ;变量共用
.datacount =10array dwordcountdup(0)temp dword?msg1 byte'Enter10numbers:',13,10,0msg2 byte'Themeanis:',0 .codestart: moveax,offsetmsg1 ;提示输入10个数据
calldispmsg〔例4-20〕数据输入输出程序-2;eg0420.asm(〔例4-20〕数据输入输出程序-3
xorebx,ebx movecx,count ;ECX=数据个数again: callread ;调用子程序,输入一个数据
moveax,temp ;获得出口参数
movarray[ebx*4],eax addebx,1 cmpebx,ecx jbagain〔例4-20〕数据输入输出程序-3 xorebx,ebx〔例4-20〕数据输入输出程序-4
pushecx ;传递参数
pushoffsetarray callmean ;调用子程序,求平均值
addesp,8 movebx,eax ;EAX返回值转存到EBX
moveax,offsetmsg2 ;提示输出平均值
calldispmsg moveax,ebx ;提示输出平均值
callwrite ;调用子程序,显示平均值
exit0
endstart〔例4-20〕数据输入输出程序-4 pushecx ;传2.子程序库子程序库:统一管理子程序模块遵循更加严格的子程序模块要求子程序文件编写完成、汇编形成目标模块利用库管理工具程序LIB.EXE:把子程序模块逐个加入到子程序库(.LIB)使用子程序库:在连接主程序模块时提供子程序库文件名操作演示2.子程序库子程序库:统一管理子程序模块操作演示数据输入输出程序-子程序模块数据输入输出程序-子程序模块数据输入输出程序-执行实例数据输入输出程序-执行实例数据输入输出程序-子程序库END数据输入输出程序-子程序库END3.库文件包含直接在主程序源文件中用库文件包含伪指令INCLUDELIB说明不用在连接时输入库文件名
INCLUDELIB文件名子程序库文件名要符合操作系统规范必要时含有路径,用于指明文件的存储位置如果没有路径名,汇编程序将在默认目录、当前目录和指定目录下寻找3.库文件包含直接在主程序源文件中用库文件包含伪指令INC4.宏汇编宏(Macro):具有宏名的一段汇编语句序列宏需要先定义宏名
MACRO
形参表
…… ;宏定义体
ENDM然后程序中进行宏调用宏名实体参数在汇编时,宏指令被汇编程序用宏定义的代码序列替代,实现宏展开4.宏汇编宏(Macro):具有宏名的一段汇编语句序列宏汇编示例宏定义WriteString macromsg pusheax leaeax,msg calldispmsg popeax
endm宏展开 pusheax leaeax,msg calldispmsg popeax宏调用 WriteStringmsg宏汇编示例宏定义宏展开宏调用5.源文件包含
INCLUDE文件名将INCLUDE伪指令指定的文本文件内容插入源程序可以包含任何文本文件一些常用的或有价值的宏定义存放在.MAC宏定义文件各种常量定义、声明语句等组织在.INC包含文件常用的子程序形成.ASM汇编语言源文件利用INCLUDE伪指令包含其他文件,其实质仍然是一个源程序,只不过是分在了几个文件书写组合两种文件包含、以及宏汇编等方法,可以精简程序框架、简化程序设计IO32.INC5.源文件包含 INCLUDE文件名IO32.INCIO32.INC.nolist ;不列表内容;filename:io32.inc ...;declareproceduresextern readc:near,readmsg:nearextern dispc:near,dispmsg:near,dispcrlf:near;declareI/Olibraries includelibio32.lib;definemacrosWriteStringMACROstring ....list ;列表内容返回IO32.INC.nolist ;不列表内容返回4.4Windows应用程序编程汇编语言可以编写32位Windows应用程序调用Windows的应用程序接口API运行于Windows操作系统平台可以利用Windows的高级特性,生成的可执行文件相对较小、性能更高从更深层次理解Windows运行机制及程序设计思想4.4Windows应用程序编程汇编语言可以编写32位Wi4.4.1操作系统函数调用操作系统以其提供的系统函数(系统功能Systemfunction)支持程序员进行编程Windows的系统函数(功能)以动态连接库DLL(Dynamic-LinkLibrary)形式提供,利用其应用程序接口API(ApplicationProgramInterface)调用DDL库中的函数API是一些类型、常量和函数的集合,提供了编程中使用库函数的途径Win16:16位Windows的APIWin32:32位Windows的API4.4.1操作系统函数调用操作系统以其提供的系统函数(系统1.动态连接库静态连接:连接程序从库文件中抽取需要的子程序插入到最终的可执行代码中动态连接:程序运行时才将代码加载到主存动态连接库:保存程序运行时需要重复使用的代码的文件3个最重要的Windows动态连接库KERNEL32.DLL:主要处理内存管理和进程调度USER32.DLL:主要控制用户界面GDI32.DLL:负责图形方面的操作导入库(ImportLibrary):程序开发的连接阶段使用,与一个动态连接库DLL对应1.动态连接库静态连接:连接程序从库文件中抽取需要的子程序2.MASM的高级语言特性条件控制伪指令:.IF.ELSEIF.ELSE.ENDIF流程控制伪指令:.WHILE.ENDW.REPEAT.UNTIL.REPEAT.UNTILCXZ.BREAK.CONTINUE过程声明伪指令PROTO:事先声明过程的结构 (包括操作系统API函数、高级语言的函数) 过程名 PROTO [调用距离][语言类型] [,参数∶[类型]]...过程调用伪指令INVOKE:实现过程调用
INVOKE 过程名[,参数,...]2.MASM的高级语言特性条件控制伪指令:3.程序退出函数Win32程序员参考手册VOIDExitProcess(UINTuExitCode //exitcodeforallthreads);汇编语言声明ExitProcessPROTO,:DWORD汇编语言调用invoke
ExitProcess,0将函数调用定义成宏exit MACROdwexitcode
invokeExitProcess,dwexitcode
ENDM宏调用exit 03.程序退出函数Win32程序员参考手册汇编语言声明汇编语4.4.2控制台应用程序Windows应用程序开始运行创建控制台(Console)窗口或创建图形界面窗口32位Windows控制台程序像增强版的MS-DOS程序使用标准控制台
标准输入设备(键盘)
标准输出设备(显示器)32位控制台程序运行在保护方式通过API使用Windows的动态链接库函数4.4.2控制台应用程序Windows应用程序开始运行1.处理器识别指令CPUID返回处理器特征信息的指令当EAX=0时执行CPUID指令EAX返回CPUID指令中能够赋给EAX的最大值EBX、EDX和ECX返回生产厂商的标识串GenuineIntel利用这个厂商标识串,确认是Intel公司处理器当EAX=1或2等值时执行CPUID指令返回处理器更详细的识别信息例如处理器型号、支持的指令集等1.处理器识别指令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〕处理器识别程序-1 .686控制台句柄控制台输〔例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运行结果〔例4-21〕处理器识别程序-2 .codeTheproc2.控制台句柄句柄(Handle)是一个32位无符号整数用来唯一确定一个对象例如某个输入设备、输出设备或者一个图形标准输入句柄
STD_INPUT_HANDLE
=-10标准输出句柄
STD_OUTPUT_HANDLE
=-11标准错误句柄
STD_ERROR_HANDLE
=-12GetStdHandle函数获取控制台输入或输出的句柄实例用于控制台程序的输入输出操作返回2.控制台句柄句柄(Handle)是一个32位无符号整数返3.控制台输出函数显示器输出API函数WriteConsole将一个字符串输出到屏幕上支持标准的ASCII控制字符,例如回车、换行等Win32API中可以使用两种字符集8位ASCII字符集,函数名以字母A结尾16位Unicode字符集,函数名以字母W结尾WriteConsole参数第一个:控制台输出句柄实例第二个:指向字符串的指针、即缓冲区地址第三个:指明字符串长度,是一个32位整数第四个:指向一个整数变量,返回实际输出的字符数第五个:保留,设置为0返回3.控制台输出函数显示器输出API函数WriteConso4.控制台输入函数键盘输入API函数ReadConsole将键盘输入的文本保存到一个缓冲区第一个:控制台输入句柄实例第二个:输入缓冲区指针第三个:要读取字符的最大数量第四个:实际输入字符数量的指针第五个:未使用,设置为0调用ReadConsole函数时系统等待用户输入、并回车确认(例如用户输入了3个字符,依次是123)第4个参数的变量保存用户输入字符个数再加2的结果(例如本例是5)(内容用十六进制数表达依次是3132330D0A)定义输入缓冲区要多留两个字节4.控制台输入函数键盘输入API函数ReadC
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 口服仿生纳米载体的制备及跨越肠吸收屏障研究
- 2025至2030年海水热泵项目投资价值分析报告
- 2025至2030年橡胶消毒柜脚项目投资价值分析报告
- 多因素耦合影响下零能耗生态厕所系统的可靠性研究
- 游客体验视角下建始县乡村旅游策略研究
- 2025至2030年复方磺胺间甲氧嘧啶钠溶液项目投资价值分析报告
- 山河智能资产支持票据发行动因、融资效果及优化策略研究
- 贵州民族大学幼儿园幼儿体质改善的实验研究
- 山区县域耕地时空演变及三位一体保护研究
- 2025年韵律服项目可行性研究报告
- 2025年度数据备份与恢复合法委托服务合同
- 2025年度跨境电商平台股权合同转让协议
- 《证券法培训》课件
- 心律失常介入并发症及预防
- 山西省2024年中考物理试题(含答案)
- 相互批评意见500条【5篇】
- 中国食物成分表2018年(标准版)第6版
- 2022版义务教育语文课程标准(2022版含新增和修订部分)
- 光纤通信原理课件 精品课课件 讲义(全套)
- 化工投料试车方案(一)
- 会所管理架构图
评论
0/150
提交评论