第七章-X86汇编语言从实模式到保护模式

2023-05-16

第七章 比高斯更快的计算

7.3 显示字符串

  • '1+2+3+…+100='字符串编译阶段,编译器将把它们拆开,形成一个个单独的字节
  • jump near start跳过没有指令的数据区
  • 11~15行初始化数据段寄存器DS和附加段寄存器ES
  • 18~28行用于显示字符串,
    首先索引寄存器SI指向DS段内待显示字符串的首地址,即标号"message"所代表的汇编地址
    用另一个索引寄存器DI指向ES段内的偏移地址0处,ES是指向0xB800段的
  • 字符串的显示依赖循环。如使用loop,需要CX寄存器
    20行循环次数为字符串长度=start-message
    22行,首先从数据段中,逻辑地址为DS:SI取得第一个字符
    将其传送到逻辑地址ES:DI即显示缓冲区
    24行,DI的内容加一,以指向该字符在显示缓冲区内的属性字节,0x07,黑底白字
    26,27行,寄存器SIDI加一指向原位置和目标位置的下一个单元
    28行,执行循环。先将CX的内容减一,然后根据CX是否为零决定是否循环,CX为零时,显示完毕。

7.4 计算1到100的累加和

AX清零,1传到寄存器CX,开始累加。CX同100比较
AX中得到累加和。

7.5 累加和各个数位的分解与显示

栈和栈段的初始化

得到累加和,要把各数位分解出来,并准备在屏幕上显示。
保存在栈中,栈段,由段寄存器SS指向。
需要栈指针寄存器SP来指示下一个数据应当压入栈内的什么位置,或者数据从哪里出栈

40~42行初始化SSSP的内容

在这里插入图片描述

分解各个数位并压栈

44行 除数传送到BX
每次除法结束后,都做一次判断,如果商为0的话,分解过程可以提前结束,必须记住实际有多少个数位。45行CX寄存器清零,用来累计

47到53行也是循环体,每次执行,分解一个数位。每次分解CX加一,表明多一个数位

48,49行,将DX清零,和AX一起形成32的被除数。

50行,or不是真正的加法。这是因为每次是除以10,所以DL中得到的余数,高四位必定是0x30低四位是0,高4位是3。所以or之后是相当于加

51行,push指令将DX内容压入栈中。push指令在8086中只能压入一个字,但其后的32位64位处理器允许压入字,双字,四字。因此必须有关键字。

执行push指令,首先将SP的内容减去操作数的字长,然后把要压入栈的数据放到逻辑地址SS:SP所在位置。

SP-2即0x0000-0x0002=0xFFFE,错位被忽略。Intel使用低端字节序,低字节在低地址,高字节在高地址。压栈操作是从高地址端向低地址短推进。

在这里插入图片描述

出栈并显示各个数位

57行,pop弹出到DX中,然后将SP的内容加上操作数的字长
执行完最后一次出栈,SP的内容重新为0

进一步认识栈

引入栈和push、pop只是为了方便程序开发。临时保存一个数值到栈中使用push指令是最简洁最省事的。否则push ax 可为

sub sp,2
mov bx,sp
mov [ss:bx],ax

pop ax类似

mov bx,sp
mox ax,[ss:bx]
add sp,2

如果你想把临时数据都保存在数据段,那么你必须在数据段中开辟一些空间,并亲自维护一个指针来跟综这些数据的存入和取出。

  • 保持栈的平衡,SP在做事之前的值和之后的值要相同,即push和pop数相等。

  • 必须充分估计需要的栈空间,如果栈段和代码段属于同一内存段,栈定义得过小,程序编写不当,栈可能破坏有用数据。

  • 请举例说明为什么在压栈操作中,栈指针需要先减去一个偏移量,然后再将数据存储到栈中在出栈操作中,在出栈操作中,栈指针需要先访问栈中的数据,然后再将栈指针向上移动一个偏移量。

    假设我们有一个栈,初始时栈指针 SP 指向栈底的内存地址,栈中已经存储了两个元素。此时我们要进行一次压栈操作和一次出栈操作,来说明为什么在这两个操作中需要先进行偏移量处理。

    假设要压入的数据为 0x1234,大小为 2 字节,压栈操作流程如下:

    1. 将栈指针 SP 减去 2,这是偏移量处理的过程,让 SP 指向栈顶空闲位置;
    2. 将数据 0x1234 存储到栈指针 SP 指向的内存位置中;
    3. 将栈指针 SP 指向 0x1234 存储的内存位置,此时 SP 指向栈顶元素的位置。

    此时栈的情况如下:

    栈顶0x1234
    元素20x5678
    元素10x9abc
    栈底SP指向

    接下来,我们进行一次出栈操作,将栈顶的元素弹出,出栈操作流程如下:

    1. 访问栈指针 SP 指向的内存位置,即访问栈顶元素 0x1234;
    2. 将栈指针 SP 加上 2,这是偏移量处理的过程,让 SP 指向下一个栈元素的位置;
    3. 返回栈顶元素 0x1234。

    此时栈的情况如下:

    栈顶0x5678
    元素20x5678
    元素10x9abc
    栈底SP指向

    可以看到,在进行压栈和出栈操作时,都需要先进行偏移量处理,这样才能保证栈指针的正确性和栈中数据的一致性。

