x86汇编语言学习笔记

以李忠老师的《x86汇编语言:从实模式到保护模式》为学习教材!

第一章 十六进制计数法

学习二进制,十进制,十六进制,以及他们之间的相互转换(太简单了,省略不记)

第二章 处理器,内存和指令

  • Intel处理器用的是小端格式 0000H(5D)0001H(00) —> 0x 005D
  • 一个处理器能识别的指令的集合,称之为该处理器的指令集
  • 一般指令组成:操作码+操作数(有些没有操作数)

    • 比如:B8005D,B8是一个字节的操作码(有些是两个字节),005D是操作数
    • 可以立即在指令里面取得的操作数称之为立即数
  • 因为操作码和操作数都是2进制数,为了区分,所以要分开存放在代码区和数据区

Intel8086处理器:

  • 有8个16bit的通用寄存器:AX,BX,CX,DX,SI,DI,BP,SP
  • 前四个又可以分成8个8bit的寄存器:AH,AL,BH,BL

处理器是自动化的,给出一个首地址,就会自动执行下去,因此一个工作他的所有代码应该集中起来,处于内存的某一段位置,称之为代码段.
数据同理,有数据段.

  • 因为程序在内存中的位置是随机的,因此我们不能使用绝对内存地址.
  • 所以处理器使用了内存分段机制:通过段:偏移地址的方式找到真实地址
  • 在开始前,CS(代码段寄存器)和DS(数据段寄存器)指向程序代码段和数据段的开始位置,然后处理器将指令里面的地址都视作偏移地址.

8086的内存分段机制
CS指向代码段起始位置,IP指向偏移地址,共同组成逻辑地址,由总线接口转成物理地址
还有6字节的指令预取队列
有四个段寄存器(CS,DS,ES附加段寄存器,SS栈寄存器)
8086的总线有20根,而寄存器却是16位的,最经典的情况,段:偏移地址中将段左移4bit

第三章 汇编语言和汇编软件


其实就是编译器+编辑器+16进制文件查看器

第四章 虚拟机的安装和使用

VirtualBox…

前四章,预备知识到这里就结束了,因为太容易所以写的很简略


第5章 编写主引导扇区代码

第一个扇区叫主引导扇区,有512字节,开机后被加载到内存地址0x07c00处,然后判断是否有效(扇区最后两个字节为0x55,0xAA,则有效),然后跳到内存0x07c00处开始执行.

显卡和显存

  • 有两种显示模式:图形模式,文本模式
  • 显卡在加电自检后初始化到80*25的文本模式
  • 8086有1M的地址数,00000H~FFFFFH

    • 00000H~9FFFFH:给常规内存(内存条)
    • A0000HBFFFF固定给显卡)
    • F0000H~FFFFFH:给ROM-BIOS

传送指令MOV
mov 目的操作数,源操作数

  • mov只改变目的操作数的值,不改变源操作数的值
  • Intel不允许直接将立即数传送到段寄存器,于是只能
  • mov 段寄存器,通用寄存器
  • mov 段寄存器,内存单元

mov byte [es:0x00],'L'

  • byte/word:16bit字节/8bit字,修饰目的操作数,如果目的操作数明确位数,则无需修饰符
  • []:取内存地址的值
  • es:代表使用ES段寄存器,而不是默认的DS
  • ‘’,使用字符需要用’’

每条指令都可以有标号

  1. flag:
  2. mov byte [es:0x00],'L'

和C语言的Goto的使用方式一样

显示十进制数

  • 需要通过除余操作来获取各位的数
  • 加上0x30为ASCII上对应数字的值

声明数据命令

  • 声明字节命令db
  • 声明字命令dw
  • 声明四字命令dq

除法命令div(两种使用方法)

  1. 16位/8位

    1. 被除数必须在AX中,执行后,商在AL中,余数在AH中
  2. 32位/16位

    1. 被除数高位在DX中,低位在AX中,执行后,商在AX中,余数在DX中

位异或命令xor
还有跳转命令jmp

