数据处理的两个基本问题

总结chapter5-8

这几章分散引入或总结了不少零碎的知识点,包括寻址方式、新增指令用法、伪指令,等等。知识本身难度不大,但是,由于比较零散,也容易给初学者造成困扰。因此,建议对内容进行分门别类梳理、归纳、总结,借助思维导图、表格等形式,让知识结构化、体系化、清晰化。不仅有助于自己学习理解,也有助于后期复习。

第五章[bx]和loop指令在上一篇博客有总结

第六章包含多个段的程序

assume cs:code
code segment

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

     mov bx,0
     mov ax,0

     mov cx,8
 s: add ax,cs:[bx]
     add bx,2
     loop s

     mov ax,4c00h
     int 21h
code ends
end
   

"dw"的含义是定义字型数据。

通过ds=0760,可知道程序从0770开始存放,由于数据存放在代码段中,程序运行的时候cs中存放代码段的段地址,所以可以从cs中得到它们的段地址。

用debug加载后,可以将ip设置为10h,从而使cs:ip指向程序中的第一条指令。再用t命令,p命令,或者是g命令执行。

 

assume cs:code
code segment

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

start :   mov bx,0
             mov ax,0

              mov cx,8
 s:          add ax,cs:[bx]
              add bx,2
              loop s

               mov ax,4c00h
               int 21h
  code ends
  end  start

加入标号start,而这个标号在伪代码end的后面出现。end的作用除了通知编译器程序结束外,还可以通知编译器程序的入口在什么地方。我们用end指令指明了程序的入口在标号start处。

我们知道在单任务系统中,可执行文件中的程序执行过程如下:

1.由其他的程序(debug\command或其他程序)将可执行文件中的程序加载入内存。

2.设置cs:ip指向程序的第一条要执行的指令(即程序的入口),从而使程序得以运行。

3.程序运行结束后,返回到加载者。有了这种方法,就可以这样来安排程序的框架:

assume cs:code

code segment

      :

      :

    数据

      :

      :

start:

       :

       :

      代码

        :

         :

code ends

end start

下面的程序实现依次用内存0:0-0:f单元中的内容改写程序中的数据,数据的传送用栈来进行。栈空间设置在程序内。

assume cs:codesg
codesg segment

     dw    0123h,0456h,0789h,0abch,0defh,0fedh,0cbah,0987h
     dw   0,0,0,0,0,0,0,0,0,0  ;10个字单元用作栈空间
start:      mov ax,cs
            mov ss,ax
            mov sp,30h  
            
            mov ax,0
            mov ds,ax
            
            mov bx,0
            mov cx,8
        s:  push [bx]
            pop cs:[bx]
            add bx,2
            loop s
                
            mov ax,4c00h
            int 21h
codesg ends
end

cs:10-cs:2f的内存空间当作栈来用,初始状态下栈为空,所以ss:sp要指向栈底,则设置ss:sp指向cs:30

预留16个字单元

dw 16 dup(0)

将数据、代码、栈放入不同的段

assume cs:b,ds:a,ss:c1
a segment

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

c1 segment
  dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
c1 ends

b segment

d:      mov ax,c1
            mov ss,ax
            mov sp,20h      ;希望用C1段当作栈空间,设置ss:sp指向c:20
            
            mov ax,a
            mov ds,ax       ;希望用ds:bx访问a段中的数据,ds指向a段
            
            mov bx,0        ;ds:bx指向a段中的第一个单元
            mov cx,8
        s:  push [bx]
            add bx,2
            loop s          ;以上将a段中的0-15个单元中的8个字型数据依次入栈
            
            mov bx,0
            mov cx,8
        s0: pop [bx]
            add bx,2
            loop s0         ;以上依次出栈8个字型数据到a段的0-15个单元中
                
            mov ax,4c00h
            int 21h
b ends
end  d                      ;d处是要执行的第一条指令,即程序的入口

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

and 和 or 指令 

and指令:逻辑与指令,按位进行与运算。

通过该指令可将操作对象的相应位设为0,其他位不变。

or指令: 逻辑或指令,按位进行或运算。

通过该指令可将操作对象的相应位设为1,其他位不变。

关于ascii码

