奇趣技术网 收藏本站
设为主页
商务合作
首页 新闻中心 行业动态 软件新闻 安全资讯 病毒预警 漏洞发布 操作系统 Dos Win9x Win2000 WinXP Win2003 WinVista Linux Unix
数据库 DB2 Access MSSQL MySQL Oracle Sybase 编程技术 ASP PHP JSP CGI/Perl XML .Net C/C++/C# VB VC Delphi Java 汇编
安全技术 安全教学 工具介绍 漏洞利用 病毒防范 入侵检测 防火墙 安全防范 汉化破解 攻击实例 加密解密 技术论坛
中华网络安全联盟 >> 程序开发 >> 汇编 >> 汇编语言---程式设计 (5)
程序开发
Asp
PHP
JSP
CGI/Perl
XML
.Net
C/C++/C#
Visual Basic
Visual C++
Delphi
Java
汇编语言
  • JDBC专题介绍(1)

  • 全面解析JDBC(9)

  • 全面解析JDBC(6)

  • 全面解析JDBC(5)

  • 全面解析JDBC(4)

  • 全面解析JDBC(1)

  • MySQL中修改密码及访问

  • SQL语法参考

  • 汇编语言---程式设计 (5)
    字体:

    中华网络安全联盟    作者:佚名    来源:网络转载    时间:2006-3-21

    汇编语言---程式设计 (5):四、桥式法:

        桥式法是利用读写记忆体的特性,将程式中若干指令直接填入,作为临时便桥,以改变此段程式的功能。
        例如在显示时,希望能提供多种变化,而又不愿减低速度及增加太多的程式。最好的方法,便是利用桥式法,在同一位址,填入需要的指令。
        桥式法用得好而又灵活时,对程式的效率极有助益。但是应该注意一点,就是只能用在可读可写的记忆区中,如若要制成「韧体」,即置入仅读记忆体(ROM) 中的程式,绝不可使用此法。
        下面的实例,即为萤幕显示的桥式应用。首先,把架桥的「材料」设置在缓冲器中,如:
        CDSPMOD   DB      88H    ;8805 = MOV [DI],AL
              DB      30H    ;3005 = XOR [DI],AL
              DB      08H    ;0805 = OR  [DI],AL
              DB      20H    ;2005 = AND [DI],AL
        CDSPMOD 即为缓冲器,其中有四个数据,分别为机器码的相异部份,如分号后所注。因为四组机器码皆有 05 ,不必再填。=右边部份,即为该机器语言相对应的指令。
        程式部份先设妥功能定义,利用一、所说的变数应用法,依序由0至3先载入暂存器BX中。根据 BX 值,将所需机器码载入程式中。
       10:CLOD:
       11:        MOV    AL,CDSPMOD[BX]    ;用BX取预存码
       12:        MOV    CS:CDSP2[1],AL    ;载入CDSP2+1
       13:CDSP:
       14:        SUB    SI,SI        ;资料由0起
       15:CDSP1:
       16:        LODSB            ;取资料
       17:CDSP2    LABEL BYTE        ;载入的位置
       18:        XOR    ES:[DI],AL    ;原码26 30 05
       19:        INC    DI        ;须改 30 部份
       20:        LOOP    CDSP1
       21:        RET

    五、流水线法:

        工业上的流水线生产作业,需要极为严格的规格限制,原器件分别研制完毕后,统一送到生产线上组装。
        程式亦可采用同样的方法,只可惜一时手头上找不到现成的、适用的例子,只得将方法概述如下:
        先设定处理流程,凡是能用这种生产流程者,皆适用。
        再设定处理流程中所采用的「生产线」,也就是缓冲器。因为流水线上所用的资料都需要由缓冲器提供。
        此缓冲器的长度由流程决定,缓冲器中的资料则由各调用本流程的原程式载入。
        各调用程式可视个别条件,将所需处理的资料,放在缓冲器内(全部或部份)。待调用后,再从原缓冲器中取出经过处理后的资料。

    六、对应表法

        凡是指根据某种需要,将经过整理的资料,以某种固定的格式,安排在一特定区域中。每当需要时,立刻可以按照排列的位置取出来使用的,皆可称之为对应表。
        这种对应表是我最喜欢利用的技巧,速度奇快不说,修改也极其容易。尤其是我做事一向不拘小节,写起程式来,专出小错。自从采用了表格对照法后,凡是适合这种形式的程式,只要想通了最理想的结构,几个指令就把程式写完了。
        兹将附录中所举的例子,对字形放大所采用的查表法,在此作进一步的介绍。
        假设有一组图形,要在萤幕上左右放大一倍。一般程式师做这种题目,都是在暂存器内移来移去,每一个字元的资料,起码要移八次之多,每次都要用借位作为转换值。而转换时,又要放进一个16位元的暂存器中,尽管可以用回路去做,时间的延误相当大,读者可参考附录二以做比较。
        当然,表格要占用空间,以本例而言,如果一次用256B,取足则要512B。
        因此这种技术可以说是以空间换取时间。在第一章第三节「效率」的第四条定律下,我们知道键盘输入速度,决定于人的操作速度,而人的反应远远不及电脑,故应以人的速度为时间边际值,尽量设法节省。
        目前,所涉及的是显示时间,每个人在电脑前,都期望着立即得到结果。因此,显示速度不仅要快,而且越快越好。所以,前述的空时交换应在可能范围中,视实际的边际效应,以作取舍。
        现在看看资料分析,下面列举的二进位资料,在左边为原图形点阵,在右边则为放大一倍后的点阵:
        原点阵              左右放大一倍
        00000001            00000000 00000011
        00000010            00000000 00001100
        00000011            00000000 00001111
        ..
        01010101            00110011 00110011
        ..
        11111111            11111111 11111111
        现在有两个因素非常明显,第一,不论什么点阵,放大后长度加一倍,一字元有256 种。放大后点形种类不变,但字元数加倍为 512个。其次,由于放大后的 512个中,有一半皆相同,故仍可用256 种表示。
        至于取前者或后者,当视情况而定。
        决定以后,将之定义在缓冲器中,以原图形的点阵资料作为索引值,即可采间接定址法,立即取得放大后点阵。
        在制作对应表时,应养成良好的习惯,根据资料的规则,以等长度、固定的格式输入。这样不仅对表中的资料能一目瞭然,而且容易输入、侦错、修改,一举数得。
        如某表格为:
        100 TBXXX  DB  0,1,3,7,0FH,1FH,3FH,7FH,0FFH,2,6,0EH,1EH,3EH,7EH,0FEH
        此表看去远不如下表来得清楚、规律:
        100 TBXXX DB  000H,001H,003H,007H,00FH,01FH,03FH,07FH
        200       DB  0FFH,002H,006H,00EH,01EH,03EH,07EH,0FEH
        从事程式写作,规律的思考方式及追求,经常事半功倍。这种小技巧看似没有多大作用。事实上,在输入时,规则化的结构可以轻易地利用现有的功能,或复制,或修改。更有利的是能一眼看出该表的意义及正确性,在程式侦错时,往往可以节省大量的时间。

    七、模式法

        所谓模式法,是指在程式的处理过程中,分析其规律,以期找到一种共同具有的「模式」。并用此模式,设计成为一个个程式单元,以追求最高效率。
        这种模式,可用「概念」来代表,但最理想的表达方法,仍以视觉图形为宜。也就是说,最好能把分析出来的模式,用图形表示,并据以理解及设计程式。
        兹以常用的功能「排序」为例,来说明模式法的应用,并设计成为程式。
        先假定需要排序的资料结构为:
        11每笔资料之长度固定为一字元。
        12资料形式为 ASCII码,16进位值,由 20H到 7EH。
        13排序时,资料数值小者排在低位,大者排在高位。
        14程式开始时参数设定为:
          AL= 高位之资料。
          AH= 低位之资料。
          DS:SI=资料存贮处。
        资料由低位开始检查,并同时排序,直到全部查完为止。排序时,交换高位及低位之资料,以使
        高位住址资料≧低位住址中之资料。
        由于人类行为与视觉息息相关,故最有效的认知方式,是以作图来说明。以下即为上一陈述之图形说明。

                        │? │
        模式一供检查            ├─┤
        AL,AH 之大小       ┌ AH <--│? │<-- AL ┐
                模 │        ├─┤     │模
        模式二交换资料    式 ┤ AL <--│? │<-- AH ├式
        其中 AH>AL     一 │        ├─┤     │二
                   └ SI =  │? │ =  SI ┘
                        ├─┤

        由上图可见在模式一中,AH为低位资料,AL为高位资料。比较 AL,AH 之大小,即可知是否符合序列规定。如符合,则继续做下去,否则依模式二,将小值放进低位,大值放进高位住址中。程式只要设法保持此一处理之形式,即可简单明瞭地完成任务。
        1: COMPAR:
        2:        MOV    AH,AL      ;设AH为低位值
        3: COMPAR1:
        4:        LODSB          ;取资料
        5:        CMP    AL,AH      ;比大、小
        6:        JAE    COMPAR      ;高位大,不变
        7:        MOV    [SI-2],AX ;交换AH,AL,排序
        8:        DEC    SI      ;向低位再查
        9:        MOV    AH,[SI-2]
       10:        JMP    COMPAR1

        当然,上面这段程式并不成立,因为没有出口,永远做不完。程式的终止有很多方法,一是用计数器,一是用位置来比较,也有用终止指令的,不一而足,各有长短。
        首先,假设在DS:SI 中,有一长度值,兹以计数器的回路来试试看:
        1:        LODSW
        2:        MOV    CX,AX      ;似此,3B 18C
            ;若用    MOV   CX,[SI]
            ;    INC   SI
            ;    INC   SI
            ;则需    6B,21T
        3:        SUB    AL,AL      ;先设最小值,备用
        4: COMPAR:
        5:        MOV    AH,AL      ;设AH为低位值
        6: COMPAR1:
        7:        LODSB          ;取资料
        8:        CMP    AL,AH      ;比大、小
        9:        JB    COMPAR2   ;低位大,需排序
       10:        LOOP    COMPAR      ;回路
       11:        RET          ;完成
       12: COMPAR2:
       13:        MOV    [SI-2],AX ;交换AH,AL,排序
       14:        DEC    SI      ;向低位再查
       15:        MOV    AH,[SI-2]
       16:        JMP    COMPAR1
        程式中的回路,对前面有一比较分支不太有利,因为回路每次要17T ,比较分支就是现成的回路,不利用形成浪费。
        若把回路改为位置比较,程式即为:
        1:        MOV    CX,SI
        2:        ADD    CX,[SI]
        3:        INC    SI
        4:        INC    SI
        5:        SUB    AL,AL      ;先设为最小值,备用
        6: COMPAR:
        7:        MOV    AH,AL      ;设AH为低位值
        8: COMPAR1:
        9:        LODSB          ;取资料
       10:        CMP    SI,CX      ;比位置到终点?
       11:        JAE    COMRET      ;完成
       12:        CMP    AL,AH      ;比大、小
       13:        JAE    COMPAR      ;高位大,再查
       14:        MOV    [SI-2],AX ;交换AH,AL,排序
       15:        DEC    SI      ;向低位再查
       16:        MOV    AH,[SI-2]
       17:        JMP    COMPAR1
       18: COMRET:
       19:        RET
        如此,在分支时,在第13条指令做回路,10,11 则比较住址以决定是否完成。这一来,完成结束只有一次,需时 16T,其余所有执行时间皆为4T,较前一回路快了13T 之多。
        再试用「终止指令」法,其必要条件为资料中有多余的组合可供选择。一般多以 00H,0FFH 等极端值比较理想,下面且以0FFH作为终止指令,并置于资料终止处。
        1:        MOV    CL,0FFH   ;终止检查用
        2:        SUB    AL,AL      ;先设为最小值,备用
        3: COMPAR:
        4:        MOV    AH,AL      ;设AH为低位值
        5: COMPAR1:
        6:        LODSB          ;取资料
        7:        CMP    AL,CL      ;比是否终止指令?
        8:        JAE    COMRET      ;完成
        9:        CMP    AL,AH      ;比大、小
       10:        JAE    COMPAR      ;高位大,再查
       11:        MOV    [SI-2],AX ;交换AH,AL,排序
       12:        DEC    SI      ;向低位再查
       13:        MOV    AH,[SI-2]
       14:        JMP    COMPAR1
       15: COMRET:
       16:        RET
        似此,程式较短,其他效果差不多。
        这段程式,在处理速度上,还大有油水。因为已经检查过的资料,因为回路关系,还会不断地重复检查,是否能够避免这种情况呢?
        事实上,当排序到某住址时,即表示由该住址起,上面已经检查完毕。因此,只要记录下来,下次再查时,将住址还原即可。
        1:        MOV    CL,0FFH   ;终止检查用
        2: COMPAR0:
        3:        SUB    AL,AL      ;先设为最小值,备用
        4: COMPAR:
        5:        MOV    AH,AL      ;设AH为低位值
        6: COMPAR1:
        7:        LODSB          ;取资料
        8:        CMP    AL,CL      ;比是否终止指令?
        9:        JAE    COMRET      ;完成
       10:        CMP    AL,AH      ;比大、小
       11:        JAE    COMPAR      ;高位大,再查
       12:        MOV    DI,SI      ;暂时保存
       13: COMPAR2:
       14:        MOV    [SI-2],AX ;交换AH,AL,排序
       15:        DEC    SI      ;向低位再查
       16:        MOV    AH,[SI-2]
       17:        LODSB          ;取排序资料
       18:        CMP    AL,AH      ;比是否该排
       19:        JB    COMPAR2   ;是
       20:        MOV    SI,DI      ;否,将原位址还原
       21:        JMP    COMPAR0   ;从头再做
       22: COMRET:
       23:        RET
        总而言之,程式的变化无穷无尽,尤其是用组合语言制作程式,更是灵活精妙。就像下围棋一般,往往一两个指令就足以将整个局势扭转过来。
        程式的效率经常决定在回路上,读者千万不要以为一两个时钟脉冲算不了什么。要知道,汪洋大海,也是由一点一滴的水珠累积而成的。
        这段程式还有不少值得深思的,读者们不妨自行研究吧!想得多了,自然会有生花妙笔。

        真要作大量的资料排序,还有更有效的方法,也是应用模式分析的原则,先找出资料的「型」。
        假如以同样性质的资料为例,为了避免资料一一查找,浪费时间。我们不妨研究一下,是否有可能,直截了当,就把资料依据大小,予以定位,一次排好?
        电脑的好处,就在于资料的规律性,我们理应利用这种优点,来找出其排序的模式。
        前例曾分为两个模式,一是查找,一是搬移。如果我们把查找改为记录,把搬移改为安排,则情形就大大的不同了。
        记录时利用间接定址技巧,每笔取到的资料,皆可视为一个数值,对应于一记录的缓冲区。如果资料中每笔资料总值大于256 且小于 65536,则可以用二字元记录之。再若资料为二进位值,可由 0至 255,即设 512个对应单位。
        假定原资料在 DS:SI中,长度在CX中。
        首先,设一记录区为:
        1: RECORD    DB    512 DUP (0)
        2:        PUSH    SI      ;程式开始
        3: CHECK:
        4:        LODSB          ;取资料,AH永远为0
        5:        MOV    BX,AX      ;利用BX间接定址
        6:        INC    WORD PTR RECORD[BX]
        7:        LOOP    CHECK
        8: STORE:
        9:        MOV    SI,OFFSET RECORD+512;指向最
                            ;后记录
       10:        MOV    BP,OFFSET RECORD    ;供检查
       11:        POP    DI      ;资料贮存处
       12: STORE1:
       13:        CMP    SI,BP      ;查是否完毕?
       14:        JE    RECEND      ;完成
       15:        DEC    SI      ;向上取
       16:        DEC    SI
       17:        MOV    CX,[SI]   ;取记录值
       18:        JCXZ    STORE1      ;无记录,重取
       19:        MOV    AX,SI      ;当前之位址
       20:        SUB    AX,BP      ;差值
       21:        SHR    AX,1      ;原有值
       22: STORE2:
       23:        REP    STOSW      ;重新载入
       24:        JMP    STORE1      ;继续
       25: RECEND:
       26:        RET
        程式的变化无穷无尽,尤其是用组合语言写作程式,简直没有止境。只要稍稍用点心,加一点点变化因素,一个巧妙无比的程式,就会跃然而出。
        写程式的乐趣,就在于心智的投入。学者们不妨试着把这      式再加以改良,其中还有不少可以下手的地方,养成习惯以后,程式自然就会精简了。

    八、预置法

        预置法适用于流程的安排,尤其是在不确定的情况下,有时需要作多项检查,不仅浪费时间,对空间也不利。
        例如有一段程式,其目的在于处理使用者所选择的流程。由于使用者事先通过介面程式,选妥各项工作,现在必须依某一顺序执行。
        这是一项难度相当大的工作,要执行固定顺序不难,下面的程式就可以达到目的。当然,一如既往,我们会尝试着将程式一再改进。最后,我们再来讨论如何能执行使用者所安排的顺序。
        设子流程有八种,使用者选用时,可令BX值等于子程式的代号。选用方式为「开关式」,即单数次为开,设定参数,复数次为关,取消设定。
        设定后,因为共有八种程式,可以用八个位元来设置所需要执行的旗号。当然,这要看程式的多少而定,八位元正好用一个旗号FLAG:
        1: SETUP:
        2:        CMP    BX,MAXVAL    ; 最大值检查
        3:        JA    SETRET        ; 超过,无效
        4:        SHL    BX,1        ; 参数乘2
        5:        JMP    SUBTB[BX]    ; 各种程式
        6: SUBTB    DW    SUB1        ; 各种程式
        7:        DW    SUB2        ; 程式中设定
        8:        ..            ; flag
        9:        DW    SUBN
       10: ENTER:
       11:        SHR    FLAG,1        ; 检查FLAG
       12:        JNC    ENTER1
       13:        CALL    SUB1        ; 有设定
       14: ENTER1:
       15:        SHR    FLAG,1
       16:        JNC    ENTER2
       17:        CALL    SUB2
       18: ENTER2:
       19: ..    ; 如此连续进行八次
        显然这种做法其笨无比,第十条以后,可用回路取代:
       10: ENTER:
       11:        MOV    CX,8
       12:        MOV    AL,FLAG     ; 暂存器较有效
       13:        OR    AL,AL
       14:        JZ    ENTRET        ; 不必做
       15:        SUB    BX,BX
       16: LOOP0:
       17:        SHR    AL,1
       18:        JNC    LOOP1
       19:        PUSH    AX
       20:        PUSH    BX
       21:        PUSH    CX
       22:        CALL    SUBTB[BX]
       23:        POP    CX
       24:        POP    BX
       25:        POP    AX
       26: LOOP1:
       27:        INC    BX
       28:        INC    BX
       29:        LOOP    LOOP0
       30: ENTRET:
       31:        RET
        这样好得多了,可是,还能不能再加改进呢?组合语言的妙处就在于变化无穷,且看看是否还能变出花样来。
        从设置开始,方式稍微改变一下,旗号的观念是供程式检查用。在应用时,要占用一个暂存器,而暂存器有限,浪费了可惜。此外,八个不同的子程式,又要占用一个计数用的暂存器,最好能够省掉。
        因此,设置的重要性就显而易见了,程式的好坏,并非仅仅在于指令的应用。原始的理念,及程式的规划,经常在程式设计之前已经决定了。
        我们称之为「预置法」,把前述的设置方式改变一下,用一组缓冲区,先定义如下:
            DB    0        ; 计数用
         BUFER    DW    8 DUP (0)    ; 存程式入口用
            DW    1        ; 终止信号
        然后再设计程式,预置及执行如次:
        1: SETUP:
        2:        CMP    BX,MAXVAL    ; 最大值检查
        3:        JA    SETRET        ; 超过,无效
        4:        SHL    BX,1        ; 参数乘2
        5:        ADD    BX,SUBTB
        6:        JMP    BX        ; 各种程式
        7: SUB3:
        8:        XOR    BUUER,BX    ; 设为第三组
        9:        JNZ    SUB31        ; 开
       10:    SUB30:
       11:        DEC    BUFER-1     ; 取消
       12:        RET
       13: SUB31:    INC    BUFER_1     ; 计数
       14:        RET
       15: SUBTB    DW    SUB1
       16:        DW    SUB2
            ..
       21:        DW    SUBN
       22: ENTER:
       23:        MOV    SI,OFFSET BUFER-1
       24:        LODSB            ; 查是否需要
       25:        OR    AL,AL        ; 为0则无
       26:        JZ    ENTRET
       27: ENTER1:
       28:        LODSW            ; 取程式资料
       29:        CMP    AX,1        ; 查程式入口
       30:        JB    ENTER1        ; 0表示不做
       31:        JZ    ENTRET        ; 1表示终止
       32:        PUSH    SI
       33:        CALL    AX        ; 执行
       34:        POP    SI
       35:        JMP    ENTER1
       36: ENTRET:
       37:        RET
        前一段调用程式需要31个字元,而现在只要21个字元,速度也快得多。不仅如此,前段程式仅能提供八个子程式,最多用十六位元,不过十六个子程式。本程式则不然,只要预留的缓冲器够,可提供的子程式可以说是无限。
        更重要的功能,是程式执行的顺序。除了这种预置法外,其他的方法,都受限于 SUBTB的安排次序,无法变更。但本方法则完全可任依使用者的需要,来决定子程式执行的顺序,以及是否执行。
        请注意在 SETUP时,BX的参数就同时代表了执行的顺序。如果要想依照设定的次序决定顺序,只要将缓冲区加大,再加一组预设程式即可,如下所示:
        1: SETUP:
        2:        SHL    AX,1        ; 输入参数
        3:        ADD    AX,OFFSET SUBTB ; 子程式入口
        4:        MOV    BX,BUFER-2    ; 位置序数
        5:        SHL    BX,1        ; 指向位置
        6:        MOV    BUFDER[BX],AX    ; 存入缓冲区
        7:        INC    WORD PTR BUFER-2; 序数加一
        8:        RET
        这一来,先调用的程式放在前面,后调用的放在后面,使用者只要知道子程式的代号,就可以随意安排调用。
        甚至于各子程式所需的参数,也可以用类似的方法,预先设置妥当,然后一次取出运用。
        预置法最宜于「用户」接口,而且作为应用程式,既简单又容易,方便灵活。
        比如有一些应用模组,即可应用此方法,分别归类、编号后,书于手册中,以提供使用者选择、应用。
        使用者选择介面的方法,可以通过萤幕提示,将各种模组显示在指定位置上。使用者利用游标,或其它选择方法,以求得到正确的编号,再依序置于缓冲区中。
        各种模组都可能需要输入参数或资料,所以,另外要准备一个参数缓冲区,在选择模组时,同时选择参数。由于各模组会自动取用参数,故只要置入即可。
        假设有一个「使用者自行设计程式」的工具套件,(“聚珍整合系统”就建立在这观念上,惜因我们人手不足,产品可能要到1991年才能上市。)萤幕提示有介面、功能、共用等各类模组,使用者选完一类后,萤幕再度提示该模组的编号。
        萤幕上的模组编号经过程式转换,得到程式编号,将此编号存入缓冲区,再查是否需要输入资料。即可按照原有流程设计,逐步执行下去,完全可以利用这种预置法。
        1: GETMOD:
        2:        SUB    AX,AX
        3:        INT    16H        ; 使用者输入
        4:        CALL    GETSUB        ; 转换为代号
        5: SETUP:                ; 代号置于AX
        6:        SHL    AX,1        ; 次序乘二
        7:        ADD    AX,OFFSET SUBTB ; 子程式入口
        8:        MOV    BX,BUFER-2
        9:        SHL    BX,1
       10:        MOV    BUFFER[BX],AX
       11:        INC    WORD PTR BUFER-2
       12:        JMP    GETVAR        ; 查取参数否
        当然,真正可以应用的程式,还要考虑很多因素,但大致上,结构就这样简单。
        写程式和画画没有两样,多看、多参考别人的程式,多想、多钻研各种方法,最后则是要多多动手,除此之外,别无其他法门。
    字体:
     
    设为主页 收藏本站 联系我们 友情连接 商务合作 网友留言
    Copyright©2006-2008 中华网络安全联盟 All rights reserved.