1
0
mirror of https://github.com/chai2010/advanced-go-programming-book.git synced 2025-05-24 04:22:22 +00:00

ch3-01: 完善

This commit is contained in:
chai2010 2018-05-21 06:51:38 +08:00
parent 32865f9369
commit 537decf3bd
8 changed files with 144 additions and 2 deletions

View File

@ -1,6 +1,108 @@
# 3.1. 快速入门
在第一章的“Hello, World 的革命”一节中我们已经见过一个Go汇编程序。本节我们将通过由浅入深的一系列小例子来快速掌握Go汇编的简单用法。
在第一章的“Hello, World 的革命”一节中我们已经见过一个Go汇编程序。本节我们将通过分析简单的Go程序输出的汇编代码然后照猫画虎用汇编实现一个简单的输出程序。
## 实现和声明
Go汇编语言并不是一个独立的语言主要原因是因为Go汇编程序无法独立使用。Go汇编代码必须以Go包的方式被组织同时包中至少要有一个Go语言文件。如果Go汇编代码中定义的变量和函数要被其它Go语言代码引用还需要通过Go语言代码将汇编中定义的符号声明出来。用于变量的定义和函数的定义Go汇编文件类似于C语言中的.c文件。而用于导出汇编中定义符号的Go源文件类似于C语言的.h文件。
## 定义整数变量
为了简单我们先用Go语言定义并赋值一个整数变量然后查看生成的汇编代码。
创建pkg.go文件内容如下
```go
package pkg
var Id = 9527
```
然后用以下命令查看的Go语言程序对应的伪汇编代码
```
$ go tool compile -S pkg.go
"".Id SNOPTRDATA size=8
0x0000 37 25 00 00 00 00 00 00 '.......
```
输出的汇编比较简单,其中`"".Id`对应Id变量符号变量的内存大小为8个字节。变量的初始化内容为`37 25 00 00 00 00 00 00`对应十六进制格式的0x2537对应十进制为9527。SNOPTRDATA是相关的标志暂时忽略。
以上的内容只是目标文件对于的汇编和Go汇编语言虽然相似当并不完全等价。Go语言官网自带了一个Go汇编语言的入门教程地址在https://golang.org/doc/asm。
Go汇编语言提供了DATA命令用于初始化变量DATA命令的语法如下
```
DATA symbol+offset(SB)/width, value
```
其中symbol为变量在汇编语言中对应的符号offset是符号开始地址的偏移量width是要初始化内存的宽度大小value是要初始化的那天。其中当前包中Go语言定义的符号symbol在汇编代码中对应`·symbol`其中·为一个特殊的unicode符号。
采用以下命令可以给Id变量初始化为十六进制的0x2537对应十进制的9527常量需要以美元符号$开头表示:
```
DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
```
变量定义好之后需要导出以共其它代码引用。Go汇编语言提供了GLOBL命令用于将符号导出
```
GLOBL symbol(SB), width
```
其中symbol对应汇编中符号的名字width为符号对应内存的大小。用以下命令将汇编中的·Id变量导出
```
GLOBL ·Id, $8
```
现在已经出版完成了用汇编定义一个整数变量的工作。
为了便于其它包使用该Id变量我们还需要在Go代码中声明该变量同时也给变量指定一个合适的类型。修改pkg.go的内容如下
```go
package pkg
var Id int
```
表示声明一个一个int类型的Id变量。因为该变量已经在汇编中定义因此Go语言部分只是声明变量声明的变量不能含义初始化的操作。
完整的汇编代码在pkg_amd64.s中
```
GLOBL ·Id(SB),$8
DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
DATA ·Id+2(SB)/1,$0x00
DATA ·Id+3(SB)/1,$0x00
DATA ·Id+4(SB)/1,$0x00
DATA ·Id+5(SB)/1,$0x00
DATA ·Id+6(SB)/1,$0x00
DATA ·Id+7(SB)/1,$0x00
```
文件名pkg_amd64.s表示为AMD64环境下的汇编代码文件。
虽然pkg包改用汇编实现但是用法和之前完全一样
```go
package main
import pkg "pkg包的路径"
func main() {
println(pkg.Id)
}
```
对于Go包的用户来说用Go汇编语言或Go语言实现并无区别。
## 定义字符串变量
TODO
## Go语言版本

3
ch3-asm/pkg.go Normal file
View File

@ -0,0 +1,3 @@
package pkg
var id int = 9527

View File

@ -6,5 +6,5 @@ Go语言中很多设计思想和工具都是传承自Plan9操作系统Go汇
对于每一个严肃的GopherGo汇编语言都是一个不可忽视的技术。因为哪怕只懂一点点汇编也便于更好地理解计算机将更容易理解Go语言中动态栈/接口等高级特性的实现原理。而且掌握了Go汇编语言之后你将不用担心再被其它所谓的任何高级编程语言用户鄙视。
本章我们将简单地探讨Go汇编语言的基础用法。
本章我们将以AMD64为主要开发环境简单地探讨Go汇编语言的基础用法。

View File

@ -0,0 +1,3 @@
package pkg
var Id = 9527

View File

@ -0,0 +1,9 @@
// +build ignore
package main
import pkg "."
func main() {
println(pkg.Id)
}

View File

@ -0,0 +1,3 @@
package pkg
var Id int

View File

@ -0,0 +1,11 @@
DATA ·Id+0(SB)/1,$0x37
DATA ·Id+1(SB)/1,$0x25
DATA ·Id+2(SB)/1,$0x00
DATA ·Id+3(SB)/1,$0x00
DATA ·Id+4(SB)/1,$0x00
DATA ·Id+5(SB)/1,$0x00
DATA ·Id+6(SB)/1,$0x00
DATA ·Id+7(SB)/1,$0x00
GLOBL ·Id(SB),$8

View File

@ -0,0 +1,11 @@
// +build ignore
package main
import (
pkg "."
)
func main() {
println(pkg.Id)
}