世界上有很多编码方案,有一种方案叫做ascii码,是在计算机系统中通常被采用的。简单地说,所谓编码方案,就是一套规则,它约定了用什么样的信息来表示现实对象。我们可以看到,显卡在处理文本信息的时候,是按照ascii码的规则进行的。这也就是说,如果我们要想在显示器上看到"a",就要给显卡提供“a“的ascii码,61h,如何提供?当然是写入显存中。

我们可以在汇编程序中,用'.....'的方式指明数据是以字符的形式给出的,编译器将它们转化为相对应的ascii码。

大小写转换

assume cs:codesg,ds:datasg
datasg segment
db 'BaSiC'
db 'iNfOMaTiOn'
datasg ends
codesg segment
 start: mov ax,datasg
        mov ds,ax       ;设置ds指向datasg段
        
        mov bx,0        ;设置(bx)=0,ds:bx指向'BaSiC'的第一个字母
        
        mov cx,5        ;设置循环次数5,因为'BaSiC'有5个字母
      s:mov al,[bx]     ;将ASCII码从ds:bx所指的单元中取出
        and al,11011111B ;将al中的ASCII码的第5位置为0,变为大写字母
        mov [bx],al      ;将转变后的ASCII码写会原单元
        inc bx           ;(bx)加1,ds:bx指向下一个字母
        loop s
        
        mov bx,5         ;设置(bx)=5,ds:bx指向'iNfOMaTiOn'的第一个字母
        mov cx,11        ;设置循环次数11,因为'iNfOMaTiOn'有11个字母
     s0:mov al,[bx]
        or al,00100000B    ;将al中的ASCII码的第5个位置为1,变为小写字母
        mov [bx],al
        inc bx
        loop s0
        
        mov ax,4c00h
        int 21h
        
codesg ends
end start

 

c语言: a[i],b[i]

汇编语言: 0[bx],5[bx]

通过比较我们可以发现,[bx+idata]的方式为高级语言实现数组提供了便利机制。

si和di是8086CPU中和bx功能相近的寄存器,si和di不能够分成两个8位寄存器来使用。

assume cs:codesg,ds:datasg
datasg segment
  db 'welcome to masm!'
  db '................'
datasg ends
codesg segment
 start: mov ax,datasg
          mov ds,ax
          mov ds,ax
          mov si,0
          mov cx,8
       s: mov ax,0[si]
          mov 16[si],ax
          add si,2
          loop s
          
          mov ax,4c00h
          int 21h
codesg ends
end start
      

[bx+si+idata]表示一个内存单元,它的偏移地址为(bx)+(si)+idata(即bx中的数值加上si中的数值再加上idata)

 

 第八章 数据处理的两个基本问题

我们定义的描述性符号:reg和sreg

reg的集合包括:ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di

sreg的集合包括: ds,ss,cs,es

在8086CPU中,只有这4个寄存器可以用在”[...]“中来进行内存单元的寻址。比如下面的指令是正确的:

mov ax,[bx]

mov ax,[bx+si]

mov ax,[bx+bi]

mov ax,[bp]

mov ax,[bp+si]

mov ax,[bp+bi]

mov ax,[si]

mov ax,[di]

mov ax,[bx+si+idata]

mov ax,[bx+di+idata]

mov ax,[bp+si+idata]

mov ax,[bp+di+idata]

div指令

div指令时除法指令,使用div做除法的时候应注意以下问题。

1.除数:有8位和16位两种,在一个reg或内存单元中。

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

2.结果:如果除数为8位,则AL存储除法操作的商,AH存储除法操作的余数。如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。

求10001/100

assume cs:code, ds:data
data segment
dd 100001
dw 100
data ends
code segment
start: mov dx,1
       mov ax,86A1h
       mov bx,64h
       div bx
       
       mov ax,4c00h
       int 21h
code ends
end start
       

商ax=03e8h,余数dx=1

 

dup

dup是一个操作符,在汇编语言中db、dw、dd等一样,也是由编译器识别处理的符号。它是和db、dw、dd等数据定义伪指令配合使用的,用来进行数据的重复。

比如:db 2 dup (0)

定义了3个字节,它们的值都是0,相当于db 0,0,0

db 3 dup(0,1,2)

定义了9个字节,它们是0,1,2,0,1,2,0,1,2.相当于db 0,1,2,0,1,2,0,1,2

 

posted on 2018-12-09 16:07  学习疯子  阅读(270)  评论(0编辑  收藏  举报