汇编 - IA-32平台

 

第一章: 1. 什么是汇编语言

第二章:IA-32平台

 

一、基本概念

CPU 由 运算器控制器寄存器等组成,由内部总线相连。

在CPU中,运算器进行信息处理寄存器进行信息存储控制器控制各种器件进行工作

寄存器是CPU中程序员可以用指令读写的部件。程序员通过改变各种寄存器中的内容来实现对CPU的控制。

 

寄存器 描述
通用 8个32位寄存器,用于存储正在处理的数据
6个16位寄存器,用于处理内存访问
指令指针 单一的32位寄存器,指向要执行的下一条指令码
浮点数据 8个80位寄存器,用于浮点数学数据
控制 5个32位寄存器,用于确定处理器的操作模式
调试 8个32位寄存器,用于在调式处理时包含信息。

 

 

 

 

 

 

 

 

 

 

 

 

1. 通用寄存器

8086 CPU 所有寄存都是16位的,可以存放两个字节。

AX, BX, CX, DX 四个寄存器通常用来存放一般性的数据,称为通用寄存器

所有的寄存器可以分成高位与低位 AH && AL

 

 

问: 一个16位寄存器所能存储的数据最大值为多少?

答: 2^16-1 

 

80386 32位寄存器 概览

寄存器 描述
EAX 用于操作数和结果数据的累加器
EBX 指向数据内存段中的数据的指针
ECX 字符串和循环操作的计数器
EDX I/O指针
EDI 用于字符串操作的目标的数据指针
ESI 用于字符串操作的源的数据指针
ESP 堆栈指针
EBP 堆栈数据指针

 

 

 

 

 

 

 

 

 

2. 字的概念

为了考虑兼容性,8086CPU可以一次性处理两种类型的数据:

字节: 1byte = 8bit , 可以存储在8位寄存器中。

字: 1world = 2byte = 16bit, 由高位字节与低位字节组成。

 

问题:使用汇编指令计算2的4次方。

2*2*2*2

mov ax, 2

add ax, ax  (ax = ax + ax)  2 + 2 = 4

add ax, ax (ax = ax + ax)  4 + 4 = 8

add ax, ax (8 + 8 )

 

 

3. 物理地址的计算方法

CPU 访问内存单元时,必须向内存提供内存单元的物理地址,8086CPU在内部用段地址偏移地址移位相加的方法形成最终的物理地址。

CPU 可以用不同的段地址和偏移地址形成同一个物理地址

 

32位、64位机表示:

1. 运算器一次最多可以处理32、64位的数据

2. 寄存器的最大宽度为32、64位

3. 寄存器和运算器之间的通路为32、64位

 

8086 CPU 相关部件逻辑结构

8086 CPU 使用两个 16位的地址 合成一个20位的物理地址

 

 

地址加法器采用 物理地址 = 段地址 * 16 + 偏移地址 的方法来合成物理地址

该公式的含义: CPU在访问内存时,用一个基础地址(段地址 * 16) 和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址

 

 

 

4. 段的概念与段寄存器

在编程时可以根据需要将若干个连续的内存单元看作一个段,用段地址 * 16 定位段的起始地址(基础地址), 用偏移地址定位段中的内存单元。

8086 CPU 有四个段寄存器: CS, DS, SS, ES

 

CS 与 IP 指示了CPU当前要读取指令的地址。 CS 为代码段寄存器,IP为指令指针寄存器

在8086 CPU 中, 任意时刻,设CS中内容为M, IP中内容为N, 则 CPU 将从内存 M * 16 + N 单元开始,读取并执行一条指令。

 

8086CPU的工作过程:

1. 从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器。

2. IP = IP+所读取指令的长度,从而指向下一条指令。

3. 执行指令,转到步骤1,重复过程。

 

mov 指令是传送指令,不能修改段寄存器中的值。

修改CS:IP 寄存器中的值: jmp 命令 【转移指令】

jmp 2AE3:3 执行后, CS=2AE3H, IP=0003H

jmp ax        类似于 jmp IP, ax 

 

jmp 段地址:偏移地址   // 用指令中给出的段地址修改CS,偏移地址修改IP

jmp  某一合法寄存器  // 用寄存器中的值修改IP

 

段寄存器 描述
CS 代码段
DS 数据段
SS 堆栈段
ES 附加段指针
FS 附加段指针
GS 附加段指针

 

 

CPU 根据什么将内存中的信息看作指令?

