编译语言入门(六)

汇编语言入门(六)

汇编语言入门(六)
2010年12月12日
  4.2编写我们的Hello,world思路。
  开始编写我们的第一个程序。
  程序要求:显示一个“Hello,Mr.286.”怎么样?
  思路:
  1要显示一个字符串,根据前面我让你们记的七八个指令够吗?答案是:不仅够,而且还用不完。
  首先定义一下总可以吧。
  hellostr db'Hello,Mr.286.$'
  最后的$不要忘了。
  2首先要考虑的问题就是找中断,找到合适的中断,该中断就能帮我们完成这个显示任务。我找到(在哪找到的,怎么找到的,别问我,到网上或书上都能找到):
  -------------------------------------------
  中断INT21H功能09H
  功能描述:输出一个字符串到标准输出设备上。如果输出操作被重定向,那么,将无法判断磁盘已满
  入口参数:AH=09H
  DSX=待输出字符的地址
  说明:待显示的字符串以’$’作为其结束标志
  出口参数:无 
  由上面看到,我们所需要作的就是把DS指向数据段,DX指向字符串的地址,AH等于9H,调用21h中断。
  movds,数据段地址
  lea dx,hellostr'hellostr已在前面1中定义了。
  mov ah,9h
  int 21h。
  由于只要在调用int 21h之前把准备的东西准备齐就行了,所以int 21h前面三行的顺序并不重要。
  3退出程序,运行完总要退出呀。再查中断手册
  --------------------------------------------
  中断INT21H功能4CH
  功能描述:终止程序的执行,并可返回一个代码
  入口参数:AH=4CH
  AL=返回的代码
  出口参数:无
  --------------------------------------------
  movah,4Ch
  moval,0
  int21h
  或
  movax,4c00h
  int21h
  这里需要说明的是返回代码有什么用,返回给谁?返回给操作系统,因为是操作系统DOS调用的这个程序,这个返回值可以通过批处理中的errorlevel得到,这里不多说明,实际上操作系统很少处理这一值,因此al你随便写什么值影响都不大。
  4.3程序实现
  data SEGMENT
  msg DB'Hello,Mr.286.$'
  data ENDS
  code SEGMENT
  ASSUME CS:code,DS:data
  start:
  MOV AX,data
  MOV DS,AX ;把data段地址赋给DS段寄存器
  lea dx,msg ;把msg偏址传给dx通用数据寄存器
  mov ah,9h
  int 21h ;调用09H功能号功能
  MOV AX,4C00h
  INT 21h ;调用4C00功能
  code ENDS
  END start
  4.4编译运行。
  把上面程序保存成hello286.asm后,就可以编译运行了。进入DOS,进入汇编目录,如果还没下载,到前面找下载地址。
  =================================================
  E:\Download\Masm>masmhello286.asm
  Microsoft(R)MacroAssemblerVersion5.00
  Copyright(C)MicrosoftCorp1981-1985,1987.Allrightsreserved.
  Objectfilename[hello286.OBJ]:
  Sourcelisting[NUL.LST]:
  Cross-reference[NUL.CRF]:
  50408+415320Bytessymbolspacefree
  0WarningErrors
  0SevereErrors
  说明:上面连续三个回车,表示我要的都是默认值。下面是零个警告,零个严重错误,(当然了,我的程序还敢错吗?)
  E:\Download\Masm>linkhello286
  Microsoft(R)OverlayLinkerVersion3.60
  Copyright(C)MicrosoftCorp1983-1987.Allrightsreserved.
  RunFile[HELLO286.EXE]:
  ListFile[NUL.MAP]:
  Libraries[.LIB]:
  LINK:warningL4021:nostacksegment
  说明:三个回车仍要默认,后面有个警告,没有栈段,这个没关系,没有的话系统会自动给一个。
  E:\Download\Masm>hello286
  Hello,Mr.286.
  说明:运行成功。
  E:\Download\Masm>
  4.4深度思考
  4.4.1是不是数据必须放数据段,代码必段放代码段呢?
  答,代码段必放代码段,否则你怎么执行呀?但数据也可以放到代码段,只是程序要作修改。code SEGMENT
  ASSUME CS:code,DS:data
  msg DB'Hello,Mr.286.$'
  start:MOV AX,data
  MOV DS,AX
  lea dx,msg
  mov ah,9h
  int 21h
  MOV AX,4C00h
  INT 21h
  code ENDS
  END start
  编译后仍然可以。
  4.4.2我编的程序在内存中是什么样子的呢?
  ------------------------------------
  E:\Download\Masm>debughello286.exe
  -u
  1420:0000B81F14MOVAX,141F
  1420:00038ED8MOVDS,AX
  1420:00058D160000LEADX,[0000]
  1420:0009B409MOVAH,09
  1420:000BCD21INT21
  1420:000DB8004CMOVAX,4C00
  1420:0010CD21INT21
  1420:0012FF362421PUSH[2124]
  1420:0016E87763CALL6390
  1420:001983C406ADDSP,+06
  1420:001CFF362421PUSH[2124]
  -d141f:0000L20
  141F:000048656C6C6F2C204D-722E3238362E2400Hello,Mr.286.$.
  141F:0010B81F148ED88D1600-00B409CD21B8004C............!..L
  -q
  E:\Download\Masm>
  ------------------------------------------
  上面是什么呀?还记得前面说的吗?
  1420:0000B81F14MOVAX,141F
  |||||
  段址:偏址机器语言mov指令把段地址的地址(141f)赋值给AX寄存器。
  1420:0012后面的是垃圾数据,不用管它,把上面程序与源程序作一个比较,看有什么不用,差别在于把标号语言转成实际地址了。
  程序前两行一执行,数据段地址就变成了141f,而那个字符串偏移地址在0000,由(LEADX,[0000]看出),所以我用-d
  141f:0000L20(后面L20表示只显示20个字节),就能把段地址显示出来了。
  所以刚才的程序在内存中就变成了:
  141f:0000Hello,Mr.286.$----->这是段地址里的内存
  1420:0000B81F14MOVAX,141F------>这是代码段里的内存。data变成了实际地址
  1420:00038ED8MOVDS,AX
  1420:00058D160000LEADX,[0000]
  ------>偏址变成了0000,因为实际上msg也就是从头开始的。当然是0了。
  1420:0009B409MOVAH,09------->注意Debug里,默认的是十六进制
  1420:000BCD21INT21
  1420:000DB8004CMOVAX,4C00
  1420:0010CD21INT21