鱼C论坛

 找回密码
 立即注册
查看: 2438|回复: 0

[学习笔记] 1~11章的一些笔记

[复制链接]
发表于 2018-6-14 01:05:27 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
最近学习了小甲鱼老师的汇编教程,感觉受益良多,在此把自己的笔记发一发,希望大佬们给点意见,新手们能一起交流。
汇编笔记1(基础知识)
第一章 基础:

寄存器:cup里的存储器,存放指令和数据。

存储器:存放指令和数据。硬盘和内存都是存储器。

存储单元(从0开始)

总线:

     地址总线:寻址能力,(64位与32位区别)n根地址(一根1个字节=1个内存单元)

     控制总线:cpu对外界器件的控制

     数据总线:决定cpu和外界数据传送速度

主板:核心器件

接口:cpu不直接控制外部器件,通过接口卡控制

存储器:

      随机存储器(ram):

      只读储存器(rom):每种硬件有自己的rom

另:1.不同cpu有不同指令集

       2.不同总线来区别二进制数据是什么

       3.cpu看到的是逻辑存储器

检测点暴露的问题:

    1.B:字节=8b:位

     2.一根地址总线对应1B的寻址能力,一根数据总线对应1bit的数据
第二章 寄存器:(8086cpu)

cpu:内部总线连接

   运算器:一次最多处理16位

   控制器:

   寄存器: 最大宽度16位(数据最大值2的16次方-1)

通用寄存器:4个寄存器(AX,BX,CX,DX)可以分为两个独立的8位寄存器。

       高位:H,低位:L

字(word)=2个字节(16位兼容两个8位)

例:mov  ax,bx      把bx移进ax(支持寄存器,段寄存器,数据,内存到寄存器,寄存器到段寄存器,寄存器到内存)(数据到寄存器sp等)

      add   ax,bx      把bx加进ax

物理地址:内存单元的唯一地址

8086内部16位与外部20位冲突解决方法:内部用两个16位合成一个20位(段地址+偏移地址)物理地址=段地址*16(二进制左移4位,16进制左移1位)+偏移地址

段:段的划分来自cpu,内存并没有分段,看需要自己看成不同段

段寄存器(不要忘记*16):

     CS(代码段地址):CS*16+IP(代码偏移地址)    ip=ip+读取的指令长度

修改CS:ip方法:jmp   段地址:偏移地址        jmp ax是令ip=ax

cs+ip决定执行与否,指向则执行,不指向则不执行。

     DS(数据段地址):当前操作的数据可以[偏移地址]的方式引用

     SS(栈寄存器):SS:sp指向栈顶元素(压入sp-,推出sp+)(先动数据)

sp指向栈的最高地址上一位。(格式化只是移指针)(栈空时指到栈外(+2))

     ES:(备用段寄存器)

另:1.汇编指令不区分大小写

        2.从后向前运算

        3.超出位进到其他寄存器(分高低位时高低位之间也无法直接进位:add al,88)

        4.cpu访问内存必须要物理地址

        5.段地址和偏移地址可以指示2的16次方个内存单元

检测点暴露的问题:

       1.不加H表示10进制,需要先转换为16进制;

       2.注意区分mov 和add;

       3.sub ax,bx    把ax减去bx;

dosbox的一些操作: (加不加空格都行)

       1.r  查看、改变cpu寄存器内容   r 寄存器(改变寄存器的值为指定值)

        2.d 查看内存中的内容   d 段地址:偏移地址   n-1(查看该地址开始的n(默认128)个内存单元)

        3.e  改写内存中的内容   e 起始地址 数据 数据。。。

        4.u  将机器指令翻译为汇编指令

        5.t  执行一条机器指令

        6.a  以汇编格式写入机器指令(执行汇编)   a 起始地址(从起始地址开始写入)

        7.p 执行到当前行,有循环则全部执行

        8.q退出dubug

        9.g 执行到某地址;like 断点
第三章 寄存器(内存):

字的存储:分进高字节中(低字节中存不下的存进高字节)

栈:后入先出

push ax:把ax元素压进栈中 push [0]把0的数据压入栈

pop ax:把栈顶推到ax中       pop [0]把数据推到0

push和pop指令可以修改寄存器和内存

栈顶越界问题:向上越界和向下越界

