计算机软件构成要素:软件视角下的计算机组成
计算机软件构成要素:软件视角下的计算机组成
2024-07-03 03:39:28  作者:天上奥特曼  网址:https://m.xinb2b.cn/tech/sao501502.html

冯诺伊曼式的计算机大概分成4个部分:CPU、内存、总线、外设

这是从硬件操作系统的角度来划分的,所以操作系统里有:内存管理模块、USB总线驱动、硬盘驱动,等等。

但是从软件的角度来看,只需要关注CPU、内存、寄存器

寄存器,是CPU里用来暂时存储数据的超高速存储单元。

汇编语言时,大多数时间就是跟寄存器打交道。

编译器,就是个代替人类写汇编语言的工具软件,所以编译器的大多数代码也是跟寄存器打交道。

寄存器、内存、汇编指令,是编译器后端绕不开的东西。

寄存器在不同的CPU平台上是不同的,叫的名字不一样,个数不一样,但是功能都差不多。

intel平台上,寄存器一开始是按功能起名字的,例如:

32位的CPU只有8个寄存器,分别是:eax,ebx,ecx,edx,ebp,esp,esi,edi。

1,eax,

16位机的时代叫ax

到了32位机的时代给扩展到了32位,所以叫“扩展的ax”extended ax,即eax

其他前面带e的寄存器,也是这么来的。

它最初的目的是作为加法器,名字里的a指的是add(按英语语法该用名词)。

但实际上,eax就是个通用寄存器。

按照C语言的二进制接口(ABI),约定它同时作为函数的返回值使用。

也就是说:

int ret = write();

在汇编里如果指定ret使用eax的话,这行的赋值不需要产生指令的(write()函数调用还是需要产生指令的)。

2,ebx,

如上面说的,它在16位时代叫bx,也是后来被扩展到32位的。

它的最初目的是作为基地址寄存器,b:base

但实际上,eb也是个通用寄存器。

3,ecx,

它的最初目的是作为计数寄存器,c:count

它可以作为通用寄存器,但在字符串传递、移位运算时,要作为计数器。

int a[10];

int b[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

for (int i = 0; i < 10; i )

a[i] = b[i];

这种代码,如果让人去写汇编的话,可以这么写:

lea edi, 80(ebp)

lea esi, 120(rbp)

mov ecx, 40

rep movsb

复制10个整数,一共40字节,目的地址放在edi源地址放在esi字节数放在ecx

ecx最初就是在这种指令里计量字节数用的,它现在依然保持着这个功能。

移位运算时,如果移位的位数不是常数,也要用ecx作为计数。

例如,a <<= i,a可以放在eax里,i就要放在ecx里。

因为就算是64位机上,合理的移位数字也不超过63位,所以实际使用的只有ecx的最低8位:它有个特别的名字,cl

4,edx,

它最初的目的是作为除法的余数、或者乘法的高位

整数除法,结果包括商和余数,eax里,余数edx里。

整数乘法,结果的位数一般是乘数位数的2倍,所以低位eax里,高位edx里。

不是乘法除法这种场合的话,edx也可以作为通用寄存器。

在16位时代,它叫dx,跟其他的一样也是后来扩充到32位的。

除法,d:divide

5,ebp,

凡是带p的寄存器,最初都是存储指针的寄存器。

ebp,栈底指针寄存器(栈帧寄存器),extended bottom pointer。

它属于特殊寄存器,在代码里的使用要特别小心,以防打乱了函数的调用链

函数的汇编代码大多是这样的:

push ebp

mov ebp, esp

...

mov esp, ebp

pop ebp

ret

首先保存ebp到栈上,然后把栈顶esp保存到ebp里,作为新函数的栈底

在整个新函数的调用期间,ebp最好不要有任何的修改,即它应该只读的

这样到了函数末尾,才可以用它回写esp,让函数正常返回。

6,esp,

它是栈顶寄存器,它存储的是函数栈的当前位置,即栈指针:extended stack pointer

esp和ebp互相配合,是CPU对函数栈的管理核心。

如果函数需要分配局部变量的话,就要把esp往低地址移动(减法),以扩大栈空间。

7,esi,edi,

这两个也是互相对应,一个做源地址寄存器,一个做目的地址寄存器,用于字符串的传递。

esi,extended source index,

edi,extended destination index。

它们两个在不是字符串传递的场合,也可以当作通用寄存器。

到了64位时代,这些寄存器全部从32位又扩展到了64位,名字改叫rax, rbx, rcx, ..., etc.

8,intel的寄存器,

0-7位(最低8位)以l结尾,al, bl, cl, dl.

8-15位以h结尾,ah, bh, ch, dh。

16位时代的寄存器只有16位,所以0-7位就是低位,low bits;8-15位就是高位,high bits。

整个16位寄存器,以x结尾:ax, bx, cx, dx。

那4个特殊寄存器:bp, sp, si, di。

到了32位时代,又都把名字前面加上了e。

到了64位时代,又把名字前面的e改成了r。

所以,rax是64位寄存器,在汇编里:它的0-7位是al8-15位是ah0-15位是ax0-31位是eax0-63位是rax

其他寄存器,也是这么起名字的。

所以,修改al是会影响ax, eax, rax的,但不会影响ah

计算机软件构成要素:软件视角下的计算机组成(1)

rax的位数分布

到了64位时代,intel又添加了8个通用寄存器,r8-r15。

这次因为寄存器太多了,intel就采取了ARM的叫法,直接按数字编号了。

intel搞了好几十年的CISC,最后还是学了RISC[捂脸]

9,最后说说内存,

内存,从软件的角度看,是个巨大的一维数组

32位的进程有0-4G的虚拟内存空间,这个数组就是:uint8_t memory[1 << 31];

64位的进程,虚拟内存空间可以有4Gx4G的空间:uint8_t memory[1 << 63];

内存的地址索引)是个无符号整数,它可以做加减运算。

