zoukankan      html  css  js  c++  java
  • Intel汇编语言程序设计学习-第六章 条件处理-中

    6.3  条件跳转

    6.3.1  条件结构

        在IA-32指令集中没有高级的逻辑结构,但无论多么复杂的结构,都可以使用比较和跳转指令组合来实现。执行条件语句包括两个步骤:首先,使用CMPAND,SUB之类的指令修改CPU标志六七次,使用条件跳转指令测试并导致向新地址的分支转移。

        例子1:使用CMP指令比较AL0,如果CPU指令设置了零标志,那么JZ(为0则跳转)指令就跳转到标号L1处:

    cmp al ,0

    jz L1

    .

    .

    L1:

     

    6.3.2  条件跳转(Jcond)指令

        条件跳转指令在标志条件为真时分支跳转到新的目的标号处,如果条件标志为假,那么执行紧跟在跳转跳转指令之后的指令。格式如下:

            jcond 目标地址

        格式中的cond指的是一个标志条件,用来表示一个或多个标志的状态。例如:

          jc    如果进位则跳转

          jnc   如果无进位则跳转

          jz    如果为零则跳转

          jnz   如果不为零则跳转

        我们已经知道算数指令。比较指令和布尔指令几乎重视会设置标志位、条件跳转指令检查标志位的状态并且根据标志位的状态决定是否跳转。

        限制:MASM在默认情况下要求跳转的目的地址在当前的过程之内,为了突破这种限制,可以声明一个全局标号(标号后面跟”::”:

    jc MyLabel

    .

    .

    MyLabel::


    通常,应尽量避免跳转到当前的过程之外,否则调试程序时会比较困难。

        在Intel386之前,跳转的目标地址被限制在跳转指令后的第一条指令+128~-127个字节范围之内。IA-32处理器可跳转到当前段内的任何地址。

        使用CMP指令:假设我们想在AX等于5时跳转到位置L1处。假设AX等于5CMP指令设置了零标志,由于零标志置位了,执行JE指令就会发生跳转:

        cmp ax,5

        je  L1       ;相等则跳转

        如果AX不等于5CMP就会清楚零标志,执行JE指令就不会发生跳转,在下面的例子中,由于AX小于6而发生了跳转:

        mov  ax ,5

        cmp  ax,6

        jl     L1    ;如果小于则跳转大于是(jg

    6.3.3  条件跳转指令的类型

         IA-32指令集中跳转中的数目惊人地多,支持根据有符号、无符号整数的比较以及对CPU状态标志的检查进行跳转的一系列指令,跳转跳转指令可分成下面四类:

    1.基于特定的标志值。

    2.根据两个操作数是否相等,或根据(ECX的值的。

    3.基于无符号操作数的比较结果的。

    4.基于有符号操作数的比较结果的。

    下表列出了基于特定CPU标志:零标志、进位标志、溢出标志、奇偶标志和符号标志的跳转指令。

    基于恒等性比较的跳转指令

        下表列出了基于两个操作数是否相等或CX,EXC值是否为零的跳转指令。

    CMP leftOp ,rightOp


    JE指令和JZ指令是等价的,JNZ指令和JNE指令时等价的。

    基于无符号数比较的跳转指令

     

    基于有符号数比较的跳转指令

     

    6.3.4  条件跳转的应用

    测试状态位

        ANDORCMPNOTTEST指令后面常跟能够改变程序流程的条件跳转指令,条件跳转指令通常要测试CPU状态标志位的值。例如,假设8位的内存操作数status中存放着同计算机相连的外部设备信息,下面的指令在位5置位时跳转到某标号处,表示机器处于脱机状态:

    mov  al ,status

    test  al,00100000b  ;测试位5

    jnz   EquipOffline

        下面的语句在位014中的任何一位置位时跳转到另一个标号处:

    mov  al ,status

    test  al ,00010011b   ;测试位0,1,4

    jnz   InputDataByte

        如果想在2,3,7全部置位时跳转某标号处,需要使用ANDCMP两条指令:

    mov   al ,status

    and   al ,10001100b

    cmp   al ,10001100b

    je     ResetMachine

        取两个整数中的较大的值:下面的指令比较AXBX中的无符号整数并把其中的较大者送DX寄存器:

    mov  dx ,ax    ;假设AX较大

    cmp  ax ,bx

    jae   L1       ;如果A>=B 就直接跳转到L1,否则就把较大的值B放到结果dx

    mov  dx ,bx

    L1:

        取三个整数中的较小值:下面的指令比较V1,V2V3三个无符号变量的值,并把其中的最小者送至AX寄存器:

    .data

    V1 WORD ?

    V2 WORD ?

    V3 WORD ?

    .code

      mov  ax ,V1  ;假设V1是最小的

      cmp  ax ,V2

      jbe   L1     ;小于等于则跳转

      mov  ax ,V2

    L1: cmp ax ,V3

      jbe   L2   

      mov  ax ,V3

    L2:


        应用:数组的顺序查找

        在数组中找到第一个非零值。

     

    应用:字符串加密(XOR

    TITLE Ecnryption Program    (Encrypt.asm)

    INCLUDE Irvine32.inc

    KEY = 239

    BUFMAX = 128

    .data

    sPrompt  BYTE  "Enter the plain text:" ,0

    sEncrypt BYTE  "Cipher text:         " ,0

    sDecrypt BYTE  "Decrypted:           " ,0

    buffer   BYTE  BUFMAX+1 DUP(0)

    bufSize  DWORD ?

    .code

    main PROC

        call  InputTheString

    call  TranslateBuffer

    mov   edx ,OFFSET sEncrypt

    call  DisplayMessage

    call  TranslateBuffer

    mov   edx ,OFFSET sDecrypt

    call  DisplayMessage

    exit

    main ENDP

     

    ;-----------------------------------

    InputTheString PROC

    ;

    ;Prompts user for a plaintext string.Saves the string

    ;and its length

    ;Receives:nothing

    ;Returns: nothing

    ;-----------------------------------

        pushad

    mov    edx ,OFFSET sPrompt

    call   WriteString

    mov    ecx ,BUFMAX

        mov    edx ,OFFSET buffer

    call   ReadString

    mov    bufSize ,eax

    call   Crlf

    popad

    ret

    InputTheString ENDP

     

    ;-----------------------------------

    DisplayMessage PROC

    ;

    ;Display the ecnrypted or decrypted message.

    ;Receives :EDX points to the message

    ;Returns  :nothing

    ;-----------------------------------

        pushad

    call  WriteString

    mov   edx ,OFFSET buffer

    call  WriteString

    call  Crlf

    call  Crlf

    popad

    ret

    DisplayMessage ENDP

     

    ;-----------------------------------

    TranslateBuffer  PROC

    ;

    ;Translates the string by exclusive-ORing each

    ;byte with the encryption key buye.

    ;Receives :nothing

    ;Returns  :nothing

        pushad

    mov ecx ,bufSize

    mov esi ,0

    L1:

        xor  buffer[esi] ,KEY

    inc  esi

    loop L1

    popad

    ret

    TranslateBuffer ENDP

    END main


    6.3.5  位测试指令

    BT ,BTC ,BTRBTS指令统称为位测试(bit testing)指令,这些指令很重要,因为他们可以在单挑院子指令内执行很多个步骤。为测试指令对多线程程序非常有用,对多线程程序而言,在不冒被其他线程中断的危险的情况下对重要的标志(称为信号量)进行测试、清除、设置或求反是非常重要的。

    BT指令

    BT(位测试,bit test)指令选择第一个操作数位n并把它复制到进位标志中:

    BT bitBase,n

    第一个操作数成为位基(bitBase,它不会被指令所修改。BT指令允许以下类型操作数:

    BT  r/m16 ,r16

    BT  r/m32 ,r32

    BT  r/m16 ,imm8

    BT  r/m32 ,imm8

    在下例中,进位标志等于变量semaphone第七位的值:

    .data

    semaphone WORD 10001000b

    .code

    BT  semaphone ,7      ;CF = 1

    Intel指令集引入BT指令之前,我们不得不把变量复制到寄存器中,然后再通过移位把第7位送到进位标志中:

    mov  ax ,semaphone

    shr   ax ,8         ;CF = 1

    BTC指令

    BTC(位测试并取反,bit test and complement)指令选择第一个操作数的位n并把它复制到标志位中,同时对位n取反。

    BTR指令

    BTR(位测试并复位,bit test and reset)指令选择第一个操作数位n并把它复制到进位标志中,同时位n清零。

    BTS指令

    BTS指令(位测试并置位,bit test and set)指令选择第一个操作数的位n并把它复制到进位标志中,同时位n置位。

    6.4  条件循环指令

        LOOPZLOOPE指令:ecx大于0,并且零标志位置位则循环。

        LOOPNZLOOPNE指令:ecx大于0,并且零标志位复位则循环。

    6.5  条件结构

        条件结构可认为是在不同的逻辑分支之间引发选择的一个或多个条件表达式,每个分支都会执行不同的指令序列。

    6.5.1  IF块结构语句

        这节不想细总结了,书上很大的篇幅就是为了解释用cmpj*来对应解释高级语言里那些IF语句什么的。没什么新东西。

    6.5.2  复合表达式

        这节是说在高级语言中的类似if(A And B) [A&&B] if(A OR B) [A||B]等在汇编里怎么对应翻译,其实比较简单,比如A&&B 可以判断A满足然后跳转到B继续判断,有一个不满足那么直接jmp到其他地方,A||B的话就是先判断A,如果满足 那么jmp到满足,否则判断B如果满足那么jmp到满足,否则jmp到不满足,这样也就明白了为什么在高级语言中 a = 0 ,b = 0  if(++a || ++b)..之后b没有被自加的原因(a = 1 ,b = 0)。比较简单,这一节也不细总结了。

    6.5.3  WHILE循环

        ...这节是说高级语言中的while怎么解析成汇编,比较简单,我们直接mark一个地方,然后满足条件就直接往上跳回去就行了,如果不满足那么就不跳,这样就自动往下执行,相当于while完了,当然也可以增加其他cmp,j*指令实现break等。

     

    6.5.4  以表格驱动的分支选择

        原理是对于多层条件语句嵌套那种,翻译成汇编会很乱,很麻烦,同时如果我们用汇编开发过程中出现了太多层的条件嵌套写着也麻烦,有一种方法是我们把每个条件和执行地址看成一个”结构体”,然后在创建一个”结构体数组”,例如

     

        条件A执行00000120处的函数,或者跳转到那里,条件B则是00000130...这样我们每次只要线性扫描这个表就行了,这个姿势叫做以表格驱动的分支选择。

    例子程序:用户从键盘输入一个字符,程序使用一个循环将该字符同表中每个项比较,对于找到的第一个匹配项,紧跟在待查找值其后存储的过程将被调用。每个过程使用EDX来装入不同的字符串偏移,然后在循环中显示该字符串:

    TITLE Table of Procedure Offsets (ProcTable.asm)

    ;This program contains a table with offsets of procedures.

    ;It uses the table to execute indirect procedure calls.

    INCLUDE Irvine32.inc

    .data

    CaseTable BYTE   'A'

              DWORD  Process_A

    EntrySize = ($ - CaseTable)

      BYTE   'B'

              DWORD  Process_B

      BYTE   'C'

              DWORD  Process_C

      BYTE   'D'

              DWORD  Process_D

    NumberOfEntries = ($ - CaseTable) / EntrySize

    prompt    BYTE   "Press capital A,B,Cor D:" ,0

    msgA      BYTE   "Process_A" ,0

    msgB      BYTE   "Process_B" ,0

    msgC      BYTE   "Process_C" ,0

    msgD      BYTE   "Process_D" ,0

    .code

    main PROC

        mov   edx ,OFFSET prompt

    call  WriteString

    call  ReadChar

    mov   ebx ,OFFSET CaseTable

    mov   ecx ,NumberOfEntries

    L1:

        cmp   al ,[ebx]

    jne   L2

    call  NEAR PTR [ebx + 1]

    call  WriteString

    call  Crlf

    jmp   L3

    L2:

        add   ebx ,EntrySize

    loop  L1

    L3:

         exit

    main ENDP

     

    Process_A PROC

        mov  edx ,OFFSET msgA

    ret

    Process_A ENDP

    Process_B PROC

        mov  edx ,OFFSET msgB

    ret

    Process_B ENDP

    Process_C PROC

        mov  edx ,OFFSET msgC

    ret

    Process_C ENDP

    Process_D PROC

        mov  edx ,OFFSET msgD

    ret

    Process_D ENDP

    END main

     

     

    同时上面有几个个地方需要注意一下:

    1.一个是函数名字直接可以当变量用了:

     

    2.A=B不占用.data定义东西的时候的地址空间(不然的话,上面那么写代码就算错了)

     

    3.CALL指令调用存储在EBX+1内存地质处的过程地址,这种间接调用格式要使用NEAR PTR运算符。

     

     

  • 相关阅读:
    bzoj1914
    bzoj3144
    bzoj2756
    poj3177
    一些比较水的题目
    bzoj2282
    屯题50AC纪念
    Base64解码中文部分中文乱码的原因
    随机生成36位字符串
    jQuery判断某个元素是否存在某个样式
  • 原文地址:https://www.cnblogs.com/csnd/p/12062276.html
Copyright © 2011-2022 走看看