汇编语言学习笔记(三)

八、逻辑运算指令

数字在计算机中以二进制存储,每个位数字为0或者1,当两个二进制数字进行逻辑按位&,逻辑按位|,逻辑异或^操作,

可以采用汇编语言提供的逻辑运算指令and,or, xor,not等指令。

and指令:

C语言&操作,将0110&1101得出结果为0100

C语言代码为

if(flag & maskit)
   count++;

汇编语言高级指令可实现:

mov eax, flag
.if eax & maskit
inc count
.endif

不采用高级指令的情况下可采用如下代码:

if01:     mov eax, flag
          and eax, flag
          jz endif01
then01:   inc count
endif01:  nop

and指令和cmp指令一样,and运算执行后,eflags寄存器的响应比特位会被设置。

同样xor,not, or等指令也会设置eflags相应比特位。

jz 指令之前介绍过,当eflags寄存器相应比特位被设置为0后该指令将逻辑跳转到指定位置。

同样ZERO?也可以判断eflags寄存器相应比特位是否被设置为0,为零则为真,反之为假

mov eax, flag
and eax, maskit
.if !ZERO?
inc count
.endif

or指令:

or指令和and指令用法一样

;flag = flag | maskit
mov eax, flag
or eax, maskit
mov flag, eax

xor指令:

;flag = flag ^ maskit;
mov eax, flag
xor eax, maskit
mov flag, eax

三种指令的两个参数类型限制是一样的

and mem, imm

and mem, reg

and reg, reg

and reg, imm

and reg, mem

or, xor参数类型和上面and一样,三种命令都不可以直接操作两个内存变量。

、逻辑移位指令

shl reg, cl 将reg中数据向左移动cl寄存器中数值大小的位数。

shl reg, imm 将reg中数据向左移动imm立即数大小的位数。

举例:

mov cl , 3
shl reg, cl
;也可以采取立即数
shl reg, 3

上述代码都是将reg中数值向左移动三位,那为什么采用cl寄存器呢?因为在老式

的8086/8088处理器上,操作数中能使用的唯一立即数为1,如果调用shl reg,3

会出问题,所以通常的做法是mov cl, 3先将3移动到cl寄存器中,再调用

shl reg, cl可完成reg数值向左移动3位。

shl 的参数出去reg,还可以是mem内存

shl mem, cl

shl mem, imm

同样shr为向右移动,参数形式和shl一样。

如果10101010调用shl向左移动一位,那么所有比特位的数字依次左移,

第0个位置比特位数字填充0,第7个比特位数字1向左移动到CF进位标记里。

数字变为01010100。

同理,shr逻辑右移也是移动后第7个比特位补充0,第0个比特位数字放入CF标记中。

写一段代码测试每个比特位数字为1的位数。

mov count, 0
mov ecx, 8
mov temp , al
.repeat
mov ah, al
and ah, 00000001b
.if !ZERO?
inc count
.endif
shr al, 1
.untilcxz
mov al, temp

由于and指令会导致第一个参数数值被修改,所以将al数值每次and操作前都

copy到ah中。最后处理完所有比特位,将temp数据copy回al中。

test命令可以避免and修改第一个参数数值的问题,同样test命令使用后

eflags寄存器相应的比特位也会被设置。

mov count, 0
mov ecx, 8
mov temp, al
.repeat
test al, 00000001b
.if !ZERO?
inc count
.endif
shr al, 1
.untilcxz
mov al, temp

、逻辑移位指令

算数左移

sal reg, cl

sal reg, imm

sal, mem, cl

sal reg, cl

参数和shl一样。移动效果和shl一样,都是将低比特位依次移动到高比特位,最高比特位

移动到CF标记里,空位补0。

移动示意图:

如果符号位为0,那么左移操作和shl一样,没什么问题。

如果符号位也就是第七个比特位为1,如1111 0000,向左移动一位那么数据为

1110 0000,左移操作后数值为原数值乘以2,负数在计算机中以补码形式存储。

整数的补码为原码,负数的补码为整数原码按位取反末尾加1, 1111 0000-1为