另:1.mov指令访问内存时可以只给出偏移地址(默认ds)

       2.可以用段寄存器表示段地址

       3.debug的t命令在执行修改SS的指令时,下一条指令也紧接着被执行

检测点暴露的问题:

      1.movadd操作的数据量和使用的寄存器有关,相应大小的寄存器调动相应的数据。

      2.e  d a命令都是操作内存的,r是直接操作寄存器的。

      3.使用栈时先设定SS:sp(最高位)
汇编笔记2(编程)
第4章(第一个程序):

用到的工具:MASM.exe  LINK.exe

伪指令:编译器处理

例:

    assume cs:codesg(定义一个代码段名称)

    codesg segment(代码段)

    start: 汇编语句

    codesg ends(配合结束)

    end

assum假设关联

start :入口(可以自己命名)

编译->可执行文件(pe)

int  中断

结束:

    程序返回:mov ax,4c00        int  21

    段结束:ends

    程序结束:end

加分号可以不用设置过程

编译:masm 文件名(加分号可跳过中间过程)

连接:link 文件名(obj文件,加分号可跳过中间过程)

简单方法:ml 文件名(编译并连接)(要有ml.exe)

psp:存放dos和程序交互命令100H,ds偏移psp后是cs:ip

另:1.dos是单任务操作系统

        2.dos修改了CS:IP使程序运行

      3.debug装入内存会在cx中存储长度

实际操作遇到的问题:

    1.non-digit in number:应当在十六进制数后加H

    2.debug默认十六进制。
第5章([bx]和loop循环):

[bx]指令:主要因为在文本编辑和debug中不一样,文本编辑中[常数]相当于常数,所以要先存到bx才表示偏移地址。

():描述符号,表示括号内的内容

idata:描述符号,表示一个常量

loop和cx:loop循环直到cx减为0(通常)

loop语句用法:跳转到s标签循环.(在之前设置s标签(s:代码))

编程考虑过程:是否安全(存放位置)->是否能存下结果->初始化(ds,cx,ss等)->调用循环->结束

段前缀:显式给出段地址(cs: ds: ss:)(ds寄存器的作用可以用es:[ ]替代)

安全空间(底层而不冲突的空间):0:200~0:2ff

另:1.执行循环最好把mov cx ,idata放在要循环的部分前

        2.汇编源程序中数据不能以字母开头,在前面加0

        3.不同段可以再用一个段寄存器

编程中的问题:

        1.loop语句在要循环的语句之后

        2.源程序中地址表示形如ds:[idata]

        3.注释采用';'
第6章(多个段的程序):

解决的问题:既要有代码又有数据

1.不使用多个段:

例:

assume cs:code

code segment

          dw 123ah,34d3H

start:mov ax,cs;设定栈

        mov ss,ax

        mov sp,0004;偏移地址为dw之和(因为数据从0开始所以直接相当于dw长度和)


        mov bx,0

        mov ax,4c00h

        int 21h

code ends

end start

db :定义字节型数据(8)--->dw:定义字型数据(16)--->dd:定义双字结构(32)

        既可以用来设置内存值,又可以用来分配内存。

直接放在代码段,段地址CS,偏移地址在最开始为0

设定start(见前面)入口使cpu区分数据和代码。--->end可以通知入口是谁

2.使用多个段:

assume cs:code,ds:data,ss:stack

data segment

          dw 1234h,2334h

data ends

stack segment

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

stack ends

code segment

start: mov ax,stack;stack,data,code都是存有段地址的常量

        mov ss,ax

        mov sp,10h;stack段的dw之和

        mov ax,4c00h

        int 21h

code ends

end start

另:

        1.不同段段地址相差至少1

实验暴露的问题:

        1.段地址是10倍

        2.loop后面要跟段标签

        3.不能直接把段标签拿来用,要放到段寄存器里才能用

汇编笔记3(数据)
第7章(更灵活定位内存):

and ah,10011010B    与运算(一0则0)可以把操作位设为0(11111101把第7位设为0)

or ah,10010010B        或运算(一1则1)可以把操作位设为1(00000010把第7位设为0)

'......'的方式表示ASCII码给出

db '1234'   = db 31h,32h,33h,34h

[bx+idata]访问偏移地址   其他写法[idata+bx],idata[bx],[bx].idata,[bx][si],[si][bx](注意常数在后有.)

