时隔很多年,重新学一遍汇编。觉得这个大灰狼学汇编的视频很好。
仔细的听,仔细的做了笔记、实验。感觉很不错!
继续加油!!
-----------------1,2,3-----------------------------
段寄存器存放 基地址AX 通用寄存器
CS 存放要被cpu执行的代码的基地址 code segment
IP 别名为指令指针寄存器,存放段地址的偏移地址CS*16+IP 就是cpu要执行的指令 debug是dos、windows都提供的实模式程序调试工具,可以查看cpu各种寄存器中的内容和机器码级跟踪程序的运行r命令用来查看和改变各个寄存器内容,
d命令查看内存中的内容,u命令将内存机器码转为汇编指令,a命令以汇编指令格式在内存写入指令t命令但不跟踪 数据段:全局变量代码段:代码堆栈段:局部变量CPU根据DS(Data Segment)这个寄存器和任意一个通用寄存器的值或其他数值组成数据段的物理地址如:
DS:[0] DS:[BX] (内存寻址) (内存访问)movds:[13ABH],1234H 内存地址的内容进行赋值 内存地址=1234
mov[13ABH],1234H CPU默认指向ds ---------------------4-----------------------------CPU如何知道一段内存空间被当作栈使用?执行入栈出栈时,如何知道哪个单元式栈顶单元?
cpu通过ss这个寄存器和sp通用寄存器来感知堆栈段的存在。ss存放基地址,sp存放栈顶的偏移地址,任何时候ss:sp都指向栈顶元素---------------------5,6-----------------------------
汇编语言中变量如何定义
如何屏幕显示如何进行调试assume关键字
如何让汇编语言“知道”,我们编写的应用程序有多少个段组成。assume表示用来假设某一段寄存器和程序中的某一个用segment...ends定义的段相关联db指令
define bytelabel db initializer,initializer,initializerlabel 表示任选标号,相当于c语言变量名msg db "hello world"vga B800F
字体属性格式7 6 5 4 3 2 1 0BL R G B I R G B闪烁 背景色 高亮 前景色
红底绿字: 01000010Bvga显存地址空间
在80*25列彩色模式下显示器可以显示25行80列每个字符可以有256种属性(背景色前景色闪烁等)一个字符在显存中占两个字节,分别存放ascii码值和属性显示缓冲总共分为8页,每页4kb,显卡可以显示任意页内容一般情况下显示第0页内容即B8000H~B8F9FHes,扩展段寄存器
不能直接给段寄存器赋值,应该先给通用寄存器赋值,然后再传给段寄存器
loop关键字
语法:标号: 指令 指令2 look 标号cx内部规定为loop的循环因子内存访问
helloworld属于数据段内容,那么其中每个字符都可以通过数据段地址存在ds寄存器中,那么要获得数据段第一个字节内容就要如下表示ds:[0] ds:[si]si寄存器相当于通用寄存器代码段地址自动获取 偏移地址不知道
;;;;;;;;;;;;;;;;;;;;;hello.asm;;;;;;;;;;;;;;;;;;;;;;;;;;;;assume cs:code,ds:data
data segment
db "hello world" data endscode segment
start: mov ax,data mov ds,ax mov bx,0b800h mov es,bx mov cx,11 mov si,0 mov bx,0 mov ah,01000010b s:mov al,ds:[si] moves:[bx],ax moves:[bx+1],ah inc si addbx,2 loop s movax,4c00h int21h code endsend start;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-------------------7-----------------------------什么是中断?
任何一个通用CPU,都具有一种能力,可以在执行完成当前正在执行的指令之后,检测到从CPU外部或内部产生的一种特殊信息,并立即对接受的信息进程处理。这种信息称之为中断信息。中断的意思是指,CPU不再接着(刚执行完的指令)向下执行,而是转去处理这个特殊信息。关于中断的疑问
中断发生时CPU如何找到中断处理程序?中断处理程序有很多种,那么每个中断处理程序放在哪里?中断处理程序完成后CPU如何继续运行之前被中断的程序?中断向量表
在内存中保存,其中存放着256个中断源所对应的中断处理程序入口中断向量表一般都保存在内存0000:0000到0000:03FE一个表项存放一个中断向量,也就是一个中断程序入口地址,这个地址包括段地址和偏移地址,每个表占两个字(4个字节),高地址存放段地址,低地址存放偏移地址。
遇到中断时CPU把cs和ip内存入栈暂时保存起来。等中断程序执行结束后通过出栈指令重新获得原来的cs和ip的值(这就是c语言函数调用具体实现)
中断过程这些操作,cpu自动完成div指令
除法指令:div 寄存器除数:有8位和16位两种,在一个寄存器或内存单元中。被除数:默认放在ax或dx中,如果除数为8位,被除数位16位默认放在ax中。如果除数为16位被除数为32位分别放在ax和dx中,dx存放高位,ax存放地位。结果:如果除数位8位,则al存储除法的商,ah存储除法的余数,如果除数是16位,则ax存储商,dx存储余数。修改中断表:
如何让CPU不去执行原来的中断处理程序,而去执行我们自己编写的处理程序?修改中断向量表的入口地址就可以实现。 -------------------8----------------------如何修改中断向量表?系统默认在0000:0000到0000:03FE专门存放中断向量表。并且每个表占用两个字。那么我们就知道0号中断表项所在的内存地址是0000:0000开始的4个字节中。汇编代码就是要对这4个字节赋予我们自己编写的中断处理程序入口地址。汇编伪代码如下: movds:[0],我们自己中断处理程序偏移地址 mov ds:[2],我们自己中断处理程序段地址中断随时都可以产生,那么当中断产生时必须马上执行中断处理程序,那么中断处理程序必须放在内存何处?
要保证任何时候中断处理程序存放位置不能被其他程序覆盖。因此我们必须在内存中找出一段空间是任何程序不适用的。在正常情况下内存地址0000:0200到0000:0300这段内存是没有其他程序使用的。中断处理程序内存分布
当中断被触发时程序将被执行,但是程序最开始是数据定义指令,而不是代码执行指令,如何解决?我们希望一开始执行中断处理程序时马上跳转到显示字符串的汇编代码中执行,这时我们就需要使用汇编指令:jump跳转指令jump分为三种:
段间跳转 jump far标号 把cs和ip寄存器的值变为标号所在的内存地址段内跳转指令 jump near标号 只修改ip寄存器值为标号的偏移地址段内短跳转指令 jump short标号 不修改cs和ip的值,编译器自动计算跳转的位置,不超过256 -------------------9--------------------------如何把一段汇编代码拷贝到指定的内存位置?可以用loop指令语句来实现,但是该语句比较繁琐,不太合适。汇编语言提供rep和movsb指令实现相同的功能。movsb指令:字节传送指令:指令在存储单元之间传送字符串使用movsb指令时ds:si指向了要拷贝字符串的首地址,es:di指向了要拷贝的目的地址。cld指令拷贝数据的方向是从低字节往高字节拷贝,也就是说每拷贝一个字节si和di加1。std指令和cld相反。;;;;;;;;;;;;;;;;;;;;;;;;;;ins.asm;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
assume cs:codecode segment
;第一步:把中断向量表中0号表项内容进行修改,使之指向我们自己编写的中断处理程序的入口地址 start: mov ax,0 mov ds,ax mov word ptr ds:[0],0200h mov word ptr ds:[2],0 ;第三步:把我们刚才编写好的0号中断处理程序拷贝到中断向量表中0号表项所指向的内存地址中 ;0000:0200 mov ax,cs mov ds,ax mov si,offset int0;ds:si 可得拷贝源地址 mov ax,0 mov es,ax mov di,200h;目的地址设置完毕es:di mov cx,offset int0end - offsetint0;计算出程序总共占多少内存 cld rep movsb;自动利用es:di,ds:si,cx ;第四步:利用代码自动引发0号中断处理程序 mov ax,1000h mov bh,1 div bh mov ax,4c00h int 21h ;第二步:编写自己的中断处理程序,实现在屏幕中央显示字符串的功能 int0:jmp short int0start db "i am student" int0start:mov ax,0b800h mov es,ax ;配置显存首地址 ;要把字符串一个个拷贝到显存地址空间中 mov ax,cs mov ds,ax mov si,202h mov di,12*160+36*2 mov cx,12 s:mov al,ds:[si] mov es:[di],al inc si add di,2 loop s mov ax,4c00h int 21h int0end:nop code endsend start;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
-------------------10--------------------------
主要内容开发环境搭建认识引导程序nasm汇编编写第一个启动程序Visual PC2004 用来启动我们编写的启动程序
VMware运行linux,利用nasm汇编器在linux上进行启动程序的编译工作知识预备
理解计算机加电过程BIOS对系统内存的分配认识引导程序的概念使用nasm进行编译制作软盘镜像当我们按下电源按钮后,计算机是如何从无到有将操作系统运行起来的?
按下开机按钮后,将发送电信号给BIOS。BIOS获得电信号后将启动自检查程序,检查周边设备是否通电完毕。检查完毕后自检程序把控制权交还给BIOS,BIOS将读取引导驱动器中的启动程序。在系统加电时,最初的1MB内存是BIOS为我们准备好的,如下:
0x00000~0x003FF 中断向量表0x00400~0x004FF BIOS数据区0x00500~0x07BFF 自由内存区0x07C00~0x07DFF 引导程序加载区 正好512字节ox07E00~0x9FFFF 自由内存区0xA0000~0xBFFFF 显示内存区0xC0000~0xFFFFF 中断处理程序认识引导程序
什么样程序才能称为引导程序?BIOS将所检查启动磁盘的第一个扇区512字节载入内存,放于内存0x0000:0x07c00处。如果第一扇区最后两个字节是55AA,那么它就是一个引导程序。引导程序特点
大小是512字节,不能多也不能少,因为BIOS只读取512B到内存中。它结尾必须是55AA,这是引导扇区标志。它总是放在磁盘第一个扇区上(0磁头0此道1扇区)因为BIOS只读取第一个扇区。NASM汇编
是一个为可移植性与模块化而设计的一个80*86的汇编器。它支持相当多的目标文件格式包括linux和windows引导程序编写
如何使用nasm编写一个引导程序?什么是nasm,它和masm有什么区别?如何在linux下安装nasm?如何用nasm编译自己编写的汇编代码?nasm和masm区别
nasm拥有一个相当简单的内存引用规则,是任何对内存中内容的存取操作必须要在地址上加方括号。但任何地址值的操作不需要。比如mov ax,bar的指令表示把bar的地址赋给ax寄存器,这相当于masm中 mov ax,offset bar。要获得bar变量的值则:mov ax,[bar]。masm movax,es:di nasm mov ax,[es:di]linux 下安装nasm,下载nasm的rpm包,安装 rpm -ivh nasm***.rpm
使用:nasm hello.asm -o hello ,反汇编:ndisasm hello -------------------11-----------------------------BIOS中断程序
系统BIOS为我们提供了众多的中断处理程序给我们调用,其中中断编号为10h的中断处理程序专门实现显示功能。特别注意:编号为10h的中断并不只提供一个程序,而是提供了很多子程序供我们调用。$和$$关键字
在nasm中$表示当前指令的偏移地址在nasm中$$表示指令所在的开始地址因此我们就可以推算出剩余字节数公式剩余字节数=510-($-$$);;;;;;;;;;;;boot.asm;;;;;;;;;;;;;;;;
;我们的启动程序实现很简单的功能,在屏幕中央打印一行字符串即可
org 07c00h ;org指令明确告诉编译器我程序的段地址是7C00h,而不是原来的0000
;int汇编指令 “int 10h”调用bois里的中断程序:显示字符串mov ax,cs
mov es,ax mov bp,msgstr ;es:bp指向的内容就是我们要显示的字符串地址了 mov cx,12 ;显示的字符串长度 mov dh,12 ;显示的行号 mov dl,36 ;显示的列号 movbh,0 ;显示的页数 moval,1 ;显示的是串结构 mov bl,0ch ;显示的字符属性 mov ah,13h ;明确调用13h子程序 msgstr: db "hello my os!" int 10h times 510-($-$$) db 0 ;重复n次每次填充值为0 dw 55aah jmp $ ;不断跳转到当前位置,是个死循环;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;