例如,知道数组a[10]的内存地址,要找它的元素a[1]的内存地址,那么加上4个字节就行。

CPU要读写内存,就必须知道内存的地址。

这个地址在CPU读写时,该放在哪里

只能是寄存器里,这就是汇编语言里常说的寻址方式

为什么CPU要有寻址方式?

因为它在读写内存的时候,必须得把内存地址以某个方式、放在某个位置

A,如果内存地址直接放在寄存器里,那就是直接基地址寻址,也就是指针

读:a = *p;

写:*p =a;

翻译成汇编,p在rdx,a在rax,就是:

读:mov rax, (rdx)

写:mov (rdx), rax

B,如果内存地址是某个已知位置偏移量的话,就是基地址 偏移量寻址

例如结构体里有个成员变量y,它离结构体的"首地址"有4个字节,那么:

p->y = 1 翻译成汇编就是mov 4(rdx), 1,

其中指针p放在rdx里,4是偏移量的字节数。

C,如果内存地址是数组的一个元素,因为数组元素的大小是一样的,用数组地址 元素个数*元素大小进行寻址最为方便,

这就是SIB寻址:scale, index, base。

base:数组的“首地址”

index:元素的索引,即它是数组的第几个元素,从0开始计数。

scale放大系数,对应着数组每个元素的大小,用C语言表示就是sizeof(array[0])

例如:

int型数组a的第i号元素,赋值为1,C代码就是 a[i] = 1,

如果a放在rbx里,i放在rcx里,那么汇编就是:mov (rbx, rcx, 4), 1,

其中,4是每个元素的大小。

D,

当然,要是给第i个int型元素的第2号字节赋值,还可以这么写:mov 2(rbx, rcx, 4), 1。

这种一般没有实际意义,因为它对应的C代码是:

a[i] &= ~0xff0000; // 保留其他3个字节,把第2号字节清零,

a[i] |= 0x010000; // 把清零之后的第2号字节设置为1。

要想判断出这2行代码的目的是给a[i]的第2号字节赋值为1,也太考验编译器了!

汇编的内存寻址方式,总的概括就是:

写内存:mov disp(base, index, scale), src

读内存:mov dst, disp(base, index, scale)

其中:

disp是相对于基地址的偏移量,

base是基地址,

index是位置索引,

scale是放大系数,

src源操作数,它可以是寄存器,也可以是常数,但不能是另一个内存地址

dst是目的操作数,它必须是寄存器

表示内存地址的那4项(disp, base, index, scale),可以酌情省略一部分[呲牙]

最后,在windows和Linux上的汇编有点不同

1,汇编的源操作数目的操作数的位置是反的

2,而且Linux上的寄存器前要加%

3,内存寻址,windows上用中括号[],Linux上用小括号(),

我这种写法是把它们两个的风格混合的写法,属于伪代码。