7.6 程序的编译和运行

Bochs中察看栈的命令是"print-stack",默认显示当前栈中的16个字

7.7 8086处理器的寻址方式

寻址方式就是如何找到要操作的数据,以及如何找到存放操作结果的地方(基于16位处理器)

  1. 寄存器寻址
mov ax,cx
add bx,0xf000
inc dx
  1. 立即(数)寻址
add bx,0xf000
mov dx,label_a

标号在编译阶段转化为立即数
立即寻址的操作数位于指令中,是指令的一部分

  1. 内存寻址
    段地址由4个段寄存器之一来提供,偏移地址要由指令来提供
    内存寻址实际上就是要寻找偏移地址,这称为有效地址
    即如何在指令中提供偏移地址,供处理器访问内存时使用
  • 直接寻址
mov ax,[0x5c0f]
add word [0x0230],0x5000
xor byte [es:label_b],0x05
  • 基址寻址
    基址寻址就是在指令的地址部分使用基址寄存器BXBP来提供偏移地址
mov [bx],dx //将DS的内容左移4位,加上基址寄存器BX的内容
add byte [bx-2],0x55  //可加减一个偏移量不改变bx内容
mov ax,[bp] //该寄存器的默认段寄存器是SS,常用于访问栈

高级语言里的函数调用,所有的参数都在栈中。为了能访问到那些被压在栈底的参数,就需要用到BP

在这里插入图片描述

  • 变址寻址
    寻址方式使用的是变址寄存器(索引寄存器)SI和DI
  • 基址变址寻址

​ 将 string db 'abcdef到z’原地反向排列

	mov bx,string 
	mov si,0
	mov di,25
order:
	mov ah,[bx+si]
	mov al,[bx+di]
	mov [bx+si],al
	mov [bx+di],ah
	
	inc si
	dec di 
	cmp si,di
	jl order

