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指令

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

   

  • 伪寄存器

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

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

    • SP: 栈指针, 栈的顶端

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

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

  • 伪寄存器用法

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

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

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

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

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

3、示例代码

package mainfunc main() {n := 10println(read(&n))}//go:noinline
func read(p *int) (v int) {v = *preturn}
  • //go:noinline:禁止Go对函数进行内联

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

  • 使用objdump工具反编译

4、结合chatGPT反编译调试

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

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

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

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

5、指针

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

package mainfunc main() {n := int32(10)println(read32(&n))}//go:noinline
func read32(p *int32) (v int32) {v = *preturn}

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

  • 取地址

package mainvar n intfunc main() {println(addr())}//go:noinline
func addr() (p *int) {return &n}

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

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

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

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

  • 强制类型转换

package mainimport "unsafe"func main() {p := 3convert(&p)}//go:noinline
func convert(p *int) {q := (*int32)(unsafe.Pointer(p))*q = 0}

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

本文链接:https://my.lmcjl.com/post/12214.html

展开阅读全文

4 评论

留下您的评论.