@H_502_0@这学期学微机原理,顺便学了点汇编,遇到了很多问题,到百度上去求助几乎没人理我,到CSDN来后发现这里的大牛们特别热情,以后就在CSDN扎根了。
@H_502_0@下面是我作的一点点笔记(有许多点子还是大牛们告诉我的),如果其中的错误的地方还希望大家指出。马上就得回家了,就不再排版了,以后再修改。
@H_502_0@我用的汇编工具是TASM,对于其它的工具可能结果不同 。
@H_502_0@(一)、汇编缩写表:
DB:Define Byte(未完)
@H_502_0@———————————————————————————————————
@H_502_0@(二)、反汇编时一般不能完全还原为原来的代码
eg:
@H_502_0@JC again;在反汇编时会以JB出现
@H_502_0@(三)、Syntax error
@H_502_0@语法错误,如宏命令与已有的指令名,标号名冲突
@H_502_0@(四)、关于MOV的用法:
@H_502_0@ Mov dst,src
@H_502_0@ Reg reg/mem/data/segreg
@H_502_0@ Mem reg/data/segreg
@H_502_0@Segreg reg/mem
@H_502_0@Ac mem(ac指ax,al,该指令较其它指令短一个字节,执行速度也快些)
@H_502_0@Mem ac
@H_502_0@ 注:
@H_502_0@1、SEGREG只能出现在MOV,PUSH,POP中
@H_502_0@ 2、Mov mem,mem;错误,如MOV byte ptr [BX],[SI]; Illegal memory reference
@H_502_0@3、MOV segreg,data;错误,立即数不能传给Segreg
@H_502_0@ 4、MOV segreg,segreg ;SEGMENT不可相互传送
@H_502_0@(五)、ASSUME作用(猜测):
@H_502_0@ASSUME 作用:汇编时在符号表中记录下——变量和标号的段存储位置,如CS、DS、SS。
@H_502_0@汇编程序遇到变量、标号时动作:
@H_502_0@1、在对变量操作指令中,汇编程序会在符号表中查找该变量的段地址存放地点、偏移地址(段地址存放地点由ASSUME 指定如果没有ASSUME 指定,会报错Can't address with currently ASSUMEd segment registers)。
@H_502_0@2、在对标号操作指令中,汇编程序会在符号表中查找该标号的段地址存放地点、偏移地址(段地址存放地点由ASSUME 指定,如果没有ASSUME 指定,会报错Near jump or call to different CS)。
@H_502_0@注意后最几段(39行后)的对变量NO(在CODE中定义)和BUF(在DATA中定义)的寻址,如果没有ASSUME,汇编时就会报错。
@H_502_0@ 30 0009 C6 07 01 mov byte ptr [bx],1;use ds
@H_502_0@ 31 000C C6 07 01 mov byte ptr ds:[bx],1;use ?
@H_502_0@ 32 000F C6 47 01 01 mov byte ptr 1[bx],1;use ds
@H_502_0@ 33 0013 C6 47 01 01 mov byte ptr ds:1[bx],1;use ?
@H_502_0@ 34 0017 36: C6 07 01 mov byte ptr ss:[bx],1;use ?
@H_502_0@ 35 001B C6 46 00 01 mov byte ptr [bp],1;use ss
@H_502_0@ 36 001F 3E: C6 46 00 01 mov byte ptr ds:[bp],1;use ?
@H_502_0@ 37 0024 3E: C7 46 00 0001 mov ds:[bp],1;use ?
@H_502_0@*Warning* /y/a.ASM(28) Argument needs type override
@H_502_0@ 38 002A 3E: C6 46 00 01 mov byte ptr ds:[bp],1;use ?
@H_502_0@ 39 002F C6 87 0000r 01 mov buf[bx],1;use ds
@H_502_0@ 40 0034 C6 87 0001r 01 mov buf+1[bx],1;use ds
@H_502_0@ 41 0039 2E: C6 87 0005r 01 mov no[bx],1;use ?
@H_502_0@ 42 003F 3E: C6 86 0000r 01 mov buf[bp],1;use ss
@H_502_0@ 43 0045 2E: C6 86 0005r 01 mov no[bp],1;use ?
@H_502_0@ 44 004B C6 06 0000r 01 mov buf,1
@H_502_0@ 45 0050 2E: C6 06 0005r 01 mov no,1
@H_502_0@注:1、使用默认段比使用段跳转速度快一些,因为段跳转会在操作码前增加一个字节
@H_502_0@ 2、使用间接寻址比使用相对寻址要快,因为相对寻址还要经相加得到地址(如NO[BX]),而且其指令较长
@H_502_0@EG:mov byte ptr [bx],1(3字节)比mov byte ptr[bp],1(四字节)短一个字节
@H_502_0@30 0009 C6 07 01 mov byte ptr [bx],1;use ds
@H_502_0@35 001B C6 46 00 01 mov byte ptr [bp],1;use ss
@H_502_0@因为mov byte ptr[bp],1在汇编时被认为是MOV TYTE PTR[BP+00],1,即相对寻址方式,而不是间接寻址方式
@H_502_0@(六)、输入时单十进制数据是以实际数值ASCII码保存的(高于实际值30H),如果只是用于加减运算、被除、被乘运算,为了方便显示,可以不必再去减30H。
@H_502_0@ 如:输入7个数(0~9),求其平均值,得到的平均值整数部分的ASCII码(高于实际值30H),所以其整数部分可以直接显示,而只有余数是实际数值
@H_502_0@(七)、关于类型指示PTR的使用:
@H_502_0@双操作数,如双方类型不明确,就应当使用PTR,否则程序就默认为WORD型。.
@H_502_0@ 36 001F 3E: C6 46 00 01 mov byte ptr ds:[bp],1;BYTE
@H_502_0@ 37 0024 3E: C7 46 00 0001 mov ds:[bp],1;WORD
@H_502_0@*Warning* /y/a.ASM(28) Argument needs type override,
@H_502_0@注:如下双内存操作数,都是不合法的:
@H_502_0@MOV [BX],[SI];error:Illegal memory reference非法内存参数
@H_502_0@MOV byte ptr [BX],byte ptr [SI];error:Illegal memory reference非法内存参数
@H_502_0@(八)、mov [2134],bx在很多汇编软件中会报错:Illegal immediate
@H_502_0@ 该指令在实际编程中是不可能用到的(我们一般都是利用变量名来对内存进行寻址)
@H_502_0@因为,汇编时内存的偏移与段基址都是浮动的(偏移地址(r)在连接时才被最终确定下来,段地址(s)在程序运行时才被最终确定下来)
@H_502_0@注:如果指令MOV [2134],BX在连接时,有另外一个段要同连接到此指令所处的段相连接,那么偏移2134必须改变,否则程序运行仍然指向2134。如果使用变量名MOV NUM,BX,在连接时就能适应偏移改变的要求(因为汇编程序建立了NUM的符号表,连接时会根据符号表中NUM的位置信息来改变指令中NUM的偏移)。
@H_502_0@(九)、标号伪指令
@H_502_0@ 用于标号或者变量的命名:
@H_502_0@ Bufw label word(无=、equ)
@H_502_0@BUFW EQU this word
@H_502_0@ Bufw = this word
@H_502_0@--------上面的三条指令应该放在地址入口前面----
@H_502_0@Bufw EQU word ptr bufb
@H_502_0@Bufw =word ptr bufb
@H_502_0@注:(ptr与this的作用是相同的)
@H_502_0@(十)、解决8086中条件跳转不能用NEAR的麻烦:
@H_502_0@Relative jump out of range by 0126h bytes
@H_502_0@8086中的条件跳转只有short类型;80186的条件跳转增加了near类型。当使用了的条件跳转超出SHORT型的范围就会报此错。(参看《汇编语言程序设计》第117页,朱玉龙 任文岚 朱彤编著 清华大学出版社)
@H_502_0@解决方法:
1、如果超过的字节数较少,可以优化代码,减少中间代码的字节数。
2、把部分中间代码移到其它位置定义成函数。
3、把条件跳转改成jmp指令和一条相反的条件跳转指令。例如:
Ll:
; ……
jz Ll
改成:
L1:
; ……
jnz L2
jmp L1 ;jmp是非条件跳转,有SHORT,NEAR,FAR型
L2:
@H_502_0@4、几乎所有的跳转指令都成对,所以上面的‘二级跳’做法总行得通。但是极少跳转指令(JCXZ和LOOP)没有相对应的指令,可以采用如下的‘三级跳’
@H_502_0@ Jcxz skip
@H_502_0@ Jmp short skip1(提前引用如果不使用SHORT,此跳转就被汇编为NEAR)
@H_502_0@Skip:jmp lab
@H_502_0@Skip1:
@H_502_0@5、可以将3、4语句写成相应的宏指令***M,如JNZ写成能支持远调用的宏指令JNZM,其中在文件头可以加入JUMPS后就完全可以实现这样的宏功能
@H_502_0@当在.asm文件头加入JUMPS时,生成的LIST文件为:
75 03 E9 FE57 je start1
@H_502_0@L1:
可以看到:TASM自动对上面的指令作了跳转处理,这里的指令码:75 03 E9 FE57表示的是两个指令:75 03指的是jne L1的机器码;E9 FE57是jmp start1的机器码
6、可以在需要使用条件跳转的指令前加入.386,在指令后加入.8086:
0F 84 FE58 je start1
这个已经不是8086的指令了,而是386指令(是一条指令)
@H_502_0@注:I、有部分汇编工具如(MASM FOR WINDOWS)带有上述5所述的功能,就不会出现超出跳转范围的错误。
@H_502_0@ II、上面的例子中,我对机器码的验证是通过DEBUG得出的.
@H_502_0@在16BIT DEBUG下
-A
-****:**** DB 75 03 E9
-****:****
-U
@H_502_0@在32位 DEBUG下
@H_502_0@-E 0100 0F 84 58 FE
-U
@H_502_0@(十一)、经常遇到在CMD下输入命令后无反映
@H_502_0@cmd没有转入 虚拟8086模式,只要运行一下8086的程序或者按Alt+Enter键进入全屏模式(或者在按Alt+Enter恢复窗口)运行就会正常
@H_502_0@(十二)、程序加载到内存时,在程序头部有一个记录,就是记录了程序的入口地址。
@H_502_0@还应该记录了关于段基址的传送指令的位置信息,如MOV AX,DATA,而END 语句只是告诉了汇编系统——程序入口在哪里,但是它并不生成相应的机器码。
@H_502_0@(十三)、变量不可以提前引用(标号可以被提前引用)
@H_502_0@ Eg: 230 00F5 2E: A1 00F8r mov ax,yy
@H_502_0@**Error** c1.ASM(141) Forward reference needs override
@H_502_0@231 00F8 6173 yy dw 'as'
@H_502_0@(十四)、以下显示字符的中断会改变AL的值:最终使AL=DL。
@H_502_0@ MOV AH,2
@H_502_0@ INT 21H
@H_502_0@(十五)、汇编中的数值表示([]表示可以省略)
@H_502_0@1、 二进制数:01组合+B,111B,1010B
@H_502_0@2、 八进制数:0~8组合+O。
@H_502_0@3、 十进制数:0~9组合+[D]
@H_502_0@4、 十六进制数:0~9组合(至少一个)+[A~F组合]+H
@H_502_0@5、 字符串:”字符”,或者’字符’
@H_502_0@注:除了DB可以直接跟任意长度的字符串(DB ‘asdfsdafsdf’),其它情况下初始化内容必须是在DB、DW、DD等等的范围之内(DD ‘ABC’超出了范围,DB ABC也超出了范围)
@H_502_0@(十六)、变量的引用,作为变量而言,它是不能被提前引用的,变量可以被汇编系统(TASM)视为标号,此时就可以被提前引用。
@H_502_0@
@H_502_0@变量的引用
提前引用
非提前引用
在转移指令后作为标号(须有标号类型)
可行(1.1)
@H_502_0@JMP 标号类型 变量
可行(2.1)
@H_502_0@JMP 标号类型 变量
作为普通变量
不行(1.2)
可行(2.2)
在内存分配伪指令后作为标号(只用于DW、DD)
可行(1.3)
@H_502_0@DD/DW 变量
@H_502_0@DD OFFSET 变量
可行(2.3)
@H_502_0@DD/DW 变量
@H_502_0@DD OFFSET 变量
@H_502_0@
下面以对字变量VW和字节变量VB的引用为例,作一个说明:
@H_502_0@1.1、提前引用:字变量VW与字节变量VB被当作标号来使用(在转移语句中,必须加标号类型)
@H_502_0@ 229 00F5 EB 38 jmp short vw
@H_502_0@ 230 00F7 EB 36 90 jmp near ptr vw
@H_502_0@ 231 00FA EB 33 90 90 90 jmp far ptr vw
@H_502_0@ 232 00FF EB 30 jmp short vb
@H_502_0@ 233 0101 EB 2E 90 jmp near ptr vb
@H_502_0@ 234 0104 EB 2B 90 90 90 jmp far ptr vb
@H_502_0@1.2、字变量VW与字节变量VB作为普通变量,不能出现在提前引用
@H_502_0@ 237 0109 2E: FF 26 012Fr jmp vw
@H_502_0@**Error** c1.ASM(148) Forward reference needs override
@H_502_0@ 238 010C 2E: FF 26 012Fr jmp word ptr vw
@H_502_0@**Error** c1.ASM(149) Forward reference needs override
@H_502_0@ 239 0110 2E: FF 2E 012Fr jmp dword ptr vw
@H_502_0@**Error** c1.ASM(150) Forward reference needs override
@H_502_0@ 240 0114 2E: FF 26 0131r jmp vb
@H_502_0@**Error** c1.ASM(151) Argument to operation or instruction has illegal size
@H_502_0@ 241 0117 2E: FF 26 0131r jmp word ptr vb
@H_502_0@**Error** c1.ASM(152) Forward reference needs override
@H_502_0@ 242 011B 2E: FF 2E 0131r jmp dword ptr vb
@H_502_0@**Error** c1.ASM(153) Forward reference needs override
@H_502_0@1.3、变量在内存分配伪指令后被作为标号来使用(如果是在DW后取偏移,在DD后取偏移加段地址,在DB后会报错),以下是提前引用
@H_502_0@ 244 011F 012Fr dw offset vw
@H_502_0@ 245 0121 0131r dw vb
@H_502_0@ 246 0123 012Fr dw vw
@H_502_0@ 247 0125 0000012Fsr dd vw
@H_502_0@ 248 0129 00000131sr dd vb
@H_502_0@ 249 012D 00 db vb
@H_502_0@**Error** c1.ASM(160) Expecting scalar type
@H_502_0@ 250 012E 00 db vw
@H_502_0@**Error** c1.ASM(161) Expecting scalar type
@H_502_0@-----------------------------------------------------------------------------------
@H_502_0@ 252 012F 0061 VW DW 'a'
@H_502_0@253 0131 BC VB DB 0BCH
@H_502_0@-----------------------------------------------------------------------------------------
@H_502_0@2.1、变量在转移指令后作为标号使用(须有标号类型)(非提前引用):
@H_502_0@ 255 0132 EB FB jmp short vw
@H_502_0@ 256 0134 EB F9 jmp near ptr vw
@H_502_0@ 257 0136 EB F7 jmp far ptr vw
@H_502_0@ 258 0138 EB F7 jmp short vb
@H_502_0@ 259 013A EB F5 jmp near ptr vb
@H_502_0@ 260 013C EB F3 jmp far ptr vb
@H_502_0@-----------------------------------------------------------------------------------
@H_502_0@2.2、变量被作为普通变量而言(用于间接转移,或者MOV等数值传递等语句),只能先定义后使用(即非提前引用)
@H_502_0@ 262 013E 2E: FF 26 012Fr jmp vw
@H_502_0@ 263 0143 2E: FF 26 012Fr jmp word ptr vw
@H_502_0@ 264 0148 2E: FF 2E 012Fr jmp dword ptr vw
@H_502_0@ 265 014D 2E: FF 26 0131r jmp vb
@H_502_0@**Error** c1.ASM(176) Argument to operation or instruction has illegal size
@H_502_0@ 266 0152 2E: FF 26 0131r jmp word ptr vb
@H_502_0@ 267 0157 2E: FF 2E 0131r jmp dword ptr vb
@H_502_0@-------------------------------------------------------------------------
@H_502_0@2.3、变量在内存分配伪指令后被作为标号来使用(如果是在DW后取偏移,在DD后取偏移加段地址,在DB后会报错),以下是非提前引用
@H_502_0@ 269 015C 012Fr dw offset vw
@H_502_0@ 270 015E 0131r dw vb
@H_502_0@ 271 0160 012Fr dw vw
@H_502_0@ 272 0162 0000012Fsr dd vw
@H_502_0@ 273 0166 00000131sr dd vb
@H_502_0@ 274 016A 00 db vb
@H_502_0@**Error** c1.ASM(185) Expecting scalar type
@H_502_0@ 275 016B 00 db vw
@H_502_0@**Error** c1.ASM(186) Expecting scalar type
@H_502_0@(十七)、关于对register的初始化对程序速度的关系
一般而言,指令长度越短,速度越快,而用寄存器对寄存器初始化,指令长度更短,程序预读取指令越快。还有指令越复杂,速度也越慢。
@H_502_0@ Eg: XOR BX较MOV BX更快
@H_502_0@ OR AX,30H较ADD AX,30H更快,虽然指令一样长,但是后者是加法运算,更为复杂一些,时间也长一些(将这两个语句放在一个比较大的循环语句中,前者的运行时间是7s,后者的运行时间是21s)。
@H_502_0@本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ahui132811/archive/2010/01/23/5249059.aspx