zoukankan      html  css  js  c++  java
  • 【8086汇编基础】03变量、数组和常量的处理

    8086汇编语言初学者教程(第三部分)

    变量

    变量是一个内存地址。对于编程者来说,使用诸如名称为“var1”这样的

    变量保存数据远远比使用5a73:235b这样的地址容易的多。特别是当你

    使用10个以上的变量的时侯。

    编译器支持这两种变量 BYTE  WORD.(字节和字)

    声明变量的方法:

    name DB value 名称 DB 值

    name DW value 名称 DW 值

    DB - stays for Define Byte.
    DW - stays for Define Word.

    name -可以是任何字母与数字构成,但是必须由字母

    开头。可以通过不命名来声明一个没有名称的的变量(这个变量

    只有地址,没有名称)

    value - 可以是任何数值支持三种进制(十六进制,二进制和

    十进制),你可以使用"?"符号表示初始值没有确定。


    你可能从第二章了解到, MOV 指令是将数值从源拷贝到目的。

    让我们再看一个 MOV 指令的例子

    
    #MAKE_COM#
    ORG 100h
    
    MOV AL, var1
    MOV BX, var2
    
    RET    ; stops the program.
    
    VAR1 DB 7
    var2 DW 1234h
    


    将上面的代码拷贝到emu8086源程序编辑器中,按下F5键编译

    并在模拟器中执行。你会看到如下画面

     

    从画面可以看出,反编译后的代码同源程序很相似,不同的是变量

    被具体的内存地址取代。当编译器生成机器代码它会自动将变量名称

    用该变量的便宜量代替。默认情况下,DS 寄存器存放段偏移

    (当执行com文件的时侯,DS 寄存器的值同 CS 寄存器(代码段)

    的值一样)。
     

    内存第一列是偏移(offset),第二列是一个十六进制值

    (hexadecimal value),第三列是十进制(decimal value)

    最后一列是 ASCII 字符。


    编译器是非大小写敏感的,所以 “VAR1” 同 “var1” 都是同一个变量。


    VAR1变量的偏移是0108h,物理地址是0b56:0108

    var2 变量的偏移是0109h,物理地址是 0b56:0109

    这个变量是字,它占用2字节。这里假定低字节存放在低地址,

    所以34h位于12h前面。
     

    你可以看到,在RET指令后面还有一些指令,这样是因为反编译工具

    无法判断数据从什么地方开始。同样,你可以写出直接使用DB的程序.

    
    #MAKE_COM#
    ORG 100h
    
    DB 0A0h
    DB 08h
    DB 01h
    
    DB 8Bh
    DB 1Eh
    DB 09h
    DB 01h
    
    DB 0C3h
    
    DB 7
    
    DB 34h
    DB 12h
    

     

    将上面的代码拷贝到emu8086原代码编辑器,按下F5键编译,并在

    模拟器中运行,你可以看到同样的反汇编结果,得到同样的功能。

    根据上面,你可以猜测,编译器将源程序转化为一些字节的集合,

    这个集合被称作机器代码(machine code),处理器懂得他们,并且

    执行它们。
     

    ORG 100是一个编译指令(它告诉编译器如何处理源代码)

    当你使用变量的时侯,这条指令特别重要。它通知编译器

    可执行程序将被调入偏移量是100h(256字节)的位置,

    有了它,编译器就可以计算出所有变量的正确地址,然后

    用这些地址(偏移量)来代替变量名称。上面的这些指令

    不会真正的编译为任何机器代码。


    为何可执行程序总是被装入偏移量100h?操作系统在CS寄存器

    (代码段)存储着程序信息,比如命令行方式下的参数等等。

    尽管上面只是一个COM文件的例子,EXE文件调入在偏移量0000

    的位置,他使用特定的段保存变量。我们在下面会学习到关于

    EXE文件的知识。
     



    数组

    数组可以看作是变量链。一个字符串是一个字节数组的例子,

    其中每一个字符都当作一个ASCII码的值(0....255)

    下面是一些定义数组的例子

    a DB 48h, 65h, 6Ch, 6Ch, 6Fh, 00h
    b DB 'Hello', 0 


    b是一个数组,当编译器发现引用了字符串值后,会自动将这些

    字符转化为对应的字节。下面图表表示的就是声明数组后在内存

    中的分布:


     
    你可以使用方括号做下标直接访问到数组中的值,例如:

    MOV AL, a[3] 

    同样,你还可以使用任意一个内存索引寄存器BX, SI, DI, BP

    例如:

    MOV SI, 3
    MOV AL, a[SI]

    如果你想声明比较复杂的数组,你可以使用DUP指令 形式如下

    number DUP ( value(s) ) 
    number - 重复的数量(任意常数)
    value - 将要复制的表达式

    例如:

    c DB 5 DUP(9)

    就相当于如下定义:

    c DB 9, 9, 9, 9, 9 

    另外一个例子:

    d DB 5 DUP(1, 2)

    等同于

    d DB 1, 2, 1, 2, 1, 2, 1, 2, 1, 2 
     

    当然,如果需要存放超过255或者小于-128的数值,你还可以

    使用DW来代替 DB。但是DW不能用于声明字符串。
     

    DUP命令展开后不能超过1020个字符(上一个例子中展开之后

    是13个字符),如果需要声明请将它们分成两行(这样,内存中

    得到的仍然是一个大数组)。



    取得变量地址 
    LEA指令(Load Effective Address 读取有效地址)或者OFFSET

    指令。OFFSET 和 LEA二者都能够获得变量的偏移量。

    LEA在使用中更有效,这是因为它能返回索引变量的地址。取得

    变量地址在很多情况下是非常有用的,例如你打算向一个过程

    传递参数。



    注意:

    在编译过程中使用如下声明数据类型
    BYTE PTR - 表示字节

    WORD PTR - 表示字(2个字节)

    例如:

    BYTE PTR [BX] ;按字节访问
    or
    WORD PTR [BX] ;按字访问

    Emu8086 容许使用如下更简洁的前缀

    b. - 等价于上面的 BYTE PTR

    w. - 等价于上面的 WORD PTR

    有时,编译器可以自动计算出数据类型,但是如果一个参与运算

    的数是立即数,这种方法就不可靠了。





    第一个例子:

    
    ORG 100h
    
    MOV    AL, VAR1      ; 将变量var1的数值放入al以便检查
    
    LEA    BX, VAR1              ; 将var1的地址存入 BX.
    
    MOV    BYTE PTR [BX], 44h    ; 修改变量var1的内容
    
    MOV    AL, VAR1              ; 将变量VAR1的数值放入AL以便检查
    
    RET
    
    VAR1   DB  22h
    
    END
    


    下面是另外一个例子,用OFFSET指令代替LEA:

    
    ORG 100h
    
    MOV    AL, VAR1              ; 将变量VAR1的值放入AL以便检查.
    
    MOV    BX, OFFSET VAR1       ; 将变量VAR1的地址放入 BX.
    
    MOV    BYTE PTR [BX], 44h    ; 修改变量VAR1内容
    
    MOV    AL, VAR1              ;将变量VAR1的值放入 AL以便检查.
    
    RET
    
    VAR1   DB  22h
    
    END
    


    上面例子的功能相同。

    这些语句:
    LEA BX, VAR1
    MOV BX, OFFSET VAR1 

    都将生成同样的机器代码: MOV BX, num
    num 是16位变量偏移


    请注意,只有这些寄存器可以放入方括号中(作为内存指针)

    BX, SI, DI, BP(请参考本教程前述章节)
     



    常量

    常量同变量很相似,但是它一直存在。定义一个变量之后,它的值

    不会改变。使用EQU定义常量:

    name equ <任意表达式>


    例如:

    k EQU 5

    MOV AX, k


    上面的例子等同于如下代码:

    MOV AX, 5




    在程序执行过程中你可以选择模拟器"View"菜单下的"Variables"

     

    你可以点一个变量然后设置Elements属性为数组大小来查看数组。

    汇编语言对于数据类型并不严格,这样以来所有的变量都可以被看

    作是数组。

    变量可以显示为下列进制

    • HEX - 十六进制 hexadecimal (基底 16).
    • BIN - 二进制 (基底 2).
    • OCT - 八进制 (基底 8).
    • SIGNED - 有符号十进制 (基底 10).
    • UNSIGNED - 无符号十进制 (基底 10).
    • CHAR - ASCII 码 (一共有256个符号,其中一些符号是不可见的).

    程序运行的时侯,你可以通过双击它来编辑变量值,或者选中

    之后点Edit按钮。

    十六进制数值以"h"结尾,二进制以"b" 结尾,八进制以"o" 结尾

    十进制没有结尾。字符串用这样的方式表示:'hello world',0

    (结尾以0表示)

    数组按照如下输入:
    1, 2, 3, 4, 5

    (数组可以是一组字节或者字,这取决于你想以字节还是

    方式编辑)

    表达式会自动计算,例如,输入如下表达式
    5 + 2
    会自动计算为7。等等....

    <<< 上一部分 <<<【8086汇编基础】02--寻址方式和MOV指令 

    >>> 下一部分 >>>【8086汇编基础】04--中断

    作者:逸云沙鸥
    出处:http://www.cnblogs.com/QuLory/
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

  • 相关阅读:
    rCore-Tutorial-Book-v3学习笔记(五)
    rCore-Tutorial-Book-v3学习笔记(四)
    rCore-Tutorial-Book-v3学习笔记(三)
    rCore-Tutorial-Book-v3学习笔记(二)
    rCore-Tutorial-Book-v3学习笔记(一)
    OpenStack 命令行速查表(转载)
    mysql数据库总结笔记
    Owncloud迁移上云案例
    Python
    高等数学(微积分)
  • 原文地址:https://www.cnblogs.com/QuLory/p/2758053.html
Copyright © 2011-2022 走看看