[bx+idata]方便数组访问,idata确定元素开头,dx作为相对地址变化。例:

[0+bx]    'abcde'                 0[bx]

[5+bx]    'fghij'                     5[bx]

si和di,作为bx的补充,性质相同

[bx+si+idata]类似[bx+idata]

需要暂存数据都采用栈的方法(ss栈段)

另:1.字母大小写相差20h

       2.利用and or 和第5位来决定大小写

      3.采用0[]  8[]这种形式可以只使用一个偏移寄存器提高效率

基础复习:

     1.一个内存单元8bit,表示为两位16进制数,一个字节8bit。

      2.不能直接把内存mov到内存

实际操作暴露的问题:

        1.能操作数值的就是几个寄存器,没有变量

         2.采用的寄存器不同(ax,al)一次读取的内存不同,地址所需偏移不同。

         3.tap和空格产生同样对齐效果但占用内存不同

         4.要双层循环应当先把cx临时存在其他地方(尽量不要在寄存器,栈),内层循环后再带回
第8章(数据处理):

reg表示寄存器,sreg表示段寄存器

[bx]寻址形式的只有bx,bp,si,di可用(8086),bx与bp,si与di不共存

bp默认段地址为ss,bx默认段地址ds。。。可以显式指定

数据位置:1.idata立即数 2.寄存器 3.内存

指明数据长度方法:

     1.根据转移的寄存器确定

     2.X ptr 例:inc word ptr [bx]

    3.命令默认:push字

数据操作过程:确定位置,确定类型(长度),修改

汇编上的结构体:bx定位整个结构体,idata定位某一数据项,si定位数组项元素

div:除法 被除数位数16(32),除数位数8(16)(div reg或者div 内存单元)

被除数为ax     除数为8位(决定类型),al存商,ah存余

被除数为 dx放高16位,ax放低16位      除数为16位(决定类型),ax存商,dx存余

dup:类型 重复次数 dup(重复内容)例:db 3 dup(1,2)===>db 1,2,1,2,1,2

实际操作的问题:

         1.div后面不能直接接除数,要存在寄存器中(除数位数由此决定)使用。

        2.一个偏移地址只决定一个内存单元

        3.出现结果不写入时,先检查分配内存是否包含

汇编笔记4(跳转)
第9章(转移指令):

8086转移指令:

无条件转移指令,条件转移指令,循环指令,过程,中断

offset(伪指令):取得标号偏移地址(也就是要配合标号使用))取得值相当于一个常数(不能直接给段寄存器)

jmp(无条件跳转):可以修改ip也可以修改cs和ip

       (基于偏移) jmp short 标号:修改ip机器指令不包含目的地址,包含偏移地址

                short 8位的转移(-128~127),near ptr 16位的转移(-32769~32767)

       (基于目的地址)jmp far ptr 标号

        (基于寄存器)jmp  16位寄存器(存有转移目的地址)

         (基于内存)jmp word ptr 内存单元地址(存有转移目的地址)

                 word段内转移 ,dword段间转移

jcxz(有条件跳转指令)(都是短转移(基于偏移(-127~128)))

         jcxz 标号(若cx=0则转移到标号处)

loop(短转移)循环cx次 loop会先对cx-1再判断cx与0的关系(基于偏移(-127~128))

短跳转越界会报错。

实际操作暴露的问题:

        1.32位方式cs在后,ip在前

         2.不同数据段偏移地址互不影响

        3.数据不能直接赋给内存

        4.实验8原理,标号代表的是偏移地址,在执行之前得到并转化,所以向上跳。

实验9(彩色打印):

B8000H~BFFFFH为显示缓冲区,分8页,默认显示第一页(B8000H~B8F9FH)

        一行共160个字节,两个字节表示一个字符(偶地址放ascii,奇地址放属性各1字节)(从0到159)

        属性:       |  7          |  6  |  5  |  4  |       3       |  2  |  1  |  0  |

                          BL              R    G     B         I          R     G   B

                        闪烁            背景                 高亮        前景

编程暴露的问题:1.ss,cs值不能直接改变,不能有像mov ss,ax这种

                  2.初始化应在入栈,循环(标号)前

                  3.注意一个字占两个内存单元,add bx,2而不是inc bx
