计算机是如何工作的

存储程序计算机工作模型

  • 冯诺依曼体系结构就是指存储程序计算机
    • 从硬件上,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;
}
  1. 通过gcc -S -o main.s main.c -m32 生成的汇编的代码,所有以.开头的都是用于链接的辅助信息,不会被实际执行
  2. 注释从main函数看起,遇到call x则跳转到该函数x,ret之后返回到call x的下一条指令
  3. 内存中栈是从高地址向低地址增长的
  4. 从main开始,eip会自动指向吓一跳指令,或者由指令修改
  5. 函数调用堆栈是由逻辑上多个堆栈叠加起来的,ebp指向堆栈栈底,esp指向栈顶,堆栈是相对的,因为每个函数都有自己的基地址
  6. 函数的返回值默认使用而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作加载(从主存复制一个字节或者一个字寄存器)、存储(从寄存器复制一个字节或者一个字到主存某个位置)、操作(作算术运算)、跳转等功能,和主存之间的行为通过总线相连。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值