爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      Win32汇编 - 过程与宏调用

      首页 知识中心 云计算 文章详情页

      Win32汇编 - 过程与宏调用

      2023-05-04 08:59:54 阅读次数:116

      过程

      堆栈操作指令

      在计算机领域,堆栈是一个不容忽视的概念,堆栈是一种后进先出(LIFO,Last-In,First-Out)的数据结构,这是因为最后压入堆栈的值总是最先被取出,而新数值在执行PUSH压栈时总是被加到堆栈的最顶端,数据也总是从堆栈的最顶端被取出,堆栈是个特殊的存储区,主要功能是暂时存放数据和地址,通常用来保护断点和现场.

      当程序运行时,栈是由CPU直接管理的线性内存数组,它使用两个寄存器(SS和ESP)来保存堆栈的状态.在保护模式下,SS寄存器存放段选择符(Segment Selector)运行在保护模式下的程序不能对其进行修改,而ESP寄存器的值通常是指向特定位置的一个32位偏移值,我们很少需要直接操作ESP寄存器,相反的ESP寄存器总是由CALL,RET,PUSH,POP等这类指令间接性的修改.

      接着来简单介绍下关于堆栈操作的两个寄存器,CPU系统提供了两个特殊的寄存器用于标识位于系统栈顶端的栈帧.
      ESP 栈指针寄存器: 栈指针寄存器,其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶.
      EBP 基址指针寄存器: 基址指针寄存器,其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部.

      ◆堆栈参数传递◆

      在通常情况下ESP是可变的,随着栈的生产而逐渐变小,而EBP寄存器是固定的,只有当函数的调用后,发生入栈操作而改变.

      1.在32位系统中,执行PUSH压栈时,堆栈指针自动减4,再将压栈的值复制到堆栈指针所指向的内存地址.
      2.在32位系统中,执行POP出栈时,从栈顶移走一个值并将其复制给内存或寄存器,然后再将堆栈指针自动加4.
      3.在32位系统中,执行CALL调用时,CPU会用堆栈保存当前被调用过程的返回地址,直到遇到RET指令再将其弹出.

      PUSH/POP指令: 在32位环境下,分别将数组中的元素100h-300h压入堆栈,并且通过POP将元素反弹出来.

      .data
      	Array DWORD 100h,200h,300h,400h
      .code
      	main PROC
      		xor eax,eax
      		push eax                      ; push 0
      		push DWORD PTR [Array]        ; push 100
      		push DWORD PTR [Array+4]      ; push 200
      		push DWORD PTR [Array+8]      ; push 300
      		pop eax                       ; pop 300
      		pop eax                       ; pop 200
      		pop eax                       ; pop 100
      		pop eax                       ; pop 0
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      PUSHFD/POPFD指令: PUSHFD在堆栈上压入EFLAGS寄存器的值,POPFD将堆栈的值弹出并送至EFLAGS寄存器.

      .data
      	SaveFlage DWORD ?
      .code
      	main PROC
      		pushfd            ; 标识入栈
      		pop SaveFlage     ; 弹出并保存到内存
      
      		push SaveFlage    ; 从内存取出,并入栈
      		popfd             ; 恢复到EFLAGS寄存器中
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      PUSHAD/POPAD指令: 将通用寄存器按照EAX,ECX,EDX,EBX,ESP,EBP,ESI,EDI的顺序压栈保存.

      .code
      	main PROC
      		pushad
      		mov eax,1000
      		mov ebx,2000
      		mov ecx,3000
      		mov edx,4000
      		popad
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      ◆声明局部变量◆

      高级语言程序中,在单个过程中创建使用和销毁的变量我们称它为局部变量(local variable),局部变量是在程序运行时,由系统动态的在栈上开辟的,在内存中通常在基址指针(EBP)之下,尽管在汇编时不能给定默认值,但可以在运行时初始化,如下一段伪代码:

      void MySub()
      {
      	int var1 = 10;
      	int var2 = 20;
      }
      

      上面的一段代码经过C编译器转换后,会变成如下的样子,其中EBP-4必须是4的倍数,因为默认就是4字节存储.

      MySub PROC
      	push ebp                  ; 将EBP存储在栈中
      	mov ebp,esp               ; 堆栈框架的基址
      	sub esp,8                 ; 创建局部变量空间
      
      	mov DWORD PTR [ebp-4],10  ; var1 = 10
      	mov DWORD PTR [ebp-8],20  ; var2 = 20
      
      	mov esp,ebp               ; 从堆栈上删除局部变量
      	pop ebp                   ; 恢复EBP指针
      	ret 8                     ; 返回,清理堆栈
      MySub ENDP
      

      如果去掉了上面的mov esp,ebp,那么当执行pop ebp时将会得到EBP等于10,执行RET指令会导致控制转移到内存地址10处执行,从而程序会崩溃.

      为了使代码更加的容易阅读,可以在上面的代码的基础上给每个变量的引用地址都定义一个符号并在代码中使用这些符号来完成编写.

      var1_local EQU DWORD PTR [ebp-4]
      var2_local EQU DWORD PTR [ebp-8]
      
      MySub PROC
      	push ebp
      	mov ebp,esp
      	sub esp,8
      	mov var1_local,10
      	mov var2_local,20
      	mov esp,ebp
      	pop ebp
      	ret 8
      MySub ENDP
      

      ◆ENTER/LEAVE 伪指令◆

      ENTRE指令自动为被调用过程创建堆栈框架,它为局部变量保留堆栈空间并在堆栈上保存EBP,该指令执行后会执行以下动作.

      1.在堆栈上压入EBP(push ebp)
      2.把EBP设为堆栈框架的基指针(mov ebp,esp)
      3.为局部变量保留适当的空间(sub esp,numbytes)

      ENTER指令有两个参数,第一个操作数是一个常量,用于指定要为局部变量保留多少堆栈空间(numbytes),第二个参数指定过程的嵌套层数,这两个操作数都是立即数,numbytes总是向上取整为4的倍数,以使ESP按照双字边界地址对其.

      比如以下代码,使用ENTER为局部变量保存8字节的堆栈空间:

      MySub PROC
      	enter 8,0
      MySub ENDP
      

      经过编译器转换后,会首先转换为以下的样子:

      MySub PROC
      	push ebp
      	mov ebp,esp
      	sub esp,8
      MySub ENDP
      

      上面的代码只有开头没有结尾,如果要使用ENTER指令分配空间的话,则必须在结尾加上LEAVE指令,这样程序才完整.

      MySub PROC
      	enter 8,0
      ....
      	leave
      	ret
      MySub ENDP
      

      下面代码和上面代码作用是相同的,它首先为局部变量保留8字节的堆栈空间然后丢弃.

      MySub PROC
      	push ebp
      	mov ebp,esp
      	sub esp,8
      ....
      	mov esp,ebp
      	pop ebp
      	ret
      MySub ENDP
      

      ◆USES/LOCAL 伪指令◆

      USES操作符: 该操作符用于指定需要压栈的寄存器,其会自动生成压栈出栈代码无需手动添加.

      .code
      	main PROC
      		mov eax,1
      		mov ebx,2
      		mov ecx,3
      		call mycall
      		push 0
      		call ExitProcess
      	main ENDP
      
      	mycall PROC USES eax ebx ecx     ; 生成压栈代码,自动压eax,ebx,ecx
      		xor eax,eax              ; 压栈的寄存器可以随意修改
      		xor ebx,ebx              ; 过程结束后会自动恢复这些寄存器
      		ret
      	mycall ENDP
      END main
      

      LOCAL操作符: 在过程内声明一个或多个命名局部变量,并赋予相应的尺寸属性,该语句必须紧跟PROC指令后面.

      .code
      	main PROC
      		LOCAL var1:WORD
      		LOCAL var2:DWORD,var3:BYTE
      
      		mov DWORD PTR [var1],1024
      		mov eax,DWORD PTR [var1]
      		mov [var2],1024            ; DWORD
      		mov eax,[var2]
      		mov [var3],10              ; BYTE
      		mov al,[var3]
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      局部变量:

      .code
      	lyshark PROC var1:WORD,var2:DWORD
      		LOCAL @loca1:BYTE,@loca2:DWORD
      		LOCAL @local_byte[100]:BYTE
      		
      		mov ax,var1
      		mov ebx,@loca2
      		
      		lea ecx,@local_byte
      		mov @local_byte[0],0
      		mov @local_byte[1],1
      		mov @local_byte[2],2
      		mov @local_byte[3],3
      	lyshark ENDP
      
      	main PROC
      		invoke lyshark,100,10000
      		ret
      	main ENDP
      END main
      

      LOCAL(申请数组):

      .code
      	main PROC
      		LOCAL var[3]:DWORD
      		
      		mov var[0],100
      		mov var[1],200
      		
      		mov eax,var[0]
      		mov ebx,var[1]
      	main ENDP
      END main
      
      .code
      	main PROC
      		LOCAL ArrayDW[10]:DWORD
      		LOCAL ArrayB[10]:BYTE
      
      		lea eax,[ArrayDW]
      		mov [ArrayDW],10
      		mov [ArrayDW + 4],20
      		mov [ArrayDW + 8],30
      	main ENDP
      END main
      

       

      过程调用指令

      CALL指令指示处理器在新的内存地址执行指令,当用户调用CALL指令时,该指令会首先将CALL指令的下一条指令的内存地址压入堆栈保存,然后将EIP寄存器修改为CALL指令的调用处,等调用结束后返回从堆栈弹出CALL的下一条指令地址.

      1.当遇到CALL指令时,程序会经过计算得到CALL指令的下一条指令的地址,并将其压入堆栈.
      2.接着会将EIP寄存器的地址指向被调用过程的地址,被调用过程被执行.
      3.最后过程内部通过RET指令返回,将从堆栈中弹出EIP的地址,程序继续向下执行.
      4.CALL相当于push+jmp,RET相当于pop+jmp.

      普通参数传递:

      .code
      	sum PROC var1:DWORD,var2:DWORD,var3:DWORD
      		mov eax,var1
      		mov ebx,var2
      		mov ecx,var3
      		ret
      	sum ENDP
      
      	main PROC
      		invoke sum,10,20,30      ; 调用并传递参数
      		ret
      	main ENDP
      END main
      

      寄存器传递参数:

      .code
      	sum PROC
      		add eax,ebx
      		add eax,ecx
      		ret
      	sum ENDP
      
      	main PROC
      		mov eax,10
      		mov ebx,20
      		mov ecx,30
      		call sum
      		ret
      	main ENDP
      END main
      

      使用PROTO声明: 如果调用的函数在之后实现, 须用 PROTO 提前声明,否则会报错

      sum PROTO :DWORD,:DWORD,:DWORD ; 函数声明的主要是参数类型,省略参数名
      
      .code
      	main PROC
      		invoke sum,10,20,30    ; 现在调用的是之后的函数
      		ret
      	main ENDP
      
      	sum PROC var1,var2,var3
      		mov eax,var1
      		add eax,var2
      		add eax,var3
      		ret
      	sum ENDP
      END main
      

      CALL/RET指令: 编写一个过程,实现对整数数组的求和,并将结果保存到EAX寄存器中.

      .data
      	array DWORD 1000h,2000h,3000h,4000h,5000h
      	theSum DWORD ?
      .code
      	main PROC
      		mov esi,offset array          ; ESI指向array
      		mov ecx,lengthof array        ; ECX=array元素个数
      		call ArraySum                 ; 调用求和指令
      		mov theSum,eax                ; 将结果保存到内存
      		push 0
      		call ExitProcess
      	main ENDP
      
      	ArraySum PROC
      		push esi           ; 保存ESI,ECX
      		push ecx
      		mov eax,0          ; 初始化累加寄存器
      	L1:
      		add eax,[esi]      ; 每个整数都和EAX中的和相加
      		add esi,TYPE DWORD ; 递增指针,继续遍历
      		loop L1
      		pop ecx            ; 恢复寄存器
      		pop esi
      		ret
      	ArraySum ENDP
      END main
      

      通过该语句块配合可以生成自定义过程,下面我们创建一个名为Sum的过程,实现EBX+ECX并将结果保存在EAX寄存器中.

      .data
      	TheSum DWORD ?
      .code
      	main PROC
      		mov ebx,100     ; 传递ebx
      		mov ecx,100     ; 传递ecx
      		call Sum        ; 调用过程
      		mov TheSum,eax  ; 保存结果到TheSum
      
      		push 0
      		call ExitProcess
      	main ENDP
      	
      	Sum PROC
      		xor eax,eax
      		add eax,ebx
      		add eax,ecx
      		ret
      	Sum ENDP
      END main
      

      INVOKE调用系统API: 默认情况下,会将返回结果保存在eax寄存器中.

      .data
      	szCaption db "MsgBox",0
      	szText db "这是一个提示框,请点击确定完成交互!",0
      .code
      	main PROC
      		.WHILE (1)
      			invoke MessageBox,NULL,offset szText,offset szCaption,MB_YESNO
      			.break .if(eax == IDYES)
      		.ENDW
      		ret
      	main ENDP
      END main
      

      模块化调用: 首先创建一个sum.asm然后在main.asm中引用sum这个文件中的函数.

      ; sum.asm 首先编译这个文件,并将其放入指定目录下
      	.386
      	.model flat, stdcall
      .code
      	sum PROC v1, v2, v3
      	    mov eax, v1
      	    add eax, v2
      	    add eax, v3
      	    ret
      	sum ENDP
      end
      
      ; main.asm 直接引用编译后的lib文件即可
      ;这里的引入路径可以是全路径, 这里是相对路径
      includelib /masm32/lib/sum.lib
      
      ;子程序声明
      sum proto :dword, :dword, :dword
      .code
      	main PROC
      		invoke sum,10,20,30    ;调用过程
      		ret
      	main ENDP
      END main
      

       

      结构与联合

      结构(struct)时逻辑上互相关联的一组变量的模板或模式,结构中的单个变量称为域(field),程序的语句可以把结构作为一个实体进行访问,也可以对结构的单个域进行访问,结构通常包括不同类型的域,而联合(union)同样也是把多个标识符组合在一起,不过与结构不同的是,联合体共用用一块内存区域,内存的大小取决于联合体中最大的元素.

      引用结构变量: 通过使用<>,{}均可声明结构体,同时可以初始化,对结构体赋初值.

      ;定义结构
      MyPoint struct
      	pos_x DWORD ?
      	pos_y DWORD ?
      MyPoint ends
      
      .data
      	;声明结构, 使用 <>、{} 均可
      	ptr1 MyPoint <10,20>
      	ptr2 MyPoint {30,40}
      
      .code
      	main PROC
      		lea edx, ptr1
      		mov eax, (MyPoint ptr [edx]).pos_x   ; 此时eax=10
      		mov ebx, (MyPoint ptr [edx]).pos_y   ; 此时ebx=20
      		mov (MyPoint PTR [edx]).pos_x,100    ; 将100写入MyPoint.pos_x结构中存储
      		ret
      	main ENDP
      END main
      

      结构初始化: 以下定义了MyStruct结构,并将user2初始化,FName=lyshark,FAge=25.

      MyStruct struct
      	FName db 20 dup(0)
      	FAge db 100
      MyStruct ends
      
      .data
      	user1 MyStruct <>
      	user2 MyStruct <'lyshark',25>
      
      .code
      	main PROC
      		;lea edx, user1
      		;mov eax,DWORD PTR (MyStruct ptr[edx]).FName
      		;mov ebx,DWORD PTR (MyStruct ptr[edx]).FAge
      
      		mov eax,DWORD PTR [user2.FName]   ; eax=lyshark
      		mov ebx,DWORD PTR [user2.FAge]    ; ebx=25
      		ret
      	main ENDP
      END main
      

      使用系统结构: 通过调用GetLocalTime获取系统时间,并存储到SYSTEMTIM结构体中.

      .data
      	sysTime SYSTEMTIME <>           ; 声明结构体
      
      .code
      	main PROC
      		invoke GetLocalTime,addr sysTime    ; 获取系统时间并放入sysTime
      		mov eax,DWORD PTR sysTime.wYear     ; 获取年份
      		mov ebx,DWORD PTR sysTime.wMonth    ; 获取月份
      		mov ecx,DWORD PTR sysTime.wDay      ; 获取天数
      		ret
      	main ENDP
      END main
      

      结构体的嵌套定义:

      MyPT struct
      	pt_x DWORD ?
      	pt_y DWORD ?
      MyPT ends
      Rect struct
      	Left MyPT <>
      	Right MyPT <>
      Rect ends
      
      .data
      	LyShark1 Rect <>
      	LyShark2 Rect {<10,20>,<100,200>}
      .code
      	main PROC
      		mov [LyShark1.Left.pt_x],100
      		mov [LyShark1.Left.pt_y],200
      		
      		mov [LyShark1.Right.pt_x],1000
      		mov [LyShark1.Right.pt_y],2000
      		mov eax,[LyShark1.Left.pt_x]
      		ret
      	main ENDP
      END main
      

      联合体的声明:

      ; 定义联合体
      MyUnion union
      	My_Dword DWORD ?
      	My_Word WORD ?
      	My_Byte BYTE ?
      MyUnion ends
      
      .data
      	test1 MyUnion {1122h}; ;只能存放初始值
      .code
      	main PROC
      		mov eax, [test1.My_Dword]
      		mov ax, [test1.My_Word]
      		mov al, [test1.My_Byte]
      		ret
      	main ENDP
      END main
      

       

      关于宏汇编

      宏过程(Macro Procedure)是一个命名的语汇编语句块,一旦定义后,宏过程就可以在程序中被调用任意多次,调用宏过程的时候,宏内的语句块将替换到调用的位置,宏的本质是替换,但像极了子过程,宏可定义在源程序的任意位置,但一般放在.data前面.

      一个简单的宏:

      MyCode macro
      	xor eax,eax
      	xor ebx,ebx
      	xor ecx,ecx
      	xor edx,edx
      endm
      
      .code
      	main PROC
      		MyCode   ; 将被替换为上面两行代码
      		ret    
      	main ENDP
      END main
      

      一个代替求和函数的宏

      MySum macro  var1, var2, var3
      	mov eax,var1
      	add eax,var2
      	add eax,var3
      endm
      
      .code
      	main PROC
      		MySum 10,20,30
      		MySum 10,20,30,40   ; 多余的参数40会被忽略
      		ret    
      	main ENDP
      END main
      

      宏参数的默认值: 通过定义默认值,可以不给默认的变量传递参数.

      ; 参数 var1、var2 通过 REQ 标识说明是必备参数
      MySum macro  var1:req, var2:req, var3:=<30>    ; var3默认值是30
      	mov eax,var1
      	add eax,var2
      	add eax,var3
      endm
      
      .code
      	main PROC
      		MySum 10,20
      		ret    
      	main ENDP
      END main
      

      使用EXITM终止宏执行: 可使用关键字exitm 终止宏代码的后面内容.

      MySum macro
      	xor eax,eax
      	xor ebx,ebx
      	xor ecx,ecx
      	exitm        ; 只会清空前三个寄存器,后面的跳过了
      	xor edx,edx
      	xor esi,esi
      endm
      
      .code
      	main PROC
      		MySum
      		ret    
      	main ENDP
      END main
      

      使用PURGE取消指定宏的展开:

      MySum macro
      	xor eax,eax
      	xor ebx,ebx
      endm
      
      .code
      	main PROC
      		MySum           ; 这个会被展开
      		purge MySum     ; 这个不会展开
      		MySum           ; 这个宏也不会展开了
      		ret
      	main ENDP
      END main
      

      在宏内使用局部标号:

      MyMax macro var1,var2
      	LOCAL jump
      	
      	mov eax,var1
      	cmp eax,var2
      	jge jump
      	xor eax,eax
      jump:	ret
      endm
      
      .code
      	main PROC
      		MyMax 20,10
      	main ENDP
      END main
      

      特殊操作符: &、<>、%、!

      &  ;替换操作符
      <> ;字符串传递操作符
      %  ;表达式操作符, 也用于得到一个变量或常量的值
      !  ;转义操作符
      ;自定义的宏
      mPrint macro Text
          PrintText '* &Text& *'
      endm
      
      .code
      main proc
          ;该宏会把参数直接替换过去
          mPrint 1234    ;* 1234 *
          
          ;要保证参数的完整应该使用 <>
          mPrint 12,34   ;* 12 *
          mPrint <12,34> ;* 12,34 *
          
          ;需要计算结果应该使用 %()
          mPrint 34+12   ;* 34+12 *
          mPrint %(34+12)   ;* 46 *
          
          ;用到 &、<、>、%、! 应该使用 ! 转义
          mPrint 10 !% 2 = %(10/2)!! ;* 10 % 2 = 5! *
          ret
      main endp
      end main
      

       

      过程小例子

      整数求和: 通过使用汇编语言实现一个整数求和的小例子.

      .data
      	String WORD 100h,200h,300h,400h,500h
      .code
      	main PROC
      		;lea edi,String           ; 取String数组的基址
      		mov edi,offset String     ; 同上,两种方式均可
      		mov ecx,lengthof String   ; 取数组中的数据个数
      		mov ax,0                  ; 累加器清零
      	L1:
      		add ax,[edi]              ; 加上一个整数
      		add edi,TYPE String       ; 指向下一个数组元素,type(2byte)
      		loop L1
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      正向复制字符串: 使用汇编语言实现字符串的复制,将数据从source复制到target内存中.

      .data
      	source BYTE "hello lyshark welcome",0h
      	target BYTE SIZEOF source DUP(0),0h       ; 取源地址数据大小
      .code
      	main PROC
      		mov esi,0                  ; 使用变址寄存器
      		mov ecx,sizeof source      ; 循环计数器
      	L1:
      		mov al,source[esi]         ; 从源地址中取一个字符
      		mov target[esi],al         ; 将该字符存储在目标地址中
      		inc esi                    ; 递增,将指针移动到下一个字符
      		loop L1
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      反向复制字符串: 使用汇编语言实现字符串的复制,将数据从source复制到target内存中且反向存储数据.

      .data
      	source BYTE "hello lyshark welcome",0h
      	target BYTE SIZEOF source DUP(0),0h
      .code
      	main PROC
      		mov esi,sizeof source
      		mov ecx,sizeof source
      		mov ebx,0
      	L1:
      		mov al,source[esi]
      		mov target[ebx],al
      		dec esi
      		inc ebx
      		loop L1
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      查看内存与寄存器: 通过调用DumpMem/DumpRegs显示内存与寄存器的快照.

      .data
      	array DWORD 1,2,3,4,5,6,7,8,9,0ah,0bh
      .code
      	main PROC
      		mov esi,offset array       ; 设置内存起始地址
      		mov ecx,lengthof array     ; 设置元素数据,偏移
      		mov ebx,type array         ; 设置元素尺寸(1=byte,2=word,4=dword)
      		call DumpMem               ; 调用内存查询子过程
      		call DumpRegs              ; 调用查询寄存器子过程
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      汇编实现性能度量: 通过调用库函数,实现对指定代码执行的性能度量.

      .data
      	StartTime DWORD ?
      .code
      	main PROC
      
      		call GetMseconds       ; 调用区本地时间过程
      		mov StartTime,eax      ; 将返回值赋值给StartTime
      
      		mov ecx,10             ; 通过调用延时过程,模拟程序的执行
      	L1:
      		mov eax,1000           ; 指定延时1s=1000ms
      		call Delay             ; 调用延时过程
      		loop L1
      
      		call GetMseconds       ; 再次调用本地时间过程
      		sub eax,StartTime      ; 结束时间减去开始时间
      		call WriteDec          ; 以十进制形式输出eax寄存器的值
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      字符输出: WriteString(字符串),WriteInt(整数),WriteHex(16进制),WriteChar(字符),WriteDec(10进制).

      .data
      	Message BYTE "Input String:",0h
      	String DWORD ?
      
      .code
      	main PROC
      		; 设置控制台背景颜色
      		mov eax,yellow +(blue*16)     ; 设置为蓝底黄字
      		call SetTextColor             ; 调用设置过程
      		call Clrscr                   ; 清除屏幕,clear
      
      		; 提示用户一段话
      		mov edx,offset Message        ; 指定输出的文字
      		call WriteString              ; 调用回写过程
      		call Crlf                     ; 调用回车
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      字符输入: ReadString(字符串),ReadInt(整数),ReadHex(16进制),ReadChar(字符),ReadDec(10进制).

      .data
      	Buffer BYTE 21 DUP(0)          ; 输入缓冲区
      	ByteCount DWORD ?              ; 存放计数器      
      .code
      	main PROC
      		mov edx,offset Buffer      ; 指向缓冲区指针
      		mov ecx,sizeof Buffer      ; 指定最多读取的字符数
      		call ReadString            ; 读取输入字符串
      		mov ByteCount,eax          ; 保存读取的字符数
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      生成伪随机数:

      .code
      	main PROC
      		mov ecx,5           ; 循环生成5个随机数
      	L1:
      		call Random32       ; 生成随机数
      		call WriteDec       ; 以十进制显示
      		mov al,TAB          ; 水平制表符
      		call WriteChar      ; 显示水平制表符
      		loop L1
      		call Crlf           ; 回车
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      

      生成自定义随机数:

      .code
      	main PROC
      		mov ecx,5           ; 循环生成5个随机数
      	L1:
      		mov eax,100         ; 0-99之间
      		call RandomRange    ; 生成随机数
      		sub eax,50          ; 范围在-50-49
      		call WriteInt       ; 十进制输出
      		mov al,TAB
      		call WriteChar      ; 输出制表符
      		loop L1
      		call Crlf           ; 回车
      
      		push 0
      		call ExitProcess
      	main ENDP
      END main
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://my.oschina.net/lyshark/blog/5550828,作者:LyShark,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:Docker 部署 Tomcat

      下一篇:【Java Web】 Tomcat 的 使用、部署

      相关文章

      2025-05-06 09:21:03

      MFC中如何使用拦截消息

      拦截消息是可以修改控件或者窗口现有的功能,MFC的子类化技术用C++语言把Windows窗口和各种控件镜像包装,是MFC的核心技术。

      2025-05-06 09:21:03
      函数 , 指定 , 控件 , 窗口 , 过程
      2025-04-01 10:29:01

      第13关:存储过程1、第14关:存储过程2。

      第13关:存储过程1、第14关:存储过程2。

      2025-04-01 10:29:01
      任务 , 存储 , 数据表 , 过程
      2025-03-26 09:31:12

      sql server 创建存储过程 实例

      存储过程(Stored Procedure)是SQL Server中的一段预编译的SQL代码,能够在数据库中保存并重复执行。它们可以接受参数,并且可以返回数据和错误信息。存储过程的使用可以提高代码的重用性、安全性和性能。

      2025-03-26 09:31:12
      SQL , 参数 , 存储 , 示例 , 过程
      2025-03-17 08:48:47

      【mySQL】mySQL动态语句(SQL语句中有变量)

      【mySQL】mySQL动态语句(SQL语句中有变量)

      2025-03-17 08:48:47
      sql , 动态 , 存储 , 语句 , 过程 , 预处理
      2025-03-17 07:58:55

      MySQL之存储过程创建和调用

      MySQL之存储过程创建和调用

      2025-03-17 07:58:55
      创建 , 存储 , 语句 , 调用 , 过程
      2025-03-12 09:31:11

      MySQL之存储过程按月创建表

      MySQL之存储过程按月创建表

      2025-03-12 09:31:11
      SQL , 创建 , 存储 , 语句 , 过程
      2025-03-04 09:07:50

      Mysql触发器|视图|定时器|存储过程

      Mysql触发器|视图|定时器|存储过程

      2025-03-04 09:07:50
      存储 , 数据 , 视图 , 触发器 , 过程
      2025-02-25 08:55:28

      python中字典重复赋值,append到list中引发的异常

      python中字典重复赋值,append到list中引发的异常

      2025-02-25 08:55:28
      date , 代码 , 字典 , 循环 , 数据 , 过程 , 迭代
      2025-02-14 08:30:05

      【C++】递归算法解决汉诺塔问题

      【C++】递归算法解决汉诺塔问题

      2025-02-14 08:30:05
      汉诺塔 , 移动 , 算法 , 过程 , 递归
      2023-05-06 09:00:26

      Word中替换图序号的宏

      大家在用word写文章时,有时候需要复制一些以前写好的文章,这时候就需要替换图中的序号,如果一个一个的重新排列图号,是非常麻烦的事情,所以,我编辑了一个“宏”,到时用宏命令替换就可以了 附:宏命令内容如下。 Sub 替换()'

      2023-05-06 09:00:26
      word
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5247312

      查看更多

      热门标签

      系统 测试 用户 分布式 Java java 计算机 docker 代码 数据 服务器 数据库 源码 管理 python
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号