1110 1111,按位取反后为0001 0000,该数值为十进制16,所以1111 0000为

-16,-16乘以2,也就是左移操作,为-32,那么-32在二进制中如何表示呢?

32用8位二进制表示为0010 0000,负数为正数原码按位取反末尾+1,0010 0000取反后

为1101 1111,末尾+1为1110 0000, 1110 0000恰好为1111 0000左移一位得到的数字。

考虑这样一个问题,如果是图中所示数字10101010左移会造成数字变为0101 0100,这样

最高位变为0怎么办?

这就是所谓的左移溢出,8位二进制能表示的二进制数为0111 11111~1111 1111 。

0111 1111 表示十进制127

1111 1111 表示十进制-1

1000 0000 是负数补码, 该数-1取反后得到1000 0000 该数值为128原码

所以1000 0000 表示-128,

那么8位二进制能表示的十进制数为127~-128

10101010表示的负数为-86,超过-64了。

凡是超过-64都会引起左移位溢出,负数补码出去符号位,最高位为0,此时逻辑左移会导致数据溢出。

算数右移

算数右移保持符号位不变,其余比特位依次向右移动,空出的比特位补零,最右边的比特位移除后进入CF标记。

计算product = num * 8;可通过移位指令完成,速度更快

;product = num1 * 8;
mov eax, num1
sal eax, 3
mov product , eax

乘以8,不是sal eax, 8,这样是乘以256,应该为移动三位。

answer =  amount /4 ;

;answer = amount/4;
mov eax, amount
shr eax, 2
mov answer, eax

十一、循环移位指令

循环移位将末尾移除来的数据放入另一端空缺的比特位。

循环左移位

rol reg, cl

rol reg, imm

rol mem, cl

rol mem, imm

循环右移位

ror reg, cl

ror reg, imm

ror mem, cl

ror mem, imm

循环右移位

循环左移位

之前检测一个8位二进制数中比特位数字为1的比特位个数程序可通过循环右移完成,

因为循环右移8位后,移位的结果和初始数值一样。

mov count , 0
mov ecx, 8
.repeat
test al, 0000 0001b
.if !ZERO?
inc count
.endif
ror al, 1
.untilcxz

十一、堆栈操作

push 指令

push reg

push mem

push imm

push指令为入栈指令,参数可以为寄存器reg, 内存mem, 立即数imm。

pop指令

pop mem

pop reg

pop出栈指令,参数只能为内存和寄存器。

将监测比特位数值为1的比特位数程序和栈操作指令结合

push eax
push al
mov count, 0
mov ecx, 8
.repeat
test al, 0000 0001b
.if !ZERO?
inc count
.endif
shr al,1
.untilcxz
pop al
pop eax

 十二、xchg交换指令

xchg交换指令用于交换两个地址空间数据,xchg参数可以为以下几种

xchg reg, reg

xchg reg, mem

xchg mem, reg

同样不可以操作两个内存。

实现两个数交换

temp = num1;
num1 = num2;
num2 = temp;

用mov指令实现为:

mov edx, num1
mov eax, num2
mov num1, eax
mov num2, edx

用push, pop指令实现为

push num1
push num2
pop   num1
pop   num2

用xchg指令实现为

mov eax, num1
xchg eax, num2
mov  num1, eax

三种办法的效率比较为mov指令最快,其次xchg指令,最后为push pop指令。

这一篇就介绍这里,下一篇讲述宏和过程。

我的公众号:

时间: 2024-11-10 21:05:41

汇编语言学习笔记(三)的相关文章

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T>

Caliburn.Micro学习笔记(三)----事件聚合IEventAggregator和 Ihandle<T> 今天 说一下Caliburn.Micro的IEventAggregator和IHandle<T>分成两篇去讲这一篇写一个简单的例子 看一它的的实现和源码 下一篇用它们做一个多语言的demo 这两个是事件的订阅和广播,很强大,但用的时候要小心发生不必要的冲突. 先看一下它的实现思想 在Caliburn.Micro里EventAggregator要以单例的形式出现这样可以

