6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理

1、Go版本

go1.14.15

2、汇编基础

  • 推荐阅读:GO汇编语言简介

  • 推荐阅读:A Quick Guide to Go's Assembler - The Go Programming Language

  • 精简指令集

    • 数据传输: MOV/LEA

    • 跳转指令: CMP/TEST/JMP/JCC

    • 栈指令: PUSH/POP

    • 函数调用指令: CALL/RET

    • 算术指令: ADD/SUB/MUL/DIV

    • 逻辑指令: AND/OR/XOR/NOT

    • 移位指令: SHL/SHR

    • JCC有条件跳转: JEQ/JNE/JLT/JLE/JGT/JGE

    • 还有针对无符号数的比较条件

  • MOV指令

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第1张图片

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第2张图片

注:图片来源于GO汇编语言简介

   

  • 伪寄存器

    • SB: 静态基址指针, 全局符号

    • FP: 帧指针, 参数和局部变量

    • SP: 栈指针, 栈的顶端

    • PC: 程序计数器, 跳转和分支

    • 注:伪寄存器仅仅存在于Go汇编中

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第3张图片

  • 伪寄存器用法

    • GLOBL text(SB),$1: 全局变量

    • MOVQ a+0(FP) AX: 函数参数

    • MOVQ b+8(SP) AX: 局部变量

    • JMP 2(PC): 向前跳转, 常用于宏函数

    • JMP -2(PC): 向后跳转, 常用于宏函数

3、示例代码

package main


func main() {

   n := 10

   println(read(&n))

}


//go:noinline
func read(p *int) (v int) {

   v = *p

   return

}
  • //go:noinline:禁止Go对函数进行内联

  • 内联:内联是一种手动或编译器优化,用于将简短函数的调用替换为函数体本身。这么做的原因是它可以消除函数调用本身的开销,也使得编译器能更高效地执行其他的优化策略

  • 使用objdump工具反编译

4、结合chatGPT反编译调试

go build s1.go                                  //编译

go tool objdump -S -s "main.read" .\s3.exe      //反编译

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第4张图片

  • 图中是用go自带的objdump工具对main.read反编译得到的汇编指令

  • 不懂就问,咱们直接问chatGPT这段汇编指令的含义(首先需要给chatGPT一些引导和背景介绍),如下图

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第5张图片

  • 上面解释的很清楚了,为了进一步理解这些指令的含义,追问

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第6张图片

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第7张图片

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第8张图片

5、指针

  • 指针本身是一个无符号整型

package main

func main() {

   n := int32(10)

   println(read32(&n))

}

//go:noinline
func read32(p *int32) (v int32) {

   v = *p

   return

}

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第9张图片

可以看到上述汇编指令中,第一行从参数p中取地址值的操作没变化,只是从AX寄存器中取值的时候,命令有MOVQ(8字节)变为MOVL(4字节),可见不同类型的指针地址本身是一样的类型(无符号整型)

  • 取地址

package main

var n int

func main() {

   println(addr())

}

//go:noinline
func addr() (p *int) {

   return &n

}

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第10张图片

直接问chatGPT,给出的解释是:

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第11张图片

    • 从上图可以看到全局变量n是存在main包的静态基地址上(SB),被不同的函数和代码块共享访问,SB 是静态基地址的缩写,它是指向静态基地址的寄存器。因此,"main.n(SB)" 就是通过 SB 指向 main 包的静态基地址上的 n 变量。

    • LEAQ 指令将全局变量 n 的有效地址存储到 AX 寄存器中,这样 AX 寄存器就包含了 n 变量的地址,可以用于读取或写入该变量的值。

    • LEAQ 指令用于将有效地址存储到一个寄存器中

  • 强制类型转换

package main

import "unsafe"

func main() {

   p := 3

   convert(&p)

}

//go:noinline
func convert(p *int) {

   q := (*int32)(unsafe.Pointer(p))

   *q = 0

}

6.Go语言学习笔记-结合chatGPT辅助学习Go语言底层原理_第12张图片

  • 这段汇编代码是将一个指向int类型变量的指针,转换为指向int32类型变量的指针,并将其所指向的内存空间的值设置为0
  • 把指针的类型强转换为int32后,原本的MOVQ指令变成了MOVL,没有产生任何额外指令,所以转换效率是非常高的

你可能感兴趣的:(golang,学习,笔记)