• golang-函数



    查看生成的汇编代码
    go tool compile -S xx.go                         //编译器对汇编代码进行优化

    go tool compile -S -N -l xx.go      //不优化

    注:如果编译时不使用 -N -l 参数,编译器会对汇编代码进行优化,编译结果会有较大差别

    c语言汇编分析

    // ch04/my_function.c
    int my_function(int arg1, int arg2) {
    return arg1 + arg2;
    }

    int main() {
    int i = my_function(1, 2);
    }

    cc -S my_function.c


    当我们在 x86_64 的机器上使用 C 语言中调用函数时,参数都是通过寄存器和栈传递的,其中:

    六个以及六个以下的参数会按照顺序分别使用 edi、esi、edx、ecx、r8d 和 r9d 六个寄存器传递;
    六个以上的参数会使用栈传递,函数的参数会以从右到左的顺序依次存入栈中;
    而函数的返回值是通过 eax 寄存器进行传递的,由于只使用一个寄存器存储返回值,所以 C 语言的函数不能同时返回多个值。

    go语言汇编分析

    //main.go
    package main

    func myFunction(a, b int) (int, int) {
    return a + b, a - b
    }

    func main() {
    myFunction(66, 77)
    }

    go tool compile -S -N -l main.go

    Go 语言使用栈传递参数和接收返回值,所以它只需要在栈上多分配一些内存就可以返回多个值。


    总结:
    C 语言和 Go 语言在设计函数的调用惯例时选择了不同的实现。C 语言同时使用寄存器和栈传递参数,使用 eax 寄存器传递返回值;而 Go 语言使用栈传递参数和返回值。我们可以对比一下这两种设计的优点和缺点:

    C 语言的方式能够极大地减少函数调用的额外开销,但是也增加了实现的复杂度;
    CPU 访问栈的开销比访问寄存器高几十倍3;
    需要单独处理函数参数过多的情况;
    Go 语言的方式能够降低实现的复杂度并支持多返回值,但是牺牲了函数调用的性能;
    不需要考虑超过寄存器数量的参数应该如何传递;
    不需要考虑不同架构上的寄存器差异;
    函数入参和出参的内存空间需要在栈上进行分配;
    Go 语言使用栈作为参数和返回值传递的方法是综合考虑后的设计,选择这种设计意味着编译器会更加简单、更容易维护。

    Go 语言函数调用惯例:
    Go 通过栈传递函数的参数和返回值,在调用函数之前会在栈上为返回值分配合适的内存空间,随后将入参从右到左按顺序压栈并拷贝参数,返回值会被存储到调用方预留好的栈空间上,我们可以简单总结出以下几条规则:

    通过堆栈传递参数,入栈的顺序是从右到左;
    函数返回值通过堆栈传递并由调用者预先分配内存空间;
    调用函数时都是传值,接收方会对入参进行复制再计算;

    附图:go汇编的分析过程

    引用:

    https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-function-call/

    https://chai2010.cn/advanced-go-programming-book/ch3-asm/ch3-04-func.html

  • 相关阅读:
    linux API 获得文件属性
    Linux 服务端设计
    Linux C++ 使用LuaBind嵌入lua脚本
    Linux 编译安装Boost (转)
    Navicat for My SQL 查看中文乱码问题
    fastbuild联编ue4 shader的使用
    fastbuild进行ue4 shader连编
    maya 插件学习之pythonCharm和Qt环境搭建
    ue4 头发渲染
    ue4 新渲染管线整理
  • 原文地址:https://www.cnblogs.com/sanmubai/p/13475568.html
Copyright © 2020-2023  润新知