OpenCV for Python 学习笔记 三

给源图像增加边界 cv2.copyMakeBorder(src,top, bottom, left, right ,borderType,value) src:源图像 top,bottem,left,right: 分别表示四个方向上边界的长度 borderType: 边界的类型 有以下几种: BORDER_REFLICATE # 直接用边界的颜色填充, aaaaaa | abcdefg | gggg BORDER_REFLECT # 倒映,abcdefg | gfedcbamn | nmabcd

NFC学习笔记——三(在windows操作系统上安装libnfc)

本篇翻译文章: 这篇文章主要是说明如何在windows操作系统上安装.配置和使用libnfc. 一.基本信息 1.操作系统: Windows Vista Home Premium SP 2 2.硬件信息: System: Dell Inspiron 1720 Processor: Intel Core 2 Duo CPU T9300 @ 2.5GHz 2.5GHz System type: 32-bit Operating System 3.所需软件: 在windows操作系统上安装软件需要下列

swift学习笔记(三)关于拷贝和引用

在swift提供的基本数据类型中,包括Int ,Float,Double,String,Enumeration,Structure,Dictionary都属于值拷贝类型. 闭包和函数同属引用类型 捕获则为拷贝.捕获即定义这些常量和变量的原作用域已不存在,闭包仍然可以在闭包函数体内引用和修改这些值 class属于引用类型. Array的情况稍微复杂一些,下面主要对集合类型进行分析: 一.关于Dictionary:无论何时将一个字典实例赋给一个常量,或者传递给一个函数方法时,在赋值或调用发生时,都会

加壳学习笔记(三)-简单的脱壳思路&amp;调试思路

首先一些windows的常用API: GetWindowTextA:以ASCII的形式的输入框 GetWindowTextW:以Unicaode宽字符的输入框 GetDlgItemTextA:以ASCII的形式的输入框 GetDlgItemTextW:以Unicaode宽字符的输入框 这些函数在使用的时候会有些参数提前入栈,如这函数要求的参数是字符串数目.还有大小写啦之类的东西,这些东西是要在调用该函数之前入栈,也就是依次push,就是说一般前面几个push接着一个call,那前面的push可能

【Unity 3D】学习笔记三十四:游戏元素——常用编辑器组件

常用编辑器组件 unity的特色之一就是编辑器可视化,很多常用的功能都可以在编辑器中完成.常用的编辑器可分为两种:原有组件和拓展组件.原有组件是编辑器原生的一些功能,拓展组件是编辑器智商通过脚本拓展的新功能. 摄像机 摄像机是unity最为核心组件之一,游戏界面中显示的一切内容都得需要摄像机来照射才能显示.摄像机组件的参数如下: clear flags:背景显示内容,默认的是skybox.前提是必须在render settings 中设置天空盒子材质. background:背景显示颜色,如果没

马哥学习笔记三十二——计算机及操作系统原理

缓存方式: 直接映射 N路关联 缓存策略: write through:通写 write back:回写 进程类别: 交互式进程(IO密集型) 批处理进程(CPU密集型) 实时进程(Real-time) CPU: 时间片长,优先级低IO:时间片短,优先级高 Linux优先级:priority 实时优先级: 1-99,数字越小,优先级越低 静态优先级:100-139,数据越小,优先级越高 实时优先级比静态优先级高 nice值:调整静态优先级   -20,19:100,139   0:120 ps

lucene学习笔记(三)

好几天没更新了.更新一下,方便自己和大家学习. 这是最基本的代码 package index; import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.document.Document;

python 学习笔记 三 字典

字典 Python的高效的key/value哈希表结构叫做"dict", dict的内容可以写成一系列的key:value对并放入{ }中, 相当于: dict = {key1:value1, key2:value2, ...}, 一个空的字典就是俩个大括号{ }. 下面是从一个空字典创建字典以及一些关键点: 数字, 字符串和元组可以作为字典的key, value可以是任何类型(包括字典). ## Can build up a dict by starting with the the