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

8086汇编(16位汇编)学习笔记06.串操作、流程转移指令

8086汇编(16位汇编)学习笔记06.串操作、流程转移指令-C/C++基础-断点社区-专业的老牌游戏安全技术交流社区 - BpSend.net

串操作

源操作数使用si,默认段为DS,可段超越

目的操作数使用di,默认段为ES,不可段超越

img

串方向

串方向由DF标志位影响,可以由指令修改

img

重复前缀

串操作指令一般都配合重复前缀使用,实现内存的批量操作。

img

流程转移指令

1.无条件跳转

直接转移 jmp

img

短跳 jmp 或者 jmp short

偏移值范围是 - 128(80H) 到 127(7FH) , 偏移值大小是 一个字节

;栈段
stack segment stack

stack ends 

;数据段
data segment 
  g_szBuf db 255 dup(0)
data ends 

;代码段
code segment

START: 
    assume ds:data   ;指定data段 作为 ds 段
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
                     ;不直接给是因为没有立即数到段寄存器
    mov ax,ax
    mov ax,ax
    jmp   LEABEL1  ; 跳转到标号 LEABEL1
    mov ax,ax
    mov ax,ax
 

 LEABEL1:  
    mov dx,dx
    mov dx,dx
    jmp   LEABEL2  ; 跳转到标号 LEABEL2
    mov dx,dx
   
LEABEL2:  
    mov cx,cx
    mov cx,cx
   
code ends 
end START 

img

img

ip 里面存的是下一条指令的地址. ip被改了,代表下一条指令 也被修改了

img

jum 既然能跳转,那么指令肯定包含了 要跳转的地址信息 ,那么是如果做到的呢

开始IP跳转IP地址偏移值机器码
0009000f6EB04
001300174EB02

从表格中我们不难分析出来 EB 代表 jmp 指令 ,其机器码中并没有直接存储 目标地址的 ip信息 ,也不是直接存储偏移,而是地址偏移值 - 2 , 即 下一条指令 到 目标地址的偏移,那为什么不存储本条指令地址和目的地址的偏移,而要存下一条的呢,因为当一条指令执行完,IP地址就指向了下一条指令的ip地址,如果要储存自己和目标指令的偏移,需要先 - 2 ,把ip地址 改回当前自己的,再去算偏移,所以就直接存储 下条指令的 ip 地址 和目标地址的偏移

上面是考虑的是 从上往下跳,如果从下往上跳呢

stack segment stack    ;栈段

stack ends 

data segment     ;数据段
  g_szBuf db 255 dup(0)
data ends 

code segment    ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
                     ;不直接给是因为没有立即数到段寄存器
    mov ax,ax
    mov ax,ax

    jmp   LEABEL1  ; 跳转到标号 LEABEL1

    mov ax,ax
    mov ax,ax
 

 LEABEL1:   

    mov dx,dx
    mov dx,dx
    jmp   LEABEL1  ; 跳转到标号 LEABEL1
    jmp   LEABEL2  ; 跳转到标号 LEABEL2
    mov dx,dx
   
LEABEL2:  
    mov cx,cx
    mov cx,cx

code ends 
end START 

img

开始IP跳转IP地址偏移值机器码
0013000f-4EBFA

FA 是 -6 , -4 = -6 +2 ,因此向上跳 也是 记录的 下条指令 到 目标地址的 偏移

近跳 jmp 或者 jmp near

短跳的偏移值 范围 是 - 128(80H) 到 127(7FH) ,如果超过这个范围,那么短跳将无法实现,此时就需要用到近跳

近跳 偏移值范围是 - 32766((8000H)) 到 32765(7FFFH) , 偏移值大小是 一个字

stack segment stack    ;栈段
stack ends 

data segment   ;数据段
  g_szBuf db 255 dup(0)
data ends 

