深圳市航顺芯片技术研发有限公司
直播中

caokyo

12年用户 522经验值
私信 关注
[问答]

请问一下x86汇编语言有哪些配套代码呢

请问一下x86汇编语言有哪些配套代码呢?

回帖(1)

朱艳丽

2021-10-25 16:45:50
  c05_mbr.asm
  ;代码清单5-1
  ;文件名:c05_mbr.asm
  ;文件说明:硬盘主引导扇区代码
  ;创建日期:2011-3-31 21:15
  mov ax,0xb800 ;指向文本模式的显示缓冲区
  mov es,ax
  ;以下显示字符串“Label offset:”
  mov byte [es:0x00],‘L’
  mov byte [es:0x01],0x07
  mov byte [es:0x02],‘a’
  mov byte [es:0x03],0x07
  mov byte [es:0x04],‘b’
  mov byte [es:0x05],0x07
  mov byte [es:0x06],‘e’
  mov byte [es:0x07],0x07
  mov byte [es:0x08],‘l’
  mov byte [es:0x09],0x07
  mov byte [es:0x0a],‘ ’
  mov byte [es:0x0b],0x07
  mov byte [es:0x0c],“o”
  mov byte [es:0x0d],0x07
  mov byte [es:0x0e],‘f’
  mov byte [es:0x0f],0x07
  mov byte [es:0x10],‘f’
  mov byte [es:0x11],0x07
  mov byte [es:0x12],‘s’
  mov byte [es:0x13],0x07
  mov byte [es:0x14],‘e’
  mov byte [es:0x15],0x07
  mov byte [es:0x16],‘t’
  mov byte [es:0x17],0x07
  mov byte [es:0x18],‘:’
  mov byte [es:0x19],0x07
  mov ax,number ;取得标号number的偏移地址
  mov bx,10
  ;设置数据段的基地址
  mov cx,cs
  mov ds,cx
  ;求个位上的数字
  mov dx,0
  div bx
  mov [0x7c00+number+0x00],dl ;保存个位上的数字
  ;求十位上的数字
  xor dx,dx
  div bx
  mov [0x7c00+number+0x01],dl ;保存十位上的数字
  ;求百位上的数字
  xor dx,dx
  div bx
  mov [0x7c00+number+0x02],dl ;保存百位上的数字
  ;求千位上的数字
  xor dx,dx
  div bx
  mov [0x7c00+number+0x03],dl ;保存千位上的数字
  ;求万位上的数字
  xor dx,dx
  div bx
  mov [0x7c00+number+0x04],dl ;保存万位上的数字
  ;以下用十进制显示标号的偏移地址
  mov al,[0x7c00+number+0x04]
  add al,0x30
  mov [es:0x1a],al
  mov byte [es:0x1b],0x04
  mov al,[0x7c00+number+0x03]
  add al,0x30
  mov [es:0x1c],al
  mov byte [es:0x1d],0x04
  mov al,[0x7c00+number+0x02]
  add al,0x30
  mov [es:0x1e],al
  mov byte [es:0x1f],0x04
  mov al,[0x7c00+number+0x01]
  add al,0x30
  mov [es:0x20],al
  mov byte [es:0x21],0x04
  mov al,[0x7c00+number+0x00]
  add al,0x30
  mov [es:0x22],al
  mov byte [es:0x23],0x04
  mov byte [es:0x24],‘D’
  mov byte [es:0x25],0x07
  infi: jmp near infi ;无限循环
  number db 0,0,0,0,0
  times 203 db 0
  db 0x55,0xaa
  c06_mbr.asm
  ;代码清单6-1
  ;文件名:c06_mbr.asm
  ;文件说明:硬盘主引导扇区代码
  ;创建日期:2011-4-12 22:12
  jmp near start
  mytext db ‘L’,0x07,‘a’,0x07,‘b’,0x07,‘e’,0x07,‘l’,0x07,‘ ’,0x07,‘o’,0x07,
  ‘f’,0x07,‘f’,0x07,‘s’,0x07,‘e’,0x07,‘t’,0x07,‘:’,0x07
  number db 0,0,0,0,0
  start:
  mov ax,0x07c0 ;设置数据段基地址
  mov ds,ax ;ds寄存器一般保存数据段基地址
  mov ax,0xb800 ;设置附加段基地址
  mov es,ax ;这里附加段指向显存位置,存放在es寄存器中
  cld ;将方向标志位DF清零,以指示传送是负方向的,与此相对应的指令是std
  mov si,mytext ;movsw指令原始数据串需要存放在ds:si位置,目的地址为es:di,因为ds目前指示的是当前代码段基地址地址,因此只要把偏移mytext存入si寄存器即可
  mov di,0 ;当前es指示显存起始位置,因此只要把偏移0存入di即可
  mov cx,(number-mytext)/2 ;实际上等于 13,cx作为计数器,每进行一次rep指令cx-1
  rep movsw ;一次传送一个字(两个字节)
  ;得到标号所代表的偏移地址
  mov ax,number ;此代码目的旨在显示number的偏移地址
  ;计算各个数位
  mov bx,ax ;bx指向当前number偏移地址
  mov cx,5 ;循环次数
  mov si,10 ;除数
  digit:
  xor dx,dx ;dx(被除数高16位)清零
  div si ;除法
  mov [bx],dl ;保存数位 ;为什么这里不用加0x7c00了?
  inc bx ;bx自加1,指向下一个内存单元,number一共定义了5个字节内存单元
  loop digit
  ;显示各个数位
  mov bx,number
  mov si,4
  show:
  mov al,[bx+si] ;从后往前显示
  add al,0x30
  mov ah,0x04
  mov [es:di],ax
  add di,2
  dec si
  jns show ;上一条指令符号位为SF=0(结果为非负)时跳转
  mov word [es:di],0x0744
  jmp near $ ;无限循环
  times 510-($-$$) db 0 ;512字节减去之后两个db指令=510字节,$当前指令偏移,$$当前代码段起始位置,填充字节0(db 0)
  db 0x55,0xaa
  c07_mbr.asm
  ;代码清单7-1
  ;文件名:c07_mbr.asm
  ;文件说明:硬盘主引导扇区代码
  ;创建日期:2011-4-13 18:02
  jmp near start
  message db ‘1+2+3+.。.+100=’
  start:
  mov ax,0x7c0 ;设置数据段的段基地址
  mov ds,ax
  mov ax,0xb800 ;设置附加段基址到显示缓冲区
  mov es,ax
  ;以下显示字符串
  mov si,message
  mov di,0
  mov cx,start-message
  @g:
  mov al,[si] ;因为这是硬盘主引导扇区代码,因此被加载到0x7c00,[si]=[ds:si],就是相对于代码段开头的相对偏移,这个相对偏移就是标签message的值
  mov [es:di],al
  inc di ;di用做显存段地址的相对偏移,字符内容信息放在低一个字节
  mov byte [es:di],0x07
  inc di ;字符显示信息放在高一个字节
  inc si ;si用作寻址字符串相对偏移
  loop @g
  ;以下计算1到100的和
  xor ax,ax ;清空ax寄存器,存放结果
  mov cx,1
  @f:
  add ax,cx
  inc cx ;cx做累加器
  cmp cx,100
  jle @f ;小于等于时跳转
  ;以下计算累加和的每个数位
  xor cx,cx ;设置堆栈段的段基地址
  mov ss,cx
  mov sp,cx ;堆栈段指针和段基址都在0x0000处,堆栈段从高地址向低地址生长
  mov bx,10
  xor cx,cx
  @d:
  inc cx ;压栈中用cx记录一共压入栈元素个数,以便之后出栈时能及时停止pop
  xor dx,dx ;被除数[dx:ax]
  div bx ;除数bx
  or dl,0x30 ;余数在dx中,但是余数最多到9,因此在dl中就够了,加0x30得到ASCII码
  push dx ;dx中只有dl有意义,但是压栈的单位必须是字(两个字节)
  cmp ax,0
  jne @d ;循环跳出时,结果5050每一位被放在栈中
  ;以下显示各个数位
  @a:
  pop dx ;出栈,栈顶元素是千位,百位,十位,个位
  mov [es:di],dl
  inc di
  mov byte [es:di],0x07
  inc di
  loop @a
  jmp near $
  8086寻址方式总结:
  1.寄存器寻址 :mov ax,cx
  2.立即寻址 :add bx,0xf000 (目的操作数立即数寻址,源操作数寄存器寻址)
  3.直接寻址 :mov ax,[0x5c0f]
  4.基址寻址:利用基址寄存器bx/bp中的值作为偏移地址,其中bx默认段寄存器为ds(数据段),bp默认段寄存器为ss(堆栈段)。堆栈段指针寄存器为sp,不要混淆。
  如:mov dx,[bp-2]
  5.变址寻址:利用变址寄存器si/di中的值作为偏移地址,默认段寄存器为ds
  如:mov [si+0x100],al
  6.基址变址寻址:利用基址寄存器bx/bp和变址寄存器si/di相加作为偏移地址
  如:add word [bx+di],0x3000
  加载程序 源程序c08_mbr.asm
  ;代码清单8-1
  ;文件名:c08_mbr.asm
  ;文件说明:硬盘主引导扇区代码(加载程序)
  ;创建日期:2011-5-5 18:17
  app_lba_start equ 100 ;声明常数(用户程序起始逻辑扇区号)
  ;常数的声明不会占用汇编地址
  SECTION mbr align=16 vstart=0x7c00
  ;设置堆栈段和栈指针
  mov ax,0
  mov ss,ax
  mov sp,ax
  mov ax,[cs:phy_base] ;计算用于加载用户程序的逻辑段地址
  mov dx,[cs:phy_base+0x02]
  mov bx,16
  div bx
  mov ds,ax ;令DS和ES指向该段以进行操作
  mov es,ax
  ;以下读取程序的起始部分
  xor di,di
  mov si,app_lba_start ;程序在硬盘上的起始逻辑扇区号
  xor bx,bx ;加载到DS:0x0000处
  call read_hard_disk_0
  ;以下判断整个程序有多大
  mov dx,[2] ;曾经把dx写成了ds,花了二十分钟排错
  mov ax,[0]
  mov bx,512 ;512字节每扇区
  div bx
  cmp dx,0
  jnz @1 ;未除尽,因此结果比实际扇区数少1
  dec ax ;已经读了一个扇区,扇区总数减1
  @1:
  cmp ax,0 ;考虑实际长度小于等于512个字节的情况
  jz direct
  ;读取剩余的扇区
  push ds ;以下要用到并改变DS寄存器
  mov cx,ax ;循环次数(剩余扇区数)
  @2:
  mov ax,ds
  add ax,0x20 ;得到下一个以512字节为边界的段地址
  mov ds,ax
  xor bx,bx ;每次读时,偏移地址始终为0x0000
  inc si ;下一个逻辑扇区
  call read_hard_disk_0
  loop @2 ;循环读,直到读完整个功能程序
  pop ds ;恢复数据段基址到用户程序头部段
  ;计算入口点代码段基址
  direct:
  mov dx,[0x08]
  mov ax,[0x06]
  call calc_segment_base
  mov [0x06],ax ;回填修正后的入口点代码段基址
  ;开始处理段重定位表
  mov cx,[0x0a] ;需要重定位的项目数量
  mov bx,0x0c ;重定位表首地址
  realloc:
  mov dx,[bx+0x02] ;32位地址的高16位
  mov ax,[bx]
  call calc_segment_base
  mov [bx],ax ;回填段的基址
  add bx,4 ;下一个重定位项(每项占4个字节)
  loop realloc
  jmp far [0x04] ;转移到用户程序
  ;-------------------------------------------------------------------------------
  read_hard_disk_0: ;从硬盘读取一个逻辑扇区
  ;输入:DI:SI=起始逻辑扇区号
  ; DS:BX=目标缓冲区地址
  push ax
  push bx
  push cx
  push dx
  mov dx,0x1f2
  mov al,1
  out dx,al ;读取的扇区数
  inc dx ;0x1f3
  mov ax,si
  out dx,al ;LBA地址7~0
  inc dx ;0x1f4
  mov al,ah
  out dx,al ;LBA地址15~8
  inc dx ;0x1f5
  mov ax,di
  out dx,al ;LBA地址23~16
  inc dx ;0x1f6
  mov al,0xe0 ;LBA28模式,主盘
  or al,ah ;LBA地址27~24
  out dx,al
  inc dx ;0x1f7
  mov al,0x20 ;读命令
  out dx,al
  .waits:
  in al,dx
  and al,0x88
  cmp al,0x08
  jnz .waits ;不忙,且硬盘已准备好数据传输
  mov cx,256 ;总共要读取的字数
  mov dx,0x1f0
  .readw:
  in ax,dx
  mov [bx],ax
  add bx,2
  loop .readw
  pop dx
  pop cx
  pop bx
  pop ax
  ret
  ;-------------------------------------------------------------------------------
  calc_segment_base: ;计算16位段地址
  ;输入:DX:AX=32位物理地址
  ;返回:AX=16位段基地址
  push dx
  add ax,[cs:phy_base]
  adc dx,[cs:phy_base+0x02]
  shr ax,4
  ror dx,4
  and dx,0xf000
  or ax,dx
  pop dx
  ret
  ;-------------------------------------------------------------------------------
  phy_base dd 0x10000 ;用户程序被加载的物理起始地址
  times 510-($-$$) db 0
  db 0x55,0xaa
举报

更多回帖

发帖
×
20
完善资料,
赚取积分