汇编语言

hehe

2016-10-19  本文已影响91人  2c3ba901516f

王爽汇编全书知识点大纲


第一章 基础知识

机器语言是机器指令的集合,电子计算机的机器指令是一系列二进制数字.计算机将之转换为一系列高低电平脉冲信号来驱动硬件工作的.

由于机器语言指令都是由01组成,难以编写,记忆和维护程序.所以汇编语言为了解决这一问题产生.汇编语言又称为机器语言的助记符

汇编指令:有对应的机器码.机器码的助记符

伪指令:没有对应的机器码,由编译器执行,计算机并不执行.

其他符号:如+,-,*,/等,由编译器识别,没有对应的机器码

(1). 存储单元的地址(地址信息),地址总线(cpu要从存储器中读取数据,首先要要确认,某个存储单元的地址.)

(2).器件的选择,读或写的命令(控制信息)控制总线(另外计算器中不只有存储器一种器件,其它器件,也有存储器.要确定从什么器件读取.)

(3).读或写的数据(数据信息),数据总线.

总线与信息传送 : 电子计算机能处理,传输的信息都是电信号,电信号当然通过导线传送,也就是总线(数根导线的集合).

读取例子:Mov Ax,[3]

CPU通过地址线将地址信息3发出cpu通过控制总线发出读命令,并选中存储器芯片,并通知他,将要从中取数据,存储器将3号单元中的数据8通过数据线送入cpu

地址总线:8根,表示能寻址0-1023的内存单元.能寻址2^8个内存单元,代表了cpu的寻址范围

假如数据总线有8根,那么每次只能传送1B数据.每次只能传送一个8位数.

假如控制总线位有8根,那么有2^8种控制方式,控制总线的宽度决定了CPU对外部器件的控制能力.

第二章 寄存器

为了和上一代cpu兼容可以拆分16位通用寄存器,拆分为两个8位寄存器.从右向左,以0开始编号.

mov ax,bl //两个寄存器尺寸不一致

mov bh,ax //两个寄存器尺寸大小不一致

mov al 20000 //20000在al中不能存储

add al 100H //100h超过al中存储的最大范围


Mov ax,2

ADD AX,AX

ADD AX,AX

ADD AX,AX

段寄存器中的地址*16+16位偏移地址

jmp 1000:0 则 CS=1000H,IP=0000H //这条指令只在debug中有效

仅修改 IP 的内容

jmp 某一合法寄存器 //在源代码中也有效

注:e命令写进去的机器码数值16进制形式,所以数字不能超过两位十六位数字,eg:111这是错误的(因为debug中默认是16进制数制).

eg:g 0012(表示从当前cs:ip指向的指令执行,一直到(ip) = 0012为止.) 用 t(trace) 命令单步执行 用 p (proceed)命令跳跃循环


mov ax,bx

sub ax,ax

jmp ax

答:一共4次,第一次:读取完mov ax,bx后.第二次:读取完sub ax,bx后.第三次:读取完jmp ax后.第四次:执行完jmp ax后.

第三章 寄存器内存访问

调试的时候,[idata]才会被翻译成内存单元.源代码中需要使用[bx/si/di..]等

表示内存单元.也可以使用段前缀, 段寄存器 : [idata]


mov 寄存器,数据

mov 寄存器,寄存器

mov 寄存器,内存单元

mov 内存单元,寄存器

mov 段寄存器,寄存器

mov 寄存器,段寄存器 //这个是自己实验添加的

mov 段寄存器,内存单元//这个是自己实验添加的

mov 内存单元,段寄存器//这个是自己实验添加的

注意事项:

  1. 从这几种格式可以看出,操作数不能同时为段寄存器
  1. 也不能同时为内存操作数.
  1. 不能将立即数直接送入段寄存器.
  1. 立即数只能放在右边,如果此时左边操作数为内存单元,需要指明内存单元尺寸
  1. 操作数不能出现ip寄存器

add 寄存器,数据

add 寄存器,寄存器

add 寄存器,内存单元

add 内存单元,寄存器

add byte/word/... ptr 内存单元,数据

注意事项:

  1. add指令中不能出现段寄存器操作数
  1. add中操作数不能同时为内存单元
  1. 第一个操作数必须是寄存器或者内存单元
  1. add指令中也不能出现ip寄存器

操作数不能是ip寄存器,栈每次操作一个字

如果将10000H~1FFFFH这段空间当做栈段,初始状态是空的,此时ss=1000h,sp=?

答:sp=0,因为此时会发生栈环绕问题,FFFF的底端无法寻址,所以就会循环跑到另一头0上面去.,此时压栈会发生,sp=0-2=0FFFEH