全部代码:

  1. ;代码清单5-1
  2. ;文件名:c05_mbr.asm
  3. ;文件说明:硬盘主引导扇区代码
  4. ;创建日期:2011-3-31 21:15
  5. mov ax,0xb800 ;指向文本模式的显示缓冲区
  6. mov es,ax ;因为立即数不能字节传入段寄存器
  7. ;以下显示字符串"Label offset:"
  8. mov byte [es:0x00],'L'
  9. mov byte [es:0x01],0x07
  10. mov byte [es:0x02],'a'
  11. mov byte [es:0x03],0x07
  12. mov byte [es:0x04],'b'
  13. mov byte [es:0x05],0x07
  14. mov byte [es:0x06],'e'
  15. mov byte [es:0x07],0x07
  16. mov byte [es:0x08],'l'
  17. mov byte [es:0x09],0x07
  18. mov byte [es:0x0a],' '
  19. mov byte [es:0x0b],0x07
  20. mov byte [es:0x0c],"o"
  21. mov byte [es:0x0d],0x07
  22. mov byte [es:0x0e],'f'
  23. mov byte [es:0x0f],0x07
  24. mov byte [es:0x10],'f'
  25. mov byte [es:0x11],0x07
  26. mov byte [es:0x12],'s'
  27. mov byte [es:0x13],0x07
  28. mov byte [es:0x14],'e'
  29. mov byte [es:0x15],0x07
  30. mov byte [es:0x16],'t'
  31. mov byte [es:0x17],0x07
  32. mov byte [es:0x18],':'
  33. mov byte [es:0x19],0x07
  34. ;这前面的代码显示"Label offset:"
  35. ;下面的代码是以十进制显示number的偏移地址
  36. mov ax,number ;取得标号number的偏移地址
  37. mov bx,10 ;用来进行运算,取各位的数
  38. ;设置数据段的基地址
  39. mov cx,cs ;将代码段的地址传入数据段
  40. mov ds,cx
  41. ;求个位上的数字
  42. mov dx,0 ;dx=0,表示是32位/16位的情况
  43. div bx ;标号number的偏移地址除以10
  44. mov [0x7c00+number+0x00],dl ;保存个位上的数字
  45. ;求十位上的数字
  46. xor dx,dx
  47. div bx
  48. mov [0x7c00+number+0x01],dl ;保存十位上的数字
  49. ;求百位上的数字
  50. xor dx,dx
  51. div bx
  52. mov [0x7c00+number+0x02],dl ;保存百位上的数字
  53. ;求千位上的数字
  54. xor dx,dx
  55. div bx
  56. mov [0x7c00+number+0x03],dl ;保存千位上的数字
  57. ;求万位上的数字
  58. xor dx,dx
  59. div bx
  60. mov [0x7c00+number+0x04],dl ;保存万位上的数字
  61. ;以下用十进制显示标号的偏移地址
  62. mov al,[0x7c00+number+0x04]
  63. add al,0x30
  64. mov [es:0x1a],al
  65. mov byte [es:0x1b],0x04
  66. mov al,[0x7c00+number+0x03]
  67. add al,0x30
  68. mov [es:0x1c],al
  69. mov byte [es:0x1d],0x04
  70. mov al,[0x7c00+number+0x02]
  71. add al,0x30
  72. mov [es:0x1e],al
  73. mov byte [es:0x1f],0x04
  74. mov al,[0x7c00+number+0x01]
  75. add al,0x30
  76. mov [es:0x20],al
  77. mov byte [es:0x21],0x04
  78. mov al,[0x7c00+number+0x00]
  79. add al,0x30
  80. mov [es:0x22],al
  81. mov byte [es:0x23],0x04
  82. mov byte [es:0x24],'D'
  83. mov byte [es:0x25],0x07
  84. infi: jmp near infi ;无限循环,jum跳转命令,后面接偏移地址,直接跳转,如果有near,跳转到相对于当前命令地址的偏移地址
  85. number db 0,0,0,0,0 ;用于占位(5个字节),位置用来保存各位的值
  86. times 203 db 0 ;把第一扇区空闲位填0
  87. db 0x55,0xaa ;检查的扇区的标志位

第六章 相同的功能,不同的代码

数据区数据写在前面,用跳转命令跳转到真正的执行代码处

数据声明时使用字面值

div是无符号数除法指令,有符号的应该用idiv

用idiv时需要注意不能溢出,如果需要把被除数扩展成32bit,用cwd命令