Ubuntu x86-64汇编(3) 数值操作指令
指令标注 Operand Notation
指令instruction即运算operation, 操作的对象为一个或多个运算数operand, 使用不同的标记表示不同的约束
<reg> 寄存器, 运算数必须是一个寄存器. Register operand. The operand must be a register.
<reg8>, <reg16>, <reg32>, <reg64> 指定大小的寄存器运算数 Register operand with specific size requirement. For example, reg8 means a byte sized register (e.g., al, bl, etc.) only and reg32 means a double-word sized register (e.g., eax, ebx, etc.) only.
<dest> 目的运算数, 可以是寄存器或内存, 其内容在运算后将被运算结果覆盖, Destination operand. The operand may be a register or memory. Since it is a destination operand, the contents will be over written with the new result (based on the specific instruction).
<RXdest> 浮点的目的运算数, 必须是一个浮点寄存器. Floating point destination register operand. The operand must be a floating point register. Since it is a destination operand, the contents will be over written with the new result (based on the specific instruction).
<src> 来源运算数, 其值参与运算, 但是在指令操作后不会变化. Source operand. Operand value is unchanged after the instruction.
<imm> 立即数, Immediate value. May be specified in decimal, hex, octal, or binary.
<mem> 内存地址, 可以是一个变量名或者是一个间接引用(如内存地址). Memory location. May be a variable name or an indirect reference (i.e., a memory address).
<op> or <operand> 运算数, Operand, register or memory.
<op8>, <op16>, <op32>, <op64> 指定大小的运算数, Operand, register or memory, with specific size requirement. For example, op8 means a byte sized operand only and reg32 means a double-word sized operand only.
<label> 标记 Program label.
数据移动 Data Movement
mov <dest>, <src>
mov ax, 42
mov cl, byte [bvar]
mov dword [dVar], eax
mov qword [qVar], rdx
将数值从来源寄存器或内存复制到目的寄存器或内存. 来源和目的必须是相同的尺寸(都是byte, 或都是word等). 目的不能是立即数, 来源和目的不能同时为内存. 如果要做内存到内存的复制, 需要两个指令.
特殊情况: 当目标寄存器为double word尺寸的整数寄存器时, 对应此double word的quadword上半部分会被全设为0.
例如当以下指令被执行时, rcx开始时被赋值为-1(全是0xF), 当100被复制到ecx后, rcx的上半部分会被0全部覆盖.
mov eax, 100 ; eax = 0x00000064
mov rcx, -1 ; rcx = 0xffffffffffffffff
mov ecx, eax ; ecx = 0x00000064
指令说明
1. 复制来源运算数到目的运算数
2. 两个运算数不能同时为内存
3. 目的运算数不能为立即数
4. 对于来源和目的都是double word的运算数, 目的运算数对应的quadword的上半部分会被置零
地址和数值 Address vs Values
获取内存内容的唯一方法是通过方括号([]), 如果不使用方括号获取的是变量的地址. 例如
mov rax, qword [var1] ; 将var1的值复制到rax
mov rax, var1 ; 将var1的地址复制到rax
因为忽略方括号不是语法错误, 编译器不会产生错误信息, 但是这容易让人产生疑惑. 另外, 变量的地址其实可以通过lea (load effective address)指令来获取, 用法举例如下
lea <reg64>, <mem> Place address of <mem> into reg64.
lea rcx, byte [bvar]
lea rsi, dword [dVar]
数值转换指令 Conversion Instructions
降级转换 Narrowing Conversion
降级转换用于将一个大尺寸的数值转换为较小类型的数值, 例如word到byte, 或double word到word
在降级转换中不需要特殊的指令, 寄存器或内存的低部可以直接访问, 例如如果数值50(0x32)存储在rax寄存器, 那么可以直接通过al访问获得小尺寸的数值
mov rax, 50
mov byte [bVal], al
这个例子因为50可以用一个byte表示, 所以al和rax的实际数值大小是一样的. 但是如果500(0x1f4)放置在rax寄存器, 那么寄存器依然可以访问, 但是结果就不一样了. bVal得到的值将会是0xf4
mov rax, 500
mov byte [bVal], al
升级转换 Widening Conversion
升级转换用于将小尺寸的数值转换为较大尺寸, 例如byte到word或word到double word. 因为尺寸扩大, 高地址部分的bit需要根据带符号或不带符号数做对应的填充. 所以做升级转换时, 必须先知道数值的符号属性, 才能对应使用正确的指令.
无符号转换
对于无符号的升级转换, 高地址部分需要置零. 例如转换值为50的al寄存器, 可以通过以下指令, 完成后rbx寄存器的值就是50
mov al, 50
mov rbx, 0
mov bl, al
这个通用的方式可以处理内存或其他寄存器. 另外有一个指令可以简化这个处理
movzx <dest>, <src>
movzx <reg16>, <op8>
movzx <reg32>, <op8>
movzx <reg32>, <op16>
movzx <reg64>, <op8>
movzx <reg64>, <op16>
; Examples
movzx cx, byte [bVar]
movzx dx, al
movzx ebx, word [wVar]
movzx ebx, cx
movzx rbx, cl
movzx rbx, cx
这会将高地址部分的bit置零. 注意: movzx指令不允许使用quadword类型作为目的运算数. 因为之前提到过, mov使用double word作为运算数时, 会同时将其高地址部分的double word也置零.
movzx使用说明
1. 两个运算数不能同时为内存 both operands can not be memory.
2. 目的运算数不能为立即数, destination operands can not be an immediate.
3. 不允许使用立即数值
有符号数的转换
对于有符号数的升级转换, 根据原数值的符号, 高地址部分需要全部被填充为0或者1. 这个操作由一个符号数扩展操作完成. 其实就是将当前数的符号位的值, 直接填充到高地址位. 用于符号数扩展的有一系列的指令, 仅工作在A寄存器上, 用于将A寄存器的数值扩展到高地址位, 有时候会将数值扩展到D寄存器. 例如cwd指令, 用于将ax中的带符号数值, 扩展成double word尺寸的数值, 放入dx(上半部分)和ax(下半部分), 这种结果通常写作 dx:ax. 而cwde指令, 将ax中的带符号数值, 扩展成double word尺寸的数值并存储在eax寄存器.
常用指令用法及说明
cbw ;Convert byte in al into word in ax. Note, only works for al to ax register.
cwd ;Convert word in ax into double-word in dx:ax. Note, only works for ax to dx:ax registers.
cwde ;Convert word in ax into word into double-word in eax. Note, only works for ax to eax register.
cdq ;Convert double-word in eax into quadword in edx:eax. Note, only works for eax to edx:eax registers.
cdqe ;Convert double-word in eax into quadword in rax. Note, only works for rax register.
cqo ;Convert quadword in rax into word in double-quadword in rdx:rax. Note, only works for rax to rdx:rax registers.
movsx, movsxd ; Signed widening conversion (via sign extension).
Note 1, both operands can not be memory.
Note 2, destination operands can not be an immediate.
Note 3, immediate values not allowed.
Note 4, special instruction (movsxd) required for 32-bit to 64-bit signed extension.
movsx <dest>, <src>
movsx <reg16>, <op8>
movsx <reg32>, <op8>
movsx <reg32>, <op16>
movsx <reg64>, <op8>
movsx <reg64>, <op16>
movsxd <reg64>, <op32>
movsx cx, byte [bVar]
movsx dx, al
movsx ebx, word [wVar]
movsx ebx, cx
movsxd rbx, dword [dVar]
整数运算指令 Integer Arithmetic Instructions
整数运算包括在整数上的加减乘除
加法 Addition
通用指令为
add <dest>, <src>
add cx, word [wVvar]
add rax, 42
add dword [dVar], eax
add qword [qVar], 300
1. 结果将被放入目的运算数, 源运算数值不变
2. 两个运算数必须是同一尺寸
3. 目的运算数不能是立即数
4. 两个运算数不能同时为内存
代码例子
bNum1 db 42
bNum1 db 73
bAns db 0
wNum1 dw 4321
wNum2 dw 1234
wAns dw 0
dNum1 dd 42000
dNum2 dd 73000
dAns dd 0
qNum1 dq 42000000
qNum2 dq 73000000
qAns dq 0 ; bAns = bNum1 + bNum2
mov al, byte [bNum1]
add al, byte [bNum2]
mov byte [bAns], al
; wAns = wNum1 + wNum2
mov ax, word [wNum1]
add ax, word [wNum2]
mov word [wAns], ax
; dAns = dNum1 + dNum2
mov eax, dword [dNum1]
add eax, dword [dNum2]
mov dword [dAns], eax
; qAns = qNum1 + qNum2
mov rax, qword [qNum1]
add rax, qword [qNum2]
mov qword [qAns], raxInstruction Set Overview
; dAns = dNum1 + dNum2
mov eax, dword [dNum1]
add eax, dword [dNum2]
mov dword [dAns], eax
; qAns = qNum1 + qNum2
mov rax, qword [qNum1]
add rax, qword [qNum2]
mov qword [qAns], rax
在一些指令里, 包括上面的指令, 可以不指定具体的数值尺寸(例如byte, word, dword), 因为另一个运算数已经明确指定了尺寸的大小. 保留是为了编程的一致性, 便于阅读和维护.
除了加法指令, 还有一个自增指令, 可以使用于byte, word, dword, qword, 在作用于内存时, 要明确标明尺寸
inc <operand>
inc word [wVvar]
inc rax
inc dword [dVar]
inc qword [qVar]
代码例子
bNum db 42
wNum dw 4321
dNum dd 42000
qNum dq 42000000
inc rax ; rax = rax + 1
inc byte [bNum] ; bNum = bNum + 1
inc word [wNum] ; wNum = wNum + 1
inc dword [dNum] ; dNum = dNum + 1
inc qword [qNum] ; qNum = qNum + 1
带进位的加法 Addition with Carry
带进位的加法是一个特殊的加法指令, 会在运算中添加前一条指令产生的结果的进位数值. 这在进行大数(超过寄存器尺寸的数字)运算时非常方便.
例如进行如下的运算 17+25=42, 第一步进行7+5的运算, 第二步要紧接着第一步立即执行, 在执行加法时包含前一步产生的进位, 信息存储于rFlag, 通常的计算指令为
adc <dest>, <src> ;<dest> = <dest> + <src> + <carryBit>
adc rcx, qword [dVvar1]
adc rax, 42
代码例子
dquad1 ddq 0x1A000000000000000
dquad2 ddq 0x2C000000000000000 ;这些都是128bit数值, 会超过64-bit寄存器的尺寸
dqSum ddq 0 mov rax, qword [dquad1]
mov rdx, qword [dquad1+8]
add rax, qword [dquad2]
adc rdx, qword [dquad2+8]
mov qword [dqsum], rax
mov qword [dqsum+8], rdx
减法 Subtraction
减法指令的格式
sub <dest>, <src> ;<dest> = <dest> <src>
sub cx, word [wVvar]
sub rax, 42
sub dword [dVar], eax
sub qword [qVar], 300
src被减去dest的数值, 并且结果会保存到desc下. src的值不会改变. desc和src的数值尺寸必须一致, desc不能是立即数, desc和src不能同时为内存.
代码例子
bNum1 db 73
bNum2 db 42
bAns db 0
wNum1 dw 1234
wNum2 dw 4321
wAns dw 0
dNum1 dd 73000
dNum2 dd 42000
dAns dd 0
qNum1 dq 73000000
qNum2 dq 73000000
qAns dd 0 ; bAns = bNum1 bNum2
mov al, byte [bNum1]
sub al, byte [bNum2]
mov byte [bAns], al
; wAns = wNum1 – wNum2
mov ax, word [wNum1]
sub ax, word [wNum2]
mov word [wAns], ax
; dAns = dNum1 – dNum2
mov eax, dword [dNum1]
sub eax, dword [dNum2]
mov dword [dAns], eax
; qAns = qNum1 qNum2
mov rax, qword [qNum1]
sub rax, qword [qNum2]
mov qword [qAns], rax
自减指令
除了基本的减法指令外, 可以使用dec指令进行自减操作, 格式为
dec <operand> ;<operand> = <operand> 1
dec word [wVvar]
dec rax
dec dword [dVar]
dec qword [qVar]
可以作用于byte, word, dword, qword, 如果使用于内存, 需要明确标明数值尺寸
代码例子
bNum db 42
wNum dw 4321
dNum dd 42000
qNum dq 42000000 dec rax ; rax = rax 1
dec byte [bNum] ; bNum = bNum 1
dec word [wNum] ; wNum = wNum 1
dec dword [dNum] ; dNum = dNum 1
dec qword [qNum] ; qNum = qNum 1
.
.
Ubuntu x86-64汇编(3) 数值操作指令的更多相关文章
- Ubuntu x86-64汇编(4) 数值操作指令
整数乘法指令 Integer Multiplication 对于有符号数的乘法有特殊的规则, 因此无符号数乘法和有符号数乘法对应着不同的指令mul和imul. 乘法会产生两倍尺寸的数值结果, 即两个n ...
- Ubuntu x86 64 settup nginx rtmp server
常常搭建nginxserver,可是好像每次的情况都不同,这次具体记录这个过程: 平台:unbutu 10.04 内核:2.6.32-33-generic 1, 编译环境搭建. sudo apt-ge ...
- 汇编实现: C库常见函数,串操作指令作用
目录 汇编实现: C库常见函数 一丶汇编实现Strncpy拷贝函数 二丶loads实现Strlen操作. 三丶stos的作用 汇编实现: C库常见函数 一丶汇编实现Strncpy拷贝函数 void _ ...
- 深入理解计算机系统(4.1)---X86的孪生兄弟,Y86指令体系结构
引言 各位猿友们好,计算机系统系列很久没更新了,实在是抱歉之极.新的一年,为了给计算机系统系列添加一些新的元素,LZ将其更改为书的原名<深入理解计算机系统>.这本书非常厚,而且难度较高,L ...
- linux常用操作指令
Linux常用操作指令: 常用指令 ls 显示文件或目录 -l 列出文件详细信息l(list) -a 列出当前目录下所有文件及目录,包括隐藏的a(a ...
- ARM指令集——条件执行、内存操作指令、跳转指令
ARM 汇编指令条件执行 在ARM模式下,任何一条数据处理指令可以选择是否根据操作的结果来更新CPSR寄存器中的ALU状态标志位.在数据处理指令中使用S后缀来实现该功能. 不要在CMP,CMN,TST ...
- 第24篇-虚拟机对象操作指令之getfield
getfield指令表示获取指定类的实例域,并将其值压入栈顶.其格式如下: getstatic indexbyte1 indexbyte2 无符号数indexbyte1和indexbyte2构建为(i ...
- 第25篇-虚拟机对象操作指令之putstatic
之前已经介绍了getstatic与getfield指令的汇编代码执行逻辑,这一篇介绍putstatic指令的执行逻辑,putfield将不再介绍,大家可以自己去研究,相信大家有这个实力. putsta ...
- 深入理解JVM(1)——栈和局部变量操作指令
将常量压入栈的指令 aconst_null 将null对象引用压入栈iconst_m1 将int类型常量-1压入栈iconst_0 将int类型常量0压入栈iconst_1 将int类型常量1压入栈i ...
随机推荐
- 日历控件My97DatePicker WdatePicker屏蔽 onchange的解决方法
http://www.cnblogs.com/wan-feng/archive/2013/12/13/3473439.html 受下面文章的启发,使用DatePicker自带的年月日相关的change ...
- ptime概述
官方给出的ptime的定义是:ptime gives the length of time in milliseconds represented by themedia in a packet.简单 ...
- Arcgis ArcMap 10 如何生成msd地图文档定义【 arcgis mxd怎么转换成msd】
.mxd是arcgis 的地图文档后缀名. .msd是arcgis 的地图服务定义文件,是 map service definition 的缩写. 基于 MSD 的服务支持 Maplex.制图表达和新 ...
- iOS:调节系统的亮度
一.简单介绍 亮度是UIScreen的一个浮点型属性,而UIScreen是一个单例,所以这个亮度是全局的,任何一个地方改动,整个手机的亮度都会改变.这个亮度在iOS5.0后被苹果开放,开发者可以很方便 ...
- checkbox反复调用attr('checked', true/false)只有第一次生效
/** * 全选 */ function checkAll() { $("input[name=ids]").attr("checked", true); } ...
- SVN详细配置与使用 ——一步步教会您使用
项目管理在项目开发活动中起到非常重要的作用,而对于初学者来说学习有一定的难度,且不说如何使用,就是搭建过程恐怕也要费一般周折,介于此下面就通过图解的方式一步一步详细的教大家如何使用SVN,你只要耐心的 ...
- RAMPS1.4 3d打印控制板接线与测试4
如果之前的操作都顺利,现在就可以插上USB线,打开printrun上位机软件了.mega2560刚刚接通电源时,RAMPS板子上的LED1(绿色)会闪几下.这说明mega2560板子中的固件正在启动. ...
- MySQL数据复制到其他主机时报错
问题1: MySQL server has gone away With statement 原因:SQl insert 插入的语句天长导致 问题2:mysql a bulk size specifi ...
- Logcat用法初探
首先定位到adb所在的目录 将手机连接上电脑. 在命令行运行: adb devices 这个命令可以列出所有连上的移动设备. 在命令行运行: adb logcat 可以显示日志. 以下是例子截图: ...
- AOP中Advice执行两遍的原因
在我的spring项目中,Aop的Advice执行了两边,就好像拦截了两遍一样. 原因是:切面应该切到接口的实现类上,而不是接口上