编程:将10000h~1000Fh这段空间当做栈,初始状态是空的,设置ax=001ah,bx=001bh,将ax,bx入栈,然后将ax,bx清零,从栈中恢复ax,bx的值.

解答:


mov ax,1000h

mov ss,ax

mov sp,10h

mov ax,001ah

mov bx,001bh

push ax

push bx

sub ax,ax

sub bx,bx

pop bx

pop ax

利用栈交换ax,bx内容


push ax

push bx

pop ax

pop bx

....

第4章 第一个程序


assume cs:code

code segment

mov ax,0123h

mov bx,0456h

add ax,bx

add ax,ax

mov ax, 4c00h

int 21h

code ends

end

程序就会运行不正常.

第五章 [bx]和loop


assume cs:code

code segment

mov ax,2

mov cx,11

s:

add ax,ax

loop s

mov ax, 4c00h

int 21h

code ends

end

例子2:计算123*236


assume cs:code

code segment

mov ax,0

mov cx,123

s:

add ax,236

loop s

mov ax, 4c00h

int 21h

code ends

end


assume cs:code

code segment

mov ax,0ffffh

mov ds,ax

mov bx,0

mov dx,0

mov cx,12

mov ah,0

s:

mov al,[bx]

add dx,ax

inc bx

loop s

mov ax, 4c00h

int 21h

code ends


assume cs:code

code segment

mov ax,0ffffh

mov ds,ax

mov ax,0020h

mov es,ax

mov bx,0

mov cx,6

s:

mov ax,[bx]

mov es:[bx],ax

add bx,2

loop s

mov ax, 4c00h

int 21h

code ends

end


assume cs:code

code segment

mov ax,0020h

mov ds,ax

mov bx,0

mov cx,64

s:

mov [bx],bl

inc bx

loop s

mov ax, 4c00h

int 21h

code ends

end

第六章 包含多个段的程序


assume cs:code

code segment

start:

程序代码

mov ax, 4c00h

int 21h

code ends

end start

end代表程序源代码结束,并指明可执行代码入口地址.

如果指明入口地址,那么从程序的首地址开始执行,不管起始地址处是否是可执行代码.


assume cs:code

code segment

dw 0123h, 0456h, 0789h, 0abch, 0defh, 0fedh, 0cbah, 0987h

dw 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0,0,0

start:

mov ax,cs

mov ss,ax

mov sp,30h

mov bx,0

mov cx,8

s:

push cs:[bx]

add bx,2

loop s

mov bx,0

mov cx,8

s1:

pop cs:[bx]

add bx,2

loop s1

mov ax, 4c00h

int 21h

code ends

end  start

然后弹出来给变量2

解析:

N分为被16整除和不被16整除。

当N被16整除时: 占有的空间为(N/16)_16

当N不被16整除时: 占有的空间为(N/16+1)_16,N/16得出的是可以整除的部分,还有一个余数,余数肯定小于16,加上一个16。

程序加载后分配空间是以16个字节为单位的,也就是说如果不足16个字节的也分配16个字节。

两种情况总结成一个通用的公式:((N+15)/16)_16


assume cs:code

a segment

db 1, 2, 3, 4, 5, 6, 7, 8

a ends

b segment

db 1, 2, 3, 4, 5, 6, 7, 8

b ends

c segment

db 0, 0, 0, 0, 0, 0, 0, 0

c ends

code segment

start:  mov ax, a

mov ds, ax

mov ax, b

mov es,ax

mov ax, c

mov ss,ax

mov ax,0

mov bx,0

mov cx,8

s: mov al,ds:[bx]

add al,es:[bx]

mov ss:[bx],al

inc bx

loop s

mov ax, 4c00h

int 21h

code ends

end start

第7章 更灵活的定位内存的方法

mov al, 'a' <=> mov al,97


assume cs:code, ds:data

data segment

db 'BaSic'

db 'iNfOrMaTiOn'

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov cx,5

s0:

mov al,[bx]

and al,11011111b

mov [bx],al

inc bx

loop s0

mov cx,11

mov bx,5

s1:

mov al,[bx]

or al,00100000b

mov [bx], al

inc bx

loop s1

mov ax, 4c00h

int 21h

code ends

end  start


assume cs:code, ds:data

data segment

db 'BaSic'

db 'MinIX'

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov cx,5

s0:

mov al,[bx]

and al,11011111b

mov [bx],al

mov al,[bx+5]

or al,00100000b

mov [bx+5],al

inc bx

loop s0

mov ax, 4c00h

int 21h

code ends

end  start


assume cs:code, ds:data

data segment

db '1\. file        '

db '2\. edit        '

db '3\. search      '

db '4\. view        '