code segment  ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
                     ;不直接给是因为没有立即数到段寄存器
    mov ax,ax
    mov ax,ax

    jmp   LEABEL1  ; 跳转到标号 LEABEL1,此时跳转范围超过一个字节

    mov ax,ax
    mov ax,ax
    db 255 dup(0)  
 
 LEABEL1:   

    mov dx,dx
    mov dx,dx
    jmp   LEABEL1  ; 跳转到标号 LEABEL1
    jmp   LEABEL2  ; 跳转到标号 LEABEL2
    mov dx,dx
   
LEABEL2:  
    mov cx,cx
    mov cx,cx
   
code ends 
end START 

img

此时 这条指令 占3个字节,偏移值是一个 word ,偏移值 是 0103 (小尾保存的 )

000c (下条指令地址) + 0103 (偏移值) = 010F 及目标地址

远跳 jmp far

上面都是在一个段内跳转,如果在不同段内跳转 ,其偏移值 可以 超过 word 的表达范围,此时就需要用远跳

img

stack segment stack    ;栈段
stack ends 

data segment   ;数据段
  g_szBuf db 255 dup(0)
data ends 

code1 segment  ;代码段
  db 64 dup(0)
LEABEL3: 
    xor ax,ax
    xor ax,ax
    db 521 dup(0)

code1 ends

code segment  ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
                     ;不直接给是因为没有立即数到段寄存器
    mov ax,ax
    mov ax,ax

    ;jmp far ptr LEABEL3  ; 跳转到标号 LEABEL3,此时是跨段跳
    jmp code1:LEABEL3    ; jmp 段名:标号名  ,效果跟上面一样  

    jmp  LEABEL1  ; 跳转到标号 LEABEL1,此时跳转范围超过一个字节

    mov ax,ax
    mov ax,ax
    db 255 dup(0)  
 
 LEABEL1:   

    mov dx,dx
    mov dx,dx
    jmp   LEABEL1  ; 跳转到标号 LEABEL1
    jmp   LEABEL2  ; 跳转到标号 LEABEL2
    mov dx,dx
   
LEABEL2:  
    mov cx,cx
    mov cx,cx
   
code ends 
end START 

img

指令偏移计算

指令中的偏移值是下一条指令到目的地址的偏移。

img

指令偏移计算练习

计算下列指令的机器码,短跳 0xEB,近跳 0xE9,远跳跳 0xEA。

0AE7:0102 jmp 0120 -- EB1C

  • 120 - 104 = 1C 所以机器码是 E91B02

0AE7:0102 jmp 0320 -- E91B02

  • 因为偏移值超过一个字 ,偏移值是字,因此这条指令是 3个字节 ,下条指令地址是 105

320 - 105 = 021B 所以机器码是 E91B02

0AE7:0102 jmp 20 -- E91BFF

  • 104 - 20 = E4 取反是 FF1C 用一个字节无法表示,所以偏移值应该是用一个字表示,那么该条指令应该是3个字节,下条指令地址应该是 105, 105 - 20 = E5 取反 FF1B 所以机器码是 E91BFF

0AE7:0402 jmp 0100 -- E9FBFD

  • 该条指令偏移值明显看出是一个字,所以指令长度3 ,下条指令地址是 405, 405 - 100 = 305 取反 FDFB,所以机器码是 E9FBFD

0AE7:0122 jmp 0110 -- EBEC

  • 124 - 110 = 14 取反是 EC 所以机器码是 EBEC

img

img

img

img

img

使用寄存器间接转移
  • 格式 jmp reg
  • reg 为通用寄存器,不涉及段寄存器
  • 功能 ip <- reg
  • 只能用于段内转移

img

使用EA的间接转移

把跳转地址存到内存, 跳转时 从 内存里取 出跳转的目标地址

img

注意:

 

在运用转移的时候需要遵循C语言的流程标准,因为类似于goto,不能从一个函数跳到另外一个函数,影响堆栈平衡。

stack segment stack    ;栈段
stack ends 

