一个菜鸟作的一点汇编笔记

这学期学微机原理,顺便学了点汇编,遇到了很多问题,到百度上去求助几乎没人理我,到CSDN来后发现这里的大牛们特别热情,以后就在CSDN扎根了。

下面是我作的一点点笔记(有许多点子还是大牛们告诉我的),如果其中的错误的地方还希望大家指出。马上就得回家了,就不再排版了,以后再修改。

 

 我用的汇编工具是TASM,对于其它的工具可能结果不同 。

(一)、汇编缩写表:

DBDefine Byte(未完)

———————————————————————————————————

(二)、反汇编时一般不能完全还原为原来的代码

eg:

 JC again;在反汇编时会以JB出现

(三)、syntax error

语法错误,如宏命令与已有的指令名,标号名冲突

 

(四)、关于MOV的用法:

       Mov dst,               src

              Reg                reg/mem/data/segreg

              Mem              reg/data/segreg

Segreg           reg/mem

Ac                 mem(acax,al,该指令较其它指令短一个字节,执行速度也快些)

Mem              ac

       :

1SEGREG只能出现在MOV,PUSH,POP

       2Mov mem,mem;错误,如MOV byte ptr [BX],[SI]; Illegal memory reference

3MOV segreg,data;错误,立即数不能传给Segreg

       4MOV segreg,segreg ;SEGMENT不可相互传送

 

(五)、ASSUME作用(猜测)

ASSUME 作用:汇编时在符号表中记录下——变量和标号的段存储位置,如CSDSSS

汇编程序遇到变量、标号时动作:

1、在对变量操作指令中,汇编程序会在符号表中查找该变量的段地址存放地点、偏移地址(段地址存放地点由ASSUME 指定如果没有ASSUME 指定,会报错Can't address with currently ASSUMEd segment registers)。

2、在对标号操作指令中,汇编程序会在符号表中查找该标号的段地址存放地点、偏移地址(段地址存放地点由ASSUME 指定, 如果没有ASSUME 指定,会报错Near jump or call to different CS)。

注意后最几段(39行后)的对变量NO(在CODE中定义)和BUF(在DATA中定义)的寻址,如果没有ASSUME,汇编时就会报错。

       30   0009  C6 07 01                        mov byte ptr [bx],1;use ds

     31       000C  C6 07 01                       mov byte ptr ds:[bx],1;use   ?

     32       000F  C6 47 01 01                   mov byte ptr 1[bx],1;use ds

     33       0013  C6 47 01 01                   mov byte ptr ds:1[bx],1;use ?

     34       0017  36: C6 07    01                mov byte ptr ss:[bx],1;use   ?

     35       001B  C6 46 00 01                   mov byte ptr [bp],1;use ss

     36       001F  3E: C6 46   00 01                  mov byte ptr ds:[bp],1;use   ?

     37       0024  3E: C7 46   00 0001               mov ds:[bp],1;use ?

*Warning* /y/a.ASM(28) Argument   needs type override

     38       002A  3E: C6 46   00 01                  mov byte ptr ds:[bp],1;use   ?

     39       002F  C6 87 0000r 01              mov buf[bx],1;use ds

     40       0034  C6 87 0001r 01              mov buf+1[bx],1;use ds

     41       0039  2E: C6 87   0005r 01      mov no[bx],1;use ?

     42       003F  3E: C6 86   0000r 01      mov buf[bp],1;use ss

     43       0045  2E: C6 86   0005r 01      mov no[bp],1;use ?

     44       004B  C6 06 0000r 01              mov buf,1

     45       0050  2E: C6 06   0005r 01      mov no,1

注:1、使用默认段比使用段跳转速度快一些,因为段跳转会在操作码前增加一个字节

       2、使用间接寻址比使用相对寻址要快,因为相对寻址还要经相加得到地址(如NO[BX]),而且其指令较长

EG:mov byte ptr [bx],13字节)比mov byte ptr[bp],1(四字节)短一个字节

30  0009      C6 07 01                    mov byte ptr [bx],1;use ds

35  001B     C6 46 00 01                mov byte ptr [bp],1;use ss

 

因为mov byte ptr[bp],1在汇编时被认为是MOV TYTE PTR[BP+00],1,即相对寻址方式,而不是间接寻址方式

 

(六)、输入时单十进制数据是以实际数值ASCII码保存的(高于实际值30H),如果只是用于加减运算、被除、被乘运算,为了方便显示,可以不必再去减30H

       如:输入7个数(0~9),求其平均值,得到的平均值整数部分的ASCII码(高于实际值30H),所以其整数部分可以直接显示,而只有余数是实际数值

 

(七)、关于类型指示PTR的使用

双操作数,如双方类型不明确,就应当使用PTR,否则程序就默认为WORD型。.

     36       001F  3E: C6 46   00 01                  mov byte ptr ds:[bp],1;BYTE

     37       0024  3E: C7 46   00 0001               mov ds:[bp],1;WORD

*Warning* /y/a.ASM(28) Argument   needs type override,

 

注:如下双内存操作数,都是不合法的:

