From d4081997b5e61b801bca7f12483fefbaadd4b38c Mon Sep 17 00:00:00 2001 From: chai2010 Date: Sun, 3 Jun 2018 07:11:02 +0800 Subject: [PATCH] =?UTF-8?q?ch3-03:=20=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ch3-asm/ch3-03-const-and-var.md | 73 +++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/ch3-asm/ch3-03-const-and-var.md b/ch3-asm/ch3-03-const-and-var.md index 4764e6a..badf8d0 100644 --- a/ch3-asm/ch3-03-const-and-var.md +++ b/ch3-asm/ch3-03-const-and-var.md @@ -26,6 +26,79 @@ $(3&1)<<2 // == $4 其中常量表达式中运算符的优先级和Go语言保持一致。 + ## 全局变量 +在Go语言中,变量根据作用域和生命周期有全局变量和局部变量之分。全局变量是包一级的变量,全局变量一般有着较为固定的内存地址,声明周期跨越整个程序运行时间。而局部变量一般是函数内定义的的变量,只有在函数被执行的时间才能被创建,当函数完成时将回回收(暂时不考虑闭包对局部变量捕获的问题)。 + +从Go汇编语言角度来看,局部变量和局部变量也大的差异。在Go汇编中全局变量和全局函数更为相似,都是通过一个认为定义的符号来引用对应的内存,区别只是内存中存放是数据还是要执行的指令。因为在冯诺伊曼系统结构的计算机中指令也是数据,而且指令和数据存放在统一编址的内存中,因此指令和数据并没有本质的差别——我们甚至可以像操作数据那样动态生成指令。而局部变量则需了解了汇编函数之后,通过SP栈空间来隐式定义。 + +在Go汇编语言中,内存是通过SB伪寄存器定位。SB是Static base pointer的缩写,意为静态内存的开始地址。所有的静态全局符号通过可以通过SB加一个偏移量定位,而我们定义的符号其实就是相对于SB内存开始地址偏移量。对于SB伪寄存器,全局变量和全局函数的符号并没有任何区别。 + +要定义全局变量,首先要声明一个变量对应的符号,以及变量对应的内存大小。导出变量符号的语法如下: + +``` +GLOBL symbol(SB), width +``` + +GLOBL汇编指令用于定义名为symbol的变量,变量对应的内存宽度为width,内存宽度部分必须用常量初始化。下面的代码通过汇编定义一个int32类型的count变量: + +``` +GLOBL ·count(SB),$4 +``` + +其中符号`·count`以中点开头表示是当前包的变量,最终符号名为被展开为`path/to/pkg.count`。count变量的大小是4个字节,常量必须以$美元符号开头。内存的宽度必须是2的指数倍,编译器最终会保证变量的其实地址对齐到机器字宽度。需要注意的是,在Go汇编中我们无法为count变量指定具体的类型。在汇编中定义全局变量时,我们值关心变量的名字和内存大小,变量最终的类型只能在Go语言中声明。 + +变量定义之后,我们可以通过DATA汇编指令指定对应内存中的数据,语法如下: + +``` +DATA symbol+offset(SB)/width, value +``` + +具体的含义是从symbol+offset偏移量开始,width宽度的内存,用value常量对应的值初始化。DATA初始化内存时,width必须是1、2、4、8几个宽度之一,因为再大的内存无法一次性用一个uint64大小的值表示。 + +对于int32类型的count变量来说,我们既可以逐个字节初始化,也可以一次性初始化: + +``` +DATA ·count+0(SB)/1,$1 +DATA ·count+1(SB)/1,$2 +DATA ·count+2(SB)/1,$3 +DATA ·count+3(SB)/1,$4 + +// or + +DATA ·count+0(SB)/4,$0x01020304 +``` + +因为X86处理器是小端序,因此用十六进制0x01020304初始化全部的4个字节,和用1、2、3、4逐个初始化4个字节是一样的效果。 + +最后还需要在Go语言中声明对应的变量(和C语言头文件声明变量的作用类似),这样垃圾回收器会更加变量的类型来管理其中的指针相关的内存数据。 + +## bool型变量 + TODO + +## int型变量 + +TODO + +## float型变量 + +TODO + +## string类型变量 + +TODO + +## slice类型变量 + +TODO + +## map/channel类型变量 + +TODO + +## 标识符规则和特殊标志 + +TODO +