data segment   ;数据段
  g_w dw 0
data ends 

code segment  ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
                     ;不直接给是因为没有立即数到段寄存器
  
    mov g_w, offset  LEABEL4 ;将 LEABEL4 的  偏移值给 g_w
    jmp g_w  
   
    mov ax,ax
    xor ax,ax

 LEABEL4:   
  
    ;带返回码的退出
    mov ax,4C00H
    int 21 
   
code ends 
end START 

img

img

stack segment stack    ;栈段
stack ends 

data segment   ;数据段
  g_w dw 0
  g_wEA dw 0
  g_wCS dw 0 
data ends 


code1 segment  ;代码段
  db 64 dup(0)
LEABEL3: 
    xor ax,ax
    xor ax,ax
    db 521 dup(0)

code1 ends

code segment  ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
                     ;不直接给是因为没有立即数到段寄存器
  
    mov g_wEA,offset LEABEL3 ;将 LEABEL3 的  偏移值给 g_wEA
    ;mov g_wCS,code          ;将 LEABEL3 的 段基址给 g_wCS
    mov  g_wCS,seg LEABEL3   ;将 LEABEL3 的  段基址给 g_wCS
  
    lea bx,g_wEA             ;将 g_wEA 的  偏移地址给 bx
    jmp dword ptr [bx]       ;取出偏移值为bx (即 g_wEA) 处的值,并跳转到该处 

   
    jmp g_w  
   
    mov ax,ax
    xor ax,ax

 LEABEL4:   
  
    ;带返回码的退出
    mov ax,4C00H
    int 21 
   
code ends 
end START 
2.条件跳转

依据标志位判断,条件成立则跳转,条件不成立则不跳。

单条件跳转

深色表示常用,需要掌握 ,其他的表是用的比较少,熟悉即可

jz/je

比较2个数,相等输出 eaqul 不等输出 not eaqul

stack segment stack    ;栈段
stack ends 

data segment   ;数据段
  g_w0 dw 1122H
  g_w1 dw 3344H
  g_w2 dw 1122H
  g_szEqu db "eaqul",0dh,0ah,'$'
  g_szNEqu db "not eaqul",0dh,0ah,'$'
data ends 

 

code segment  ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
                     ;不直接给是因为没有立即数到段寄存器
  
   
    mov ax,g_w0   ;将 g_w0 的值 给 ax
    cmp ax,g_w1   ; ax的值 和 g_w1 作比较
  
    jz  LEABEL2   ; 如果比较的值相等则跳转 LEABEL2 标号处

    ;输出字符串  g_szNEqu
    lea dx,g_szNEqu
    mov ah,09H
    int 21H

    mov ax,g_w0   ;将 g_w0 的值 给 ax
    cmp ax,g_w2   ; ax的值 和 g_w2 作比较
  
    jz  LEABEL2   ; 如果比较的值相等则跳转 LEABEL2 标号处

    ;输出字符串  g_szNEqu
    lea dx,g_szNEqu
    mov ah,09H
    int 21H

    jmp EXIT

LEABEL2:
    ;输出字符串  g_szEqu
    lea dx,g_szEqu
    mov ah,09H
    int 21H

 EXIT:  

    ;带返回码的退出
    mov ax,4C00H
    int 21H 
   
code ends 
end START 

img

jcxz

判断2个字符串是否相等,相等则输出 eaqul 否则输出 eaqul not

stack segment stack    ;栈段
stack ends 

data segment   ;数据段
  g_w0 dw 1122H
  g_w1 dw 3344H
  g_w2 dw 1122H
  g_szEqu db "eaqul",0dh,0ah,'$'
  g_szNEqu db "eaqul not ",0dh,0ah,'$'
data ends 

 

