您的位置:首页 > 理论基础

计算机是如何工作的

2017-02-25 20:11 197 查看

存储程序计算机工作模型

冯诺依曼体系结构就是指存储程序计算机

从硬件上,CPU和内存由总线连接,CPU上有一个寄存器叫IP(Instruction Pointer),64位下叫rip, 可以认为是一个指针,总是指向内存中的代码段(cs code segment),cpu从IP指向的内存地址取来一条指令执行,执行完后,IP自加一,取下一条指令继续执行。

从程序员来看,内存有指令和数据,cpu抽象成一个for循环,从内存取下一条指令,解释执行指令

32位下, eip每一次自加到下一条指令,因为指令长度是不同的,eip除了可以自加外,可以被call,ret, jmp和条件跳转改变(对应c里的if-else,函数调用,return等)

寄存器

32位下有8个通用寄存器

eax 累加器

ebx 基地址寄存器

ecx 计数寄存器

edx 数据寄存器

ebp 堆栈基指针(寄存器)

esi edi 变址寄存器

esp 堆栈顶寄存器

段寄存器

cs 代码段寄存器,其值为代码段的段值

ds 数据段寄存器,其值为数据段的段值

es 附加段寄存器,其值为附加段的段值

ss 堆栈段寄存器,其值为堆栈段的段值

fs 附加段寄存器,其值为附加数据段的段值

gs 附加段寄存器,其值为附加数据段的段值

cpu在实际取指令时根据cs:eip来准确定位一个指令


每一个进程都有自己的堆栈


寻址方式

movl %eax, %edx

edx = eax; 寄存器寻址

movl $0x123, %edx

edx = 0x123 立即寻址,立即数是以$开头的数值

movl 0x123, %edx

edx = (int32_t)0x123 直接寻址 直接访问一个指定的内存地址的数据

movl (%ebx), %edx

edx = (int32_t)ebx 间接寻址 将寄存器的值作为一个内存地址来访问内存

movl 4(%ebx), %edx

edx = (int32_t)(ebx + 4) 变址寻址(displaced) 在间接寻址之时改变寄存器的数值

常用指令

pushl %eax

subl $4, %esp

movl %eax, (%esp)

popl %eax

movl (%esp), %eax

addl $4, %esp

call 0x12345

pushl %eip

movl $0x12345, %eip

ret

popl %eip

eip寄存器不能被程序员直接修改,只能通过特殊指令间接修改


enter

pushl %ebp

movl %esp, %ebp

leave

movl %ebp, %esp

popl %ebp

汇编一个简单的c程序

int g(int x)
{
return x + 5;
}

int f(int x)
{
return g(x);
}

int main()
{
return f(3) + 9;
}


通过gcc -S -o main.s main.c -m32 生成的汇编的代码,所有以.开头的都是用于链接的辅助信息,不会被实际执行

注释从main函数看起,遇到call x则跳转到该函数x,ret之后返回到call x的下一条指令

内存中栈是从高地址向低地址增长的

从main开始,eip会自动指向吓一跳指令,或者由指令修改

函数调用堆栈是由逻辑上多个堆栈叠加起来的,ebp指向堆栈栈底,esp指向栈顶,堆栈是相对的,因为每个函数都有自己的基地址

函数的返回值默认使用而eax寄存器存储返回给上一级函数

g:
pushl   %ebp
movl    %esp, %ebp
movl    8(%ebp), %eax   #将f传来的参数放到eax,即eax = 8
addl    $5, %eax        #eax = 8 + 3 = 11
popl    %ebp            #将调用g的函数ebp给pop回来,即ebp指回f的栈基址
ret                     #popl %eip,此时eip指回调用该函数的下一条指令
f:
pushl   %ebp            #将ebp压栈
movl    %esp, %ebp      #修改ebp的值,此时ebp和esp指向同一个位置
pushl   8(%ebp)         #取ebp+8里的数,即将main调用f时传进的3压栈,相当于subl $4, %eax movl 8(%ebp) %eax movl %eax (%esp)
call    g               #pushl %eip,跳转到g继续执行
addl    $4, %esp        #对应于上面的pushl 8(%ebp)感觉这句话可以不用,因为下面有个leave
leave                   #把esp指向ebp的位置
ret                     #popl %eip,eip指回调用它的函数的下一条指令
main:                       #eip最初指向main
pushl   %ebp            #将ebp压栈
movl    %esp, %ebp      #修改ebp的值,此时ebp和esp指向同一个位置
pushl   $3              #将esp减掉4,然后将3压栈
call    f               #pushl %eip,此时压入的eip指向的是下一行,然后eip指向了f,跳转到f继续执行
addl    $4, %esp
addl    $9, %eax
leave                   #回到main函数最初的状态
ret                     #返回到main函数之前的堆栈


总结

计算机系统是由硬件和系统软件组成的,它们共同工作来运行应用程序。虽然系统的具体实现方式随着时间不断变化,大师系统内在的概念没有变化。所有计算机系统都有相似的硬件和软件组件,它们执行着相似的课程。

本次课程使我重新复习了汇编程序设计,并对c语言和汇编的对应有了更深一步的了解,让我能更看清楚自己所写的c语言代码在内存中的表示方式。并且从汇编代码看起来,cpu作加载(从主存复制一个字节或者一个字寄存器)、存储(从寄存器复制一个字节或者一个字到主存某个位置)、操作(作算术运算)、跳转等功能,和主存之间的行为通过总线相连。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  计算机 cpu linux