爆款云主机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:25 阅读次数:466

      数组,汇编语言

      整理复习汇编语言的知识点,以前在学习《Intel汇编语言程序设计 - 第五版》时没有很认真的整理笔记,主要因为当时是以学习理解为目的没有整理的很详细,这次是我第三次阅读此书,每一次阅读都会有新的收获,这次复习,我想把书中的重点,再一次做一个归纳与总结(注:16位汇编部分跳过),并且继续尝试写一些有趣的案例,这些案例中所涉及的指令都是逆向中的重点,一些不重要的我就直接省略了,一来提高自己,二来分享知识,转载请加出处,敲代码备注挺难受的。

      本次复习重点在于理解数组中常用的寻址方式以及标志位的测试命令,数组寻址包括了,直接寻址,间接寻址,立即数寻址,基址变址寻址,比例因子寻址,通过ESI内存寻址,通过ESP堆栈寻址,指针寻址。

      再次强调:该笔记主要学习的是汇编语言,不是研究编译特性的,不会涉及到编译器的优化与代码还原。

      <br>

      数组取值操作符: 数组取值操作符是对数组操作之前必须要掌握的,以下命令主要实现对数组元素的统计,取偏移值等,后期数组寻址会用到.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .data
      	WordVar1 WORD 1234h
      	DwordVar2 DWORD 12345678h
      	
      	ArrayBT BYTE 1,2,3,4,5,6,7,8,9,0h
      	ArrayDW DWORD 1000,2000,3000,4000,5000,6000,7000,8000,9000,0h
      	ArrayTP DWORD 30 DUP(?)
      .code
      
      	main PROC
      		; 使用 OFFSET 可返回数据标号的偏移地址,单位是字节.
      		; 偏移地址代表标号距DS数据段基址的距离.
      		xor eax,eax
      		mov eax,offset WordVar1
      		mov eax,offset DwordVar2
      		
      		; 使用 PTR 可指定默认取出参数的大小(DWORD/WORD/BYTE)
      		mov eax,dword ptr ds:[DwordVar2]     ; eax = 12345678h
      		xor eax,eax
      		mov ax,word ptr ds:[DwordVar2]       ; ax = 5678h
      		mov ax,word ptr ds:[DwordVar2 + 2]   ; ax = 1234h
      		
      		; 使用 LENGTHOF 可以计算数组元素的数量
      		xor eax,eax
      		mov eax,lengthof ArrayDW             ; eax = 10
      		mov eax,lengthof ArrayBT             ; eax = 10
      		
      		; 使用 TYPE 可返回按照字节计算的单个元素的大小.
      		xor eax,eax
      		mov eax,TYPE WordVar1                ; eax = 2
      		mov eax,TYPE DwordVar2               ; eax = 4
      		mov eax,TYPE ArrayDW                 ; eax = 4
      		
      		; 使用 SIZEOF 返回等于LENGTHOF(总元素数)和TYPE(每个元素占用字节)返回值的乘基.
      		xor eax,eax
      		mov eax,sizeof ArrayBT               ; eax = 10
      		mov eax,sizeof ArrayTP               ; eax = 120
      		
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      数组直接寻址: 在声明变量名称的后面加上偏移地址即可实现直接寻址,直接寻址中可以通过立即数寻址,也可以通过寄存器相加的方式寻址,如果遇到双字等还可以使用基址变址寻址,这些寻址都属于直接寻址.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .data
      	ArrayB BYTE 10h,20h,30h,40h,50h
      	ArrayW WORD 100h,200h,300h,400h
      	ArrayDW DWORD 1h,2h,3h,4h,5h,6h,7h,8h,9h
      .code
      	main PROC
      		; 针对字节的寻址操作
      		mov al,[ArrayB]           ; al=10
      		mov al,[ArrayB+1]         ; al=20
      		mov al,[ArrayB+2]         ; al=30
      
      		; 针对内存单元字存储操作
      		mov bx,[ArrayW]           ; bx=100
      		mov bx,[ArrayW+2]         ; bx=200
      		mov bx,[ArrayW+4]         ; bx=300
      
      		; 针对内存单元双字存储操作
      		mov eax,[ArrayDW]         ; eax=00000001
      		mov eax,[ArrayDW+4]       ; eax=00000002
      		mov eax,[ArrayDW+8]       ; eax=00000003
      		
      		; 基址加偏移寻址: 通过循环eax的值进行寻址,每次eax递增2
      		mov esi,offset ArrayW
      		mov eax,0
      		mov ecx,lengthof ArrayW
      	s1:
      		mov dx,word ptr ds:[esi + eax]
      		add eax,2
      		loop s1
      		
      		; 基址变址寻址: 循环取出数组中的元素
      		mov esi,offset ArrayDW                 ; 数组基址
      		mov eax,0                              ; 定义为元素下标
      		mov ecx,lengthof ArrayDW               ; 循环次数
      	s2:
      		mov edi,dword ptr ds:[esi + eax * 4]   ; 取出数值放入edi
      		inc eax                                ; 数组递增
      		loop s2
      		
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      数组间接寻址: 数组中没有固定的编号,处理此类数组唯一可行的方法是用寄存器作为指针并操作寄存器的值,这种方法称为间接寻址,间接寻址通常可通过ESI实现内存寻址,也可通过ESP实现对堆栈的寻址操作.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .data
      	ArrayDW DWORD 1h,2h,3h,4h,5h,6h,7h,8h,9h
      .code
      	main PROC
      		; 第一种: 通过使用ESI寄存器实现寻址.
      		mov esi,offset ArrayDW               ; 取出数组基地址
      		mov ecx,lengthof ArrayDW             ; 取出数组元素个数
      	s1:
      		mov eax,dword ptr ds:[esi]           ; 间接寻址
      		add esi,4                            ; 每次递增4
      		loop s1
      		
      		; 第二种: 通过ESP堆栈寄存器,实现寻址.
      		mov eax,100                ; eax=1
      		mov ebx,200                ; ebx=2
      		mov ecx,300                ; ecx=3
      		push eax                   ; push 1
      		push ebx                   ; push 2
      		push ecx                   ; push 3
      
      		mov edx,[esp + 8]          ; EDX = [ESP+8] = 1
      		mov edx,[esp + 4]          ; EDX = [ESP+4] = 2 
      		mov edx,[esp]              ; EDX = [ESP] = 3
      		
      		; 第三种(高级版): 通过ESP堆栈寄存器,实现寻址.
      		push ebp
      		mov ebp,esp                      ; 保存栈地址
      		lea eax,dword ptr ds:[ArrayDW]   ; 获取到ArrayDW基地址
      		; -> 先将数据压栈
      		mov ecx,9                        ; 循环9次
      	s2:	push dword ptr ss:[eax]          ; 将数据压入堆栈
      		add eax,4                        ; 每次递增4字节
      		loop s2
      		; -> 在堆栈中取数据
      		mov eax,32                       ; 此处是 4*9=36 36 - 4 = 32
      		mov ecx,9                        ; 循环9次
      	s3:	mov edx,dword ptr ss:[esp + eax] ; 寻找栈中元素
      		sub eax,4                        ; 每次递减4字节
      		loop s3
      		
      		add esp,36               ; 用完之后修正堆栈
      		pop ebp                  ; 恢复ebp
      
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      比例因子寻址: 通过使用比例因子,以下例子每个DWORD=4字节,且总元素下标=0-3,得出比例因子3* type arrayDW.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .data
      	ArrayW  WORD  1h,2h,3h,4h,5h
      	ArrayDW DWORD 1h,2h,3h,4h,5h,6h,7h,8h,9h
      
      	TwoArray DWORD 10h,20h,30h,40h,50h
      	RowSize = ($ - TwoArray)            ; 每行所占空间 20 字节
      		 DWORD 60h,70h,80h,90h,0ah
      		 DWORD 0bh,0ch,0dh,0eh,0fh
      .code
      	main PROC
      	
      		; 第一种比例因子寻址
      		mov esi,0                 ; 初始化因子
      		mov ecx,9                 ; 设置循环次数
      	s1:
      		mov eax,ArrayDW[esi * 4]  ; 通过因子寻址,4 = DWORD
      		add esi,1                 ; 递增因子
      		loop s1
      		
      		; 第二种比例因子寻址
      		mov esi,0
      		lea edi,word ptr ds:[ArrayW]
      		mov ecx,5
      	s2:
      		mov ax,word ptr ds:[edi + esi * type ArrayW]
      		inc esi
      		loop s2
      		
      		; 第三种二维数组寻址
      		row_index = 1
      		column_index = 2
      		
      		mov ebx,offset TwoArray            ; 数组首地址
      		add ebx,RowSize * row_index        ; 控制寻址行
      		mov esi,column_index               ; 控制行中第几个
      		mov eax, dword ptr ds:[ebx + esi * TYPE TwoArray]
      		
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      通过比例因子可以模拟实现二维数组寻址操作,过程也很简单.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .data
      	TwoArray DWORD 10h,20h,30h,40h,50h
      	RowSize = ($ - TwoArray)            ; 每行所占空间 20 字节
      		 DWORD 60h,70h,80h,90h,0ah
      		 DWORD 0bh,0ch,0dh,0eh,0fh
      .code
      	main PROC
      		lea esi,dword ptr ds:[TwoArray]  ; 取基地址
      		mov eax,0                        ; 控制外层循环变量
      		mov ecx,3                        ; 外层循环次数
      	s1:
      		push ecx                         ; 保存外循环次数
      		push eax
      		
      		mov ecx,5                        ; 内层循环数
      	s2:	add eax,4                        ; 每次递增4
      		mov edx,dword ptr ds:[esi + eax] ; 定位到内层循环元素
      		loop s2
      		
      		pop eax
      		pop ecx
      		add eax,20                       ; 控制外层数组
      		loop s1	
      
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      通过比例因子实现对数组求和操作,代码如下:

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .data
      	ArrayA DWORD 10h,20h,30h,40h,50h
      	ArrayB DWORD 10h,20h,30h,40h,50h
      	NewArray DWORD 5 dup(0)
      .code
      	main PROC
      		; 循环让数组中的每一个数加10后回写
      		mov ebx,0
      		mov ecx,5
      	s1:
      		mov eax,dword ptr ds:[ArrayA + ebx * 4]
      		add eax,10
      		mov dword ptr ds:[ArrayA + ebx * 4],eax
      		inc ebx
      		loop s1
      		
      		; 循环让数组A与数组B相加后赋值到数组NewArray
      		mov ebx,0
      		mov ecx,5
      	s2:
      		mov esi,dword ptr ds:[ArrayA + ebx]
      		add esi,dword ptr ds:[ArrayB + ebx]
      		mov dword ptr ds:[NewArray + ebx],esi
      		add ebx,4
      		loop s2
      
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      数组指针寻址: 变量地址的变量称为指针变量(pointer variable),Intel处理器使用两种基本类型的指针,即near(近指针)和far(远指针),保护模式下使用Near指针,所以它被存储在双字变量中.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .data
      	ArrayA  WORD  1h,2h,3h,4h,5h
      	ArrayB DWORD 1h,2h,3h,4h,5h
      	
      	PtrA DWORD offset ArrayA     ; 指针 PtrA --> ArrayA
      	PtrB DWORD offset ArrayB     ; 指针 PTRB --> ArrayB
      .code
      	main PROC
      	
      		mov ebx,0            ; 寻址因子
      		mov ecx,5            ; 循环次数
      	s1:
      		mov esi,dword ptr ds:[PtrA]          ; 将指针指向PtrA
      		mov ax,word ptr ds:[esi + ebx * 2]   ; 每次递增2字节
      		
      		mov esi,dword ptr ds:[PtrB]          ; 将指针指向PtrB
      		mov eax,dword ptr cs:[esi + ebx * 4] ; 每次递增4字节
      		inc esi              ; 基地址递增
      		inc ebx              ; 因子递增
      		loop s1
      
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      常见标志位测试: 标志寄存器又称程序状态寄存器,其主要用于存放条件码标志,控制标志和系统标志的寄存器,标志寄存器中存放的有条件标志,也有控制标志,这些标志则会影响跳转的实现,逆向中常见的标志位有如下几种.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .code
      	main PROC
      	; CF 进位标志位: 当执行一个加法(或减法)运算,使最高位产生进位(或借位)时,CF为1;否则为0
      		mov ax,0ffffh
      		add ax,1    ; cf = 1 af = 1
      
      	; PF 奇偶标志位: 当运算结果中,所有bit位(例:1001010)中1的个数为偶数时,则PF=1;为基数PF=0
      		mov eax,00000000b
      		add eax,00000111b  ; pf = 0
      		
      		mov eax,00000000b
      		add eax,00000011b  ; pf = 1
      
      	; ZF 零标志位: 若当前的运算结果为零,则ZF=1; 否则ZF=0
      		mov eax,2
      		sub eax,2   ; zf = 1 cf = 0 af = 0
      	
      	; SF 符号标志位: 若运算结果为负数,则SF=1;若为非负数则SF=0
      		mov eax,3e8h
      		sub eax,3e9h  ; sf = 1 cf = 1 af = 1 zf = 0
      	
      	; DF 方向标志位: 当DF=0时为正向传送数据(cld),否则为逆向传送数据(std)
      		cld
      		mov eax,1      ; df = 0
      		std
      		mov eax,1      ; df = 1
      
      	; OF 溢出标志位: 记录是否产生了溢出,当补码运算有溢出时OF=1;否则OF=0
      		mov al,64h
      		add al,64h     ; of = 1 cf = 0 pf = 0 af = 0
      	
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      TEST 位与指令: 该指令在对操作数之间执行隐含与运算操作,并设置相应的标志位,与AND指令唯一的不同在于,该指令只会设置相应的标志,并不会替换目的操作数中的数值,常用于测试某些位是否被设置.

      TEST指令可以同时检测设置多个标志位的值,该指令执行时总是清除溢出标志和进位标志,它修改符号标志,基偶标志,零标志的方式与AND指令相同.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .code
      	main PROC
      		mov al,00001111b
      		test al,2            ; zf=0 pf=0
      
      		mov al,00100101b
      		test al,00001001b    ; zf=0 pf=0
      		
      		mov al,00100100b
      		test al,00001001b    ; zf=1 pf=1
      		
      		mov eax,0100h
      		test eax,eax         ; zf=0
      		
      		mov eax,0
      		test eax,eax         ; zf=0
      		
      		or al,80h            ; 设置符号标志 zf=0 pf=0 sf=1
      		and al,7fh           ; 清除符号标志 zf=1 pf=1 sf=0
      		
      		mov al,0
      		or al,1              ; 清除符号标志 zf=0 pf=0
      
      		stc                  ; 设置进位标志 cf = 1
      		clc                  ; 清除进位标志 cf = 0
      		
      		mov al,07fh          ; AL = +127
      		inc al               ; 设置溢出标志 AL = 80h (-128) of=1 af=1 sf=1
      		or eax,0             ; 清除溢出标志
      
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      CMP 比较指令: 该指令作用是在源操作数和目的操作数中间执行隐含的减法运算,两个操作数都不会被修改,仅会影响标志位的变化,CMP指令是高级语言实现程序逻辑的关键,也是汇编中非常重要的指令常与跳转指令合用.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .code
      	main PROC
      		; 比较5和10
      		mov ax,5
      		cmp ax,10      ; 5-10 > zf=0 cf=1 pf=0 af=1 sf=1
      		
      		; 比较两个相同数
      		mov ax,1000
      		mov cx,1000
      		cmp cx,ax      ; 1000-1000 > zf=1 cf=0 pf=1 sf=0
      		
      		; 比较100和0
      		mov ax,100
      		cmp ax,0       ; 100-0 > zf=0 cf=0 pf=0
      		
      		; 比较100和50
      		mov eax,100
      		mov ebx,50
      		cmp eax,ebx    ; 100-50 > zf=0 cf=0 pf=0
      		
      		; 比较-100和50
      		mov eax,-100
      		mov ebx,50
      		cmp eax,ebx    ; -100-50 > sf=1 pf=1
      		
      		; 比较-100和-50
      		mov eax,-100
      		mov ebx,-50
      		cmp eax,ebx    ; -100--50 > cf=1 af=1 pf=0
      	
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      标志跳转指令: 跳转指令分为多种,第一种常见的跳转指令就是基于特定CPU的标志寄存器来实现的跳转形式.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .code
      	main PROC
      		; JZ/JE 当ZF置1时 也就是结果为零则跳转 (leftOp - rightOp = 0)
      		mov eax,1
      		sub eax,1     ; zf=1 pf=1
      		je jump
      		
      		mov eax,1
      		mov ebx,1
      		cmp eax,ebx   ; zf=1
      		jz jump
      		
      		; JNZ/JNE 当ZF置0时 也就是结果不为零则跳转 (leftOp - rightOp != 0)
      		mov eax,2
      		sub eax,1
      		jnz jump      ; zf=0 pf=0
      		
      		mov eax,2
      		cmp eax,1
      		jne jump      ; zf=0
      		
      		; JC/JNC 当 CF=1/0 设置进位标志则跳/未设置进位标志则跳
      		mov al,0
      		cmp al,1
      		jc jump
      		jnc jump
      		
      		; JO/JNO 当 OF=1/0 设置溢出标志则跳/未设置溢出标志则跳
      		mov al,0ffh
      		add al,1
      		jo jump
      		
      		; JS/JNS 当 SF=1/0 设置符号标志则跳/未设置符号标志则跳
      		mov eax,1
      		cmp eax,1
      		js jump       ; cf=0 af=0
      		
      		; JP/JNP PF=1/0 设置奇偶标志则跳(偶)/未设置奇偶标志则跳(基)
      		mov al,00100100b
      		cmp al,0
      		jp jump        ; zp=0
      	jump:
      		xor eax,eax
      		xor ebx,ebx
      		
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      比较跳转标志: 通过使用cmp eax,ebx比较等式两边的值,影响相应的标志寄存器中的值,从而决定是否要跳转,常用的如下:

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .code
      	main PROC
      		; JA(无符号)/JG(有符号) 跳转标志: (left > right) 大于则跳转
      		mov eax,100
      		mov ebx,200
      		cmp ebx,eax    ; 无符号 ebx > eax
      		ja jump        ; zf=0 pf=0
      		
      		mov eax,20
      		mov ebx,-100
      		cmp eax,ebx    ; 有符号 eax > ebx
      		jg jump        ; zf=0 cf=1 pf=1 af=1
      		
      		; JAE(无符号)/JGE(有符号) 跳转标志: (left >= right) 大于或等于则跳转
      		mov eax,50
      		mov ebx,20
      		cmp eax,ebx    ; 无符号 eax >= ebx
      		jae jump       ; jae 被替换成了jnb 小于则跳 (eax<ebx)
      		
      		mov eax,50
      		mov ebx,-20
      		cmp eax,ebx    ; 有符号 eax >= ebx
      		jge jump       ; zf=0 af=1 pf=0 sf
      		
      		; JB(无符号)/JL(有符号) 跳转标志:(left < right) 小于则跳转
      		mov eax,10
      		mov ebx,20
      		cmp eax,ebx     ; 无符号 eax < ebx
      		jb jump         ; cf=0 af=0 pf=1
      		
      		mov eax,-10
      		mov ebx,20
      		cmp eax,ebx     ; 有符号 eax < ebx
      		jl jump
      		
      		; JBE(无符号)/JLE(有符号) 跳转标志:(left <= right) 小于或等于则跳转
      		mov eax,20
      		mov ebx,20
      		cmp eax,ebx    ; 无符号 eax <= ebx
      		jbe jump       ; zf=1
      		
      		mov eax,-20
      		mov ebx,10
      		cmp eax,ebx    ; 无符号 eax,ebx
      		jle jump       ; sf=1
      		
      		; JNB(不小于则跳 同JAE)/JNA(不大于则跳 同JBE) 跳转标志:(lef !>< right) 无符号
      		mov eax,10
      		mov ebx,5
      		cmp eax,ebx    ; eax !< ebx
      		jnb jump
      		
      		mov eax,5
      		mov ebx,10
      		cmp eax,ebx    ; eax !> ebx
      		jbe jump
      
      		; JNB(不小于则跳 同JAE)/JNA(不大于则跳 同JBE) 跳转标志:(lef !>< right) 无符号
      		mov eax,10
      		mov ebx,5
      		cmp eax,ebx    ; eax !< ebx
      		jnb jump       ; zf=0 cf=0
      		
      		mov eax,5
      		mov ebx,10
      		cmp eax,ebx    ; eax !> ebx
      		jbe jump       ; cf=1 af=1 zf=0
      		
      		; JNL(不小于则跳 同JGE)/JNG(不大于则跳 同JLE) 跳转标志:(lef !>< right) 有符号
      		mov eax,10
      		mov ebx,-5
      		cmp eax,ebx    ; eax !< ebx
      		jnl jump       ; sf=0 cf=1 pf=1 af=1 zf=0
      		
      		mov eax,-10
      		mov ebx,5
      		cmp eax,ebx    ; eax !> ebx
      		jng jump       ; sf=1
      
      	jump:
      		xor eax,eax
      		xor ebx,ebx
      		
      		invoke ExitProcess,0
      	main ENDP
      END main
      

      BT/BSF/BSR 位测试指令: 首先BT系列命令主要用于对特定寄存器进行测试,清除,设置或求反等操作,它会影响CF标志位,而BSF/BSR命令则是对特定位中的值进行正反向扫描操作,它会影响ZF标志位.

      	.386p
      	.model flat,stdcall
      	option casemap:none
      
      include windows.inc
      include kernel32.inc
      includelib kernel32.lib
      
      .code
      	main PROC
      		; bt 普通的位测试命令
      		xor edx,edx
      		mov dx,10000001b
      		bt dx,7              ; 把DX第7位送入CF = 1
      		bt dx,6              ; 把DX第六位送入CF = 0
      		
      		; bts 位测试并置位
      		mov dx,10000001b
      		bts dx,6             ; cf = 0
      		bts dx,7             ; cf = 1
      		
      		; btr 位测试并复位.在执行BT同时,把操作数的指定位置为0
      		mov dx,10000001b
      		btr dx,7
      		btr dx,6             ; cf = 0
      		
      		;btc 位测试并取反.在执行BT同时,把操作数的指定位取反
      		mov dx,10000001b
      		btc dx,0             ; cf = 1
      		btc dx,0             ; cf = 0
      		
      		; BSF 执行位扫描 由低->高位 | BSR 由高 -> 到低
      		xor edx,edx
      		mov dx, 0000111100001100b
      		bsf cx,dx            ; 正向扫描,将扫描到1的位置放入CX
      		bsr cx,dx            ; 反向扫描 zf=0 pf=0
      		
      		xor ecx,ecx
      		mov cx,0
      		mov dx,0
      		bsf cx,dx
      		lahf
      
      		invoke ExitProcess,0
      	main ENDP
      END main
      
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://my.oschina.net/lyshark/blog/5597338,作者:LyShark,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:Win32汇编:汇编版PE结构解析器

      下一篇:Win32汇编:仿写多态与虚函数

      相关文章

      2025-05-19 09:04:14

      复杂度的OJ练习

      复杂度的OJ练习

      2025-05-19 09:04:14
      代码 , 复杂度 , 思路 , 数组 , 算法
      2025-05-16 09:15:24

      如何将一串数字用函数的方法倒过来(C语言)

      如何将一串数字用函数的方法倒过来(C语言)

      2025-05-16 09:15:24
      函数 , 数字 , 数组
      2025-05-16 09:15:24

      jQuery遍历对象、数组、集合

      jQuery遍历对象、数组、集合

      2025-05-16 09:15:24
      jQuery , 对象 , 数组 , 遍历 , 集合
      2025-05-16 09:15:17

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      递归,搜索,回溯算法(3)之穷举,暴搜,深搜,回溯,剪枝

      2025-05-16 09:15:17
      回溯 , 子集 , 数组 , 算法 , 递归
      2025-05-14 10:33:31

      计算机小白的成长历程——数组(1)

      计算机小白的成长历程——数组(1)

      2025-05-14 10:33:31
      strlen , 个数 , 元素 , 内存 , 十六进制 , 地址 , 数组
      2025-05-14 10:33:31

      计算机小白的成长历程——习题演练(函数篇)

      计算机小白的成长历程——习题演练(函数篇)

      2025-05-14 10:33:31
      函数 , 字符串 , 数组 , 知识点 , 编写 , 迭代 , 递归
      2025-05-14 10:02:48

      typescript 将数组清空

      在TypeScript或JavaScript开发中,数组是用于存储和管理一组数据的基础数据结构。当需要清空一个数组时,有多种方法可以实现,而选择合适的方法不仅影响代码的可读性,还会对性能产生一定的影响。不同场景下,选择适合的清空数组的方法至关重要。

      2025-05-14 10:02:48
      length , pop , 引用 , 数组 , 方法
      2025-05-13 09:50:28

      Java 两个小时以后

      最大正方形在一个由 '0' 和 '1' 组成的二维矩阵内,找到只包含 '1' 的最大正方形,并返回其面积。 

      2025-05-13 09:50:28
      length , matrix , nums , target , 数组
      2025-05-13 09:50:17

      java实现167. 两数之和 II - 输入有序数组

      给你一个下标从 1 开始的整数数组 numbers ,该数组已按 非递减顺序排列  ,请你从数组中找出满足相加之和等于目标数 target 的两个数。

      2025-05-13 09:50:17
      target , 两个 , 数组 , 整数
      2025-05-13 09:50:17

      java实现6. Z 字形变换

      将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。

      2025-05-13 09:50:17
      字符 , 字符串 , 数组
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5236462

      查看更多

      最新文章

      复杂度的OJ练习

      2025-05-19 09:04:14

      如何将一串数字用函数的方法倒过来(C语言)

      2025-05-16 09:15:24

      Java 两个小时以后

      2025-05-13 09:50:28

      用go语言,现有一棵无向、无根的树,树中有 n 个节点,按从 0 到 n - 1 编号 给你一个整数 n 和一个长度为 n - 1 的二维整数数组 edges

      2025-05-13 09:49:12

      存在重复元素 II-128. 最长连续序列

      2025-05-12 08:58:16

      Java基础(Arrays工具类)(asList()方法)(详细)

      2025-05-09 08:50:35

      查看更多

      热门文章

      Arrays类的使用

      2023-06-08 06:23:00

      Python打乱列表/数组原顺序,新列表/数组中元素随机分布

      2023-04-13 09:36:44

      Java 程序设计 第2章 Java基本语法 笔记

      2023-02-24 09:13:25

      Python数组列表过滤

      2023-04-17 09:39:09

      Win32汇编:汇编版PE结构解析器

      2023-05-04 08:57:32

      js面试题-1:检查是否存在重复元素

      2023-02-22 06:11:15

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

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

      天翼云电脑(公众版)

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

      对象存储

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

      云硬盘

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

      查看更多

      随机文章

      【Java】请写出你最常见到的 5 个 runtime exception

      用go语言,给定一个从1开始、长度为n的整数数组nums,定义一个函数greaterCount(arr, val)可以返回数组arr中大于val的元素数量。

      【C++滑动窗口】2653. 滑动子数组的美丽值|1785

      【C++ 滑动窗口】2122. 还原原数组|2158

      #私藏项目实操分享# Python 中的数组哪去了?

      用go语言,给定一个从 0 开始索引的整数数组 nums 和一个整数 k,请设计一个算法来使得数组中的所有元素都大于或等于 k,返回所需的最少操作次数。

      • 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号