本章汇编:

                                               ;代码清单7-1
                                               ;文件名:c07_mbr.asm
                                               ;文件说明:硬盘主引导扇区代码
                                               ;创建日期:2011-4-13 18:02                             
     00000000 E90E00                           jmp near start
                                      	
     00000003 312B322B332B2E2E2E-      message db '1+2+3+...+100='
     0000000C 2B3130303D         
                                              
                                       start:
     00000011 B8C007                           mov ax,0x7c0           ;设置数据段的段基地址 
     00000014 8ED8                             mov ds,ax
                                      
     00000016 B800B8                           mov ax,0xb800          ;设置附加段基址到显示缓冲区
     00000019 8EC0                             mov es,ax
                                      
                                               ;以下显示字符串 
     0000001B BE[0300]                         mov si,message          
     0000001E BF0000                           mov di,0
     00000021 B90E00                           mov cx,start-message
                                           @g:
     00000024 8A04                             mov al,[si]
     00000026 268805                           mov [es:di],al
     00000029 47                               inc di
     0000002A 26C60507                         mov byte [es:di],0x07
     0000002E 47                               inc di
     0000002F 46                               inc si
     00000030 E2F2                             loop @g
                                      
                                               ;以下计算1到100的和 
     00000032 31C0                             xor ax,ax
     00000034 B90100                           mov cx,1
                                           @f:
     00000037 01C8                             add ax,cx
     00000039 41                               inc cx
     0000003A 83F964                           cmp cx,100
     0000003D 7EF8                             jle @f
                                      
                                               ;以下计算累加和的每个数位 
     0000003F 31C9                             xor cx,cx              ;设置堆栈段的段基地址
     00000041 8ED1                             mov ss,cx
     00000043 89CC                             mov sp,cx
                                      
     00000045 BB0A00                           mov bx,10
     00000048 31C9                             xor cx,cx
                                           @d:
     0000004A 41                               inc cx
     0000004B 31D2                             xor dx,dx
     0000004D F7F3                             div bx
     0000004F 80CA30                           or dl,0x30
     00000052 52                               push dx
     00000053 83F800                           cmp ax,0
     00000056 75F2                             jne @d
                                      
                                               ;以下显示各个数位 
                                           @a:
     00000058 5A                               pop dx
     00000059 268815                           mov [es:di],dl
     0000005C 47                               inc di
     0000005D 26C60507                         mov byte [es:di],0x07
     00000061 47                               inc di
     00000062 E2F4                             loop @a
                                             
     00000064 E9FDFF                           jmp near $ 
                                             
                                      
     00000067 00<rept>                times 510-($-$$) db 0
     000001FE 55AA                                     db 0x55,0xaa

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第七章-X86汇编语言从实模式到保护模式 的相关文章

  • Jmeter性能测试(24)--dubbo接口测试

    一 Dubbo简介 dubbo是一个分布式服务框架 xff0c 致力于提供高性能和透明化的RPC远程服务调用方案 xff0c 以及SOA服务治理方案 其核心部分包含如下几点 xff1a 1 远程通讯 xff1a 提供对多种基于长连接的NIO
  • 自定义mavlink及收发测试(px4固件V1.11.0,QGC源码4.0)

    一 实现收 1 先定义uORB消息 a01 GPS msg uint64 timestamp time since system start microseconds uint64 lat Latitude uint64 lon Longi
  • 自定义mavlink及收发测试2(px4固件V1.11.0,QGC源码V4.0)

    一 1 下载安装一个mavlink文件或者在原文件上修改 安装步骤 xff08 包含mavlink generator xff09 可参照文章 PX4自定义Mavlink消息 xff08 一 xff09 px4发送 Sense97的博客 C
  • Ubuntu20.04 | 更新软件源 sudo apt-get update 出现错误

    之前使用了清华的官方源 清华大学开源软件镜像站 Tsinghua Open Source Mirror 错误提示 xff1a 忽略 1 https mirrors tuna tsinghua edu cn ubuntu focal InRe
  • PCB封装库的制作

    以下几个元件制作为例 xff1a 元件SMA封装 步骤 xff1a 1 创建PCB库文件 xff1a 单击 File 菜单 xff0c 选择 New 选项中的 Library 选项 xff0c 再选择 PCB Library xff0c 进
  • PCB板自动布线

    自动布线 步骤 xff1a 1 整体删除同层的走线 xff1a 打开PCB文件 xff0c 在层的选项卡中选择顶层 Top Layer xff0c 在 Edit 菜单下选择 Select 选项 xff0c 选择 All on Layer 选
  • 独立按键实验

    按键简介 按键是一种电子开关 xff0c 使用时 xff0c 按下按钮 xff0c 则开关接通 xff0c 松开手时 开关断开 开发板上使用的按键及内部简易图如下图所示 xff1a 按键管脚两端距离长的表示默认是导通状态 xff08 1 2
  • IO 扩展(串转并)-74HC595-16*16LED点阵实验

    51 单片机的IO 口非常有限 xff0c 有时候若想要连接更多外围设备 xff0c 需要通过 IO 扩展来实现 本文介绍一种 IO 口扩展方式 串转并 xff0c 使用的芯片是 74HC595 若有4个 74HC595 芯片 xff0c
  • LED 点阵实验~点亮一个点、数字、汉字、图

    LED 点阵简介 LED 点阵是由发光二极管排列组成的显示器件 xff0c 如下所示为8 8LED 点阵 xff1a 以 16 16LED 点阵为例 xff0c 其内部结构图如下所示 xff1a 16 16 点阵共由 256 个发光二极管组
  • 定时器中断

    定时器简介 介绍定时器之前 xff0c 先说明几个CPU 时序的有关知识 振荡周期 xff1a 为单片机提供定时信号的振荡源的周期状态周期 xff1a 1 个状态周期 61 2 个振荡周期机器周期 xff1a 1 个机器周期 61 6 个状
  • 红外遥控实验

    红外线简介 人眼所能看到的可见光 xff0c 按波长从长到短排列 xff0c 依次为红 xff08 660nm xff09 橙 xff08 610nm xff09 黄 xff08 585nm xff09 绿 xff08 555nm xff0
  • Jmeter性能测试(25)--linux环境运行jmeter并生成报告

    jmeter是一个java开发的利用多线程原理来模拟并发进行性能测试的工具 xff0c 一般来说 xff0c GUI模式只用于创建脚本以及用来debug xff0c 执行测试时建议使用非GUI模式运行 这篇博客 xff0c 介绍下在linu
  • 题目:输入三个整数x,y,z,把这三个数由小到大输出

    程序分析 xff1a 方式一 xff1a 先将两个数比较 xff0c 再将较大值与第三个数比较 xff0c 得到最大值 然后比较剩余的两个值 最后 xff0c 将数值以X lt Y lt Z的顺序输出 方式二 xff1a 将三个数分别两两进
  • 对话框QDialog

    对话框是 GUI 程序中不可或缺的组成部分 很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置 对话框通常会是一个顶层窗口 xff0c 出现在程序最上层 xff0c 用于实现短期任务或者简洁的用户交互 Qt 中使用QDialog类
  • 布局管理器~登录界面的搭建实例

    所谓的图形用户界面 xff08 GUI xff09 xff0c 本质上就是一堆组件的叠加 创建一个窗口 xff0c 把按钮放上面 xff0c 把图标放上面 xff0c 这样就成了一个界面 因此 xff0c 组件位置的放置尤其重要 xff0c
  • 常用控件及自定义控件

    QLabel QLabel可以用来显示文本 xff0c 图片和动画等 显示文本 xff08 普通文本 HTML xff09 通过QLabel类的setText函数设置显示的内容 void setText const QString amp
  • Dev-c++ 5.11版本调试方法(七小时折磨调试成功,超详细版)

    一 出现的问题是 1 设置断点之后点调试不出现蓝行 2 点了调试之后出现黑框 然后又闪退 3 添加查看之后也看不了变量的值 等等各种问题 xff08 查找 一个个试验 xff0c 还有整理 xff0c 花了起码六七小时 xff0c 几乎一天
  • Pycharm调试Debug篇(详细)

    pycharm中的debug模式 首先 xff0c 还是用示例说话 xff0c 我们书写一段简短的代码 xff0c 来帮我们完成今天要讲的内容 def sum demo x y for in range 2 x 43 61 1 y 43 6
  • Qt --- 信号与槽

    信号与槽概述 信号与槽是 Qt 框架引以为豪的机制之一 所谓信号与槽 xff0c 实际就是观察者模式 发布 订阅模式 当某个事件发生之后 xff0c 比如 xff0c 按钮检测到自己被点击了一下 xff0c 它就会发出一个信号 xff08
  • 不可不知道的串口常识

    串口 xff1a 串口是一个泛称 xff0c UART xff0c TTL xff0c RS232 xff0c RS485都遵循类似的通信时序协议 xff0c 因此都被通称为串口 串口 UART口 COM xff08 cluster com