第10章(call和ret):

ret指令:用栈中命令修改ip(出栈)(ip先正常加再被覆盖)

retf指令:依次出栈ip和cs

call指令:将当前ip(call指令下一个指令开始地址)或cs和ip入栈,转移(非短转移)

        基于标号: (段内)call 标号:ip入栈后到标号处执行

                            (段间)call far ptr 标号 :cs入栈,ip入栈后到标号处执行

         基于寄存器:(段内)      call 16位寄存器

        基于内存:(段内)call word ptr 内存单元地址(ip入栈后执行内存单元中的地址)

                           (段间)call dword ptr 内存单元地址(存放顺序cs ip)(csip入栈后执行内存单元中的地址)

call+ret实现子程序:call和ret配对

         call到mov ax,4c00h int 21h后,再用ret返回回来就可以实现子程序调用

             子程序参数和结果需要寄存器较少时存放在寄存器中(参数寄存器,结果寄存器)

                      参数和结果较多时将批量数据存在内存中或栈中,首地址放在寄存器中

发生寄存器冲突(不同操作依赖同一寄存器)使用栈push pop来避免冲突

mul:乘法命令(mul 寄存器;mul byte ptr 内存地址;mul word存在 ptr 内存地址)

                        8位*8位(结果放入ax)默认al*

                       16位*16位(结果放入dx+ax)默认ax*

实验代码不难,鱼c论坛上都有(判断0用cx+jcxz的方法)

检测点暴露的问题:1.sp和bp默认段寄存器都是ss

                            2.0B8000h部分是显卡地址是动态变化的,debug跟踪会有问题

                           3.子程序设计时开始入栈,ret出栈以提高通用性

汇编笔记5(标志与中断)

第11章(标志寄存器):

标志寄存器都是16位                                                

flag:按位起作用(其他寄存器是整个起作用)

1,3,5,12,13,14,15为保留位,不具有意义                                                   debug中的对应

零位标志位ZF:(6)上一次指令执行后结果为0则为1                                            (0)NZ (1) ZR

奇偶标志位PF:(2)二进制1的个数为偶数为1,为奇数为0                                   PO     PE

符号标志位SF:(7)结果为负为1,为正为0(对于有符号数)                              PL      NG

进位标志位CF:(0)无符号运算时记录进位和借位(都为1)                                  NC      CY

溢出标志位OF(11)有符号数运算时的进位和错位(只要最高位改变)                NV   

方向标志位DF(10)控制每次操作后si,di的递增递减

CF的运用:置0方法:sub ax,ax

      inc,loop不影响CF                 add会影响,所以使用inc改变数值而不是add

adc:adc ax,bx==>(ax)=(ax)+(bx)+CF(先算低位后高位)

带进位的加法指令:利用CF位,把上一次的进位加到本次,adc也会影响CF,可以达到任意位相加

sbb:sbb ax,bx==>(ax)-(bx)-CF(先算高位后低位)

cmp:功能相当于减法,但不保存值,只作为判断依据(操作寄存器不变化,只影响flag寄存器中标志)

              考虑结果正负需要考虑SF和OF

              检测比较结果的条件转移

          1.无符号考虑ZF,CF    有符号考虑SF,OF,ZF

(以下指令都是无符号,且都是根据flag寄存器判断,也就是不配合cmp也可以用)

je:等于则转移        ZF

jne:不等于则转移   

jb:低于则转移     CF

jnb:不低于则转移

ja:高于则转移        CF和ZF

jna:不高于则转移

DF的运用:

串传宗指令:movsb(以字节为单位传送)movsw(以字为单位)

将ds:si中的字节送入es:di中并对1si,di递增(DF=0)或递减(DF=1)

配合rep(根据cx值执行多次串传送指令)使用

DF设置指令:cld(设为0),std(设为1)

pushf:将标志寄存器结果入栈

popf:将出栈结果传入标志寄存器

另:1.mov,push,pop等传送指令不改变标志位

问题总结:1.10H这种代表十进制,对应1的个数为16

实际操作的问题:

        1.call调用子程序用结束程序隔开,je等跳转用jmp隔开

       2.cmp也要注意操作对象位数相同

       3.注意混合使用跳转命令提高效率

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-20 02:07

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表