Skip to content

Commit e56f76f

Browse files
authored
style: 修改排版
1 parent f7b86df commit e56f76f

File tree

1 file changed

+10
-10
lines changed

1 file changed

+10
-10
lines changed

ch3-asm/ch3-01-basic.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@ Go 汇编程序始终是幽灵一样的存在。我们将通过分析简单的 G
44

55
## 3.1.1 实现和声明
66

7-
Go 汇编语言并不是一个独立的语言,因为 Go 汇编程序无法独立使用。Go 汇编代码必须以 Go 包的方式组织,同时包中至少要有一个 Go 语言文件用于指明当前包名等基本包信息。如果 Go 汇编代码中定义的变量和函数要被其它 Go 语言代码引用,还需要通过 Go 语言代码将汇编中定义的符号声明出来。用于变量的定义和函数的定义 Go 汇编文件类似于 C 语言中的. c 文件,而用于导出汇编中定义符号的 Go 源文件类似于 C 语言的. h 文件。
7+
Go 汇编语言并不是一个独立的语言,因为 Go 汇编程序无法独立使用。Go 汇编代码必须以 Go 包的方式组织,同时包中至少要有一个 Go 语言文件用于指明当前包名等基本包信息。如果 Go 汇编代码中定义的变量和函数要被其它 Go 语言代码引用,还需要通过 Go 语言代码将汇编中定义的符号声明出来。用于变量的定义和函数的定义 Go 汇编文件类似于 C 语言中的 `.c` 文件,而用于导出汇编中定义符号的 Go 源文件类似于 C 语言的 `.h` 文件。
88

99
## 3.1.2 定义整数变量
1010

1111
为了简单,我们先用 Go 语言定义并赋值一个整数变量,然后查看生成的汇编代码。
1212

13-
首先创建一个 pkg.go 文件,内容如下:
13+
首先创建一个 `pkg.go` 文件,内容如下:
1414

1515
```go
1616
package pkg
@@ -59,7 +59,7 @@ GLOBL ·Id, $8
5959

6060
现在已经初步完成了用汇编定义一个整数变量的工作。
6161

62-
为了便于其它包使用该 Id 变量,我们还需要在 Go 代码中声明该变量,同时也给变量指定一个合适的类型。修改 pkg.go 的内容如下:
62+
为了便于其它包使用该 Id 变量,我们还需要在 Go 代码中声明该变量,同时也给变量指定一个合适的类型。修改 `pkg.go` 的内容如下:
6363

6464
```go
6565
package pkg
@@ -69,7 +69,7 @@ var Id int
6969

7070
现状 Go 语言的代码不再是定义一个变量,语义变成了声明一个变量(声明一个变量时不能再进行初始化操作)。而 Id 变量的定义工作已经在汇编语言中完成了。
7171

72-
我们将完整的汇编代码放到 pkg_amd64.s 文件中:
72+
我们将完整的汇编代码放到 `pkg_amd64.s` 文件中:
7373

7474
```
7575
#include "textflag.h"
@@ -86,7 +86,7 @@ DATA ·Id+6(SB)/1,$0x00
8686
DATA ·Id+7(SB)/1,$0x00
8787
```
8888

89-
文件名 pkg_amd64.s 的后缀名表示 AMD64 环境下的汇编代码文件。
89+
文件名 `pkg_amd64.s` 的后缀名表示 AMD64 环境下的汇编代码文件。
9090

9191
虽然 pkg 包是用汇编实现,但是用法和之前的 Go 语言版本完全一样:
9292

@@ -107,7 +107,7 @@ func main() {
107107

108108
在前一个例子中,我们通过汇编定义了一个整数变量。现在我们提高一点难度,尝试通过汇编定义一个字符串变量。虽然从 Go 语言角度看,定义字符串和整数变量的写法基本相同,但是字符串底层却有着比单个整数更复杂的数据结构。
109109

110-
实验的流程和前面的例子一样,还是先用 Go 语言实现类似的功能,然后观察分析生成的汇编代码,最后用 Go 汇编语言仿写。首先创建 pkg.go 文件,用 Go 语言定义字符串:
110+
实验的流程和前面的例子一样,还是先用 Go 语言实现类似的功能,然后观察分析生成的汇编代码,最后用 Go 汇编语言仿写。首先创建 `pkg.go` 文件,用 Go 语言定义字符串:
111111

112112
```go
113113
package pkg
@@ -128,7 +128,7 @@ go.string."gopher" SRODATA dupok size=6
128128

129129
输出中出现了一个新的符号 go.string."gopher",根据其长度和内容分析可以猜测是对应底层的 "gopher" 字符串数据。因为 Go 语言的字符串并不是值类型,Go 字符串其实是一种只读的引用类型。如果多个代码中出现了相同的 "gopher" 只读字符串时,程序链接后可以引用的同一个符号 go.string."gopher"。因此,该符号有一个 SRODATA 标志表示这个数据在只读内存段,dupok 表示出现多个相同标识符的数据时只保留一个就可以了。
130130

131-
而真正的 Go 字符串变量 Name 对应的大小却只有 16 个字节了。其实 Name 变量并没有直接对应 “gopher” 字符串,而是对应 16 字节大小的 reflect.StringHeader 结构体:
131+
而真正的 Go 字符串变量 `Name` 对应的大小却只有 16 个字节了。其实 `Name` 变量并没有直接对应 “gopher” 字符串,而是对应 16 字节大小的 reflect.StringHeader 结构体:
132132

133133
```go
134134
type reflect.StringHeader struct {
@@ -137,9 +137,9 @@ type reflect.StringHeader struct {
137137
}
138138
```
139139

140-
从汇编角度看,Name 变量其实对应的是 reflect.StringHeader 结构体类型。前 8 个字节对应底层真实字符串数据的指针,也就是符号 go.string."gopher" 对应的地址。后 8 个字节对应底层真实字符串数据的有效长度,这里是 6 个字节。
140+
从汇编角度看,`Name` 变量其实对应的是 `reflect.StringHeader` 结构体类型。前 8 个字节对应底层真实字符串数据的指针,也就是符号 go.string."gopher" 对应的地址。后 8 个字节对应底层真实字符串数据的有效长度,这里是 6 个字节。
141141

142-
现在创建 pkg_amd64.s 文件,尝试通过汇编代码重新定义并初始化 Name 字符串:
142+
现在创建 pkg_amd64.s 文件,尝试通过汇编代码重新定义并初始化 `Name` 字符串:
143143

144144
```
145145
GLOBL ·NameData(SB),$8
@@ -152,7 +152,7 @@ DATA ·Name+8(SB)/8,$6
152152

153153
因为在 Go 汇编语言中,go.string."gopher" 不是一个合法的符号,因此我们无法通过手工创建(这是给编译器保留的部分特权,因为手工创建类似符号可能打破编译器输出代码的某些规则)。因此我们新创建了一个 ·NameData 符号表示底层的字符串数据。然后定义 ·Name 符号内存大小为 16 字节,其中前 8 个字节用 ·NameData 符号对应的地址初始化,后 8 个字节为常量 6 表示字符串长度。
154154

155-
当用汇编定义好字符串变量并导出之后,还需要在 Go 语言中声明该字符串变量。然后就可以用 Go 语言代码测试 Name 变量了:
155+
当用汇编定义好字符串变量并导出之后,还需要在 Go 语言中声明该字符串变量。然后就可以用 Go 语言代码测试 `Name` 变量了:
156156

157157
```go
158158
package main

0 commit comments

Comments
 (0)