32位x86处理器编程导入——《x86汇编语言:从实模式到保护模式》读书笔记08
在说正题之前,我们先看2个概念。
1.指令集架构(ISA)
ISA 的全称是 instruction set architecture,中文就是指令集架构,是指对程序员实际“可见”的指令集,包含了程序员编写一个能正确运行的二进制机器语言程序的所有信息,涉及到指令、 I/O 设备等。例如 Intel 的 IA-32、Intel 64、ARM 的 ARMv7、ARMv8 等等。
2.微架构
微架构(Microarchitecture)又称为微体系结构/微处理器体系结构。是将一种给定的指令集架构在处理器中执行的方法。一种给定的指令集可以在不同的微架构中执行。 [1]
需要说明的是:
微架构与指令集是两个概念:指令集是CPU选择的语言,而微架构是具体的实现.[2]
ARM公司将自己研发的指令集叫做ARM指令集,同时它还研发具体的微架构(如Cortex系列)并对外授权。但是,一款CPU使用了ARM指令集不等于它就使用了ARM研发的微架构。Intel、高通、苹果、Nvidia等厂商都自行开发了兼容ARM指令集的微架构,同时还有许多厂商使用ARM开发的微架构来制造CPU。通常,业界认为只有具备独立的微架构研发能力的企业才算具备了CPU研发能力,而是否使用自行研发的指令集则无关紧要。厂商研发CPU时并不需要获得指令集授权就可以获得指令集的相关资料与规范,指令集本身的技术含量并不是很高。获得授权主要是为了避免法律问题。然而微架构的设计细节是各家厂商绝对保密的,而且由于其技术复杂,即便获得相应文档也难以山寨。
[2]
如前所述,仅仅从ARM购买微架构来组装芯片的厂商是不能被称作CPU研发企业的,这些芯片也不能被称为“xx厂商研发的CPU”.典型如华为的海思920、三星Exynos 5430,只能说是“使用ARM Cortex-A15核心的芯片”。但是如果一款兼容ARM指令集的芯片使用了厂商自主研发的微架构,情况就不同了。高通骁龙800、苹果A7就是这样的例子——它们分别使用了高通、苹果自主研发的CPU.
[2]
3. 32位寄存器
(1)通用寄存器
在16位处理器内,有8个通用寄存器,分别是AX,BX,CX,DX,SI,DI,BP,SP. 其中,前4个还可以拆分成2个独立的寄存器来用。32处理器在16位处理器的基础上,扩展了这8个通用寄存器的长度,使之达到32位。它们的名字分别是EAX,EBX,ECX,EDX,ESI,EDI,ESP,EBP.
注意:
- 在使用这些寄存器的时候,指令的源操作数和目的操作数必须具有相同的长度(个别特殊用途的指令除外)。如果目的操作数是32位寄存器,源操作数是立即数,那么立即数被视为是32位的。
- 32位通用寄存器的高16位是不能独立使用的,但是低16位保持同16位处理器的兼容性(可以拆成8位的来用)。
- 可以在32位的处理器上运行16位处理器上的软件。
(2)指令指针寄存器
在32位模式下,为了生成32位物理地址,处理器需要使用32位的指令指针寄存器,也就是说之前的16位的IP扩展成为32位的EIP。当处理器工作在16位模式下时,依然使用16位的IP;工作在32位模式下时,使用32位的EIP。
注意:和之前一样,EIP也只能由处理器自己使用,程序员无法直接访问。 对IP和EIP的修改通常是通过某些隐式的指令进行的,比如JMP,CALL,RET,IRET等等。
(3)标志寄存器
在32位处理器中,标志寄存器由之前16位的FLAGS扩展为32位的EFLAGS,低16位的每个字段和原先保持一致。
下图摘自《 The Intel Architecture Software Developer’s Manual——Volume 3 》
(4)段寄存器
在32位模式下,对内存的访问从理论上来说不需要分段,因为有32根地址线,可以直接寻址4G的内存。但是,IA-32结构的处理器是基于分段模型的,因此,32位处理器依然需要以段为单位访问内存,即使它工作在32位模式下。
不过,可以采取一个变通的方案,即只分一个段。也就是说段的基地址是0x0000_0000,段的长度是4GB。在这种情况下,相当于不分段,即平坦模型(Flat Mode)。
在32位模式下,处理器要求在加载程序时,先定义该程序拥有的段,然后才可以使用这些段。定义段时,除了起始地址外,还附加了段界限、特权级别、类型等属性。当程序访问一个段时,处理器将通过固件进行各种检查工作,以防止对内存的违规访问。
在32位模式下,传统的段寄存器,如CS,SS,DS,ES保存的不再是16位的段基地址,而是段选择子(到底什么是段选择子,我们以后再说)。另外,32位处理器还增加了两个额外的段寄存器,分别是FS和GS。
4.实模式与保护模式
8086是16位的处理器,可以通过分段来访问1M的内存,段的最大长度是64KB。8086只有一种工作模式,就是我们现在所说的“实模式”。1985年,Intel公司推出了80386,获得了极大的成功。80386以及后续的处理器,都向前兼容,可以运行实模式下的8086程序。而且,在加电时,这些处理器都自动处于实模式下。只有在一番设置之后,才能运行在保护模式下。
5.逻辑地址和线性地址
在8086,我们把“段地址:段内偏移地址”称为逻辑地址。8086CPU内部有一个地址加法器,用来把逻辑地址转换成物理地址。转换规则是:物理地址=段地址×10H+段内偏移量
但是在80386中,情况就不同了。80386的逻辑地址(也叫虚拟地址)构成是“段选择子:段内偏移量”。逻辑地址经过80386CPU内部的分段部件转换后成为线性地址。线性地址再经过分页部件转换就成为物理地址。如果禁用分页机制,那么线性地址就是物理地址。
6.处理器的寻址方式
在16位处理器上,内存寻址方式为:
在32位处理器上,内存寻址方式为:
也是就是说,在指定有效地址的时候,可以使用所有的32位通用寄存器作为基址寄存器。同时,还可以再加上一个除ESP之外的32位通用寄存器作为变址寄存器。另外,变址寄存器还允许乘以一个比例因子(1或2或4或8)。最后,还可以加上一个8位或者32位的偏移量。
举例:
add eax,[0x2008]
sub eax,[eax+0x04]
mov ecx,[edx+esi*8+0x02]
7.汇编器指令 BITS
相同的机器指令,在16位模式和32位模式下的解释和执行效果是不同的。举例来说:
8B5022,这条机器码,在16位模式下,对应的汇编指令是:mov dx,[bx+si+0x02]; 但是,在32位模式下,对应的汇编指令却是 mov edx,[eax+0x02];
NASM汇编器中有一个伪指令——BITS.
'BITS'指令指定 NASM 产生的代码是被设计运行在 16 位模式的处理器上还是运行在32位模式的处理器上。语法是'BITS 16'或'BITS 32'. NASM以.bin格式输出时,默认是16位模式。如果我们需要编译成32位的,则需要加上[bits 32](方括号可以有,也可以没有。)
8.一般指令的扩展
(1)loop指令
在16位处理器上,loop指令的循环次数在寄存器CX中。在32位处理器上,如果当前模式是16位的,那么loop指令执行时,仍然使用CX寄存器;如果运行在32位模式下,则使用ECX;
(2)mul指令
在16位处理器上,无符号数乘法指令mul的格式为
mul r/m8 ; AX <- AL * r/m8
mul r/m16 ; DX:AX <- AX * r/m16
说明:这里的r/m8表示8位的通用寄存器或内存单元, r/m16表示16位的通用寄存器或内存单元,下面的r/m32表示32位的通用寄存器或内存单元
在32位处理器上,除了依然支持上面的的操作,另外还支持以下扩展格式:
mul r/m32 ;EDX:EAX <- EAX * r/m32
有符号数乘法指令imul与此相同。
(3)div指令
在16位处理器上,无符号除法指令div的格式为:
div r/m8 ; AX ÷ r/m8 = AL …… AH
div r/m16 ; DX:AX ÷ r/m16 = AX ……DX
在32位处理器上,除了依然支持上面的操作,还支持以下扩展格式:
div r/m32 ; EDX:EAX ÷ r/m32 = EAX……EDX
有符号数除法指令idiv于此相同;
(4)push和pop指令
操作数是立即数的情况
32处理器的栈操作指令push和pop也有所扩展,允许压入双字操作数。特别是,它支持立即数的压栈操作。指令格式为(imm8/16/32表示8位或16位或32位立即数):
push imm8 ;操作码为6A
push imm16 ; 操作码为68
push imm32; 操作码也为68
还是举书上的例子吧:
- 例1:压入一个字节
push byte 0x55;
这里的关键字byte是给编译器看的,告诉它压入的是字节(毕竟0x55可以解释为字0x0055或者双字0x0000_0055).这条指令的16位形式(用bits 16 编译)和32位形式(用bits 32 编译)是一样的,机器码都是
6A 55
但是,执行的时候就不同了。注意,无论什么时候,处理器都不会压入一个字节。它要么压入字,要么压入双字。
在16位模式下,默认的操作数是16位。于是处理器将0x55作符号扩展,扩展成16位的0x0055,然后压入栈。(压栈时用sp寄存器,且先将sp减去2);
在32位模式下,处理器将0x55扩展成32位的0x0000_0055,然后压入。(压栈时用esp寄存器,且先将esp减去4)
- 例2:压入一个字
压入一个字,必须用word关键字来修饰,如
push word 0xfffb
在16位模式下,默认的操作数是16位的。处理器直接压入该字(压栈时用sp寄存器,且先将sp减去2);
在32位模式下,处理器将0xfffb扩展成32位的0xffff_fffb,然后压入。(压栈时用esp寄存器,且先将esp减去4)
- 例3:压入一个双字
如果压入双字,则必须用关键字dword来修饰。如
push dword 0xfb
在16位模式下,压入的是0x0000_00fb(压栈时用sp寄存器,且先将sp减去4);
在32位模式下,压入的也是0x0000_00fb(压栈时用esp寄存器,且先将esp减去4).
操作数位于通用寄存器或者内存单元的情况
对于操作数位于通用寄存器或者内存单元的情况,只能压入字或者双字。指令格式为:
push r/m16
push r/m32
比如:
push ax
push edx
如果操作数位于内存单元中,则必须用关键字word或者dword修饰,如:
push word [0x2000]
push dword [ecx+esi*2+0x02]
无论操作数位于寄存器还是内存单元,
在16位模式下,压入字的时候,将sp的内容减去2;压入双字的时候,将sp的内容减去4;
在32位模式下,压入字的时候,将esp的内容减去2;压入双字的时候,将esp的内容减去4.
操作数是段寄存器的情况
指令格式为:
push cs/ds/es/fs/gs/ss
在16位模式下,将sp的内容减去2,然后直接压入段寄存器的内容;
在32位模式下,先将段寄存器的内容扩展为32位(高16位全为0),然后将esp的内容减去4,再压入扩展后的32位的值。
今天就说到这里,下次我们开启保护模式之旅
参考资料:
[2]知乎:王强,http://zhuanlan.zhihu.com/xpenrynidea/19893066
32位x86处理器编程导入——《x86汇编语言:从实模式到保护模式》读书笔记08的更多相关文章
- 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16
一.Intel 32 位处理器的工作模式 如上图所示,Intel 32 位处理器有3种工作模式. (1)实模式:工作方式相当于一个8086 (2)保护模式:提供支持多任务环境的工作方式,建立保护机制 ...
- ASM:《X86汇编语言-从实模式到保护模式》第10章:32位x86处理器的编程架构
★PART1:32位的x86处理器执行方式和架构 1. 寄存器的拓展(IA-32) 从80386开始,处理器内的寄存器从16位拓展到32位,命名其实就是在前面加上e(Extend)就好了,8个通用寄存 ...
- x86-1-32位x86 处理器编程架构
x86(32位)-1-32位x86 处理器编程架构 Intel 32 位处理器架构简称IA-32(Intel Architecture,32-bit) x86是指intel的86系列的CPU统称,比如 ...
- ASM:《X86汇编语言-从实模式到保护模式》第16章:Intel处理器的分页机制和动态页面分配
第16章讲的是分页机制和动态页面分配的问题,说实话这个一开始接触是会把人绕晕的,但是这个的确太重要了,有了分页机制内存管理就变得很简单,而且能直接实现平坦模式. ★PART1:Intel X86基础分 ...
- 存储器的保护(一)——《x86汇编语言:从实模式到保护模式》读书笔记18
本文是原书第12章的学习笔记. 说句题外话,这篇博文是补写的,因为让我误删了,可恶的是CSDN的回收站里找不到! 好吧,那就再写一遍,我有坚强的意志.司马迁曰:“文王拘而演<周易>:仲尼厄 ...
- 进入保护模式(二)——《x86汇编语言:从实模式到保护模式》读书笔记14
首先来段题外话:之前我发现我贴出的代码都没有行号,给讲解带来不便.所以从现在起,我要给代码加上行号.我写博客用的这个插入代码的插件,确实不支持自动插入行号.我真的没有找到什么好方法,无奈之下,只能按照 ...
- 存储器的保护(三)——《x86汇编语言:从实模式到保护模式》读书笔记20
存储器的保护(三) 修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响).要求:对内存的读写按双字的长度进行,并在检测的同时显示已检测的内存数量 ...
- 进入保护模式(三)——《x86汇编语言:从实模式到保护模式》读书笔记17
(十)保护模式下的栈 ;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作 mov cx,00000000000_11_000B ;加载堆栈段选择子 mov ss,cx mov esp,0x7c00 ...
- 硬盘和显卡的访问与控制(一)——《x86汇编语言:从实模式到保护模式》读书笔记01
本文是<x86汇编语言:从实模式到保护模式>(电子工业出版社)的读书实验笔记. 这篇文章我们先不分析代码,而是说一下在Bochs环境下如何看到实验结果. 需要的源码文件 第一个文件是加载程 ...
随机推荐
- vee-validate表单校验的基本使用
今天主要记录一下用vee-validate来进行表单校验的几个基本使用.包括最基础的必填和长度校验:异步请求服务的校验(重名校验),还有延迟校验.如何引入等就不在这里赘述了,直接进入主题. 1.必填和 ...
- HTML5+CSS3从入门到精通 中文pdf版
HTML5+CSS3从入门到精通是通过基础知识+中小实例+综合案例的方式,讲述了用HTML5+ CSS3设计构建网站的必备知识,相对于专业指南.高级程序设计.开发指南同类图书,本书是一本适合快速入手的 ...
- android 仿QQ气泡聊天界面
1.现在的QQ,微信等一些APP的聊天界面都是气泡聊天界面,左边是接收到的消息,右边是发送的消息, 这个效果其实就是一个ListView在加载它的Item的时候,分别用了不同的布局xml文件. 2.效 ...
- GeoServer中GeoWebCache(GWC)的使用
本文介绍GeoWebCache的使用方法,包括如何切缓存,访问缓存wms/wmts服务,如何复用栅格缓存等. 文章大部分内容转载自https://www.cnblogs.com/naaoveGIS/p ...
- java关键字(更新)
1.final: ①final修饰类:该类不能被继承: ②final修饰方法:该方法不能被子类重写: ③final修饰变量:一.修饰基本数据类型变量,必须初始化,且值不能被改变:二.修饰引用数据类型变 ...
- poi将图片导入excel(Java代码)
package com.fh.util;import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; imp ...
- ASP.NET -- 获取浏览器信息
1. 获取浏览器信息 private void GetBrowserInfo() { StringBuilder sb = new StringBuilder(); sb.AppendLine(str ...
- 文件参数化-utp框架之根据yaml文件自动生成python文件+utp运行用例
根据yaml文件自动生成python文件 utp框架: bin目录:存放执行文件(run.py) cases目录:存放生成的用例的python文件(该目录下的文件为根据data目录下的测试用例生成的p ...
- leecode刷题(7)-- 加一
leecode刷题(7)-- 加一 加一 描述: 给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 ...
- redis源码分析(3)sds
sds是redis中用来处理字符串的数据结构.sds的定义在sds.h中: typedef char *sds; 简洁明了!简明扼要!(X,玩我呢是吧!这特么不就是c中的字符串么?!).像redis这 ...