首页 > 编程语言 >8086 汇编学习 Part 2

8086 汇编学习 Part 2

时间:2024-04-05 23:22:22浏览次数:27  
标签:汇编 8086 16 指令 地址 Part 内存 寄存器 CPU

寄存器及数据存储

CPU组成

  • 运算器进行信息处理
  • 寄存器进行信息存储
  • 控制器协调各种器件进行工作
  • 内部总线先实现 CPU 内各个器件之间的联系

寄存器

寄存器是 CPU 内部的信息存储单元。
8086 CPU 有 14 个寄存器:

  • 通用寄存器:AX, BX, CX, DX
  • 变址寄存器:SI,DI
  • 指针寄存器:SP,BP
  • 指令指针寄存器: IP
  • 段寄存器: CS, SS, DS, ES
  • 标志寄存器: PSW
    8086 CPU 所有的寄存器都是 16 位的,可以存放两个字节。

通用寄存器

一个 16 位寄存器存储一个 16 位的数据
每一位保存一个二进制位能保存的最大值为 \(2^{16} - 1\) (FFFFH)

如何兼容 8 位寄存器环境下编写的程序?

通用寄存器均可以分为两个独立的 8 位寄存器使用,AX 可以分为 AH 和 AL,BX, CX, DX 同理

“字”在寄存器中的存储

8086 是 16 位 CPU,字长 为 16 bit
一个可以存在一个 16 位寄存器中

  • 这个字的高位字节存在这个寄存器的高 8 位寄存器
  • 这个字的低位字节存在这个寄存器的低 8 位寄存器

mov指令

  • MOV (通用寄存器) , (数据)
  • MOV (寄存器) , (寄存器)
  • MOV (寄存器) , (内存单元)
  • MOV (内存单元) , (寄存器)
  • MOV (段寄存器) , (通用寄存器)
    汇编指令不区分大小写
    数值默认为 10 进制,写入 16 进制需在末尾添加 'H'
    在低位寄存器出现溢出时,不会进位到高位

确定物理地址的方法

CPU 访问内存单元时要给出内存单元的地址。
所有内存单元构成的存储空间是一个一维的线性空间。
每一个内存单元都有唯一的地址,叫物理地址
8086 有 20 位地址总线,可传送 20 位地址,寻址能力是 \(2^{20} = 1 M\) 。
8086 是 16 位结构的 CPU,运算器一次最多处理 16 位的数据,寄存器的最大宽度为 16 位。
在 8086 内部处理的、传输、暂存的地址也是 16 位,寻址能力只有 64 KB

如何处理地址总线 20 位的寻址能力受限于 16 位地址长度这一问题?

用两个 16 位地址(段地址和偏移地址)合成一个 20 位的物理地址。
地址加法器合成物理地址的方法: \(物理地址 = 段地址 * 16 + 偏移地址\)

内存的分段表示法

内存并没有分段,段的划分来自于 CPU
Assembly336b8fa9b12d81a3d.png
段地址 : 偏移地址
同一段内存可以有多种分段方案

  • \(段地址 * 16\) 必然是 16 的倍数, 所以一个段的起始地址也一定是 16 的倍数。
  • 偏移地址为 16 位,16 位地址的寻址能力为 64K,所以一个段的长度最大为 64K。
  • 可以用不同的段地址和偏移地址形成同一个物理地址。
    8086 有丰富的取址方式,因此偏移地址可以用多种方法提供。

段寄存器

段寄存器存放段地址,段寄存器只能由寄存器赋值,不支持用字面值直接赋值。
8086 CPU 有 4 个段地寄存器

  • CS 代码段寄存器
  • DS 数据段寄存器
  • SS 栈段寄存器
  • ES 附加段寄存器

Debug

Debug 是 DOS 系统中著名的调试程序。
使用 Debug 程序,可以查看 CPU 各种寄存器中的内容、内存的情况,并且在机器指令级跟踪程序的运行。

常用 Debug 命令

  • R 命令 查看、改变 CPU 寄存器的内容
    -R 查看所有寄存器内容
    -R (寄存器名) (数据) 修改特定寄存器中的数据
  • D 命令 查看内存中的内容
    -D 列出预设地址内存处的 128 个字节的内容,每次偏移 128 个字节
    -D (段地址:偏移地址) 列出内存中指定地址处的内容
    -D (段地址:偏移地址) (结尾偏移地址) 列出内存中指定地址范围内的内容
  • E 命令 改变内存中的内容
    -E (段地址:偏移地址) (数据1) (数据2) .... 改变内存中的内容
    -E (段地址:偏移地址) 逐个询问式修改,空格代表接受并继续回车代表修改结束
  • U 命令将内存中的机器指令翻译成汇编指令
    -U (段地址:偏移地址)
  • A 命令以汇编指令的格式在内存中写入机器指令
    -A (段地址:偏移地址) 逐行输入汇编指令
  • T 命令执行机器指令
    -T 执行 CS:IP 处的指令
  • Q 命令推出 Debug

