我们了解模块化编程前先给出一个例子,方便大家快速了解。
SECTION MBR vstart=0x7c00 ; 起始地址编译在0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00 ; 上面这些都没什么用,但是都是必须的
; 就把这些理解为初始化吧
call main
jmp $
eax_plus_1s:
inc eax
ret
ebx_plus_1s:
inc ebx
ret
main:
mov eax, 0
mov ebx, 0
call eax_plus_1s
call eax_plus_1s
call ebx_plus_1s
add eax, ebx
ret
times 510 - ($ - $$) db 0
db 0x55,0xaa
这段代码用到了了我们今天要学的所有知识。
我们用bochs运行一下。
什么?这次几天,你就忘了?
算了,重新发一下命令。
nasm -o a.bin a.S
dd if=a.bin of=hd60M.img bs=512 count=1 conv=notrunc
bochsdbg -f bochsrc
输入c运行等一会后,再输入r命令查看寄存器数据。
得到结果3。
?
这段代码实际上看意思应该就大概知道了。
首先我们讲讲代码段,也就是上面代码中的。
main:
...
格式如下:
代码段名:
代码段
?或者
代码段名称: 代码
代码段中的本质到底是什么呢?
我们可以大胆猜测一下,有如下可能:
我们可以把这个存入ax看一下试试。
SECTION MBR vstart=0x7c00 ; 起始地址编译在0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00 ; 上面这些都没什么用,但是都是必须的
; 就把这些理解为初始化吧
mov ax, main
jmp $
times 510 - ($ - $$) db 0
db 0x55,0xaa
运行试试。
7c18应该就是一个地址,那就和c语言的标签类似。
call指令就是调用代码段,和函数调用差不多。
jmp就和c语言的goto差不多。
里面的
jmp $
就是原地循环,$就是当前指令的地址。
ret指令和return差不多。
call指令语法很简单:
call 标号
功能如下:
??call指令可以实现调用一个子程序,在子程序里使用ret指令结束子程序的执行并返回主程序(类比C语言中的main函数调用cube函数进行理解),主程序继续往下执行。
call指令是一个流程转移指令,就是让程序执行的顺序发生短暂的改变,去执行别处地址上的指令,遇到ret指令后再回到原来的地方继续往下顺序执行,本质和jmp大同小异,区别是在jmp基础上增加了程序回到原来跳转处的功能。
执行的指令如下:
例子?懒得写了
接下来就是jmp指令了!
感觉今天这篇怪水的...
cpu要执行指令之前必须先取指(把指令从内存传输到cpu中),从而必须要给出指令所在内存单元的物理地址,寄存器cs:ip就是这个物理地址所对应的段地址和偏移地址(段地址16+偏移地址=物理地址*),而jmp指令就是用来修改ip或者cs和ip的内容,使cpu执行jmp所指向的那条指令(发生跳转/转移),不会执行原定顺序的下一条指令。所以jmp指令要给出两个信息,如下:
jmp指令要给出两种信息:
备注:在源程序中,不能直接使用“jmp 2000:0100"这样的转移指令来实现段间转移,这种方式在debug模式中使用的汇编指令,在源程序中写,编译器并不识别(编译报错)
懒得写了,截的别人的图。
例子?懒得写了
我们这个都是按照上面图片讲的,例子都没有。
这个指令应该是我们这节课最简单的一个指令了。
inc指令差不多相当于c语言中的++一样,不过没有先后一说。
也就是
inc ax
相当于汇编中的
add ax, 1
这也太tm简单了,我就不再讲了。
? ? ? ? 总结:
? ? ? ? 这节课主要讲的就是汇编模块化编程,还有一个自加指令。
? ? ? ? 还是很简单的。? ? ? ? 最后建议大家还是自己多试试,不要只看:
? ? ? ? 纸上得来终觉浅,绝知此事要躬行。