首页 > 编程语言 >Go语言中局部变量的逃逸分析(从汇编的角度)

Go语言中局部变量的逃逸分析(从汇编的角度)

时间:2024-05-25 21:29:05浏览次数:34  
标签:SP 局部变量 go 逃逸 escape Go SB main

Go语言中局部变量的逃逸分析(从汇编的角度)

正常情况下,局部变量是存储在栈中的,如果将局部变量的地址当作函数值返回,这势必会导致悬挂指针的错误,因为函数返回后,函数的栈帧就会被回收,返回的局部变量地址自然就访问不到了。但是Go语言会进行逃逸分析,编译器如果遇到这种情况,就会将该变量分配到堆中而不是栈中,这样函数返回后,返回的地址自然就可以访问到之前的局部变量。

源码

package main

func main() {
    n := escape()
    *n = 20
    print(*n)
}

//go:noinline
func escape() *int {
    n := 11
    return &n
}

本次使用的Go版本

jagitch@34c4dd4d4a3e:relations$ go version
go version go1.22.2 linux/amd64

编译

go build main.go

反编译

jagitch@34c4dd4d4a3e:go-asm$ go tool objdump -S -s "main.escape" main
TEXT main.escape(SB) /home/coder/workspace/own/jagitch-code/gitee/go-study/go-asm/main.go
func escape() *int {
  0x45d160              493b6610                CMPQ SP, 0x10(R14)
  0x45d164              7621                    JBE 0x45d187
  0x45d166              55                      PUSHQ BP
  0x45d167              4889e5                  MOVQ SP, BP
  0x45d16a              4883ec10                SUBQ $0x10, SP
        n := 11
  0x45d16e              488d050b5d0000          LEAQ 0x5d0b(IP), AX
  0x45d175              e8e6edfaff              CALL runtime.newobject(SB)
  0x45d17a              48c7000b000000          MOVQ $0xb, 0(AX)
        return &n
  0x45d181              4883c410                ADDQ $0x10, SP
  0x45d185              5d                      POPQ BP
  0x45d186              c3                      RET
func escape() *int {
  0x45d187              e874cdffff              CALL runtime.morestack_noctxt.abi0(SB)
  0x45d18c              ebd2                    JMP main.escape(SB)
Go反汇编代码解析
  1. CMPQ SP, 0x10(R14) 判断是否需要增长栈

  2. JBE 0x45d187 如果需要则跳转到0x45d187执行增长栈的逻辑

  3. PUSHQ BP 将BP压站

  4. MOVQ SP, BP 保存main.escape函数的栈帧基址

  5. SUBQ $0x10, SP 在栈上分配16个字节的空间

  6. LEAQ 0x5d0b(IP), AX 将堆上的一个地址保存到AX

  7. CALL runtime.newobject(SB) 根据AX中的地址,创建对象

  8. MOVQ $0xb, 0(AX) 将11保存到0(AX)中,即保存到刚刚创建的对象的地址处

  9. ADDQ $0x10, SP 清理栈帧

  10. POPQ BP 恢复调用者的函数栈帧基址

  11. RET 返回

  12. CALL runtime.morestack_noctxt.abi0(SB) 调用运行时中的函数去扩展栈空间

  13. JMP main.escape(SB)跳转到函数开始重新执行函数

结论

从反汇编的代码中可以看出,将局部变量的地址返回时,该局部变量会使用CALL runtime.newobject(SB)在堆中分配而不是分配在栈中,即使函数返回了,该指针指向的内存地址还是可以正常使用。

标签:SP,局部变量,go,逃逸,escape,Go,SB,main
From: https://blog.csdn.net/fuxily/article/details/139203287

相关文章

  • Django中型项目的目录结构和一个应用创建启动示例
    一个中等Django项目的目录结构包含多个应用、配置文件、静态文件和模板文件等。myproject/├──manage.py#Django项目管理脚本,用于运行服务器、迁移数据库等管理命令├──myproject/#项目配置目录,包含全局配置文件和静态、模板文件│├──__init__.......
  • 网络工程师必会的新一代网络安全工具Goby安装、子网扫描、资产收集、漏洞扫描与报告生
    1.什么是Goby?Goby是一款基于网络空间测绘技术的新一代网络安全工具,它通过给目标网络建立完整的资产知识库,进行网络安全事件应急与漏洞应急。Goby可提供最全面的资产识别,目前预置了超过10万种规则识别引擎,能够针对硬件设备和软件业务系统进行自动化识别和分类,全面的分析出......
  • 运维系列&go系列:cannot find package “xxx“ in any of的通用解决方案
    cannotfindpackage“xxx“inanyof的通用解决方案目录问题背景解决通用解决方案这个问题遇到频率还是比较高,这次总结出来,希望能让更多的人脱离苦海!如有帮助,欢迎留下足迹哦!问题背景作者的问题:提示找不到的是工程内部自定义的包名今天出了个奇怪的事情,编译......
  • 基于python+django框架旅游景区景点购票系统设计与实现(源码+LW+安装+基础课)
     博主介绍:黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。项目配有对应开发文档、开题报告、任务书、P......
  • Go - Choosing a value or pointer receiver
    ChoosingavalueorpointerreceiverTherearetworeasonstouseapointerreceiver.Thefirstissothatthemethodcanmodifythevaluethatitsreceiverpointsto.Thesecondistoavoidcopyingthevalueoneachmethodcall.Thiscanbemoreefficien......
  • Golang 序列化与反序列化,包含字段首字母小写和字段时间格式化
     golang结构体json的时间 序列化与反序列化 格式化解决方案 //最近开发项目时候发现一个结构体的Json转换的时间格式问题。//即这种1993-01-01T20:08:23.000000028+08:00这种表示UTC方法。//从我们习惯来说,更喜欢希望的是1993-01-0120:08:23这种格式如......
  • 【启程Golang之旅】基本变量与类型讲解
    欢迎来到Golang的世界!在当今快节奏的软件开发领域,选择一种高效、简洁的编程语言至关重要。而在这方面,Golang(又称Go)无疑是一个备受瞩目的选择。在本文中,带领您探索Golang的世界,一步步地了解这门语言的基础知识和实用技巧。目录变量的概念数据类型的概念数据类型转换基本......
  • logo设计从创意到草稿到成品的过程(商标设计详解)
    一logo的设计过程1了解需求设计师先了解企业和产品的特点,总结提炼一些关键词2调研分析设计师需要了解客户的竞争对手,确保自己的设计的logo作品和竞争对手比有足够的辨识度3开始设计先发散思维,头脑风暴,提炼出logo的核心关键词,记录4草图为了快速记录稍纵即逝的灵感......
  • go go-redis 使用lua保证操作的原子性
      Redis是应对高并发的常用工具,在常用缓存技巧中讲过相关技巧。但有些业务场景,使用Redis会遇到问题,如电商里的秒杀、扣减库存等。拿减库存举例,一般需要两步:先扣减库存,获取扣减后的库存值V如果V小于0,说明库存不够,需要将扣减的值再加回去;如果V大于等于0,则执行后续操作......
  • Django应用创建到启动的简单示例
    一、系统环境和前置安装Ubuntu系统192.168.2.101,客户端192.168.2.100python3及虚拟环境管理库python3-venv创建项目文件创建djangoweb项目配置ALLOW_HOSTS=['*']二、创建并注册app创建django-adminstartappapp1注册app修改项目配置文件settings.py,在INSTALLED_APPS......