《汇编超浓缩教程》由会员分享,可在线阅读,更多相关《汇编超浓缩教程(16页珍藏版)》请在金锄头文库上搜索。
1、汇编超浓缩教程汇编超浓缩教程汇编语言超浓缩教程“ 哎哟,哥们儿,还捣鼓汇编呢?那东西没用,兄弟用 VB“钓“一个 API 就够你忙活个十天半月的,还不一定搞出来。 ”此君之言倒也不虚,那吾等还有无必要研他一究呢?(废话,当然有啦!要不然你写这篇文章干嘛。 )别急,别急,让我把这个中原委慢慢道来:一、所有电脑语言写出的程序运行时在内存中都以机器码方式存储,机器码可以被比较准确的翻译成汇编语言,这是因为汇编语言兼容性最好,故几乎所有跟踪、调试工具(包括 WIN95/98 下)都是以汇编示人的,如果阁下对 CRACK 颇感兴趣;二、汇编直接与硬件打交道,如果你想搞通程序在执行时在电脑中的来龙去脉,也
2、就是搞清电脑每个组成部分究竟在干什么、究竟怎么干?一个真正的硬件发烧友,不懂这些可不行。三、如今玩 DOS 的多是“高手” ,如能像吾一样混入(我不是高手) “高手”内部,不仅可以从“高手”朋友那儿套些黑客级“机密” ,还可以自诩“高手”尽情享受强烈的虚荣感-#$%定义段assume cs:prognam ;把上面定义段的段基址放入 CSmov cx,100h ; 装入循环次数mov dl,0 ; 装入第一个 ASCII 码,随后每次循环装入新码next: mov ah,2int 21hinc dl ;INC:递增指令,每次将数据寄存器 DL 内的数值加 1loop next ; 循环指令,执
3、行一次,CX 减 1,直到 CX 为 0,循环停止int 20hprognam ends ;段终止end ;汇编终止在汇编语言的源程序中,每一个程序行都包含三项元素:start: mov dl,1 ;装入第一个 ASCII 码,随后每次循环装入新码标识符 表达式 注解在原始文件中加上注解可使程序更易理解,便于以后参考。每行注解以“;”与程序行分离。编译器对注解不予理会,注解的数据不会出现在 OBJ、EXE 或 COM 文件中。由于我们在写源程序时,并不知道每一程序行的地址,所以必须以符号名称来代表相对地址,称为“标识符” 。我们通常在适当行的适当位置上,键入标识符。标识符(label)最长可达
4、 31 个字节,因此我们在程序中,尽量以简洁的文字做为标识符。现在,你可以将此 ASCII.ASM 文件编译成 ASCII.COM 了。1.MASM ASCII,2.LINK ASCII,3.EXE2BIN ASCII ASCII.COM。注意:当你以编译器汇编你设计的程序时,常会发生打字错误、标识符名称拼错、十六进制数少了、逻辑错误等。汇编老手常给新人的忠告是:最好料到自己所写的程序一定会有些错误(别人告诉我的) ;如果第一次执行程序后,就得到期望的结果,你最好还是在检查一遍,因为它可能是错的。原则上,只要大体的逻辑架构正确,查找程序中错误的过程,与写程序本身相比甚至更有意思。写大程序时,最
5、好能分成许多模块,如此可使程序本身的目的较单纯,易于撰写与查错,另外也可让程序中不同部份之间的界限较清楚,节省编译的时间。如果读程序有读不懂的地方最好用纸笔记下有关寄存器、内存等内容,在纸上慢慢比划,就豁然开朗了。 下面我们将写一个能从键盘取得一个十进制的数值,并将其转换成十六进制数值而显示于屏幕上的“大程序” 。前言:要让 8086 执行这样的功能,我们必须先将此问题分解成一连串的步骤,称为程序规划。首先,以流程图的方式,来确保整个程序在逻辑上没有问题(不用说了吧!什么语言都要有此步骤) 。这种模块化的规划方式,称之为“由上而下的程序规划” 。而在真正写程序时,却是从最小的单位模块(子程序)
6、开始,当每个模块都完成之后,再合并成大程序;这种大处著眼,小处著手的方式称为“由下而上的程序设计” 。我们的第一个模块是 BINIHEX,其主要用途是从 8086 的 BX 寄存器中取出二进制数,并以十六进制方式显示在屏幕上。注意:子程序如不能独立运行,实属正常。binihex segmentassume cs:binihexmov ch,4 ;记录转换后的十六进制位数(四位)rotate: mov cl,4 ;利用 CL 当计数器,记录寄存器数位移动次数rol bx,cl ;循环寄存器 BX 的内容,以便依序处理 4 个十六进制数mov al,bl ;把 bx 低八位 bl 内数据转移至 a
7、land al,0fh ;把无用位清零add al,30h ;把 AL 内数据加 30H,并存入 alcmp al,3ah ;与 3ah 比较jl printit ;小于 3ah 则转移add al,7h ;把 AL 内数据加 30H,并存入 alprintit:mov dl,al ;把 ASCII 码装入 DLmov ah,2int 21hdec ch ;ch 减一,减到零时,零标志置 1jnz rotate ;JNZ:当零标志未置 1,则跳到指定地址。即:不等,则转移int 20h ;从子程序退回主程序binihex endsend利用循环左移指令 ROL 循环寄存器 BX(BX 内容将由
8、第二个子程序提供)的内容,以便依序处理 4 个十六进制数:1. 利用 CL 当计数器,记录寄存器移位的次数。2.将 BX 的第一个十六进制值移到最右边。利用 AND (逻辑“与”运算:对应位都为时,其结果为,其余情况为零)把不要的部份清零,得到结果:先将 BL 值存入 AL中,再利用 AND 以 0Fh(00001111)将 AL 的左边四位清零。由于到的 ASCII 码为 30h 到 39h,而到之 ASCII 码为 41h 到 46h,间断了 7h,所以得到结果:若 AL 之内容小于 3Ah,则 AL 值只加30h,否则 AL 再加 7h。ADD 指令会将两个表达式相加,其结果存于左边表达
9、式内。标志寄存器(Flag Register)是一个单独的十六位寄存器,有 9 个标志位,某些汇编指令(大部份是涉及比较、算术或逻辑运算的指令)执行时,会将相关标志位置 1 或清 0, 常碰到的标志位有零标志(ZF) 、符号标志(SF) 、溢出标志(OF)和进位标志(CF) 。 标志位保存了某个指令执行后对它的影响,可用其他相关指令,查出标志的状态,根据状态产生动作。CMP 指令很像减法,是将两个表达式的值相减,但寄存器或内存的内容并未改变,只是相对的标志位发生改变而已:若 AL 值小于 3Ah,则正负号标志位会置 0,反之则置 1。 JL 指令可解释为:小于就转移到指定位置,大于、等于则向下
10、执行。CMP 和 JG 、JL 等条件转移指令一起使用,可以形成程序的分支结构,是写汇编程序常用技巧。第二个模块 DECIBIN 用来接收键盘打入的十进制数,并将它转换成二进制数放于 BX 寄存器中,供模块 1 BINIHEX 使用。decibin segmentassume cs:decibinmov bx,0 ;BX 清零newchar:mov ah,1 ;int 21h ;读一个键盘输入符号入 al,并显示sub al,30h ;al 减去 30H,结果存于 al 中,完成 ASCII 码转二进制码jl exit ;小于零则转移cmp al,9djg exit ;左右则转移cbw ;8
11、位 al 转换成 16 位 axxchg ax,bx ;互换 ax 和 bx 内数据mov cx,10d ;十进制数 10 入 cxmul cx ;表达式的值与 ax 内容相乘,并将结果存于 axxchg ax,bxadd bx,axjmp newchar ;无条件转移exit: int 20 ;回主程序decibin endsendCBW 实际结果是:若 AL 中的值为正,则 AH 填入 00h;反之,则AH 填入 FFh。XCHG 常用于需要暂时保留某个寄存器中的内容时。当然,还得一个子程序(CRLF)使后显示的十六进制数不会盖掉先输入的十进制数。crlf segmentassume cs
12、:crlfmov dl,0dh ;回车的 ASCII 码 0DH 入 DLmov ah,2int 21hmov dl,0ah ;换行的 ASSII 码 0AH 入 AHmov ah,2int 21hint 20 ;回主程序crlf endsend现在我们就可以将 BINIHEX、DECIBIN 及 CRLF 等模块合并成一个大程序了。首先,我们要将这三个模块子程序略加改动。然后,再写一段程序来调用每一个子程序。crlf proc near;mov dl,0dhmov ah,2int 21hmov dl,0ahmov ah,2int 21hretcrlf endp类似 SEGMENT 与 END
13、S 的伪指令,PROC 与 ENDP 也是成对出现,用来识别并定义一个程序。其实,PROC 真正的作用只是告诉编译器:所调用的程序是属于近程(NEAR)或远程(FAR) 。 一般的程序是由 DEBUG 直接调用的,所以用 INT 20 返回,用 CALL 指令所调用的程序则改用返回指令 RET,RET 会把控制权转移到栈顶所指的地址,而该地址是由调用此程序的 CALL 指令所放入的。各模块都搞定了,然后我们把子程序组合起来就大功告成decihex segment ;主程序assume cs:decihexorg 100hmov cx,4 ;循环次数入 cx;由于子程序要用到 cx,故子程序要将
14、 cx 入栈repeat: call decibin;调用十进制转二进制子程序call crlf ;调用添加回、换行符子程序call binihex ;调用二进制转十六进制并显示子程序call crlfloop repeat ;循环 4 次,可连续运算 4 次mov ah,4ch ; 调用 DOS21 号中断 4c 号功能,退出程序,作用跟 INT 20Hint 21H ; 一样,但适用面更广,INT20H 退不出时,试一下它decibin proc near push cx ;将 cx 压入堆栈,; exit: pop cx ;将 cx 还原; retdecibin endp binihex
15、 proc near push cx pop cx retbinihex endp crlf proc nearpush cx pop cx retcrlf endpdecihex ends endCALL 指令用来调用子程序,并将控制权转移到子程序地址,同时将 CALL 的下行一指令地址定为返回地址,并压入堆栈中。CALL 可分为近程(NEAR)及远程(FAR)两种:1.NEAR:IP 的内容被压入堆栈中,用于程序与程序在同一段中。2.FAR:CS 、IP 寄存器的内容依次压入堆栈中,用于程序与程序在不同段中。PUSH、POP 又是一对指令用于将寄存器内容压入、弹出,用来保护寄存器数据,子程序调用中运用较多。堆栈指针有个“后进先出”原则,像 PUSH AX,PUSH BXPOP BX,POP AX 这样才能作到保护数据丝毫不差。汇编语言超浓缩教程到这要告一段落了,希望能奠定你独立设计的基础。而更多更好的技巧则全依赖你平时的积累了。祝你成功!