当前位置: 首页 > news >正文

Ubuntu x86-64汇编(5) 控制指令

控制指令 Control Instructions

汇编的控制指令主要包含标签, 无条件跳转和有条件跳转几种

标签 Label

标签用于标记跳转的目的, 必须以字母开头, 后面跟着字母, 数字和下划线, 最后以冒号:结束
yasm里的标签是区分大小写的

无条件跳转 Unconditional Control Instructions

格式

jmp   <label>
jmp   startLoop
jmp   ifDone
jmp   last

条件跳转 Conditional Control Instructions

条件跳转一般发生在一个比较指令之后, 比较的结果决定跳转是否执行. 比较指令的结果会存储在rFlag寄存器. 条件跳转要紧接着比较指令进行, 以免结果被其他指令修改.
比较指令的格式

cmp   <op1>, <op2>

<op1> 和 <op2> 必须是同一尺寸且不能修改. 不能同时为内存. <op1>不能为立即数. 跳转指令je和jne对无符号数和有符号数同样适用. 但是其他的跳转指令会有区别, 适用于有符号数的有 jl, jle, jg, jge; 适用于无符号数的有 jb, jbe, ja, jae. 列表如下

je    <label>   ; if <op1> == <op2>
jne   <label>   ; if <op1> != <op2>
jl    <label>   ; signed, if <op1> < <op2>
jle   <label>   ; signed, if <op1> <= <op2>
jg    <label>   ; signed, if <op1> > <op2>
jge   <label>   ; signed; if <op1> >= <op2>
jb    <label>   ; unsigned, if <op1> < <op2>
jbe   <label>   ; unsigned, if <op1> <= <op2>
ja    <label>   ; unsigned, if <op1> > <op2>
jae   <label>   ; unsigned, if <op1> >= <op2>

举例对于下面的判断语句
if (currNum > myMax)
  myMax = currNum;

;先定义变量
currNum  dq  0
myMax    dq  0
; 代码为
    mov   rax, qword [currNum]
    cmp   rax, qword [myMax]    ;if currNum <= myMax
    jle   notNewMax             ;   skip set new max
    mov   qword [myMax], rax
notNewMax:

另一个例子
if (x != 0) {
    ans = x / y;
    errFlg = FALSE;
} else {
    ans = 0;
    errFlg = TRUE;
}

代码

TRUE   equ 1
FALSE  equ 0
x      dd  0
y      dd  0
ans    dd  0
errFlg db  FALSE
;
;
    cmp    dword [x], 0   ; if statement
    je     doElse
    mov    eax, dword [x]
    cdq
    idiv   dword [y]
    mov    dword [ans], eax
    mov    byte [errFlg], FALSE
    jmp    skpElse
doElse:
    mov    dword [ans], 0
    mov    byte [errFlg], TRUE
skpElse:

这个例子中因为是带符号数, 所以使用了idiv和cdq.

超出跳转范围 Jump Out Of Range

一般来讲, 条件跳转的目标标签要在128byte以内, 如果超出的话就会出现jump out-of-range错误. 但是无条件跳转是没有这个限制的. 可以用以下的方法解决这个问题

    cmp   rcx, 0
    je    endOfLoop
    jmp   startOfLoop
endOfLoop:

用je + jmp 代替 jne, 就避免了条件跳转的限制

枚举 Iteration

这个控制指令用于枚举或循环. 一个基本的循环由一个计数器和一个顶上或底下的判断和跳转组成. 例如

maxN  dq   30
sum   dq   0
; 下面的代码用于计算从1到maxN的奇数之和.
mov   rcx, qword [maxN]   ; loop counter
mov   rax, 1              ; odd integer counter
sumLoop:
    add   qword [sum], rax    ; sum current odd integer
    add   rax, 2              ; set next odd integer
    dec   rcx                 ; decrement loop counter
    cmp   rcx, 0
    jne   sumLoop

在这个例子中, rcx 用于循环的计数, rax用于存储当前循环的奇数, 用1初始化并每次加2.
另外我们也可以用loop指令来实现, 其格式如下, 执行时会递减rcx寄存器的值, 与0比较, 当不等于0时跳转(到开始处再次循环)
loop   <label>
之前的代码可以用loop改写为:

