汇编过程
汇编语言从源程序到可执行程序需要经历的过程有编译、连接。编译是通过编译器将源文件转化为程序(目标文件.obj格式),连接是将目标文件转化为可执行文件(.exe格式)。
这里解释一下源文件和程序的以及可执行文件的区别:
源文件中除了汇编指令外,还包含着很多伪指令,这些伪指令是为了让编译器对汇编指令的处理,起到一个辅助的作用,所以当汇编器对源代码编译之后,所剩下的最终由计算机指令、处理的指令或数据才是程序。而可执行文件则是要对程序进行再一次包装,使其包含更多的信息,以便能够使得CPU能将其写入内存中执行。
第一个汇编程序
通过一个例子来了解汇编程序
assume cs: codeseg ;将通过assume将cs与定义的codeseg关联
codeseg segment ;表示代码段开始
mov ax, 0123H
mov bx, 1026H
add ax, bx
mov ax, 4c00H
int 21H;产生中断,这一句和上面一句必须要有
codeseg ends;段结束标志
end;整个结束标志
其中codeseg成为标号,xxx segment … xxx ends、end以及assume都是伪指令。
mov ax, 4c00H
int 21H
这两条指令所实现的功能是程序返回,将控制器重新交给shell。
新的指令
**[]**里面可以是寄存器,也可以是立即数,表示偏移地址,段地址默认在ds中。
inc ax是将ax里的内容+1。
loop指令:当执行loop的时候,首先它要自动的将cx的内容-1,然后判断cx中的值是否为0,不为0的话,就跳转到标号处执行。即cx中是存放loop循环的次数。
assume cs:codeseg
codeseg segment
mov ax, 2
mov cx, 11
s: add ax, ax
loop s
mov ax, 4c00h
int 21h
codeseg ends
end
这样就实现了将ax累加11次。其中s就是一个标号,codeseg也是一个标号。
mov al, ds:[bx]
表示将地址ds:[bx]中的内容放到al中。
另外mov al, ds:[0]和mov al, [0]不同的编译器对其解释不同,masm是将[0]看作一个常数,而Debug是将其看作一个内存单元,所以以后要给定地址的时候,统一前面的格式mov al, ds:[0]
来个例子,将地址ffff:0-ffff:b中的数据累加,ffff:0:ffff:b也可以写成ffff0-ffffb,0-b是12个数字,所以要循环12次。
assume cs:code
code segment
mov ax, ffffh
mov ds, ax ;将ffff作为段地址
mov bx, 0 ;初始化bx,将其作为每次偏移地址,每次循环累加
mov cx, 12;设置循环次数
mov dx, 0 ;初始化累加寄存器
s:
mov al, ds:[bx]
mov ah, 0 ;设置偏移地址
add dx, ax;ax每次的都往dx里累加
inc bx
loop s
code ends
end
下面两句指令是设置偏移地址的好把戏,感觉需要熟记。
mov al, ds:[bx]
mov ah, 0
这里用al,而不用ax的原因,我觉得是默认将偏移地址当成8位,将bx的高位舍弃,当循环的次数比较多时,是可以用ax的。
mov al, ds:[bx] 中的ds成为段前缀
mov ds:[0], ax是将al放到ds:0是位置上。
jmp cs:ip
jmp:ip
如
jmp:125ah:1表示修改cs为125ah,ip为1
jmp 25表示修改ip为25。
实验
向内存0: 200-0: 23F中依次传送数据0-63(3FH)
assume cs:code
code segment
mov ax, 20h
mov ds, ax
mov bx, 0
mov cx, 3fh
s:
mov ds:[bx], bx
inc bx
jmp s
mov ax, 4c00h
int 21h
code ends
end
可以将地址0:200-0:23F转化为20:0-20:3F,这样数据和偏移地址就可以共用一个寄存器。