首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

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

  • 25-03-05 12:41
  • 2463
  • 5511
blog.csdn.net

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

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

源码

package main

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

//go:noinline
func escape() *int {
    n := 11
    return &n
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

本次使用的Go版本

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

编译

go build main.go
  • 1

反编译

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)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
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)在堆中分配而不是分配在栈中,即使函数返回了,该指针指向的内存地址还是可以正常使用。

文章知识点与官方知识档案匹配,可进一步学习相关知识
Go技能树初窥门径go变量和常量4816 人正在系统学习中
注:本文转载自blog.csdn.net的gopyer的文章"https://blog.csdn.net/fuxily/article/details/139203287"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2492) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2024 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top