MOV [BX],[SI];errorIllegal memory reference非法内存参数

MOV byte ptr [BX],[SI];errorIllegal memory reference非法内存参数

MOV byte ptr [BX], byte ptr [SI];errorIllegal memory reference非法内存参数

(八)、mov [2134],bx在很多汇编软件中会报错:Illegal immediate

       该指令在实际编程中是不可能用到的(我们一般都是利用变量名来对内存进行寻址)

因为,汇编时内存的偏移与段基址都是浮动的(偏移地址(r)在连接时才被最终确定下来,段地址(s)在程序运行时才被最终确定下来)

注:如果指令MOV [2134],BX在连接时,有另外一个段要同连接到此指令所处的段相连接,那么偏移2134必须改变,否则程序运行仍然指向2134。如果使用变量名MOV NUM,BX,在连接时就能适应偏移改变的要求(因为汇编程序建立了NUM的符号表,连接时会根据符号表中NUM的位置信息来改变指令中NUM的偏移)。

 

(九)、标号伪指令

       用于标号或者变量的命名:

       Bufw label word(=equ)

BUFW EQU this word

       Bufw =   this word

--------上面的三条指令应该放在地址入口前面----  

Bufw EQU word ptr bufb

Bufw =word ptr bufb

注:(ptrthis的作用是相同的)

(十)、解决8086中条件跳转不能用NEAR的麻烦:

Relative jump out of range by 0126h bytes

8086中的条件跳转只有short类型;80186的条件跳转增加了near类型。当使用了的条件跳转超出SHORT型的范围就会报此错。(参看《汇编语言程序设计》第117页,朱玉龙 任文岚 朱彤编著 清华大学出版社)

解决方法:
1
、如果超过的字节数较少,可以优化代码,减少中间代码的字节数。

2
、把部分中间代码移到其它位置定义成函数。

3
、把条件跳转改成jmp指令和一条相反的条件跳转指令。例如:

Ll:
; ……
jz Ll
改成:

L1:
; ……
jnz L2
jmp L1 ;jmp
是非条件跳转,有SHORT,NEAR,FAR

L2:

4、几乎所有的跳转指令都成对,所以上面的‘二级跳’做法总行得通。但是极少跳转指令(JCXZLOOP)没有相对应的指令,可以采用如下的‘三级跳’

       Jcxz skip

       Jmp short skip1(提前引用如果不使用SHORT,此跳转就被汇编为NEAR)

Skip:jmp lab

Skip1:

5、可以将34语句写成相应的宏指令***M,如JNZ写成能支持远调用的宏指令JNZM,其中在文件头可以加入JUMPS后就完全可以实现这样的宏功能

当在.asm文件头加入JUMPS,生成的LIST文件为:
75 03 E9 FE57     je start1

L1:
可以看到:TASM自动对上面的指令作了跳转处理,这里的指令码:75 03 E9 FE57表示的是两个指令:75 03指的是jne L1的机器码;E9 FE57jmp start1的机器码

6
、可以在需要使用条件跳转的指令前加入.386,在指令后加入
.8086:
0F 84 FE58 je start1
这个已经不是8086的指令了,而是386指令(是一条指令)

注:I、有部分汇编工具如(MASM FOR WINDOWS)带有上述5所述的功能,就不会出现超出跳转范围的错误。

  II上面的例子中,我对机器码的验证是通过DEBUG得出的.

16BIT DEBUG
-A
-****:**** DB 75 03 E9
-****:****
-U

 

32 DEBUG

-E 0100 0F 84 58 FE
-U

(十一)、经常遇到在CMD下输入命令后无反映

cmd没有转入 虚拟8086模式,只要运行一下8086的程序或者按Alt+Enter键进入全屏模式(或者在按Alt+Enter恢复窗口)运行就会正常

 

(十二)、程序加载到内存时,在程序头部有一个记录,就是记录了程序的入口地址。

还应该记录了关于段基址的传送指令的位置信息,如MOV AXDATA,而END 语句只是告诉了汇编系统——程序入口在哪里,但是它并不生成相应的机器码。

(十三)、变量不可以提前引用(标号可以被提前引用)

   Eg: 230     00F5  2E: A1 00F8r                 mov ax,yy

**Error** c1.ASM(141) Forward reference needs override

231  00F8  6173                      yy  dw 'as'

(十四)、以下显示字符的中断会改变AL的值:最终使AL=DL

       MOV AH,2

       INT 21H

(十五)、汇编中的数值表示([]表示可以省略)

1、  二进制数:01组合+B111B1010B

2、  八进制数:0~8组合+O

3、  十进制数:0~9组合+[D]

4、  十六进制数:0~9组合(至少一个)+[A~F组合]+H

5、  字符串:字符,或者字符

注:除了DB可以直接跟任意长度的字符串(DB ‘asdfsdafsdf’),其它情况下初始化内容必须是在DBDWDD等等的范围之内(DD ‘ABC’超出了范围,DB ABC也超出了范围)

(十六)、变量的引用,作为变量而言,它是不能被提前引用的,变量可以被汇编系统(TASM)视为标号,此时就可以被提前引用。

      

