linux内核分析之-x86汇编原理

本文介绍了冯·诺依曼结构计算机的基本原理,并详细解析了x86汇编语言中的通用寄存器类型及常见指令。通过分析一段简单C程序对应的汇编代码,展示了程序如何在底层被执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

linux内核分析之-x86汇编原理

作者:郎勇

前言

冯·诺依曼提出了在数字计算机内部的存储器中存放程序的概念(Stored Program Concept),这是所有现代电子计算机的范式,被称为“冯· 诺依曼结构”,按这一结构建造的电脑称为存储程序计算机(Stored Program Computer),又称为通用计算机。冯·诺依曼计算机主要由运算器、控制器、存储器和输入输出设备组成,它的的特点是:程序以二进制代码的形式存放在存储器中;所有的指令都是由操作码和地址码组成;指令在其存储过程中按照执行的顺序(摘自百度百科);

学习汇编,有助于我们更好地理解通用计算机的运行原理,因此无论在我们的学习和工作中是否会涉及到汇编,了解汇编的基本知识,对开阔我们程序开发人员的视野,是大有帮助的。编写本博客的初衷是为了完成网易云课堂的随堂作业,希望自己在编写本博客的过程中,对x86汇编原理获得更深一步的认识,与此同时,也希望能帮助所有看到这篇博客的人。

对系统学习linux内核感兴趣的同学,可以前往
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000


通用寄存器的类型

16bit32bitdesc
AXEAX累加器(Accumulator)
BXEBX基地址寄存器(Base Register)
CXECX计数寄存器(Count Register)
DXEDX数据寄存器(Data Register)
BPEBP堆栈基指针(Base Pointer)
SIESI变址寄存器(Index Register)
DIEDI变址寄存器(Index Register)
SPESP堆栈顶指针(Stack Pointer)

此外还有一个需要了解的寄存器是IP\EIP指令指针寄存器(Instruction Pointer),它可以存放下次将要执行的指令在代码段的偏移量。可以理解为它总是指向下一条将要执行的指令的编号。IP\EIP寄存器通常是不可以直接操作的,通常只能通过jmp、call或者ret等指令进行间接修改。

常见的汇编指令

  • 数据传输指令 MOV, PUSH, POP等
  • 程序转移指令 CALL, RET, JMP等
  • 算数运算指令 ADD,SUB,MUL,DIV等
  • 逻辑运算指令 AND,OR,XOR,NOT等

一段简单的C程序对应的汇编程序

我们编写一段简单的c程序

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

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

int main(void)
{
      return f(3) + 1;
}

执行命令gcc –S –o main.s main.c -m32生成c程序对应的汇编代码

这里写图片描述

为了方便查看起见,把所有.开头的行删除,因为这些行是汇编器命令,这里我们并不关心。结果如下:

g:
    pushl   %ebp
    movl    %esp, %ebp
    movl    8(%ebp), %eax
    addl    $11, %eax
    popl    %ebp
    ret
f:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    8(%ebp), %eax
    movl    %eax, (%esp)
    call    g
    leave
    ret
main:
    pushl   %ebp
    movl    %esp, %ebp
    subl    $4, %esp
    movl    $3, (%esp)
    call    f
    addl    $1, %eax
    leave
    ret

程序从入口函数main开始分析:

pushl   %ebp
movl    %esp, %ebp

这两句相当于enter指令,用来在程序开头启用新的栈底地址,将之前的堆栈基地址保存到栈顶指向的内存地址中,然后将esp和ebp指针对齐。

subl    $4, %esp

将esp向栈顶偏移4个字节的距离

movl    $3, (%esp)

将立即数3存储到esp寄存器指向的内存地址中

call    f

程序跳转到函数f的入口地址,eip中存放函数f的第一条指令

pushl   %ebp
movl    %esp, %ebp
subl    $4, %esp

此三条指令跟main函数的前三条指令完成的功能是一样的。

movl    8(%ebp), %eax

将堆栈基地址向栈底偏移8个字节的长度,内容取出后存储到eax中。此时eax中存储的内容是3。

movl    %eax, (%esp)

将eax中的内容(即3)存储到esp对应的内存地址中。

call    g

程序跳转到函数g的入口地址,eip中存放函数g的第一条指令。

pushl   %ebp
movl    %esp, %ebp

此三条指令跟main函数和f函数的前两条指令完成的功能是一样的。

movl    8(%ebp), %eax

将堆栈基地址向栈底偏移8个字节的长度,内容取出后存储到eax中。此时eax中存储的内容是3。

addl    $11, %eax

将立即数11加到eax中,eax中的内存为14

popl    %ebp

弹出esp中的内容,恢复函数f的堆栈基地址

ret

eip恢复为函数g返回后,函数f继续执行的代码段偏移

leave
ret

弹出esp中的内容,恢复函数main的堆栈基地址,eip恢复为函数f返回后,函数main继续执行的代码段偏移

addl    $1, %eax

将立即数1加到eax中,此时eax的内容为14+1=15

leave
ret

弹出esp中的内容,恢复之前调用函数的堆栈基地址,eip恢复为函数main返回后,调用函数继续执行的代码段偏移

结论

计算机的运行过程,就是一个按次序读取存储器中代码指令,然后通过cpu解释并执行指令的过程。执行时所用到的基本数据结构是堆栈。cpu可以直接操作寄存器中的内容。

原创作品转载请注明出处

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值