随机推荐

  • 【Linux】磁盘分区和挂载

    目录 Linux磁盘分区和挂载 linux分区 查看所有设备挂载情况 挂载案例 步骤1 xff1a 新建一块硬盘 操作步骤2 xff1a 虚拟机硬盘分区 步骤3 xff1a 虚拟机硬盘分区格式化 步骤4 xff1a 将磁盘挂载到根目录下ne
  • RealSense D435i + imu 标定 Ros Melodic

    准备工作 ubuntu ros melodic环境 librealsense realsense ros 一 修改rs camera launch文件中的参数 修改之前装好的realsense环境中的 src realsense ros r
  • Jmeter性能测试(26)---生成HTML性能测试报告

    性能测试工具Jmeter由于其体积小 使用方便 学习成本低等原因 xff0c 在现在的性能测试过程中 xff0c 使用率越来越高 xff0c 但其本身也有一定的缺点 xff0c 比如提供的测试结果可视化做的很一般 不过从3 0版本开始 xf
  • 【mcuclub】时钟模块DS1302

    一 实物图 二 原理图 编号名称功能1VCC2双供电配置中的主电源供应引脚 DS1302工作于 VCC1和VCC2中较大者 当VCC2比VCC1高0 2V 时 xff0c VCC2 给 DS1302供电 当VCC1比VCC2高时 VCC1给
  • 【mcuclub】定时器/计数器

    一 简介 定时器实际上就是Soc当中的一个内部外设 定时器常与计数器扯到一起 xff0c 计数器也是Soc当中的一个内部外设 xff0c 计数器顾名思义是用来计数的 xff0c 就和我们的秒表一样 xff0c 秒表实际上就是一个计数器 xf
  • 基于A*算法自动引导车的路径规划(Matlab代码实现)

    x1f4a5 x1f4a5 x1f49e x1f49e 欢迎来到本博客 x1f4a5 x1f4a5 x1f3c6 博主优势 xff1a x1f31e x1f31e x1f31e 博客内容尽量做到思维缜密 xff0c 逻辑清晰 xff0c 为
  • 【文章转载】使用常见Matlab工具箱调节pid参数(飞机垂直速度控制系统设计)

    申明 xff1a 这是一篇转载文章 xff0c 本人害怕原链接失效 xff0c 故转载 xff0c 没有商用 xff0c 作者也可也私我删除 使用常见Matlab工具箱调节pid参数 小白的第一篇知乎文章 xff0c 如果有不准确的地方 x
  • 制作自己的ORBSLAM2数据集,并实现三维重建(代码自己写的)

    2 ORBSLAM2 测试自己拍摄的数据集 使用手机 摄像机等设备拍摄视频 xff0c 对应我们只能使用单目 Monocular 2 1对相机标定 首先我们要对相机进行标定 xff0c 使用 MATLAB 里面的标定工具包 标定好之 后创建
  • c++的好处

    1 更新迭代慢 xff0c 技术成熟的很高 xff0c 基本不会有太大的改动 xff0c 工作后学习压力小 2 C C 43 43 是系统编程层级唯一的一门高级语言 xff0c 速度快 xff0c 效率高 不用担心今后会被取代 3 C C
  • lacp协议

    LACP xff08 Link Aggregation Control Protocol xff0c 链路聚合控制协议 xff09 将多条链路逻辑上模拟成一条链路 xff0c 以增加网络带宽 xff08 通常网络多条链路情况下 xff0c
  • Windows 10 下安装Linux

    使用Hype V 快速安装 选择的Ubuntu 22 04 LTS 安装一切正常 xff0c 登录提示 登录以后提示connecting to sesman ip 127 0 0 1 port 3350 关闭查看菜单的 增强模式 xff0c
  • mvvm是什么?

    1 总结 一句话总结 xff1a vm层 xff08 视图模型层 xff09 通过接口从后台m层 xff08 model层 xff09 请求数据 xff0c vm层继而和v view层 实现数据的双向绑定 2 mvc和mvvm的关系 xff
  • 汉诺塔问题(C语言实现)

    前言 一 汉诺塔圆盘的移动步数 二 汉诺塔圆盘移动步骤 总结 前言 汉诺塔 xff08 Tower of Hanoi xff09 xff0c 又称河内塔 xff0c 是一个源于印度古老传说的益智玩具 大梵天创造世界的时候做了三根金刚石柱子
  • ubuntu 16.04版本安装docker以及创建docker容器

    一 简介 Docker 是一个开源的应用容器引擎 xff0c 让开发者可以打包他们的应用以及依赖包到一个可移植的容器中 xff0c 然后发布到任何流行的 Linux 机器上 xff0c 也可以实现虚拟化 容器是完全使用沙箱机制 xff0c
  • 字符串操作函数strstr

    目录 一 strstr函数介绍 二 strstr函数的模拟 三 代码实现 一 strstr函数介绍 在编写程序的过程中 xff0c 我们不可避免地会调用字符串操作函数 xff0c 今天要介绍的字符串操作函数是strstr函数 strstr函
  • 【无标题】前端工程师面试题手册-有点长但是很有用

    不是原作者 想想要获取更多前端开发相关学习资料 xff0c 请加微信1124692领取 前端工程师面试题手册 目录 1 前端基础 11 1 1 HTTP HTML 浏览器
  • 超详细的VMware虚拟机安装Linux图文教程保姆级

    目录 一 下载VMware 二 安装VMware 三 下载Linux 四 安装Linux 五 设置本地机与虚拟机之间的数据传输 xff08 复制 粘贴等操作 xff09 一 下载VMware VMware官网有两个版本 xff0c 分别是
  • 仿牛客技术博客项目常见问题及解答(三)

    书接上回 xff1a 仿牛客技术博客项目常见问题及解答 xff08 二 xff09 李孛欢的博客 CSDN博客 13 项目中的kafka是怎么用的 xff1f kafka入门 Apache Kafka是一个分布式流平台 一个分布式的流平台应
  • [Java] 继承 和 多态(学习总结)

    目录 继承 一 继承主要表示概念层上的 is a 的关系 二 什么是继承 三 语法 四 继承方式 xff1a 五 访问权限 六 构造方法 七 父类的属性和方法的访问 八 重载和重写 xff08 前提是子类是有权限的 xff09 九 执行顺序
  • 第七章-X86汇编语言从实模式到保护模式

    第七章 比高斯更快的计算 7 3 显示字符串 39 1 43 2 43 3 43 43 100 61 39 字符串编译阶段 xff0c 编译器将把它们拆开 xff0c 形成一个个单独的字节jump near start跳过没有指令的数据区1