您的位置:首页 > 编程语言

汇编语言表格驱动分支选择代码分析(4)

2009-10-21 10:48 489 查看
来自于《Intel汇编语言程序设计》(第四版)第六章。

 

 

先引用原书的话来解释一下表格驱动分支选择:

 

表格驱动分支选择是使用表格查找法来替代多路选择结构的一种方法。为了使用该方法,我们必须创建一个包含查找值和过程偏移的表格,程序使用循环来搜索该表格,当需要大量的比较时,这种方法是工作的最好的。

 

下面是书中的例子程序,用户从键盘输入一个字符,程序使用一个循环将该字符同表中的每个子项比较,如果一个匹配项被发现,那么紧跟其后存储的过程地址将被调用。每个过程使用EDX来装入不同字符串的偏移,然后在循环中显示该字符串。

 

看概念总是感觉比较复杂,其实非常简单,看一下代码就全明白了。

 

原代码如下:

 

TITLE Table of Procedure Offsets             (PorcTble.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'                           ; look up value

                  DWORD Process_A         ; address of procedure

EntrySize = ( $ - CaseTable )

                  BYTE 'B'

                  DWORD Process_B

                  BYTE 'C'

                  DWORD Process_C

                  BYTE 'D'

                  DWORD Process_D

NumberOfEntries = 4

prompt BYTE "Press  capital A,B,C or 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         ; ask user for input

          call WriteString

          call ReadChar                           ; read character into AL

          mov ebx,OFFSET CaseTable     ; point EBX to the table

          mov ecx,NumberOfEntries        ; loop count

L1:

          cmp al , [ebx]                           ; match found?

          jne L2                                       ; no: continue

          call NEAR PTR [ebx+1]              ; yes : call the procedure

 

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

 

          call WriteString                         ; display message

          call Crlf

          jmp L3                                      ; exit the search

L2:

          add ebx,EntrySize                    ; point to the next entry

          loop L1                                     ; repeat until ECX=0

L3:

          exit

main ENDP

 

;下面的每个过程将一个不同的字符串偏移送至EDX

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

 

 

 

以上便是所有代码。下面来逐步分析。

 

首先是数据段,进行了一些变量的定义,比较难理解的有可能是

 

EntrySize = ( $ - CaseTable )

 

这句,其实这个是为了计算出每个单元(一个字符+一个函数)的长度,这样在A结束之后减去CaseTable的首地址,就得到了一个单元的地址大小。

 

下面看一下代码段。让我们将main作为一个整体看一下:

 

main PROC

          mov  edx,OFFSET prompt         ; 将要打印的提示用户输入的字符串移至edx寄存器,等待打印

          call WriteString                         ; 打印EDX中的内容

          call ReadChar                           ; 读取一个字符到AL寄存器中

          mov ebx,OFFSET CaseTable     ; 将EBX指向CaseTable首地址

          mov ecx,NumberOfEntries        ; 在ECX中保存要循环的值(这里为4)

L1:

          cmp al , [ebx]                           ; 将用户输入的保存在AL中的字符串与CaseTable中的字符进行比较

          jne L2                                       ; 如果不是,则跳转到L2

          call NEAR PTR [ebx+1]              ; 如果匹配,则会执行到这里,间接调用 EBX+1 地址处的过程

 

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

 

          call WriteString                         ; 打印EDX寄存器中的值

          call Crlf                                     ; 将光标移动到下一行开始

          jmp L3                                      ; 跳转到L3

L2:

          add ebx,EntrySize                    ; 将EBX指向下一个单元

          loop L1                                     ; 跳转到L1循环直到ECX=0

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

 

 

只是将要打印的字符串送至EDX等待调用WriteString进行打印而已。

 

以上便是所有代码讲解。 

 

 

关于表格驱动分支选择,摘自原书:

 

表格驱动分支选择需要在初始化工作上有一些开销,但可以减少编写代码的数量。表格中可以包含大量的比较信息。而且这种方法比一系列很长的比较,跳转和调用指令的组合更加容易修改,表格甚至可以在运行时动态配置。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息