• 《汇编语言》知识重点总结


    《汇编语言》

    前言

    正式工作之后打算着手做一些逆向方面的研究,听前辈们的建议,必须先把汇编学会,于是我用第一个月把《汇编语言》(第三版-王爽著)看了一遍,但是人的记忆力是有限的,所以打算以博客的形式再回忆一遍,相信通过这种形式,能让自己对知识理解的更加模块化和具体化,也方便自己日后复习,同时也方便了看到这篇博客的同道中人。

    作用

    汇编语言在整个计算机编程语言中的地位可以说是没什么用,很少有人会直接拿汇编语言去写项目,如果这么干的话,不得麻烦死(但是不排除确实有这种需求的时候的做法)。更多时候汇编语言的使用场景是在反编译别人的二进制代码之后,对汇编代码的逻辑还原,并且对于计算机系统整体的理解,我相信没有什么比学习汇编语言更快、更好。

    名词、汇编指令的示例和说明(8086cpu)

    • 寄存器:用于存放cpu的数据信息,共14个,分别是:AX,BX,CX,DX,SI,DI,SP,BP,IP,CS,SS,DS,ES,PSW。

    • 字节、字和双字:1双字(DWROD)=2字(WORD)=4字节(byte)。1字节(byte)=8位(bit),比如,寄存器ax是16位寄存器,在内部可以在分为ah和al,分别代表高8位和低8位。

    • 内存访问:一般利用寄存器ds,es,ss才可以间接访问内存,比如要访问2000:0200位置的数据,并将该位置的数据传送入ax,应该这样:

    mov ax,2000h
    mov ds,ax
    mov si,200h
    mov ax,ds:[si]
    
    • 栈内存:在内存访问中有一类特殊的访问,就是栈内存,在操作栈的时候,最好指定一块用于自己使用的内存区域,以便自定义栈的大小和位置。示例:
    assume cs:code
    stack segment 
        db 128 dup (0) 
    stack ends
    code segment
    start:
        mov ax,stack
        mov ss,ax
        mov sp,128    ;目前栈顶在ss:sp处(即stack:128),也就是上面定义的stack中的128字节
        mov ax,'a'
        push ax    ;将'a'入栈,栈顶在ss:sp处(即stack:126)
        push ax
        pop bx    ;出栈,将数据保存在bx中
        mov ax,4c00h
        int 21h
    code ends
    end start
    
    • 标志位:在内存中占1字节大小,用于运算和程序中的状态等。常用的标志有ZF,PF,SF,CF,OF,DF
    ZF:是否为0
    
    PF:1的个数是否为偶数
    
    SF:是否为负数
    
    有符号整数,只看结果是不是大于7,也就是首位是不是0
    
    CF:是否存在进位或借位(无符号整数)
    
    直接进行无符号运算,首位进位就置1
    
    OF:是否存在溢出(有符号整数)
    
    16位cpu,有符号溢出范围79H(127),-80H(128)
    
    DF:方向标志位,与movsb配合使用
    
    
    • 指令
    数据传送指令:
    mov:数据传送
    示例:mov ax,bx
    说明:将bx中的数据传送到ax中,因为使用的是ax和bx,所以数据的长度是16位,下面的例子都相同,如果有操作数据中有寄存器,那么按照寄存器的数据长度计算
    
    push:入栈
    示例:push ax
    解释:将ax的数据入栈,传送到ss:sp栈顶处
    
    pop:出栈
    示例:pop ax
    解释:将ss:sp位置的数据出栈,传送入ax中
    
    pushf:所有标志位入栈
    示例:pushf
    解释:标志位入栈,防止后面的操作对标志位产生影响的通常做法
    
    popf:标志位出栈
    示例:popf
    解释:标志位出栈,用于还原入栈的标志位
    
    xchg:交换,目前没用到
    
    算数运算指令
    add:加法
    示例:add ax,2
    解释:将ax中的数据加2,即ax+0002h
    
    sub:减法
    示例:sub ax,2
    解释:将ax中的数据减2,即ax-0002h
    
    adc:加法(带符号位)
    示例:adc ax,2    ;CF=1
    解释:将ax中的数据加3,即ax+0002h+1h
    
    sbb:减法(带符号位)
    示例:sbb ax,2    ;CF=1
    解释:将ax中的数据减3,即ax-0002h-1h
    
    inc:自增
    示例:inc si
    解释:将si中的数据加1,常用在循环或条件转移中
    
    dec:自减
    示例:dec ax
    解释:将ax中的数据减1
    
    cmp:比较
    示例:cmp ax,0
    解释:相当于减法,ax-0,只不过不影响寄存器的值,而只影响标志寄存器,因为条件转移指令是依据标志寄存器的指令,所以cmp常与条件转移指令配合使用进行条件转移
    
    mul:乘法
    示例:mul bx或mul bl
    解释:分为两种情况:
    1. 指令参数是8位寄存器如bl时,乘数1默认放在al寄存器中,另一个乘数2放在8位寄存器如bl中,结果存在ax中
    2. 指令参数是16位寄存器如bx时,乘数1默认放在ax寄存器中,另一个乘数2是指定的16位寄存器如bx中的数据,结果的高16位存在dx,低16位存在ax中
    
    div:除法
    示例:div bx或div bl
    解释:同样分为两种情况:
    1. 指令参数是8位寄存器时,被除数(除法前面那个数。。。)则为16位,默认存放于ax中,除数则是存放于指定8位寄存器如bl中,结果为:al存储商,ah存储余数
    2. 指令参数是16位寄存器时,被除数则为32位,默认存放于ax和dx中,dx存高16位,ax存低16位,除数存放于指定16位寄存器如bx中,结果:ax存储商,dx存储余数
    
    aaa:目前没有用到
    
    逻辑指令
    and:逻辑与
    示例:and al,11011111b
    解释:示例中结果是将al中第6位置为0,其他位保持不变,常用与简化运算如,将小写字母转化为大写字母,只需要将字母与11011111做逻辑与运算即可实现
    
    or:逻辑或
    示例:or al,00100000
    解释:示例中结果是将al中第6位置为1,其他位保持不变,同样也能实现将大写字母转化为小写字母的简化运算,需要将字母与00100000做逻辑或运算即可实现
    
    not:逻辑非,不常用
    示例:
    解释:
    
    xor:逻辑异或,目前不常用
    示例:
    解释:
    
    test:不常用
    shl:逻辑左移
    示例:shl al,1或mov cl,3;shl al,cl
    解释:逻辑左移的意思就是左移后,移出的数据存放在标志寄存器CF中,而最低位用0补齐,也分为两种情况:
    1. 左移1位:直接shl al,1即可
    2. 左移超过1位:需要先将欲移动的位数据存入cl中,再通过左移cl个位的数据来实现
    
    shr:逻辑右移
    示例:shr al,1或move cl,2;shr al,cl
    解释:逻辑右移与逻辑左移类似,这里就不多讲了,同样也是两种情况
    
    sal
    sar
    rol
    ror
    rcl
    rcr
    
    转移指令
    无条件转移指令
    jmp:无条件转移指令
    示例:jmp short s;s:inc ax
    解释:jmp转移指令可以实现段内短转移、段内近转移和段间转移这三种基本需求
    1. 段内短转移:只对IP寄存器修改,修改范围为-128~127,也就是说向前最多转移+127个字节,向后最多转移-128个字节
    2. 段内近转移:与短转移基本相同,不过是16位的位移,即修改IP的范围是-32768~32767
    3. 远转移(段间转移):可以转移到指定的内存处,上面的两个转移只是在同一个段中的转移,是根据位移定位的转移方式,而远转移可以指定转移的目的地址
    
    条件转移指令
    jcxz:如果cx寄存器的值为0,则转移到指定标号
    示例:mov cx,0;jcxz s
    解释:如果条件满足cx寄存器的值为0,则转移到指定的标号处,常用的场景是:遍历一个以'0'字符结尾的字符串,根据这个0判断字符串是否到末尾的简单实现方式
    
    je:如果cmp得差结果等于0,则转移到指定标号
    示例:mov bx,3;cmp bx,3;je s
    解释:将会转移到s处
    
    jb:如果cmp的差结果小于0,则转移到指定标号
    示例:mov bx,3;cmp bx,4;jb s
    解释:将会转移到s处
    
    ja:如果cmp的差结果大于0,则转移到指定标号
    示例:mov bx,3;cmp bx,2;ja s
    解释:将会转移到s处
    
    jnb:如果cmp的差结果不小于0,则转移到指定标号
    示例:mov bx,3;cmp bx,3;jnb s
    解释:将会转移到s处
    
    jna:如果cmp的差的记过不大于0,则转移到指定标号
    示例:mov bx,3;cmp bx,3;jna s
    解释:将会转移到s处
    
    循环指令
    loop:汇编语言中的循环语句
    示例:mov cx,10;loop s
    解释:将s程序段循环执行10次(循环次数由cx的值指定)
    
    过程
    call:调用子程序,常与ret成对使用
    示例:call s;s:ret
    解释:转移到子程序,类似于转移指令,但相当于执行了
    push IP
    jmp near s这两条指令,记录了转移的位置,可以使用ret返回此IP的位置
    
    ret:在子程序中同于返回call的指令处,常与call成对使用,并且是近转移
    示例:call s;s:ret
    解释:从子程序跳出,相当于执行了
    pop IP,程序执行的下一条语句就是原来call的IP的地址,从而实现了近转移
    
    retf:在子程序中同于返回call的指令处,常与call成对使用,并且是远转移
    示例:call s;s:retf
    解释:从子程序跳出,相当于执行了
    pop IP
    pop CS程序执行的下一条语句就是原来call的IP的地址,从而实现了远转移
    
    中断
    int:系统中断
    示例:mov ax,4c00h;int 21h
    解释:BIOS和DOS都提供了一些默认的中断进程,用于持续检测中断码,如果接受到中断码,则会在TF=1的情况下在下一条指令去执行可屏蔽中断进程,我们也可以自定义中断进程去替代系统的中断进程。示例中的中断是去执行21号中断的ah=4c的子程序,子程序为退出当前DOS
    
    iret:与int配合使用,在子程序中返回,与ret,retf类似
    
    
    处理机控制指令
    cld:设置DF为0(即正向拷贝)
    示例:cld;rep movsb
    解释:设置标志寄存器DF为0,即设置拷贝的方向为正向
    
    std:这是DF为1(即反向拷贝)
    示例:std;rep movsb
    解释:设置标志寄存器DF为1,即设置拷贝的方向为反向
    
    cli:设置TF标志位为1
    示例:cli
    解释:设置TF为1后,当接受到可屏蔽中断时,会在下一条指令执行中断
    
    sti:设置TF标志位为0
    示例:sti
    解释:设置TF为0后,当接受到可屏蔽中断时,会忽略中断继续执行当前程序直至结束
    
    nop:添加一个占位的一字节数据
    示例:funcend:nop
    解释:常用来记录子程序的段结束的位置,比如offset funcend就可以获取func结束位置的偏移地址
    
    clc
    cmc
    stc
    hlt
    wait
    esc
    lock
    
    串处理指令
    movsb:复制字符串
    示例:rep movsb
    解释:可以正向或反向复制指定为的字符串到目标地址,参数必须将ds:si源地址、es:di目的地址、cx长度、标志DF指定,然后调用rep movsb
    
    movsw
    示例:
    解释:
    
    cmps
    scas
    lods
    stos
    配合使用:
    rep
    repe
    repne
    

    书中的一些值得注意的问题(自己的笔记上的内容,某些描述可能不是很准确,可以选择性跳过)

    mov ax,0 可以用sub ax,ax替代,而且后者2字节,前者3字节
    当16进制数,首位数字为英文,则需要在前面加上0,比如:0A432H
    在汇编程序中,mov al,[0]指令与debug程序不同,汇编编译器会将它解释为mov al,0
    DOS和合法程序都不会使用0:200~0:2ff这段256字节的空间
    直接DEBUG显示的CS就是当前程序段的字节长度
    为什么mov 4c00h;int 21h长度为5字节
    暂存数据的时候,一般用栈
    bp寄存器默认使用ss作为段寄存器
    没有寄存器名存在的情况下指定内存单元的长度:mov word/byte ptr [bx],1
    push/pop只对字操作
    在10.1节,ret和retf的示例中,在执行命令之前,为什么都要mov bx,0
    mul乘法,与div除法原理相似,都分为8位和16位的计算
    16位cpu,有符号溢出范围79H(127),-80H(128)
    DF:方向标志位,与movsb配合使用
    adc指令的意义:进行大数的加法或减法 
    inc和loop不影响cf位
    cmp指令只会影响标志位
    CF能说明操作符的大小
    SF=1并不能说明运算的结果的正负,因为可能发生溢出
    但SF和OF同时可以说明正负
    SF=1,OF=1:(ah)<(bh)
    SF=1,OF=0:(ah)>(bh)
    SF=0,OF=1:(ah)<(bh)
    SF=0,OF=0:(ah)>=(bh)
    cld和std分别设置DF为0(正向)和1(反向)
    Debug中的标志位对应关系
    flag:1--0
    OF:OV,NV
    SF:NG,PL
    ZF:ZR,NZ
    PF:PE,PO
    CF:CY,NC
    DF:DN,UP
    loop执行分两步
    cx--
    cx不等于0,转移
    中断过程
    取得中断类型吗N
    pushf,将标志寄存器入栈保存
    TF=0,IF=0
    push cs
    push ip
    (IP)=4*N,(CS)=4*N+2
    动态获取到一段代码的长度,可以设置一个nop字节,获取长度只需要:
    
    mov cx,offset do0end-offset do0
    do0:
        mov xx,xxx
        mov 4c00h
        int 21h
    do0end:nop
    
    jmp short s占2字节内存
    设置栈顶的ss和sp之间不会响应任何中断,所以在实验二的时候,执行mov ss,0后,mov ax,0执行了,只是debug不能将它中断显示
    一般在中断例程中还存在子程序,一般通过ah来指定
    如果将字符串后的0写成字符'0',则利用jcxz无法跳转
    在进行逻辑移位shl或shr时,移位大于1,必须用cl保存位移数,并将最后一次移出的保存到CF中
    在CMOS RAM中,端口为70h(地址端口)和71h(数据端口)存储时间信息的单元分别为:秒:0分:2时:4日:7月:8年:9,都占一个字节
    在PC中,外中断可分为可屏蔽中断和不可屏蔽中断
    可屏蔽中断在IF=1时,cpu会在执行完当前指令后响应中断,IF=0则不响应此中断
    不可屏蔽中断是cpu必须响应的中断,一般不会使用
    设置IF:sti,设置IF=1; cli,设置IF=0,IF=0不会执行屏蔽中断
    通码:按下键盘的一个键产生的扫描码;断码:松开一个键产生的扫描码,
    断码=通码+80h
    都被送到60h端口
    扫描码一个字节中,通码的第7位为0,断码第7位为1
    地址标号和数据标号
    地址标号,只能在代码段使用
    数据标号,不仅表示内存单元的地址,还表示内存单元的长度,与地址标号不同是标号后无符号“:”
    直接定址表:可以通过依据数据,直接计算出所要找的元素的位置的表
    键盘缓冲区的字单元中,高位字节存储扫描码,低位字节存储ASCII码。
    int 16h用于从键盘缓冲区读取字符,ah存储扫描码(高位),al存储字符(低位)
    
  • 相关阅读:
    C#获取指定日期为一年中的第几周
    Javascript arguments详解
    select2 插件
    [转]oracle存储过程中update不成功的一个原因
    [转]Oracle存储过程给变量赋值的方法
    [转]cron表达式详解
    [转]ssh中如何实现定时任务(spring对quartz的支持)
    [转]Oracle存储过程总结
    [转]Oracle 树操作(select…start with…connect by…prior)
    [转]oracle在删除表表空间用户时,如何释放磁盘空间
  • 原文地址:https://www.cnblogs.com/qjx-2016/p/9375730.html
Copyright © 2020-2023  润新知