文档详情

GoLang函数栈的使用详细讲解.docx

发布:2025-05-19约3.88千字共8页下载文档
文本预览下载声明

GoLang函数栈的使用详细讲解

目录函数栈帧寄存器

函数栈帧

我们的代码会被编译成机器指令并写入到可执行文件,当程序执行时,可执行文件被加载到内存,这些机器指令会被存储到虚拟地址空间中的代码段,在代码段内部,指令是低地址向高地址堆积的。堆区存储的是需要程序员手动alloc并free的空间,需要自己来控制。

虚拟内存空间是对存储器的一层抽象,是为了更好的来管理存储器,虚拟内存和存储器之间存在映射关系。

如果在一个函数中调用了另外一个函数,编译器就会对应生成一条call指令,当call指令被执行时,就会跳转到被调用函数入口处开始执行,而每个函数的最后都有一条ret指令,负责在函数结束后跳回到调用处继续执行。

call指令做了两件事,将下一条指令的地址入栈,这就是IP寄存器中存储的值,第二,跳转到被调用函数入口处执行。

函数执行时需要有足够的内存空间用来存储参数,局部变量,返回值,这块空间对应的就是栈,栈区是从高地址向低地址生长的,且先进后出。分配给函数的栈空间被称为函数栈帧。

C语言中,每个栈帧对应着一个未运行完的函数。栈帧中保存了该函数的返回地址和局部变量。

寄存器

ESP寄存器:ESP即Extendedstackpointer的缩写,直译过来就是扩展的栈指针寄存器。SP是16位的,ESP是32位的,RSP是64位的,存放的都是栈顶地址。

EBP寄存器:EBP即Extendedbasepointer的缩写,直译过来就是扩展的基址指针寄存器。该指针总是指向当前栈帧的底部。

IP寄存器:指令指针,它指向代码段中的地址,是一个16位专用寄存器,它指向当前需要取出的指令字节,也就是下一个将要执行的指令在代码段中的地址。

eax:累加(Accumulator)寄存器,常用于函数返回值

ebx:基址(Base)寄存器,以它为基址访问内存

ecx:计数器(Counter)寄存器,常用作字符串和循环操作中的计数器

edx:数据(Data)寄存器,常用于乘除法和I/O指针

esi:源地址寄存器

edi:目的地址寄存器

esp:堆栈指针

ebp:栈指针寄存器

当然,以上功能并未限制寄存器的使用,特殊情况为了效率也可作其他用途。

这八个寄存器低16位分别有一个引用别名ax,bx,cx,dx,bp,si,di,sp,

其中ax,bx,cx,dx,的高8位又引用至ah,bh,ch,dh,低八位引用至al,bl,cl,dl

在64-bit模式下,有16个通用寄存器,但是这16个寄存器是兼容32位模式的,

32位方式下寄存器名分别为eax,ebx,ecx,edx,edi,esi,ebp,esp,r8dr15d.

在64位模式下,他们被扩展为rax,rbx,rcx,rdx,rdi,rsi,rbp,rsp,r8r15.

其中r8r15这八个寄存器是64-bit模式下新加入的寄存器。

我们看到CPU在执行代码段中的指令,而这当中又伴随着内存的分配,于是在函数栈帧上就会有相应的变化。

intadd(inta,intb)

intc=4;

c=a+b;

returnc;

intmain()

inta=1;

intb=2;

intsum=3;

sum=add(a,b);

return0;

生成的汇编代码的方式

1、使用gcc+objdump

gcc-save-temps-fverbose-asm-g-obtestasm.c

objdump-S--disassemblebb.objdump

2、使用第三方网站来生成,进入/,选择语言为C,编译器为x86-64gcc12.2,粘贴进你的代码,就能看到汇编代码,如下

add:

pushrbp

movrbp,rsp

movDWORDPTR[rbp-20],edi

movDWORDPTR[rbp-24],esi

movDWORDPTR[rbp-4],4

movedx,DWORDPTR[rbp-20]

moveax,DWORDPTR[rbp-24]

显示全部
相似文档