前言
本文是我学习Go汇编的一些心得,网上关于Go的汇编资料实在是太少了,本人计算机不是科班,所以__可能会有错误__。
进程内存地址空间
操作系统执行程序时,会把程序的二进制部分加载进内存,同时分配一定的内存空间。如下图所示
TEXT/Code segment
TEXT segment,或者叫Code segment,保存了程序的指令。
- 只能执行
- 固定长度
Data segment
Data segment 保留着进程初始化的全局和静态的变量。这个数据段可以变为初始化只读区域(initialized read-only area)和初始化读写区域(initialized read-write area)。
Gvar Section
一个全局变量初始化和存储在data segment。这个区域可读/写,但是不能在进程之间共享数据。
BSS Section
这个section保存着未初始化的数据。 这个section的又叫做零初始化数据section(zero-initialized data section)
Heap Section
heap是进程的线性增长地址空间,当程序使用malloc()获取的动态内存,这份内存就是在heap之中。heap区域是在BSS segement之后,并会“增长”到更高的地址空间。heap区域是所有共享库、动态模块都可见的。
- 可读写
- 变量大小
- 请求之后动态分配,需要自己释放
Stack Segment
这个Segement保存所有局部变量。当调用函数时,这个函数的局部变量就全部分布在stask上(这个函数就形成了stack frame)。当函数退出时,所有该函数相关的局部变量会自动从stask上退出。其他信息,包括返回地址和局部参数,也是保存在stack的stack frame之上。stack是LIFO(last in first out 先进后出)结构,一般是分配在内存的高地址上,因此是向低位增长,还有每个寄存器,中间值或者stack frame。
- 可读写
- 变量大小
- 动态增长\缩小
跟Go asm有什么关系?
Go有几个虚拟寄存器
- FP (stack frame pointer) stack帧低位指针,指向参数和局部变量,offset为正数
- SP(virtual stack pointer)stack帧高位指针(栈顶),offset应为负数
- PC (program counter) 程序计数器,负责跳转和分支
- SB (static base pointer) 静态全局符号(symbol)
其中FP和SP的区别如下图所示:
High +-----------------+
| |
| Stack frame 0 |
| |
+-----------------+
| | <---+ SP
| Stack frame 1 |
| | <---+ FP
Low +-----------------+
这里有个疑问的地方,啥是符号(symbol),根据Symbol里的解释是:
符号(symbol)是帮助人们标记特定内存地址的东西
也就是说例如
TEXT DEMO(SB)
就代表指向code segment中代表DEMO函数的内存地址。
寄存器
每种CPU都有不同的寄存器,AMD64平台里常用的有以下几个:
- [A-D]X //通用的64位寄存器
- R8-15 // 之前的其实是A-Dx、SI、DI等寄存器占用了
- SI // 源(source register)
- DI // 目的地 (destination register)
- X0-15 // sse用
- Y0-15 // avx2 用
了解完内存结构和寄存器后,下一篇将学习各种符号的意义:)