飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 100434|回复: 153

[分享] [讲座]跟我学汇编

[复制链接]
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

    发表于 2005-2-7 22:20:02 | 显示全部楼层 |阅读模式
    1 本讲座以汇编初学者或对汇编一点也不了解的读者为对象,汇编高手不属于该范围,但强烈建议高手指导并增补、修改本文。
    2 任何读者可以跟此贴,提出疑问,或解答其中的问题,但对于所有跟贴,水贴、内容有错、毫不相干贴将直接删除,有意义的贴可能会合并到下一讲的内容中,合并后也将删除,请跟贴者谅解。同时按学习进步,请提问者逐步提,不要我没开口,你就问怎么编个病毒的问题。
    3 借以抛砖引玉,但不希望大家只朝我扔砖头,希望大家踊跃思考,使之完善
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

     楼主| 发表于 2005-2-7 22:20:46 | 显示全部楼层
    第负一讲 学习汇编前你应该知道的知识

      大家坐好了,。不要,不要,不要,男女同学不要相互,女同学不要对我....
      
    1 汇编需要什么工具和程序,到哪里下载?
      目前阶段,汇编程序仅需要两个程序就够了。 masm.exe,link.exe。二者可由http://www.20cn.org/~unique/Download/Tool/masm.rar下载,前者是编译程序,后者是链接程序。
      另外,为了验证和调试程序,还需要一个程序debug.exe,该程序由windows本身就提供,所以就不提供下载地址了。
      将二者下载后,放到某一个目录中(任意目录都可以),考虑到很多命令需要通过键盘敲入,所以建议你不要把文件放入到长文件名目录、中文目录或很深的目录中。比如你可以建一个“D:\Masm”目录,并建议此后的程序都放这个目录,此后称这个目录为汇编目录。


    2 学习汇编需要有哪些编程方面的知识。
      没有任何编程方面的知识,学习此语言等于缘木求鱼,所以请放弃学习的想法。一般来说至少要知道如下几点:
      *)程序的运行逻辑结构有顺序(按语句依次执行)、分支结构(IF...THEN...ELSE...),循环结构(FOR...NEXT)三种结构。
      *)知道什么是子程序,什么是调用。
      *)汇编程序员的视角。不同编程视角编程要求是不一样的。比如删除文件,
          >>用户的视角是找到“删除”按钮或菜单,然后单击一下即可。
          >>高级程序员的视角是知道删除的文件,并发出删除命令。这些通过API实现。
          >>汇编程员的视角是得到要删除的文件名,找到该文件所在位置,通过调用删除“中断命令”进行删除。
          >>操作系统开发人员的视角则是接到删除命令后,先找到系统根目录区,由根目录区的链接依次找到子目录区,直到找到要删除的文件,然后按照操作系统删除文件的规则对该文件名进行修改。比如DOS,只把第一个字符改成"?"。

      按程序语句等价的角度看,一行VB的打印语句,用汇编实现大约需要一百二十多行。知道汇编语言的视角后就要知道,前面的道路是坎坷的,没有耐心是不行的。想通过几分钟几行程序就完成很复杂的操作不是件容易的事。

    3 学汇编有什么用?
      汇编产生于DOS时代或更早,而现在是Windows时代,所以可能遗憾地说:尽管还有批牛人在用汇编开发核心级程序,但我们几乎没什么用,除了必要时间能拿来分析一两个程序的部分代码之外,别的也就没干什么用了。并且并不是所有的汇编命令都能在windows下使用。而泛泛地追求“时髦”而学本语言,最后的结果是损了夫人又折兵。所以学之前你要考虑好。我劝那些为了当“黑客”而学汇编的人就此止步。
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

     楼主| 发表于 2005-2-7 22:21:29 | 显示全部楼层
    第零讲 预备知识

    1 一个汇编程序的编译过程是怎么样的。
      1)首先你需要找一个编辑器,编辑器用任何“纯文本”编辑器都可以。比如记事本。编好以后保存到汇编目录中。扩展名为asm,比如myfirst.asm。但这里建议你找一个能显示出当前行的编译器。这样出错后排错很容易。
      2)然后在DOS下进入D:\Masm目录中,输入“masm myfirst.asm",如果有错系统会提示出错的行位置和出错原因。
      3)然后再输入“link myfirst.obj”,即可看到当前目录下有一个myfirst.exe程序。

    2 宏汇编和汇编有什么区别吗?
      二者的区别在于前者提供宏,后者不提供。后者已找不到了,所以你可以认为二者没有区别。

    3 机器语言、汇编语言、高级语言的关系
      最早的计算机采用机器语言,这种语言直接用二进制数表示,通过直接输入二进制数,插拔电路板等实现,这种“编程”很容易出错,每个命令都是通过查命令表实现,既然是通过“查表”实现的,那当然也可以让计算机来代替人查表实现了。于是就产生了汇编语言,所以不管别人怎么定义机、汇语言,我就认为,二者是等价。后来人们发现,用汇编语言编某一功能的时候,连续一段代码都是相同或相似,于是就考虑用一句语言来代替这一段汇编语言,于是就产生了高级语言。因此,所有高级语言都能转化成汇编语言,而所以汇编语言又可转化成机器语言。反之,所有机器语言可以转成汇编语言(因为二者等价)。但并不是所以汇编语言都能转成高级语言。

    4 计算机的组成
      通常都把计算机定义成五部分:运算器、控制器、存储器、输入系统、输出系统。
      为了简单其间,我们如此理解:运算器+控制器=CPU。存储器=内存(暂不包括外存,永不包括CACHE)。输入系统=键盘(不包括鼠标),输入系统=显示器(不包括打印机,绘图仪)。

    5 寄存器和内存的区别
      寄存器在CPU中。内存在内存条中。前者的速度比后者快100倍左右。后面的程序要求每条指定要么没有内存数据,要么在有一个寄存器的参与下有一个内存数据。(也就是说,不存在只访问内存的指令)。

    6 汇编语言的计数
      与生活中的计数不一样,汇编中的计数是从0开始的。比如16个计数,则是从0~15,而不是生活中的1~16。这一点看起来简单,真运算起来就不是件容易的事了,不信等着瞧。

    7 进制问题
      又与生活中不一样的地方是进制。切记下面的常识:
      *)计算机内部存储都用二进制。
      *)我们的汇编源程序默认都用十进制。(除非你指明类型)
      *)我们用的调试程序debug默认的都是十六进制。(无法指明其他类型)
      其中十六进制的十六个个位数依次是:0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F。

    8 进制转换
      一个比较简单的方法是查表法。
      十进制 十六进制 二进制
          0      0      0000
          1      1      0001
          2      2      0010
          3      3      0011
          4      4      0100
          5      5      0101
          6      6      0110
          7      7      0111
          8      8      1000
          9      9      1001
          10    A      1010
          11    B      1011
          12    C      1100
          13    D      1101
          14    E      1110
          15    F      1111
      
      好了,结合6,7,8三条。大家来算一个“题”。某一组数据显示时,每个数据占了四个位置,
    每行共十六个。问:十六进制的13位置在哪里(第几行,第几列)。
      格式如下: m m m m n n n n o o o o p p p p '注:之所以没用ABC是怕与上面十六进制弄混。
                       r  r  r   r  s  s s s  t t t  t u u u u
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

     楼主| 发表于 2005-2-7 22:22:58 | 显示全部楼层
    第一讲 基础知识

    1 访问内存
      程序在内存中,访问内存是几乎每一程序都要进行的操作,计算机对内存编址是线性的,也就是说是一维的,比如256M的内存,地址就应该是从0~(256M-1),这个地址称为物理地址或绝对地址。
    1.1 地址表示
      但从汇编程序员的角度看,内存却是二维的,要说明一个地址,需要给出两个值,就象你在平面上指定一点需要说出(X,Y)坐标一样,汇编程序员的内存视角也需要两个“坐标”,前一个称为段地址(Segment),后一个称为偏移地址(Offset),该地址称为逻辑地址。
      比如“1234:3DF5”就是一个地址。“1F3F:”不是一个地址,因为他只有段地址,没有编移地址。注意此后的地址都用十六进制表示。
    1.2 地址计算
      前面提到,计算机编址是一维的,汇编程序员是二维的,那么二者怎么换算呢?由后者到前者的换算方法是,“段地址串”后面加个“0”,然后再加上偏移地址。
      比如“1234:3DF5”(十六进制的加减运算参见相关资料)
    12340 ‘串后加了一个0
    3DF5
    -----
    16135  ’注意此串仍然是十六进制。
        所以,汇编程序员眼中的地址“1234:3DF5”就是物理地址(计算机编址):16135。
        知道了由后者向前者的转换,那么由前者向后者的转换呢?
      “不知道”,为什么不知道,继续往下看。
    1.3 到底哪个地址对。
        知道了1.2的地址算法后,我又发现一个问题:
        “1000:6135”的物理地址是多少呢? 10000+6135=16135。
        “1001:6125”的物理地址呢? 10010+6125=16135。
        ......
        那么到底哪个对呢?问题的回答是这样的:假设我现在让你按一下“L”键,我可以告诉你如下几种方法中的一种或几种。1 请按一下“L”键; 2请按一下键盘上第四行第十个键;3 请按一下第十列中的第四个键;4 请按一下“K”右边的键;5 按标准指法单击一下右手无名指。
        举上面的例子也就是说,同一个地址有很多种表示方式,具体用哪一种,要看实际使用时的情况。但无论用哪种方式,只要能达到目的即可。(实际中该问题一般不会受此问题困扰,但初学时突然想不通)。
    1.4 有多少内存可以访问
      无论是段地址还是偏移地址都是四位十六进制(如果不够四位,前面补0)。也就是说:总共可以访问的地址说是:0000:0000~FFFF:FFFF。 总共FFFF0+FFFF+1=10FFF0个地址。也就是不到1M的空间。
      记住如下结论:
      *)不管你实际内存有多少,目前我们只能访问不到1M的空间。
      *)而实际上连这1M也用不完。其中上端的384K的址只能读不能写,只能读,一般称为ROM。
      *)低端的640K可以读写。但这640K的低端100多K也不能随便写,因此DOS系统使用该区。
      *)原来1024M的内存,汇编程序只能使用其中400多K。这段内存的容易相当于一个普通文档的大小。不过这就足够了。

    2 DEBUG的使用
    先记住以下两个命令:D命令和Q命令。前者是显示内存内容,后者是退出DEBUG命令。
    -------------以下为抄别的人内容---------------
    DEBUG.EXE程序是专门为分析、研制和开发汇编语言程序而设计的一种调试工具,具有跟踪程序执行、观察中间运行结果、显示和修改寄存器或存储单元内容等多种功能。它能使程序设计人员或用户触及到机器内部,因此可以说它是80X86CPU的心灵窗口,也是我们学习汇编语言必须掌握的调试工具。

        1)DEBUG程序使用

    在DOS提示符下键入命令:

        C>DEBUG [盘符:][路径][文件名.EXE][参数1][参数2]

      这时屏幕上出现DEBUG的提示符“-”,表示系统在DEBUG管理之下,此时可以用DEBUG进行程序调试。若所有选项省略,仅把DEBUG装入内存,可对当前内存中的内容进行调试,或者再用N和L命令,从指定盘上装入要调试的程序;若命令行中有文件名,则DOS把DEBUG程序调入内存后,再由DEBUG将指定的文件名装入内存。
    2)DEBUG的常用命令
    (1)退出命令 Q
        格式:Q
        功能:退出DEBUG,返回到操作系统。
    (2)显示存储单元命令 D
    格式1:D[起始地址]
        格式2:D[起始地址][结束地址|字节数]
        功能:格式1从起始地址开始按十六进制显示80H个单元的内容,每行16个单元,共8行,每行右边显示16个单元的ASCII码,不可显示的ASCII码则显示“·”。格式2显示指定范围内存储单元的内容,其他显示方式与格式1一样。如果缺省起始地址或地址范围,则从当前的地址开始按格式1显示。
    例如:    -D 200          ;表示从DS:0200H开始显示128个单元内容
                    -D 100 120    ;表示显示DS:0100-DS:0120单元的内容
        说明:在DEBUG中,地址表示方式有如下形式:
        段寄存器名:相对地址,如:DS:100
    段基值:偏移地址(相对地址),如:23A0:1500

    --------------------------小抄结束--------------------------------

    3 验证第一节里的内容
    运行“开始/程序/附件/MS-DOS命令提示符”(这是win2000,win98下自己找吧)
    在“_”下输入D,显示
    -d
    1398:0100  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1398:0110  00 00 00 00 00 00 00 00-00 00 00 00 34 00 87 13  ............4...
    1398:0120  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1398:0130  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1398:0140  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1398:0150  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1398:0160  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1398:0170  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    -
    我们记下:1398:011C的值是个34。1389:011C的物理地址应该是:13A9C。
    那么1000:3A9C的物理地址也应该是13A9C,他的内存也应该是34,(因为本来就是一个地址吗,就象第三行第十列和第十列第三行当然应该是同一个位置)。
    -d 1000:3A9C
    1000:3A90                                      34 00 87 13              4...
    1000:3AA0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1000:3AB0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1000:3AC0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1000:3AD0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1000:3AE0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1000:3AF0  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1000:3B00  00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    1000:3B10  00 00 00 00 00 00 00 00-00 00 00 00              ............
    -
    果然如此,同样你可以验证:13A9:000C也肯定是指这一个地址,不信试试。
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

     楼主| 发表于 2005-2-7 22:23:28 | 显示全部楼层
    4 DEBUG命令
    -------------------继续小抄----------------
    前面已学过:显示存储单元命令 D
    再学一个命令
    (1)修改存储单元命令 E

    格式1:E[起始地址] [内容表]

    格式2:E[地址]

    功能:格式1按内容表的内容修改从起始地址开始的多个存储单元内容,即用内容表指定的内容来代替存储单元当前内容。

    例如:—E DS:0100 'VAR' 12 34

    表示从DS:0100 为起始单元的连续五个字节单元内容依次被修改为

    'V'、'A'、'R'、12H、34H。

    格式2是逐个修改指定地址单元的当前内容。

    如:—E DS:0010

    156F:0010 41.5F

    其中156F:0010单元原来的值是41H,5FH为输入的修改值。若只修改一个单元的内容,这时按回车键即可;若还想继续修改下一个单元内容,此时应按空格键,就显示下一个单元的内容,需修改就键入新的内容,不修改再按空格跳过,如此重复直到修改完毕,按回车键返回DEBUG“-”提示符。如果在修改过程中,将空格键换成按“-”键,则表示可以修改前一个单元的内容。

    -------------------小抄结束----------------

    5 使用DOS时,汇编用户可以从DOS操作系统中得到什么?
      现在编程,通常很多功能都是通过调用系统API。很多高级语言都直接把这些API包装起来,以系统接口或函数的方式提供给用户,那么汇编函数都能得到什么呢?
      首先,汇编用户有很多东西可以调用。他们主要是:
      5.1 BIOS提供的接口。现在硬件与软件的区分已越来越不明显,很多硬件不仅仅是电路,而还要提供一些固化写入硬件的一部分“程序”,这些程序以ROM的方式出现,汇编用户最大的好处就是可以直接使用这些“程序”,这些使用不仅功能强大,而且效率非常高。
      5.2 DOS功能调用,作为操作系统也象BIOS一样向用户提供了相应的“程序”。这些程序在很大程序上扩充了BIOS。与BIOS不同的是,这部分程序放在内存中,它可以被修改。而BIOS中不能再修改。
      ==========================================================
      以上两种接口都通过一种相同的格式调用,这些程序统称为“中断”,现在先不要理解中断的本意,你现在可以认为是系统提供给你的函数。
      ============================================================
      5.3 系统共享数据区。编过程序的人都知道全局变量的好处,全局变量方便之外在于任何函数、过程都可以调用、读取、修改。全局变量不足之处是危险性,有一个过程改了这个变量值,其它的也得跟着改变了。DOS操作系统同样也提供了这样的共享数据区,该区是整个系统的共享区,任何程序都可以查找、修改。当然,修改某处必然会对其它程序造成影响。

    6 再谈中断
      前面5.2已提到中断了,现在问题是不同硬件不一样,即使相同硬件的ROM,不同版本,各个BIOS中断程序所处的位置也不一样,DOS中断也一样,不同版本、不同配置,在内存位置也不一样。那么你使用某一个中断,系统怎么知道你使用的那个中断程序在哪呢?
      为了解决这一问题,DOS会在启动的时候,把所有这些(BIOS和DOS)中断的首地址保存到一个地址。这个地址很容易记,这段地址是内存的绝对零地址(0000:0000)。前面已讲过,每个地址在汇编程序员角度来看是二维的,也就是分为段地址和偏移地址。每个地址各占两个字节,所以要表示这个二维地址需要4个字节。所以每个中断首地址由4个字节表示。一共256个中断,占用了1024个字节的位置。
      另外需要注意的是,这4个表示地址的字节,数据是由低向高的。比如12 34 56 78所表示的地址是:7856:3412。
    一般用INT M表示中断M,如果M是十六进制,则在后面加上一个H。比如19号中断,十六进制应该是13H。所以该中断就是INT 13H。

    7 再谈系统共享数据区
      该共享数据区在绝对地址:0040:0000开始。

    8 验证我上面说的内容
      8.1 找中断
      运行DEBUG后。输入D 0000:0000。显示绝对零地址的内容。
      C:\>debug
    -d 0:0
    0000:0000  68 10 A7 00 8B 01 70 00-16 00 9B 03 8B 01 70 00  h.....p.......p.
    0000:0010  8B 01 70 00 B9 06 0E 02-40 07 0E 02 FF 03 0E 02  ..p.....@.......
    0000:0020  46 07 0E 02 0A 04 0E 02-3A 00 9B 03 54 00 9B 03  F.......:...T...
    0000:0030  6E 00 9B 03 88 00 9B 03-A2 00 9B 03 FF 03 0E 02  n...............
    0000:0040  A9 08 0E 02 99 09 0E 02-9F 09 0E 02 5D 04 0E 02  ............]...
    0000:0050  A5 09 0E 02 0D 02 DC 02-B8 09 0E 02 8B 05 0E 02  ................
    0000:0060  02 0C 0E 02 08 0C 0E 02-13 0C 0E 02 AD 06 0E 02  ................
    0000:0070  AD 06 0E 02 A4 F0 00 F0-37 05 0E 02 71 84 00 C0  ........7...q...
    -u 0070:018B
    0070:018B 1E            PUSH    DS
    0070:018C 50            PUSH    AX
    0070:018D B84000        MOV    AX,0040
    0070:0190 8ED8          MOV    DS,AX
    0070:0192 F70614030024  TEST    WORD PTR [0314],2400
    0070:0198 754F          JNZ    01E9
    0070:019A 55            PUSH    BP
    0070:019B 8BEC          MOV    BP,SP
    0070:019D 8B460A        MOV    AX,[BP+0A]
    0070:01A0 5D            POP    BP
    0070:01A1 A90001        TEST    AX,0100
    0070:01A4 7543          JNZ    01E9
    0070:01A6 A90002        TEST    AX,0200
    0070:01A9 7422          JZ      01CD
    首先,D命令把中断首地址显示出来。每4个表示一个地址。其中INT 0的中断首地址为:00A7:1068,INT 1的中断地址为:0070:018B.......0070:018B是中断3的首地址。后面那个U命令就表示显示该地址的“中断程序”的内存。
        你们可以试着找找INT 13H的位置在哪。
      8.2 验证系统共享数据区
        系统共享数据区内容极为丰富,我实在记不住哪么多了。我曾记在一个本上,可惜那个本早在N年前(3<N<6)就丢了。兄弟们谁找到这个地址的内容,一定要贴上来,这里有东西可以让大家眼界大开。
        前几年,我用的286计算机是黑白显示器(555555~~~~~~~~~,别嫌我老、旧、慢呀),可当时有个游戏非要彩显,不是彩显不让运行。我就是改了这个区的某一个位,让哪游戏“以为”我用的是彩显,于是游戏能用了。虽然不好看,但总能用。
        在DOS下,你每按一个键,系统都会记下来,下面我们一起找找这个键盘缓冲区的地址。知道这个地址,你就可以作一个“虚拟”键盘,通过发命令来模拟某个人在按键。这个地址位于:0040:001E。 其中每个键有两个字节,一个字节是ASCII码,一个是扫描码。共16个。
    C:\>debug
    -d 40:0
    0040:0000  F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F  ..........x.x...
    0040:0010  22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 20 39  "....(....*.*. 9
    0040:0020  34 05 30 0B 3A 27 30 0B-0D 1C 64 20 20 39 34 05  4.0.:'0...d  94.
    0040:0030  30 0B 3A 27 30 0B 0D 1C-71 10 0D 1C 64 20 00 00  0.:'0...q...d ..
    0040:0040  A2 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00  ..........P.....
    0040:0050  00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    0040:0060  0F 0C 00 D4 03 29 30 7F-03 00 C0 00 A1 B7 11 00  .....)0.........
    0040:0070  00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01  ................
    -d 0040:0000
    0040:0000  F8 03 F8 02 E8 03 E8 02-BC 03 78 03 78 02 80 9F  ..........x.x...
    0040:0010  22 C8 00 80 02 28 00 00-00 00 2A 00 2A 00 3A 27  "....(....*.*.:'
    0040:0020  30 0B 30 0B 30 0B 30 0B-0D 1C 64 20 20 39 30 0B  0.0.0.0...d  90.
    0040:0030  30 0B 30 0B 30 0B 08 0E-08 0E 34 05 30 0B 00 00  0.0.0.....4.0...
    0040:0040  1F 00 C3 00 A2 AF 09 E1-C8 03 50 00 00 10 00 00  ..........P.....
    0040:0050  00 18 00 00 00 00 00 00-00 00 00 00 00 00 00 00  ................
    0040:0060  0F 0C 00 D4 03 29 30 7F-03 00 C0 00 24 B8 11 00  .....)0.....$...
    0040:0070  00 00 00 00 00 00 00 00-14 14 14 00 01 01 01 01  ................
    -
    既然是键盘缓冲区,每个输入的键都会显示在该区中,第一次我只输入了“d 40:0”,所以你可以在此后显示数据右边字符中找到这些字符,注意是间隔开的。
    第二次我输入“d 0040:0000”,则右边显示的是“d 0040:0000”的内容。你可以找找。
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

     楼主| 发表于 2005-2-7 22:24:01 | 显示全部楼层
    第二讲 内存映象

      之所以把这个内存单独放一章,是为了说明它的重要性,后面的几乎很多程序都需要你对这一章的理解。这里的内存映象就是指当你把一个可执行文件(EXE或COM文件)放到内存后,整个内存“看”起来是什么样子的。
      前面讲过,这里汇编程序只能访问1M的内存空间,所以下面就以1M内存为例。并且以DOS操作系统作为讲解对象,所以所编出来的程序也仅是DOS程序。事实上,通过winasm可以访问远远超过1M的空间,并且可以编出FOR windows的程序。但那是另外的话题。我们暂且不说那些。

    2.1 内存映象
      首先,这1M内存如果我们不再以二维的方式看,而是一维的,线性地看(二维和一维的转化方式参见前面章节)。但描述还是以二维的方式描述,从最底端到最高端依次是:
      1 中断向量区:该区由0000:0000~0000:03FF。这里存着系统的所有中断的中断向量表,对于中断向量表,你现在先理解为一些程序的首地址。由这个地址你就能找到该程序。
      2 系统数据区:该区由0040:0000~0040:XXXX(不好意思,忘了),这里存着整个系统中,DOS操作系统要用的数据,由于这个区的数据对用户是开放的,所以用户当然也可以从这里读出来用。
      3 DOS操作系统区:操作系统常驻内存,你向计算机发的每个命令其实都是操作系统执行的。这个区的大小主要是由操作系统的版本和用户的配置大小决定,如果是驱动程序配置,就放到根目录下的config.sys里,如果是程序,就放到autoexec.bat里。这里设置在现在的windows 95/98/nt/me/2000/xp/2003中仍然有,所以我就不多说了。
      4 用户程序,这个当然就是你执行的程序了,这种程序分两种,一种是扩展名为com文件,一种是exe文件,从程序内部看,前者程序的四个段重合(后面要讲这四个段),所以最大长度只等于一个段,用前面段地址的理解就是com文件最大只能是64K,所以com文件只适合小的程序。而exe,四个段可任何分配,并可扩充段,而且每个段的段地址可以任何改动,因此exe的访问内存能力大多了。这种格式访问能力只受地址结构的限制了。
        用户程序所占的内存大小完全由程序本身决定,但最大,只能到640K。这一点,怪不得别人,只能怪当前计算机软硬件设置高手高手高高手们(包括比尔盖茨)们的失误了,60年代的超级计算机只有36K的内存,所以他们就在80年代得到一个结论:640K的内存足够了。
        如果用户程序大于由操作系统所占内存的顶底到640K之间的内存量,就会显示:内存不够,因而程序不能执行。这种现象对于一开始就用windows的人来说,几乎没见过,但对于一开始用DOS并打汉字的人来说,再正常不过。如果小于这段内存,多余部分就空着。
      5 从640K到1M-64K,这段内存就很难说清了。这段内存中有一部分被硬件占有,有一部分是显示缓冲区点有,还有一部分是系统ROM占有。
      6 从1M-64K到1M之间的这段64K的内存叫作HMA。这段内存是小孩没娘,说来话长,我们先不说他。
    PYG19周年生日快乐!
  • TA的每日心情
    难过
    7 天前
  • 签到天数: 11 天

    [LV.3]偶尔看看II

     楼主| 发表于 2005-2-7 22:24:27 | 显示全部楼层
    2.2 验证上面的理论

    2.2.1 中断向量表
        中断向量表就是所有中断向量首地址表,这里保存着每个中断程序的首地址,几乎所有的汇编书都把中断后面后面的章节中,并且对中断的解释也仅从字面意思解释,所以导致大学对中断的不重要和误解。没耐心的没到这个章节就不学汇编了,有耐心的到这里才豁然开朗。我现在不讲中断的原意。我直接告诉你,你把中断当成API也许更合适。也就是说,别人把很多已作好的功能放到了内存中。并且把调用这一功能的号告诉了你,你只要调用这些功能号,系统就自动从这个中断向量表中找到对应的中断,然后执行你的功能。
        首先让你感受一下中断的魅力一下吧。比如中断21H的2A功能调用是读取系统的日期,这个调用的规则是,调用前AH寄存器置为2A。调用后年在CX中,月在DH中,DL在日中,星期在AL中。
    -a
    139D:0100 mov ah,2a
    139D:0102 int 21
    139D:0104 int 3
    139D:0105
    -g=100

    AX=2A05  BX=0000  CX=07D4  DX=0C18  SP=FFEE  BP=0000  SI=0000  DI=0000
    DS=139D  ES=139D  SS=139D  CS=139D  IP=0104  NV UP EI PL NZ NA PO NC
    139D:0104 CC            INT    3
    -
    可能上面的程序你目前还看不懂。不过没关系,“mov ah,2a”表示调用功能号是2a号。“int 21”表示调用十六进制21号中断,“int 3”表示3号中断,表示程序运行到这一句时停一下。“g=100”表示从“139D:0100 ”开始执行。
    AX=2A05  BX=0000  CX=07D4  DX=0C18  SP=FFEE  BP=0000  SI=0000  DI=0000
    DS=139D  ES=139D  SS=139D  CS=139D  IP=0104  NV UP EI PL NZ NA PO NC
    表示执行的结果。其中CX是年,这个年是由CX中存。07D4十进制就是2004年。DH+DL=DX,所以DH=0C,DL=18。二者转化为十进制就是DH=12,DL=24,也就是今天了。AX=AH+AL=2A05,所以AL=05。那就是今天是星期五。
    上面可能你们现在还看不懂,不过通过解说你应该可以知道,仅仅两行命令,就读到了现在的值。现在需要作的就是把这些值提取出来用作他用了。

        从中断的作来与中断向量表又有什么关系呢?原来你在汇编里运行int 21时,系统就在上面的中断向量表中找到int 21的中断地址,该中断的地址应该位于:0000:0084~0000:0087,具体算法前面已说明了。
    -d 0000:0084 0087
    0000:0080              7C 10 A7 00                              |...
    -
    找到内容是:00A7:107C。然后系统就转到这个地址执行int 21。

    2.2.2 系统数据区前面都已说明过。不再多说。系统区,很多DOS中断程序实现部分就在这个区。程序运行区依不同的程序而不用。

    2.2.3 640K~1M之间,这期间有些地方是ROM,有些地方是硬件的BIOS区。我仅以两个例子说明这一区。
      ROM区:ROM区就是只读内存,也就是说这个区的数据只能读不能写。比如F000:0000开始的内存是ROM。我们来写一下,然后再看看效果。
    -d f000:0000 0005 '显示由F000:0000到F000:0005的六个字节值。
    F000:0000  04 E8 A2 FF F9 C3                                ......
    -e f000:0000    '修改命令
    F000:0000  04.00  E8.00  A2.00  FF.00  F9.00  C3.00'注意,.后面的是我改的,把这几个值都改成0了。
    -d f000:0000 0005 '再次显示这个区的数据。
    F000:0000  04 E8 A2 FF F9 C3                                ......
    -
    通过上面测试,发现该区数据仍然未改变。但你要是试别的RAM区的,肯定会变。如果想试你自己试试吧。

      显示缓冲区:在文本方式下,B800:0000开始的地址保存着屏幕上每个字符位置的值。在文本方式下,屏幕被分为80 X 25。每个位置有两个值,一个值是ASCII字符,一个值是该ASCII的属性值(主要是颜色)。所以一个屏幕共有80X25X2=400个字符。
    我们来改:
    -d b800:0000 0010 '显示屏幕缓冲区的内容,注意此时本行最左边的“-”是屏幕左上角。
    B800:0000  2D 07 64 07 20 07 62 07-38 07 30 07 30 07 3A 07  -.d. .b.8.0.0.:.
    B800:0010  30                                                0
    -
    看上面的命令,屏幕最上边一行是“-d b800:0000 0010”,所以他的内容就是“2D 07 64 07 20 07 62 07-38 07 30 07 30 07 3A 07”其中,2D是“-”的ASCII值,07是“-”的属性值。64是“d”的ASCII值,07是“d”的属性值。。。。。
    现在修改这些值。我把左上角的字改成黄颜色的“-”,那当然是改b800:0001的属性值了。
    -e b800:0001  0e
    是不是左上角的颜色变成黄色了吗?
    好了,把第二个字符变成绿色的“-”吧?
    -e b800:0002 2d 0b
    变了吗?
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2005-2-15 18:26:38 | 显示全部楼层
    老大这个讲座的内容还有续文吗?
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2005-2-18 13:30:19 | 显示全部楼层
    都存起来了, 慢慢学。。。谢谢
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2005-3-7 21:49:33 | 显示全部楼层
    好啊

    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

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