db '5\. options      '

db '6\. help        '

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov cx, 6

s0:

mov al,[bx+3]

and al,11011111b

mov [bx+3],al

add bx,16

loop s0

mov ax, 4c00h

int 21h

code ends

end  start


assume cs:codesg, ds:datasg

datasg segment

db 'ibm            '

db 'dec            '

db 'dos            '

db 'vax            '

datasg segment

codesg segment

start:mov ax,datasg

mov ds,ax

mov bx,0

mov cx,4

mov ax,0

s0: mov dx,cx

mov si,0

mov cx,3

s1:mov al,[bx+si]

and al,11011111b

mov [bx+si], al

inc si

loop s1

add bx,16

mov cx,dx

loop s0

codesg ends

end start

这里注意保存外层循环的cx值.可以用其它寄存器保存,也可以保存在内存单元中,也可以保存在栈中


assume cs:codesg, ds:datasg

datasg segment

db '1\. display      '

db '2\. brows        '

db '3\. replace      '

db '4\. modify      '

datasg segment

codesg segment

start:

mov ax, datasg

mov ds,ax

mov bx,0

mov cx,4

s1:

push cx

mov cx,4

mov si,0

s2:

mov al,[bx+si+3]

and al,11011111b

mov [bx+si+3],al

inc si

loop s2

add bx, 16

pop cx

loop s1

mov ax, 4c00h

int 21h

codesg ends

end start

注意:si需要在循环中每次重置为0

第八章 数据处理的两个基本问题

公司名称:DEC

总裁姓名:Ken Olsen

排名:137

收入: 40(40亿美元)

著名产品:PDP(小型机)


mov ax,seg

mov ds,ax

mov bx,60h

mov word ptr [bx+0ch],38

mov word ptr [bx+0eh],70

mov byte ptr [bx+10h],'V'

inc bx

mov byte ptr [bx+10h],'A'

inc bx

mov byte ptr [bx+10h],'X'

div reg

div 内存单元 //必须指明内存单元尺寸

因为100001大于65536,化成16进制为186A1


mov dx,1

mov ax,86A1h

mov bx,100

div bx


mov ax,1001

mov bl,100

div bl


assume cs:code, ds:data

data segment

dd 100001

dw 100

dw 0

data ends

code segment

start:

mov ax, data

mov ds,ax

mov bx,0

mov ax,[bx]

mov dx,[bx+2]

div word ptr [bx+4]

mov [bx+6],ax

mov ax, 4c00h

int 21h

code ends

end  start

eg:db 3 dup (0,1,2) 一共占用3*3=9个字节


assume cs:code,ds:data,es:table

data segment

db '1975','1976','1977','1978','1979','1980','1981','1982','1983'

db '1984','1985','1986','1987','1988','1989','1990','1991','1992'

db '1993','1994','1995'

dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514

dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000

dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226

dw 11452,14430,15257,17800

data ends

table segment

db 21 dup ('year summ ne ?? ')

table ends

code segment

start:

mov ax,data

mov ds,ax

mov ax,table

mov es,ax

mov bx,0

mov si,0

mov di,0

mov cx,21

s1:

mov ax,[bx]

mov es:[di],ax

mov ax,[bx+2]

mov es:[di+2],ax

mov byte ptr [di+4],' '

mov ax,84[bx]

mov es:[di+5],ax

mov ax,84[bx+2]

mov es:[di+7],ax

mov byte ptr [di+9],' '

mov ax,168[si]

mov es:[di+10],ax

mov byte ptr [di+12],' '

mov dx,86[bx]

mov ax,84[bx]

div word ptr 168[si]

mov es:[di+13],ax

mov es:[di+15],' '

add bx,4

add si,2

add di,16

loop s1

mov ax, 4c00h

int 21h

code ends

end start

第九章 转移指令的原理

(1).只修改ip:段内转移

(2).同时修改Cs和IP时,称为段间转移.

(1)无条件转移指令(如:jmp)

(2)条件转移指令

(3)循环指令

(4)过程

(5)中断

位移计算:要跳转的标号的偏移地址 减掉 跳转指令的下一条指令的偏移地址,位移在编译时由汇编器算出.


assume cs:code

code segment

start:

mov ax,2000h

mov ds,ax

mov bx,0

s:

mov cx, 0

mov cl,[bx]

jcxz ok

inc bx

jmp short s

ok:

mov dx, bx

mov ax, 4c00h

int 21h

code ends

end  start


assume cs:code

code segment

start:  mov ax,2000h

mov ds,ax

mov bx,0

s:mov cl,[bx]

mov ch,0

inc cx

inc bx

loop s

ok:dec bx

mov dx,bx

