• 汇编语言——王爽


    使用debug执行汇编程序的步骤:

    dir进入界面

    编译:masm

    链接:link

    执行:debug 文件名

    汇编程序格式

    assume cs:code    cs是寄存器,code是标号;

    code segment                //代码段开始

    ... ...

    mov ax,4c00h

    int 21h                        //上两行表示程序结束,唤起中断;

    code ends                        //代码段结束

    end                                //程序结束

    汇编语言包括代码段,数据段,栈段三部分,后两个通过预先定义数据来实现;

    如何区分不同的段完全根据指令;

    [bx]和内存单元的描述

    用[0]表示内存单元时,0表示单元的偏移地址,段地址在ds中,单元的长度(类型)可以有具体的指令中其他的操作对象指出(如寄存器);

    这段话得到,会有专门的寄存器存储内存单元的长度,放置越界;即内存单元的长度由寄存器指出。

    合法指令:mov ax 1合法指令;mov ds,1是非法指令;

    数据寄存器和地址寄存器:

    ax,bx,cx,dx是数据寄存器,向其中写入数据是合理的,而ds,cs,ip,ss,sp则不是,它们是地址寄存器,不能直接写入数据,只能通过数据寄存器送入数据。

    Loop指令

    loop指令的格式

    loop 标号

    操作步骤

    1.(cx)=(cx)-1;

    2.判断cx中的值,不为0则转至标号处执行,为0则向下执行;

    cx的值表示循环次数;

    提前结束循环命令

    p指令可以一次执行完循环所有指令,g指令可以一直执行到具体指令处,g 偏移地址

    Debug 和masm对指令的不同理解

    Debug和masm对”mov ax,[0]“的理解不同,Debug将[idata]理解为一个内存单元,idata是偏移地址,masm编译器将“[idata]”解释为数据"idata";

    在汇编源程序中编写如下程序。

    assume cs:code
    code segment
        mov ax,2000    
        mov ds,ax
        mov al,[0]
        mov bl,[1]
        mov cl,[2]
        mov dl,[3]

    mov ax,4c00h
    int 21h

    code ends
    end

    执行后寄存器结果如下:

    可以看到,[0]被理解为0,[1]被理解为1;

     因此,需要使用bx作为偏移地址,用[bx]代表偏移地址,很麻烦;可以采用ds:[0]的方式显示的指出地址:

    mov ax,ds:[0]的含义就是将段地址为ds,偏移地址为0的内存出的数据送入ax中;

    总结

    从上面可以看出,如果要访问一个内存单元,需在指令中使用[...]来表示内存单元,如果在[]里用一个常量idata直接给出内存单元的偏移地址,就要在[]前现实的给出段地址所在的寄存器;如果[]里使用寄存器,则段地址默认在ds中,当然也可以显式的给出段地址所在的寄存器。(P112)

    loop和[bx]联合使用

    编写程序计算fff:0~ffff:b单元中数据的和;程序如下:

    assume cs:code
    code segment
        mov ax,0ffffh
        mov ds,ax
        mov bx,0
         mov dx,0
    s:    mov al,ds:[bx]
        mov ah,0
        add dx,ax
        inc bx
        loop s

    mov ax,4c00h
    int 21h

    code ends

    end

     段前缀

    可以显式的给出段地址所在的段寄存器,汇编语言中显式的指出内存单元段地址的:ds:,cs:,ss:,es:被称为段前缀

    mov ax,ds:[bx],段地址在ax中

    mov ax,cs:[bx],段地址在cs中

    mov ax,es:[0],段地址在es中

    一段安全的空间(P117)

    不能随意写入

    有些内存空间不能随意改写,如下面的代码在0:26处写入数据,结果引起死机。

    mov ax,0

    mov ds,ax

    mov [26],ax

    结果引发了 inc sp,系统死机;因此不能随意向内存中写入内容;

    哪里有安全的空间

    1.一般的PC机中,0:200~0:2ff这256个字节的内存空间是没有程序或系统使用的,是可以安全的写入数据的;

    2.使用debug查看内存空间的内容,如果都是0,说明可以使用。

    段前缀的使用(P120)

    问题:将内存ffff:0~ffff:b单元中的数据复制到0:200~0:20b单元中

    assume cs:code
    code segment
        mov ax,0ffffh
        mov ds,ax
        mov ax,0020h
        mov es,ax
        mov bx,0

    s:    mov dl,[bx]
        mov es:[bx],dl
        inc bx
        loop s

    mov ax,4c00h
    int 21h

    code ends
    end

     包含多个段的程序(123)

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

    data segment       ;数据段

        dw 0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
    data ends


    stack segment                ;栈段

        dw 0,0,0,0, 0,0,0,0
    stack ends

    code segment                ;代码段

    start:    mov ax,stack
        mov ss,ax
        mov ax,20h
        mov sp,ax

        mov bx,0
        mov cx,8
        
    s:    push cs:[bx]
        add bx,2
        loop s
        
        mov bx,0
        mov cx,8
    s0:    pop cs:[bx]
        add bx,2
        loop s0
        
        mov ax,4c00h
        int 21h
        
    code ends


    end start

    更灵活的定位内存地址的方法

    and和or指令

    and:都为一才为1,否则为0;

    or指令:都为0才为0,否则为1;

    以字符形式给出的数据

    在汇编程序中,使用'......'的方式知名数据以字符的形式给出,编译器将把他们转换为对应的ASCII码,

    assume cs:code,ds:data
    data segment
        db    'uniX'       ;定义了'uniX'的字符
        db    'foRK'
    data ends

    code segment

      start:  mov al,'a'
        mov bl,'b'
        
    mov ax,4c00h
    int 21h

    code ends
    end start

    大小写转换(P140)

    转换方法:加减20H,或者使用and,or指令

    [bx+idata]

    [bx+idata]表示一个内存单元,偏移地址为(bx)+idata

    mov ax,[bx+200]:将一个内存单元的内容送入ax,偏移地址为bx的数值+200,段地址在ds中;

    该指令的格式:

    mov ax,[bx+200]

    mov ax,200[bx]

    mov ax,[bx].200

    三种格式都可以。

    SI和DI

    SI,DI是8086中和bx功能相近的寄存器,但si,di不能被分解为两个8位寄存器来使用。

    [bx+si+idata],[bx+di+idata]:

    格式如下:

    mov ax,[bx+200+si]

    mov ax,[bx].200[si]

    mov ax,[bx][si].200

    mov ax,200[bx][si]

    数据处理的两个基本问题-寻址方式总结

    1.数据在什么地方

    2.数据有多长

    使用reg描述一个寄存器,使用sreg描述一个段寄存器

    reg:ax,bx,cx,dx,al,ah,bl,bh,cl,ch,dl,dh,sp,si,di,bp

    sreg:ds,cs,ss,es

    只有bx,si,di,bp可以用于内存寻址;这四个寄存器可以单个出现,当组合出现时只能以以下四种组合出现:bx和si,bx和di,bp和si,bp和di;即有相同字母的寄存器不能同时出现;

    综上,寻址方式如下:

    指令处理的数据在哪里

    (1)立即数

    mov ax,1

    (2)寄存器

    mov ax,bx

    (3)段地址和偏移地址

    mov ax,ds:[1]

    指令要处理的数据有多长

    (1)通过寄存器名知名要处理的数据尺寸

    mov ax,1表明数据为字

    mov al,1表明数据为字节

    (2)没有寄存器存在的情况下,用操作符 X ptr 指明内存单元的长度,X在汇编指令中可以为word或byte.

    mov word ptr ds:[0],1                向ds:[0]处写入1(单位为字);

    mov byte ptr ds:[0],1                数据长度为字节;

    (3)其他方法

    有些指令默认了访问的是字单元还是字节单元;如push,pop都为字操作;

    寻址方式综合应用:修改结构体数据

    问题:

    内存中一处记录某公司的信息,要求将排名修改为40,收入修改为70,产品修改为VAX;

    原信息:

    代码:

    assume cs:code,ds:data

    data segment
        db 'DEC','Ken Oslen'
        dw 137,40
        db 'PDP'

    data ends


    code segment

    start:    mov ax,data
        mov ds,ax
        mov bx,0
        mov word ptr [bx].0ch,38
        mov word ptr [bx].0eh,70
        
    mov si,0
        mov byte ptr [bx].10h[si],'V'
    inc si
        mov byte ptr [bx].10h[si],'A'
    inc si
        mov byte ptr [bx].10h[si],'X'
        的
    mov ax,4c00h
    int 21h
    code ends

    end start

    div,dd,dup指令

    div除法指令

    除数:8位或16位,存储在reg或内存单元中;

    被除数:默认在AX或DX和AX中,如果除数为8位,被除数则为16位,默认在AX中存放,如果除数为16位,被除数为32位,低位存放在AX中,高位存放在DX中,

    结果:如果除数为8位,AL存储除法操作的商,AH存储除法操作的余数;

               如果除数位16位,AX存储除法操作的商,DX存储除法操作的余数;

    格式:        div reg

                      div 内存单元

    具体:        div  byte ptr ds:[0]        除数是8位

                       div word ptr ds:[0]        除数是16位

    伪指令dd

    dd可以用来定义双字数据,即占据2个字长度的数据;

    dup

    dup和db,dw,dd等数据定义伪指令配合使用,用来进行数据重复。

    之前:                                db 0,0,0                 db 1,2,3                                 

    现在(使用dup):          db 3 dup (0)                db 1 dup(1,2,3)                

    db 3 dup(0,1,2) :db 0,1,2,0,1,2,0,1,2

    dup格式如下:

    转移指令原理

    可以修改CS,IP的指令统称为转移指令,

    只修改IP时,称为段内转移,同时修改CS,IP时,称为段间转移,段内转移又分为短转移和近转移,短转移IP修改范围为-128~127;近转移修改范围为-32768~32767.

    转移指令还分为:无条件转移指令,条件转移指令,循环指令,过程,循环,中断

    操作符offset

    offset可以获得标号的偏移地址,并不是标号的实际地址;

    assume cs:codeseg

    codeseg segment

    start:        mov ax,offset start

            s:        mov ax,offset a

    codeseg ends

    end start

    以上代码中,offset获取了start的偏移地址,为0,因此mov ax,offset start相当于mov ax,0;

    jmp指令

    jmp为无条件转移指令,可以修改IP,也可以同时修改CS,IP.本质是看读一个字,还是两个字,两个字就是

    jmp要给出两种信息:

    转移的目的地地址

    转移的距离(段间转移,段内短转移,段内近转移);

    段间转移的指令:

    jmp far ptr 标号

    jmp dword ptr 内存单元地址

    段内转移:

    jmp reg

    jmp short 标号

    jmp word ptr 内存单元地址

    jmp near ptr 标号

    依据位移进行转移的jmp指令

    jmp short 标号(转到标号处执行指令)

    实现段内短转移,对IP的修改范围为-128~127,也就是说,转移只能在这个范围内;标号指明了转移的目的地;

    jmp指令的本意:编译器通过分析,告诉CPU当前IP应该偏移多少;

    jmp near ptr 标号

    实现段内近转移

     转移的目的地地址在指令中的jmp指令

    jmp far ptr 标号:实现段间转移

    jmp far ptr将会包括转移到的地址。

    转移地址在寄存器中的jmp指令

    格式:jmp reg(16位)

    功能:IP=reg

    如 jmp ax等同于mov ip,ax

    转移地址在内存中的jmp指令

    从这两个功能我们可以看到如何切换进程和线程,将TCB中的相关数据取出即可;

    jmp word ptr 内存单元地址(段内转移)

    mov ax,0123h

    mov ds:[0],ax

    jmp word ptr ds:[0]

    执行后,ip=0123h

    jmp dword ptr 内存单元地址(段间转移)

    mov ax,0123h

    mov ds:[0],ax

    mov word ptr ds:[2],0

    mov dword ptr ds:[0]

    执行后cs=0,ip=0123h;

    jcxz指令

    格式 jcxz 标号

    jcxz是有条件转移指令,所有有条件转移指令都是短转移,在对应机器码内包含的是位移,而不是目的地地址。修改范围为-128~127.

    loop指令
    根据位移进行转移的意义

    编译器对转移位移超界的检测:

    如果转移位移超界,编译时将报错

    实验

    CALL和ret指令

    ret指令用栈中的数据,修改IP的内容,实现近转移;retf指令用栈中的数据,修改CS,IP的内容,实现远转移

  • 相关阅读:
    Linux内核基础 - list_move_tail函数详解
    【新员工座位安排系统】python实现-附ChatGPT解析
    Clickhouse MaterializeMySQL引擎详解
    【大画数据结构】第二话 —— 无头单链表的基本操作
    智能AI创作系统ChatGPT详细搭建教程/AI绘画系统/支持GPT联网提问/支持Prompt应用/支持国内AI模型
    【定时开关机】windows 10 如何设置定时开关机
    基于标准反向传播算法的改进BP神经网络算法(Matlab代码实现)
    资源管理游戏模版进入The Sandbox
    C++异步并发编程future、promise和packaged_task三者的区别和联系
    微信小程序毕业设计论文_SSM项目会议预约管理+后台管理系统_项目源代码
  • 原文地址:https://blog.csdn.net/qq_41790844/article/details/133390343