CS、IP 与代码段

CPU 将内存中 CS:IP 指向的内容当作指令执行。

8086 读取和执行指令

  1. 从 CS:IP 指向内存单元读取指令,读取的指令进入指令缓冲器
  2. IP = IP + 所读指令的长度,从而指向下一条指令
  3. 执行指令,跳转到步骤 1
  4. 重复此过程

jmp 指令

执行何处的指令,取决于 CS:IP 指向的数据
可以通过改变 CS 和 IP 中的内容,来控制 CPU 要执行的目标指令
Bebug 可以改变 CS 和 IP 的值,但是 Debug 是调试手段,并非程序方式。
8086 CPU 不提供对 IP 修改的指令,不能使用 MOV 指令修改,只能由 CPU 自行修改
使用转移指令 jmp

  • jmp (段地址:偏移地址) 用段地址修改 CS ,偏移地址修改 IP
  • jmp (某一合法寄存器) 用某一合法寄存器的数据修改 IP

内存中”字“的存储

8086 CPU 中,16 位作为 1 个字。
16 位的字,高 8 位存放高字节,低 8 位存放低字节,从而实现存储在 1 个 16 位的寄存器中。

字单元

子单元由两个地址连续的内存单元组成,存放一个字型数据
在一个字单元中,低地址单元存放低位字节,高地址单元存放高位字节

用 DS 和 [addres] 实现字的传送

CPU 要读取一个内存单元的时候,必须给出这个内存单元的地址
在 8086 PC 中,内存地址由段地址和偏移地址组成(段地址:偏移地址)
用 DS 和 [address] 配合,用 DS 寄存器存放要访问的数据的段地址
偏移地址用 [...] 形式给出
MOV 指令中,只写 [address] 时,默认段地址就是 DS 。

DS 和数据段

对内存单元中数据的访问

对于 8086 , 可以根据需要将一组内存单元定义为一个段

  • \(物理地址 = 段地址 * 16 + 偏移地址\)
  • 将一组长度为 \(N(N \leq 64K)\) 、地址连续、起始地址为 16 的倍数的内存单元当作专门存储数据的内存空间,从而定义了一个数据段。
    用 DS 存放数据段的段地址,用指令访问数据段中的具体单元,单元地址由 [address]指出。

加法 add 和减法 sub 指令

  • add (寄存器) , (数据)
  • add (寄存器) , (寄存器)
  • add (寄存器) , (内存单元)
  • add (内存单元) , (寄存器)
    段寄存器不能作为被加数,add 指令的参数不能全为内存单元
  • sub (寄存器) , (数据)
  • sub (寄存器) , (寄存器)
  • sub (寄存器) , (内存单元)
  • sub (内存单元) , (寄存器)
    段寄存器不能作为被减数,sub 指令的参数不能全为内存单元

栈及栈操作的实现

栈是一种只能在一端进行插入或删除操作的数据结构。
栈有两个基本的操作

  • 入栈:将一个新的元素放到栈顶
  • 出栈:从栈顶取出一个元素
    栈顶元素总是最后入栈,需要出栈时,又最先被从栈中取出。
    栈的操作规则:LIFO (Last In First Out ,后进先出)
    CPU 提供的栈机制,支持用栈的方式访问内存空间,可以将一段内存当作栈来使用。
    PUSH (寄存器) 将寄存器中的数据送入栈,实质上就是一种内存传送指令,与 MOV 不同的是,PUSH 指令访问的内存单元的地址不作为参数,而是由 SS:SP 所指向的。
    POP (寄存器) 从栈顶取出数据送入寄存器,实质同 PUSH。
    栈顶寄存器 SS 存放栈顶的段地址,栈顶指针寄存器 SP 存放栈顶的偏移地址,
    SS:SP 任意时刻都指向栈顶元素

栈指令执行过程

  • PUSH (寄存器)
    1. SP = SP - 2
    2. 将寄存器中的内容送入 SS:SP 指向的内存单元处,SS:SP 此时指向新栈顶
  • POP (寄存器)
    1. 将 SS:SP 指向的内存单元处的数据送入寄存器中
    2. SP = SP + 2
    3. SS:SP 指向当前栈顶下面的单元,以当前栈顶下面的单元为新的栈顶。