code segment  ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    cld
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
    mov es,ax        ;不直接给是因为没有立即数到段寄存器
  
   
   mov cx,offset g_szNEqu - offset g_szEqu
   lea si,g_szEqu
   lea di,g_szNEqu
   repz cmpsb       ;2个字符串进行比较,直到cx等于0,或者不等退出
   
   jcxz LEABEL2    ;如果 cx 等于 0 则跳转,否则不跳转

    ;输出字符串  g_szNEqu
    lea dx,g_szNEqu
    mov ah,09H
    int 21H

    jmp EXIT

LEABEL2:
    ;输出字符串  g_szEqu
    lea dx,g_szEqu
    mov ah,09H
    int 21H

 EXIT:  

    ;带返回码的退出
    mov ax,4C00H
    int 21H 
   
code ends 
end START 

C:>DEBUG JMP.EXE

-G

EAQUI

NOT

NORMALLY (0000)

PROGRAM TERMINATED

image.png

无符号数判断

image.png

有符号数判断

image.png

3.LOOP

使用频率很高 只能用于短转移

格式: loop 标号

image.png

image.png

字符串小写转大写,并输出

stack segment stack    ;栈段
stack ends 

data segment   ;数据段
  g_w0 dw 1122H
  g_w1 dw 3344H
  g_w2 dw 1122H
  g_sz db "helloworld",0,0dh,0ah,'$'
  g_szEqu db "eaqul",0dh,0ah,'$'
  g_szNEqu db "eaqul not ",0dh,0ah,'$'
data ends 

 

code segment  ;代码段

START: 

    assume ds:data   ;指定data段 作为 ds 段
    cld
    mov ax,data      ;先把data的偏移值给ax
    mov ds,ax        ;ax再把data的偏移值给ds
    mov es,ax        ;不直接给是因为没有立即数到段寄存器
  
   
    ;输出字符串  g_szNEqu
    lea dx,g_sz
    mov ah,09H
    int 21H

    mov cx,offset g_szEqu - offset g_sz -4 ;去掉\0 和\r\n,'$'
    lea bx,g_sz


LEABELLOOP:
    ;小写转大写
    mov si,cx
    sub byte ptr[bx+si-1], 20h
    loop LEABELLOOP  

    ;输出字符串  g_szNEqu
    lea dx,g_sz
    mov ah,09H
    int 21H

 EXIT:  

    ;带返回码的退出
    mov ax,4C00H
    int 21H 
   
code ends 

img


http://www.kler.cn/a/461234.html

相关文章:

  • 沙箱模拟支付宝支付3--支付的实现
  • Spring 核心技术解析【纯干货版】- IV:Spring 切面编程模块 Spring-Aop 模块精讲
  • 网络分析工具-tcpdump
  • Python 测验
  • unity中Timeline动画的播放和播放中如何判断播放结束
  • 活动预告 |【Part2】Microsoft 安全在线技术公开课:安全性、合规性和身份基础知识
  • 《鸿蒙之光HarmonyOS NEXT原生应用开发入门》简介
  • Synopsys软件基本使用方法
  • deepin系统Docker使用指南:常用命令精讲
  • 建筑机器人崛起 | KMDA-7611助力智能喷涂一体机器人
  • 【数据结构】单向循环链表的使用
  • 01-2023年上半年软件设计师考试java真题解析
  • 小程序 手写tab超出滑动。view超出可以横滑动
  • Kafka高性能设计
  • 手写顺序流程图组件
  • Windows onnxruntime编译openvino
  • 部分开源数据整理
  • win32汇编环境下,对话框程序中生成listview列表控件,点击标题栏自动排序的示例
  • STM32 高级 物联网通讯之LoRa通讯
  • SNIPE-IT详细安装教程(已安装成功)
  • RabbitMQ - 2 ( 21000 字 RabbitMQ 入门级教程 )
  • Android学习小记3
  • 耳切法简述
  • 矩阵的因子分解3-LU分解和LDU分解
  • WebSocket 入门详解
  • 【每日学点鸿蒙知识】Taro、native层获取文件宽度、位置变化callback、数据迁移、oh_modules说明等