CPU将CS:IP指向的内存单元中的内容看作指令。

 

 

二、实验 查看CPU 和 内存,用机器指令和汇编指令编程

1. 环境搭建

参考

https://segmentfault.com/q/1010000000366869

https://jingyan.baidu.com/album/da1091fbd26bfe027849d68c.html?picindex=6

 

使用Debug程序来查看CPU 与 和内存

下载 DOSBox 与 debug.exe 程序

 

mount c: ~/users/Documents/

debug

使用环境 DOSBox && debug.exe

DOSBox 是一个8086的一个模拟器

debug是 DOS、Windows 提供的实模式程序调式工具。可以查看CPU各种寄存器中内容、内存的情况和机器码级跟踪程序的运行。

 

 

第三步: 使用Debug

Debug 的 R 命令查看、改变CPU寄存的内容

Debug 的 D 命令查看内存中的内容

Debug 的 E 命令改写内存中的内容

Debug 的 U 命令将内存中的机器指令翻译成汇编指令

Debug 的 T 命令执行一条机器指令

Debug 的 A 命令以汇编指令的格式在内存中写入一条机器指令。

 

第四步: 用 R 命令查看、改变CPU寄存器的内容

 

 

修改寄存中内容

使用R命令修改寄存器中的值 ,在 R 命令之后加寄存器的名来进行。

 

 

第五步:用Debug 的 D 命令查看内存中的内容

 

安全调试软件:

OllyDbg 反汇编工具

SoftICE 调式器

WinDbg

IDA Pro

 

 

 

 

内存中字的存储

字单元: 即存放一个字型数据(16位)的内存单元,由两个地址连续的内存单元组成,高地址内存单元中存放字形数据的高位字节,低地址内存单元中存放字形数据的低位字节。

8086 CPU 中有一个DS奇存器,通常用来存放要访问数据的段地址。

 

如何把一个数据送入寄存器?

mov bx, 1000H  # 将1000存放在bx寄存器
mov ds, bx        # 将 bx 存放在在 ds 段寄存器中
mov al, [0]        # 将 1000:0 中的数据读到al中

 

解释如下:

[...] 表示偏移地址。

DS段寄存器只能通过通用寄存器的值存入。

数据 -> 通用寄存器 -> 段寄存器

 

问题: 写几条指令,将 al 中的数据送入内存单元 10000H?

 

分析: 怎样将数据从寄存器送入内存单元?

mov bx, 1000H
mov ds, bx
mov [0], al

 

CPU提供栈的机制

PUSH && POP 入栈与出栈操作都是以字为单位进行。

 

CPU 是如何知道栈顶的位置?

8086 CPU 使用 段寄存器 SS 和 寄存器 SP,栈顶的段地址存放在SS中,偏移地址存放在SP中。

任意时刻, SS:SP 指向栈顶元素。 push 指令和pop指令执行时,cpu从SS 和 SP 中得到栈顶的地址。

 

push ax

第一步: SP = SP - 2, SS:SP 指向当前栈顶前面的单元,以当前栈顶前面的单元为新的栈顶

第二步: 将ax中的内容送入 SS:SP指向的内存单元处,SS:SP 此时指向新栈顶。

 

 

[0] 表示内存单元,它的偏移地址是0.

mov ax, [0]

上面指令将一个内存单元内容送入ax, 这个内存单元的长度为2字节(字单元),存放一个字,偏移地址为0,段地址在ds中。

mov al, [0]

上面指令将一个内存单元内容送入al, 这个内存单元的长度为1字节(字节单元),存放一个字节,偏移地址为0,段地址在ds中。

mov ax, [bx]

将一个内存单元内容送入ax, 这个内存单元的长度为2字节(字单元),存放一个字,偏移地址在bx中,段地址在ds中。(ax) = ((ds) * 16 + (bx))

mov al, [bx]

将一个内存单元的内容送入al, 这个内存单元的长度为1字节(字节单元),存放一个字节,偏移地址在bx中,段地址在ds中。

 

使用()来表示一个寄存器或一个内存单元中的内容。

(ax) 表示ax中的内容, (al)表示al中的内容。

(20000H)表示内存20000H单元的内容()中的内存单元的地址为物理地址。

((ds) * 16 + (bx)) 表示 ds中内容为ADR1, bx中内容为 ADR2, 内存 ADR1*16+ADR2 单元的内容。

 

posted @ 2017-09-16 23:13  elewei  阅读(892)  评论(0编辑  收藏  举报