mov   rcx, qword [maxN]  ; loop counter
mov   rax, 1             ; odd integer counter
sumLoop:
add   qword [sum], rax   ; sum current odd integer
add   rax, 2             ; set next odd integer
loop  sumLoop

因为循环中会改写并检查rcx寄存器, 如果未初始化rcx寄存器, 将导致未知的循环次数. loop指令在编程中很有用, 但是受限于rcx寄存器. 如果需要多层的loop, 需要在循环内外进行rcx当前值的保存和恢复.

代码例子 平方数求和 Sum of Squares

;  Simple example program to compute the
;  sum of squares from 1 to N.
; **********************************************
;  Data declarations
section   .data
; ----
;  Define constants
SUCCESS   equ  0       ; Successful operation
SYS_exit  equ  60      ; call code for terminate

;  Define Data.
n         dd   10
sumOfSquares  dq  0

; *******************************************************
section   .text
global    _start
_start:
; ----
;  Compute sum of squares from 1 to N.
;  Approach:
;    for (i=1; i<N; i++)
;      sumOfSqaures += i^2;
mov   rbx, 1           ; i
mov   ecx, dword [n]

sumLoop:
mov   rax, rbx         ; get i
mul   rax              ; i^2
add   qword [sumOfSquares], rax
inc   rbx
loop  sumLoop

; ----
;  Done, terminate program.
last:
mov   rax, SYS_exit   ; call code for exit
mov   rdi, SUCCESS    ; exit with success
syscall

 

.

 

相关文章:

  • DOM4J使用简介
  • Python学习之路13-记分
  • 怎样解决chm类型的文件在Windows操作系统中无法打开
  • k8s 环境搭建,etcd启动失败
  • 给Notepad++ 加右键菜单带图标
  • SharePoint On Premise/ SharePoint Online增强格式的文本栏
  • Android SQLite
  • nginx keepalive
  • 一个关于ceph的可用空间测试
  • C# Socket系列1
  • 简历查看下载网站列表
  • Android的ListView中用上下文菜单
  • Django之Form组件
  • LVS负载均衡群集
  • 360前端星计划—深入CSS
  • 11111111
  • C# 免费离线人脸识别 2.0 Demo
  • github指令
  • Idea+maven+scala构建包并在spark on yarn 运行
  • IP路由与转发
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • leetcode386. Lexicographical Numbers
  • OSS Web直传 (文件图片)
  • SpringBoot 实战 (三) | 配置文件详解
  • 彻底搞懂浏览器Event-loop
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 聊聊flink的TableFactory
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • ( 10 )MySQL中的外键
  • (+3)1.3敏捷宣言与敏捷过程的特点
  • (Oracle)SQL优化技巧(一):分页查询
  • (二) Windows 下 Sublime Text 3 安装离线插件 Anaconda
  • (二)Pytorch快速搭建神经网络模型实现气温预测回归(代码+详细注解)
  • (附源码)springboot家庭财务分析系统 毕业设计641323
  • (每日持续更新)信息系统项目管理(第四版)(高级项目管理)考试重点整理第3章 信息系统治理(一)
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (轉貼) 蒼井そら挑戰筋肉擂台 (Misc)
  • **PHP分步表单提交思路(分页表单提交)
  • **python多态
  • ... 是什么 ?... 有什么用处?
  • .net Application的目录
  • .net core 6 redis操作类
  • .NET 实现 NTFS 文件系统的硬链接 mklink /J(Junction)
  • .NETCORE 开发登录接口MFA谷歌多因子身份验证
  • .NET单元测试
  • .NET开源项目介绍及资源推荐:数据持久层
  • /dev/sda2 is mounted; will not make a filesystem here!
  • :not(:first-child)和:not(:last-child)的用法
  • @converter 只能用mysql吗_python-MySQLConverter对象没有mysql-connector属性’...
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [ 渗透测试面试篇 ] 渗透测试面试题大集合(详解)(十)RCE (远程代码/命令执行漏洞)相关面试题
  • [Android]使用Retrofit进行网络请求
  • [C#] 基于 yield 语句的迭代器逻辑懒执行
  • [c#基础]值类型和引用类型的Equals,==的区别