在说正题之前,我们先看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位的值。

今天就说到这里,下次我们开启保护模式之旅

参考资料:

[1]百度百科:http://baike.baidu.com/link?url=I1wsXUAGa541Pn8h1XVgSnR6GmUsfWK8VOjpALlzmE7vOccJVOpxkQfKjYYHODUe2BxqOw2q5KAB6pS4ZQjD9K

[2]知乎:王强,http://zhuanlan.zhihu.com/xpenrynidea/19893066

32位x86处理器编程导入——《x86汇编语言:从实模式到保护模式》读书笔记08的更多相关文章

  1. 16位模式/32位模式下PUSH指令探究——《x86汇编语言:从实模式到保护模式》读书笔记16

    一.Intel 32 位处理器的工作模式 如上图所示,Intel 32 位处理器有3种工作模式. (1)实模式:工作方式相当于一个8086 (2)保护模式:提供支持多任务环境的工作方式,建立保护机制 ...

  2. ASM:《X86汇编语言-从实模式到保护模式》第10章:32位x86处理器的编程架构

    ★PART1:32位的x86处理器执行方式和架构 1. 寄存器的拓展(IA-32) 从80386开始,处理器内的寄存器从16位拓展到32位,命名其实就是在前面加上e(Extend)就好了,8个通用寄存 ...

  3. x86-1-32位x86 处理器编程架构

    x86(32位)-1-32位x86 处理器编程架构 Intel 32 位处理器架构简称IA-32(Intel Architecture,32-bit) x86是指intel的86系列的CPU统称,比如 ...

  4. ASM:《X86汇编语言-从实模式到保护模式》第16章:Intel处理器的分页机制和动态页面分配

    第16章讲的是分页机制和动态页面分配的问题,说实话这个一开始接触是会把人绕晕的,但是这个的确太重要了,有了分页机制内存管理就变得很简单,而且能直接实现平坦模式. ★PART1:Intel X86基础分 ...

  5. 存储器的保护(一)——《x86汇编语言:从实模式到保护模式》读书笔记18

    本文是原书第12章的学习笔记. 说句题外话,这篇博文是补写的,因为让我误删了,可恶的是CSDN的回收站里找不到! 好吧,那就再写一遍,我有坚强的意志.司马迁曰:“文王拘而演<周易>:仲尼厄 ...

  6. 进入保护模式(二)——《x86汇编语言:从实模式到保护模式》读书笔记14

    首先来段题外话:之前我发现我贴出的代码都没有行号,给讲解带来不便.所以从现在起,我要给代码加上行号.我写博客用的这个插入代码的插件,确实不支持自动插入行号.我真的没有找到什么好方法,无奈之下,只能按照 ...

  7. 存储器的保护(三)——《x86汇编语言:从实模式到保护模式》读书笔记20

    存储器的保护(三) 修改本章代码清单,使之可以检测1MB以上的内存空间(从地址0x0010_0000开始,不考虑高速缓存的影响).要求:对内存的读写按双字的长度进行,并在检测的同时显示已检测的内存数量 ...

  8. 进入保护模式(三)——《x86汇编语言:从实模式到保护模式》读书笔记17

    (十)保护模式下的栈 ;以下用简单的示例来帮助阐述32位保护模式下的堆栈操作 mov cx,00000000000_11_000B ;加载堆栈段选择子 mov ss,cx mov esp,0x7c00 ...

  9. 硬盘和显卡的访问与控制(一)——《x86汇编语言:从实模式到保护模式》读书笔记01

    本文是<x86汇编语言:从实模式到保护模式>(电子工业出版社)的读书实验笔记. 这篇文章我们先不分析代码,而是说一下在Bochs环境下如何看到实验结果. 需要的源码文件 第一个文件是加载程 ...

随机推荐

  1. mysql数据库学习小结

    数据库的学习可以从以下几个层次了解掌握,这样思路清晰后后面不管怎么变化都可以随时应变: 1.mysql基础知识 2.操作数据库的方法,增 删 改 查 3.jdbc连接数据库,工作原理 难点重点,如:P ...

  2. duilib入门简明教程 -- 第一个程序 Hello World(3)

    小伙伴们有点迫不及待了么,来看一看Hello World吧: 新建一个空的win32项目,新建一个main.cpp文件,将以下代码复制进去: #include <windows.h> #i ...

  3. Vue 兄弟组件通过事件广播传递数据

    非父子组件传值 通过事件广播实现非父子组件传值1.新建js,引入并实例化Vue import Vue from 'vue' var VueEvent = new Vue(); export defau ...

  4. ubuntu 安装 删除 卸载 Deb 包文件

    图形界面: 安装deb 直接双击图标,输入密码后就可自动安装. 卸载deb 1. 菜单-系统->系统管理->新立得软件包管理器 或 Alt+F2(运行窗口)输入 sudo synaptic ...

  5. OC 术语表

    术语表 本附录包含了很多会用到的非正式定义术语.有些术语与Obective-C语言有关,其他术语则有自己的语源,来自面向对象程序设计的规范.在后一种情况中,术语的含义只有明确应用于Obective-C ...

  6. day6学python 生成器迭代器+压缩文件

    生成器迭代器+压缩文件 readme的规范 1软件定位,软件的基本功能2运行代码的方法:安装环境,启动命令3简要的使用说明4代码目录结构说明,更详细点可以说明软件的基本原理5常见问题说明 ====== ...

  7. (原创)数据结构之利用KMP算法解决串的模式匹配问题

      给定一个主串S(长度<=10^6)和一个模式T(长度<=10^5),要求在主串S中找出与模式T相匹配的子串,返回相匹配的子串中的第一个字符在主串S中出现的位置. 输入格式: 输入有两行 ...

  8. hosts是什么意思?Hosts文件有什么作用和功能?

    hosts是什么意思?Hosts文件有什么作用和功能? 熟悉网络的朋友们都会用到hosts文件,针对还不清楚hosts是什么意思以及hosts文件有什么功能和作用?针对此问题,本文就为大家进行解答   ...

  9. 【bzoj4817】树点涂色 LCT+线段树+dfs序

    Description Bob有一棵n个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同.定义一条路 径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. ...

  10. quartz实例以及主要事项(注解)

    实现任务类: package com.vnetoo.nec.base.quartz; import org.springframework.context.annotation.Lazy;import ...