你要是真写能用的汇编的话,最好查一下标准写法,免得汇编器报语法错误。

  • 人的尿液一般是什么颜色(人的尿液有12种颜色)
  • 2024-07-03人的尿液有12种颜色人的尿液其实有多达12种颜色,比彩虹颜色还丰富,不同颜色还能看出身体哪儿出了问题……近日,美国俄亥俄一家学术医疗中心制作了一张尿液比色卡,声称可以凭借尿液颜色来判断身体健康状况你知道吗?人的尿液除了黄。
  • 跟猫有关的好看电影(部关于猫的最佳电影)
  • 2024-07-03部关于猫的最佳电影和狗一样,猫也是很好的伙伴当然,它们是独立的生物,但它们也与人类形成了难以置信的联系(甚至研究证明它们可以提升我们的情绪)因此,我们的猫科动物朋友启发了这么多关于猫的电影也就不足为奇了,无论是令人大开。
  • 夏季的衣服40岁妇女穿的搭配(40岁女性春季别乱穿)
  • 2024-07-0340岁女性春季别乱穿40岁的女性,在穿搭中最重要的是体现出自身的“气质感”,40岁不同于20岁,这时候自己早已蜕下了年轻时的“青涩”,自身气质也随着年龄的增加会变得越发成熟沉稳对于40岁的女性朋友而言,穿得太过“稚嫩”显。
  • 山居秋暝五年级上册课文翻译(秋思唐张籍五年级)
  • 2024-07-03秋思唐张籍五年级洛阳城里见秋风,欲作家书意万重复恐匆匆说不尽,行人临发又开封注释意万重:形容要表达的意思很多复恐:又怕行人:这里指捎信的人开封:把封好的信拆开译文洛阳城里刮起了秋风,很想写一封家信,要说的话很多,可又。
  • 不木不泰啥意思
  • 2024-07-03不木不泰啥意思不忎和不忈的意思都是不仁,忎和忈都是仁的古字一、忎忎古同“仁”部首心部,部外笔画3画,总笔画7画,结构上下二、忈忈是古时“仁”的异体字,指仁爱、亲在网络上,由于“忈”字的结构是上面一个“二”,下面一个。
  • 佘诗曼演过的好看的电视剧(美人计佘诗曼新剧杀青)
  • 2024-07-03美人计佘诗曼新剧杀青在我最近正为剧荒发愁的时候,佘诗曼的一条微博成功地吸引了我的注意前两天她的新剧《鬓边不是海棠红》刚刚杀青,随后她便在微博发文:我要讲一个我和二奶奶的故事给你们听此次故事背景设定是在民国,佘诗曼在其中扮。
  • 王者荣耀抢先服有什么用(王者荣耀抢先服信息)
  • 2024-07-03王者荣耀抢先服信息抢先服会比正式服提前3-7天更新,这段时间抢先服玩家不能和正式服其他玩家开黑,只能和本服匹配抢先服不能和微信好友、QQ好友成为游戏好友当抢先服提前更新版本时,如果玩家已更新至抢先服最新版本,如果要登录。
  • 在什么样的春晚中吃年夜饭(为什么过年吃饺子)
  • 2024-07-03为什么过年吃饺子2020年春节联欢晚会在除夕之夜为广大观众献上了一台高水准的视听盛宴据统计,截至25日零时春晚电视直播5.89亿人次,新媒体平台直播11.16亿人次,另有560多家海外媒体转播报道了春晚,触达人次超过。
  • nba单机推荐(中超化NBA2022版)
  • 2024-07-03中超化NBA2022版NBA球队中超版近年来NBA在萧华的带领下开辟了球衣广告,篮球菠菜合法化等一系列神奇操作萧华的世界一直都是以钱为主要比赛次之,可能以后会禁止比赛中身体接触,汗毛碰汗毛就技犯据猜测未来二年萧华计划如下:。
  • 蒙古帝国是如何兴起和建立的(蒙古人建立的帝国都短)
  • 2024-07-03蒙古人建立的帝国都短莫卧儿帝国,确实是蒙古人在世界上建立过的大帝国中,时间最长久的蒙古人在中国建立的元朝不到100年,在俄罗斯建立的金帐汗国200多年,而在印度建立的莫卧儿帝国则长达300多年这么长的一个时期,差不多相当。
  • 夏天上火的人能吃鸭肉吗(夏天吃鸭肉补身体祛湿热)
  • 2024-07-03夏天吃鸭肉补身体祛湿热鸭肉的做法:【香菇烧鸭肉】“鸭肉,是我们家经常出现的食材,经常用来炖烫或者烧肉吃,但是儿子似乎对2条腿的食物总是不那么喜欢,考虑到鸭肉滋阴,对于正发育期的孩子是很好的食材,所以想办法让孩子多吃点便是当。
  • 18款速腾1 4t豪华版操作讲解(全款16.18万买速腾)
  • 2024-07-03全款16.18万买速腾很多人喜欢买速腾是因为这车更加有德系质感,从第一代的PQ35平台再到现在的MQB-A2平台,轴距加长到了现在的2731mm,凭借着强大的产品竞争力和口碑,使得该车成为了A级轿车的标杆新款速腾前脸造型线。