mov ax,4c00h

int 21h

code ends

end start

inc cx是防止当cx为0时,loop指令会首先cx=cx-1会变成0ffffh,就会循环ffff次.


assume cs:codesg

codesg segment

mov ax,4c00h

int 21h

start: mov ax,0            ax=0

s: nop                占一字节,机器码90

nop                占一字节,机器码90

mov di,offset s    (di)=s偏移地址

mov si,offset s2    (si)=s2偏移地址

mov ax,cs:[si]      (ax)=jmp short s1指令对应的机器码EBF6

mov cs:[di],ax      jmp short s1覆盖s处指令2条nop指令

s0: jmp short s        执行到这里,不会再继续向下执行,直接跳回mov ax,4c00h了

s1: mov ax,0

int 21h

mov ax,0

s2: jmp short s1

nop

codesg ends

end start

因为jmp short s1<=>EB 位移.位移等于S1标号偏移地址减去nop指令的偏移地址大约为-10.当跳转到s处执行jmp short s1,实际上是执行EB -10.会向前跳转10个字节,也就是说会执行程序返回的代码.


assume cs:code, ds:data

data segment

db 'welcome to masm!'

data ends

code segment

start:

mov ax, data

mov ds, ax

mov bx,0

mov ax,0b800h

mov es, ax

mov di,11*160+72

mov cx,16

s:

mov al,[bx]

mov es:[di], al

mov byte ptr es:[di+1],00000010b

mov es:160[di],al

mov byte ptr es:161[di],00100100b

mov es:320[di],al

mov byte ptr es:321[di],01110001b

add di,2

inc bx

loop s

mov ax, 4c00h

int 21h

code ends

end  start

第十章 call和ret指令

(cs)=((ss)_16+(sp)),(sp)=(sp)+2

(sp)=(sp) - 2

((ss)*16+(sp)) = (ip)

(ip)=(ip)+16位位移

有等同于 push ip,jmp near ptr 标号

push cs,push ip, jmp far ptr 标号

push ip, jmp reg

push ip, jmp word ptr 内存单元地址

push cs, push ip,jmp dword ptr 内存单元地址


assume cs:code

code segment

main:

call sub1

:

:

call sub2

:

:

mov ax, 4c00h

int 21h

sub1:

:

:

sub2:

:

code ends

所以c语言中的函数名其实就是一个标识子程序的地址


mov al,100

mov bl,10

mul bl

计算 100 * 10000,必须用16位乘法


mov ax,100

mov bx,10000

mul bx


cube:

mov ax,bx

mul bx

mul bx

ret


capital:

and byte ptr [si], 11011111b

inc si

loop capital

ret


capital:mov cl, [si]

mov ch,0

jcxz ok

and byte ptr [si],11011111b

inc si

jmp short capital

ok : ret

如果调用该子程序中的代码中使用了cx寄存器,将产生错误.解决办法是在该子程序开头压栈保存需要使用的寄存器,在返回前弹出该寄存器的值.改正如下


capital:push cx

push si

change:

mov cl, [si]

mov ch,0

jcxz ok

and byte ptr [si],11011111b

inc si

jmp short change

ok :pop si

pop cx

ret


子程序标号:

子程序中使用的寄存器入栈保存

子程序指令标号:

....

子程序返回标号:

子程序中保存的寄存器出栈恢复

子程序返回(ret,retf)


show_str:

push ax

push bx

push cx

push dx

push es

push si

push di

begn:

mov ax,0b800h

mov es,ax

mov al,160

mul dh

mov bx,ax

mov al,2

mul dl

add bx,ax

mov di,bx

mov al,cl

mov ch,0

s:

mov cl,[si]

jcxz retn

mov es:[di],cl

mov es:[di+1],al

inc si

add di,2

jmp short s

retn:

pop di

pop si

pop es

pop dx

pop cx

pop bx

pop ax

ret


divdw:

push ax

push bx

push cx

push dx

begn:

mov bx,ax

mov ax,dx

mov dx,0

div cx

push ax

mov ax,bx

div cx

mov cx,dx

pop dx

retn:

pop dx

pop cx

pop bx

pop ax

ret


dtoc:

push ax

push bx

push cx

push dx

push ds

push si

push 0

begn:

mov dx,0

mov bx,10

div bx

mov cx,ax

jcxz sw1

add dx,30h

push dx

jmp short begn

sw1:add dx,30h

push dx

sw2:

pop cx

jcxz retn

mov [si],cl

inc si

jmp short sw2

retn:

mov [si+1],0

pop si

pop ds

pop dx

pop cx

pop bx

pop ax

ret

上一篇 下一篇

猜你喜欢

热点阅读