栈顶越界问题

栈空时使用 POP 指令或栈满时使用 PUSH 指令,都会导致栈顶越界
8086 CPU 不保证对栈的操作不会越界,需要在编程时注意。

标签:汇编,8086,16,指令,地址,Part,内存,寄存器,CPU
From: https://www.cnblogs.com/AlwaysBeShine/p/18116804

相关文章

  • Day1 数组第一章part01
    1.数组理论基础重点:数组是存放在连续内存空间上的相同类型数据的集合。数组下标都是从0开始的。数组内存空间的地址是连续的。正是因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。例如删除下标为3的元素,需要对下标......
  • 记一次dlopen使用问题导致Framework重启,tombstones、pmap与反汇编分析(上)
    关键词:AndroidFramework动态库动态链接Binder1、事件起因AndroidStudio一次更新后发现installApp,设备就重启了,跑了一遍开机动画但不是从开机第一屏开始重启,tombstones内容查看发现是surfaceflinger挂在libbinder.so,那installapp做了什么这个不得而知,理论上有问题应该挂的......
  • Android NDK之使用 arm-v7a 汇编实现两数之和
    AndroidNDK之使用arm-v7a汇编实现两数之和关键词:NDKarmv7aWebRTCarm汇编CMake最近适配对讲程序,在webrtc的库编译的过程中,发现其为arm的平台定制了汇编程序以优化平方根倒数算法速度,上次写汇编还是8086的,借此机会初步尝试下android上arm汇编具体jni工程建立就不介绍了,An......
  • 书生浦语第二期实战营——第二课_part2
    这里写目录标题1基于`InternLM2-Chat-7B`运行`Lagent`智能体1.1介绍1.2实践准备运行1.3作业2部署`浦语·灵笔2`模型2.1介绍2.2实践(1)环境配置(2)图文写作(3)图片理解2.3作业(1)图文创作(2)视觉问答正文主要内容:运行Lagent智能体、部署浦语·灵笔2模型B......
  • QOJ #1280.Fibonacci Partition/Fibonacci性质大杂烩
    QOJ#1280.FibonacciPartition(为什么布置的作业题没有任何可见AC记录啊/kk)拿下了QOJ上的用户首杀(同时目前也是QOJ可见的submission中唯一一个过掉这个题的,另一个是vjudge上我的提交)。也许是这个题实在是太冷门了,但是从Fibonacci-Lucas数列的性质应用上是一道非常......
  • 书生浦语第二期实战营——第二课_part1
    目录0环境配置1部署`InternLM2-Chat-1.8B`智能对话模型1.1课程内容:(1)准备工作(2)代码流程1.2课程作业2部署`八戒-Chat-1.8B`模型2.1课程(1)准备工作(2)开启服务(3)本地对话2.2作业(1)snapshot_download(2)hf_hub_download(3)hf_hub_url(4)huggingface-cli正文:所有操......
  • 黑马点评part1 -- 短信登录
    目录 1.导入项目: 2.基于Session实现短信验证登录2.1原理 : 2.2发送短信验证码: 2.3短信验证码登录和验证功能:2.4登录验证功能2 .5隐藏用户敏感信息2.6session共享问题2.7Redis代替session2.8基于Redis实现短信登录UserSer......
  • 8086 汇编学习 Part 1
    学习汇编语言的重要性编程语言发展不可替代性效率:用于开发软件的核心部件,可以快速执行和实时响应。底层:开发操作系统内核,嵌入式系统等计算机及外围设备的驱动程序作用:直击计算机系统的核心,可以加深对计算机原理和操作系统的理解。学习内容理解硬件结构,掌握指令集,理解......
  • 每日面经分享(python进阶 part2)
    Python中的装饰器和上下文管理器区别是什么?它们分别适用于哪些场景?a.装饰器用于在函数或类的外部添加额外功能,而上下文管理器用于管理资源的获取和释放。b.装饰器是一种用于修改函数或类行为的技术。适用于需要在函数或类的外部添加额外功能的场景,比如日志记录、性能监......
  • Linux C编程一站式学习 part3: Linux系统编程
    LinuxC编程一站式学习(akaedu.github.io)28.文件与I/O29.文件系统30.进程31.Shell脚本32.正则表达式33.信号34.终端、作业控制与守护进程35.线程36.TCP/IP协议基础37.socket编程......