GO 汇编学习笔记(一)

GO 汇编学习笔记(一)—— 简单示例

​​ GO 汇编学习笔记(一)

GO 汇编学习笔记(二)

GO 汇编学习笔记(三)

GO 汇编学习笔记(四)

GO 汇编学习笔记(五)

  1. 为什么要学习GO汇编

    ​ 对于一个严肃的GO语言开发者,GO汇编都是不可忽视的技术,了解了GO的汇编可以帮助你更好的理解计算机原理,也更容易理解GO语言的动态栈等高级特性。本文参考 http://books.studygolang.com/advanced-go-programming-book/ch3-asm 但是里面部分示例有错误,无法编译通过;本文都用以修改

  2. 简单入门

    ​ GO汇编并不是独立的语言,GO汇编无法被独立使用,它必须以GO包的方式组织,同时包里面至少要有一个GO语言文件用于指明当前包名等基本信息,如果汇编定义的函数要被其它GO代码引用,还需要通过Go代码将汇编声明出来。此时用于定义的汇编文件类似与c++中的 .cxx 文件,GO源码类似于.h 文件。

  3. 简单示例

    首先定义一个 test 的package文件

    package test
    var id = 1234
    

    运行 go tool compile -S test.go 命令进行编译 生成 test.o

    go.cuinfo.packagename. SDWARFINFO dupok size=0
            0x0000 74 65 73 74                                      test
    "".id SNOPTRDATA size=8
            0x0000 d2 04 00 00 00 00 00 00                          ........
    
    
     其中`go tool compile`命令用于调用Go语言提供的底层命令工具,其中`-S`参数表示输出汇编格式。输出的汇编比较简单,其中`"".Id`对应Id变量符号,变量的内存大小为8个字节。变量的初始化内容为`d2 04 00 00 00 00 00 00`,对应十六进制格式的0x04d2,对应十进制为9527。SNOPTRDATA是相关的标志,其中NOPTR表示数据中不包含指针数据。
     
     以上的内容只是目标文件对应的汇编,和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变量初始化为十六进制的0xd204

    DATA ·Id+0(SB)/1,$0xd2
    DATA ·Id+1(SB)/1,$0x04
    

    ​ 变量定义好之后需要导出以供其它代码引用。Go汇编语言提供了GLOBL命令用于将符号导出:

    GLOBL symbol(SB), width
    

    ​ 其中symbol对应汇编中符号的名字,width为符号对应内存的大小。用以下命令将汇编中的·Id变量导出:

    GLOBL ·Id, $8
    

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

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

    package test
    //此时ID是一个声明,不是定义一个变量,声明无需初始化操作
    var Id int64
    

    ​ 同级目录下汇编文件如下:

    //test_amd64.s#include "textflag.h"//这里必须说明 Id不含指针类型,NOPTR 并且包含头文件GLOBL ·Id(SB),NOPTR,$8DATA  ·Id+0(SB)/1,$0x01DATA  ·Id+1(SB)/1,$0x00DATA  ·Id+2(SB)/1,$0x00DATA  ·Id+3(SB)/1,$0x00DATA  ·Id+4(SB)/1,$0x00DATA  ·Id+5(SB)/1,$0x00DATA  ·Id+6(SB)/1,$0x00DATA  ·Id+7(SB)/1,$0x00
    

    运行结果:

    package mainimport test "modlearn/test"func main() {	println(test.Id)}//out out 1
    
  4. 定义字符串变量

    package testvar Id int//新增的var STR = "aaaaaaaaaaaaaaaaaaaaaaaaa"
    

    然后用 go tool compile -S test.go 伪汇编代码:

    go.cuinfo.packagename. SDWARFINFO dupok size=0        0x0000 74 65 73 74                                      testgo.string."aaaaaaaaaaaaaaaaaaaaaaaaa" SRODATA dupok size=25        0x0000 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61  aaaaaaaaaaaaaaaa        0x0010 61 61 61 61 61 61 61 61 61                       aaaaaaaaa"".Id SNOPTRBSS size=8"".STR SDATA size=16        0x0000 00 00 00 00 00 00 00 00 19 00 00 00 00 00 00 00  ................        rel 0+8 t=1 go.string."aaaaaaaaaaaaaaaaaaaaaaaaa"+0
    

    由此可见go的string类型里面有两个变量 “text”是一个只读&引用的字符串,SRODATA标志表示这个数据在只读内存段,dupok 表示出现多个相同标识符的数据时只保留一个就可以了。变量只有16个字节大小,其实值得是string结构体的大小。前8个字节代表字符串指针,后8个字节代表字符串长度

    type reflect.StringHeader struct {    Data uintptr    Len  int}
    

    重新定义go

    package testvar Id int//新增的var STR string
    

    同级目录下汇编文件如下:

    //test_amd64.s#include "textflag.h"//这里必须说明 Id不含指针类型,NOPTR 并且包含头文件GLOBL ·Id(SB),NOPTR,$8DATA  ·Id+0(SB)/1,$0x01DATA  ·Id+1(SB)/1,$0x00DATA  ·Id+2(SB)/1,$0x00DATA  ·Id+3(SB)/1,$0x00DATA  ·Id+4(SB)/1,$0x00DATA  ·Id+5(SB)/1,$0x00DATA  ·Id+6(SB)/1,$0x00DATA  ·Id+7(SB)/1,$0x00//定义一个变量,赋值,而且位只读GLOBL ·NameData(SB),NOPTR,$8DATA  ·NameData(SB)/8,$"gopher"GLOBL ·STR(SB),RODATA,$16DATA  ·STR+0(SB)/8,$·NameData(SB)DATA  ·STR+8(SB)/8,$6
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值