mirror of
https://github.com/chai2010/advanced-go-programming-book.git
synced 2025-05-23 20:02:22 +00:00
fix typo
This commit is contained in:
parent
6b31ef828d
commit
17834eb155
@ -167,7 +167,7 @@ func main() {
|
||||
pkgpath.NameData: missing Go //type information for global symbol: size 8
|
||||
```
|
||||
|
||||
错误提示汇编中定义的NameData符号没有类型信息。其实Go汇编语言中定义的数据并没有所谓的类型,每个符号只不过是对应一块内存而已,因此NameData符号也是没有类型的。但是Go语言是再带垃圾回收器的语言,而Go汇编语言是工作在自动垃圾回收体系框架内的。档Go语言的垃圾回收器在扫描到NameData变量的时候,无法知晓该变量内部是否包含指针,因此就出现了这种错误。错误的根本原因并不是NameData没有类型,而是NameData变量没有标注是否会含有指针信息。
|
||||
错误提示汇编中定义的NameData符号没有类型信息。其实Go汇编语言中定义的数据并没有所谓的类型,每个符号只不过是对应一块内存而已,因此NameData符号也是没有类型的。但是Go语言是再带垃圾回收器的语言,而Go汇编语言是工作在自动垃圾回收体系框架内的。当Go语言的垃圾回收器在扫描到NameData变量的时候,无法知晓该变量内部是否包含指针,因此就出现了这种错误。错误的根本原因并不是NameData没有类型,而是NameData变量没有标注是否会含有指针信息。
|
||||
|
||||
通过给NameData变量增加一个NOPTR标志,表示其中不会包含指针数据可以修复该错误:
|
||||
|
||||
@ -177,7 +177,7 @@ pkgpath.NameData: missing Go //type information for global symbol: size 8
|
||||
GLOBL ·NameData(SB),NOPTR,$8
|
||||
```
|
||||
|
||||
通过给·NameData增加NOPTR标志档方式表示其中不含指针数据。我们也可以通过给·NameData变量在Go语言中增加一个不含指针并且大小为8个字节的类型来修改该错误:
|
||||
通过给·NameData增加NOPTR标志的方式表示其中不含指针数据。我们也可以通过给·NameData变量在Go语言中增加一个不含指针并且大小为8个字节的类型来修改该错误:
|
||||
|
||||
```go
|
||||
package pkg
|
||||
@ -211,7 +211,7 @@ DATA ·Name+8(SB)/8,$6
|
||||
DATA ·Name+16(SB)/8,$"gopher"
|
||||
```
|
||||
|
||||
在新的结构中,Name符号对应的内存从16字节变为24字节,多出的8个字节存放底层的“gopher”字符串。·Name符号前16个字节依然对应reflect.StringHeader结构体:Data部分对应`$·Name+16(SB)`,表示数据的地址为Name符号往后偏移16个字节的位置;Len部分依然对应6个字节的长度。这是C语言程序员经常使用档技巧。
|
||||
在新的结构中,Name符号对应的内存从16字节变为24字节,多出的8个字节存放底层的“gopher”字符串。·Name符号前16个字节依然对应reflect.StringHeader结构体:Data部分对应`$·Name+16(SB)`,表示数据的地址为Name符号往后偏移16个字节的位置;Len部分依然对应6个字节的长度。这是C语言程序员经常使用的技巧。
|
||||
|
||||
|
||||
## 3.1.4 定义main函数
|
||||
@ -248,7 +248,7 @@ Go语言函数在函数调用时,完全通过栈传递调用参数和返回值
|
||||
|
||||
Go语言函数或方法符号在编译为目标文件后,目标文件中的每个符号均包含对应包的绝对导入路径。因此目标文件的符号可能非常复杂,比如“path/to/pkg.(*SomeType).SomeMethod”或“go.string."abc"”等名字。目标文件的符号名中不仅仅包含普通的字母,还可能包含点号、星号、小括弧和双引号等诸多特殊字符。而Go语言的汇编器是从plan9移植过来的二把刀,并不能处理这些特殊的字符,导致了用Go汇编语言手工实现Go诸多特性时遇到种种限制。
|
||||
|
||||
Go汇编语言同样遵循Go语言少即是多的哲学,它只保留了最基本的特性:定义变量和全局函数。其中在变量和全局函数等名字中引入特殊等分隔符号支持Go语言等包体系。为了简化Go汇编器的词法扫描程序的实现,特别引入了Unicode中的中点`·`和大写的除法`/`,对应的Unicode码点为`U+00B7`和`U+2215`。汇编器编译后,中点`·`会被替换为ASCII中的点“.”,大写的除法会被替换为ASCII码中的除法“/”,比如`math/rand·Int`会被替换为`math/rand.Int`。这样可以将中点和浮点数中的小数点、大写的除法和表达式中的除法符号分开,可以简化汇编程序词法分析部分的实现。
|
||||
Go汇编语言同样遵循Go语言少即是多的哲学,它只保留了最基本的特性:定义变量和全局函数。其中在变量和全局函数等名字中引入特殊的分隔符号支持Go语言等包体系。为了简化Go汇编器的词法扫描程序的实现,特别引入了Unicode中的中点`·`和大写的除法`/`,对应的Unicode码点为`U+00B7`和`U+2215`。汇编器编译后,中点`·`会被替换为ASCII中的点“.”,大写的除法会被替换为ASCII码中的除法“/”,比如`math/rand·Int`会被替换为`math/rand.Int`。这样可以将中点和浮点数中的小数点、大写的除法和表达式中的除法符号分开,可以简化汇编程序词法分析部分的实现。
|
||||
|
||||
即使暂时抛开Go汇编语言设计取舍的问题,在不同的操作系统不同等输入法中如何输入中点`·`和除法`/`两个字符就是一个挑战。这两个字符在 https://golang.org/doc/asm 文档中均有描述,因此直接从该页面复制是最简单可靠的方式。
|
||||
|
||||
|
@ -26,7 +26,7 @@ $(3&1)<<2 // == $4
|
||||
|
||||
其中常量表达式中运算符的优先级和Go语言保持一致。
|
||||
|
||||
Go汇编语言中的常量其实不仅仅只有编译时常量,还包含运行时常量。比如包中全局的变量和全局函数在运行时地址也是固定不变的,这里地址不会变量的包变量和函数的地址也是一种汇编常量。
|
||||
Go汇编语言中的常量其实不仅仅只有编译时常量,还包含运行时常量。比如包中全局的变量和全局函数在运行时地址也是固定不变的,这里地址不会改变的包变量和函数的地址也是一种汇编常量。
|
||||
|
||||
下面是本章第一节用汇编定义的字符串代码:
|
||||
|
||||
|
@ -199,7 +199,7 @@ TEXT ·Foo(SB), $32-0
|
||||
RET
|
||||
```
|
||||
|
||||
Foo函数有3个局部变量,但是没有调用其它的函数,因为对齐和填充的问题导致函数的栈帧大小为32个字节。因为Foo函数没有参数和返回值,因此参数和返回值大小为0个字节,当然这个部分可以省略不写。而局部变量中先定义的变量c离伪SP寄存器对应的地址最远,最后定义的变量a离伪SP寄存器最近。有两个因素导致出现这种逆序的结果:一个从Go语言函数角度理解,先定义的c变量地址要比后定义的变量的地址更小;另一个是伪SP寄存器对应栈帧的底部,而X86中栈是从高向地生长的,所以最先定义有着更小地址的c变量离栈的底部伪SP更远。
|
||||
Foo函数有3个局部变量,但是没有调用其它的函数,因为对齐和填充的问题导致函数的栈帧大小为32个字节。因为Foo函数没有参数和返回值,因此参数和返回值大小为0个字节,当然这个部分可以省略不写。而局部变量中先定义的变量c离伪SP寄存器对应的地址最近,最后定义的变量a离伪SP寄存器最远。有两个因素导致出现这种逆序的结果:一个从Go语言函数角度理解,先定义的c变量地址要比后定义的变量的地址更大;另一个是伪SP寄存器对应栈帧的底部,而X86中栈是从高向低生长的,所以最先定义有着更大地址的c变量离栈的底部伪SP更近。
|
||||
|
||||
我们同样可以通过结构体来模拟局部变量的布局:
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user