变量的引用

 

提前引用

非提前引用

在转移指令后作为标号(须有标号类型)

可行(1.1)

JMP 标号类型 变量

可行(2.1)

JMP 标号类型 变量

作为普通变量

不行(1.2

可行(2.2)

在内存分配伪指令后作为标号(只用于DWDD

可行(1.3)

DD/DW 变量

DD OFFSET 变量

可行(2.3)

DD/DW 变量

DD OFFSET 变量

下面以对字变量VW和字节变量VB的引用为例,作一个说明:

1.1、提前引用:字变量VW与字节变量VB被当作标号来使用(在转移语句中,必须加标号类型)

    229  00F5  EB 38             jmp short vw

    230  00F7  EB 36 90                jmp near ptr vw

    231  00FA  EB 33 90 90 90       jmp far ptr vw

    232  00FF  EB 30             jmp short vb

    233  0101  EB 2E 90                jmp near ptr vb

    234  0104  EB 2B 90 90 90       jmp far ptr vb

1.2、字变量VW与字节变量VB作为普通变量,不能出现在提前引用

    237  0109  2E: FF 26   012Fr           jmp vw

**Error** c1.ASM(148) Forward reference needs override

    238  010C  2E: FF 26   012Fr           jmp word ptr vw

**Error** c1.ASM(149) Forward reference needs override

    239  0110  2E: FF 2E   012Fr           jmp dword ptr vw

**Error** c1.ASM(150) Forward reference needs override

    240  0114  2E: FF 26   0131r           jmp vb

**Error** c1.ASM(151) Argument to operation or instruction has illegal size

    241  0117  2E: FF 26   0131r           jmp word ptr vb

**Error** c1.ASM(152) Forward reference needs override

    242  011B  2E: FF 2E  0131r           jmp dword ptr vb

**Error** c1.ASM(153) Forward reference needs override

1.3、变量在内存分配伪指令后被作为标号来使用(如果是在DW后取偏移,在DD后取偏移加段地址,在DB后会报错),以下是提前引用   

    244  011F  012Fr                     dw offset vw

    245  0121  0131r                     dw vb

    246  0123  012Fr                     dw vw

    247  0125  0000012Fsr             dd  vw

    248  0129  00000131sr             dd  vb

    249  012D  00                         db  vb

**Error** c1.ASM(160) Expecting      scalar type

    250  012E  00                          db  vw

**Error** c1.ASM(161) Expecting      scalar type

-----------------------------------------------------------------------------------

    252       012F  0061             VW    DW 'a'

253       0131  BC                 VB      DB 0BCH

-----------------------------------------------------------------------------------------

2.1、变量在转移指令后作为标号使用(须有标号类型)(非提前引用):

    255  0132  EB FB             jmp short vw

    256  0134  EB F9             jmp near ptr vw

    257  0136  EB F7             jmp far ptr vw

    258  0138  EB F7             jmp short vb

    259  013A  EB F5             jmp near ptr vb

    260  013C  EB F3             jmp far ptr vb

-----------------------------------------------------------------------------------

2.2、变量被作为普通变量而言(用于间接转移,或者MOV等数值传递等语句),只能先定义后使用(即非提前引用)

    262  013E  2E: FF 26   012Fr           jmp vw

    263  0143  2E: FF 26   012Fr           jmp word ptr vw

    264  0148  2E: FF 2E   012Fr           jmp dword ptr vw

    265  014D  2E: FF 26  0131r           jmp vb

**Error** c1.ASM(176) Argument to operation or instruction has illegal size

    266  0152  2E: FF 26   0131r           jmp word ptr vb

    267  0157  2E: FF 2E   0131r           jmp dword ptr vb

------------------------------------------------------------------------- 

2.3、变量在内存分配伪指令后被作为标号来使用(如果是在DW后取偏移,在DD后取偏移加段地址,在DB后会报错),以下是非提前引用

 

    269  015C  012Fr                     dw offset vw

    270  015E  0131r                     dw vb

    271  0160  012Fr                     dw vw

    272  0162  0000012Fsr             dd  vw

    273  0166  00000131sr             dd  vb

    274  016A  00                          db  vb

**Error** c1.ASM(185) Expecting      scalar type

    275  016B  00                          db  vw

**Error** c1.ASM(186) Expecting      scalar type

(十七)、对指令执行速度的一些想法

       一般而言,指令长度越短,速度越快(减少指令预读时间);而用寄存器对寄存器初始化,相对用立即数对寄存器初始化而言,指令长度更短,程序预读取指令也越快;还有指令越复杂,速度也越慢。

       Eg:  XOR BXMOV BX,0更快;后者是用立即数对BX置0,指令长度较长

              OR AX,30HADD AX,30H更快,虽然指令一样长,但是后者是加法运算,更为复杂一些,时间也长一些(将这两个语句放在一个比较大的循环语句中,前者的运行时间是7s,后者的运行时间是21s)。

另外,用移位的方式来实现乘法较用MUL指令实现乘法,速度也会快一些。

你可能感兴趣的:(一个菜鸟作的一点汇编笔记)