试着理解下Golang中的汇编语言

161 篇文章 12 订阅

Go中runtime(包括调度器)源码有部分代码使用的是汇编语言,而这些汇编代码并非针对特殊体系结构的汇编语言,它是Go引入的一种伪汇编,其同样需要经过汇编器转换为机器指令才能被CPU执行。需要关注的是,Go中伪汇编的汇编代码一旦经过汇编器的转换,之后再调用调试工具反汇编出来的代码,就再也不是Go中伪汇编代码了,而是跟平台相关的汇编代码。

Go中汇编格式跟AT&T汇编大体相似,本文就具有部分差异做简单说明。

首先就是寄存器

Go中汇编语言使用的寄存器跟AMD64不一样,对应关系如下:

除了上述寄存器跟AMD64 CPU硬件寄存器一一对应之外,Go还引入了一些没有任何硬件寄存器与之对应的用来存放内存地址的虚拟寄存器,引入它们的目的主要是为了方便程序编写人员和编译器来定位内存中的代码和数据。

再来看下Go中汇编语言最常使用的两个虚拟寄存器。

FP虚拟寄存器:主要用来引用函数参数。

Go规定了函数调用时的参数都必须放在栈上,如被调用函数使用first_arg+0(FP)来引用函数调用者传递进来的第一个参数,使用second_arg+8(FP)来引用函数调用者传递进来的第二个参数,以此类推,first_arg和second_arg仅是帮助阅读源码的符号,对编译器来说毫无实际意义,+0和+8表示相对于虚拟寄存器FP的偏移量。

用一个runtime源码片段看下FP的使用,片段如下: 

// func gogo(buf *gobuf)// restore state from Gobuf; longjmpTEXT runtime·gogo(SB), NOSPLIT, $16-8  MOVQ  buf+0(FP), BX    // gobuf  MOVQ  gobuf_g(BX), DX  MOVQ  0(DX), CX    // make sure g != nil...

上述片段为Go的runtime中的一个叫gogo的函数,它接受一个gobuf类型的指针,代码中的【MOVL  buf+0(FP), BX】指令把调用者传递过来的指针buf放到BX寄存器中。

可以看出,gogo函数是通过buf+0(FP)这种方式获取参数的。

从被调用函数,也就是gogo函数的角度来看,FP与函数栈帧关系应如下图所示:

由上图可知,FP指向调用者的栈帧,而不是被调用函数的栈帧。

SB虚拟寄存器:保存程序地址空间的起始地址,主要用来定位全局符号。

Go中汇编语言函数的定义、调用以及全局变量的定义和引用都会用到SB。

再来看下操作码

AT&T格式的寄存器操作码一般使用的是小写且其前有%符号,而Go中汇编语言使用的寄存器操作码全部是大写,且其前无%符号,来看个例子感受下:

# AT&T格式mov %rbp,%rsp# go汇编格式MOVQ BP,SP

之后来看下寄存器的操作数宽度也就是操作数的位数

AT&T格式的汇编指令中如果有寄存器操作数,那根据寄存器的名字就可以看出来操作数是多少位,比如rax、eax、ax、al分别表示64、32、16、8位的寄存器,所以不需要操作码后缀,如果没有寄存器操作数,又是访存指令的话,操作码后可加b、w、l、q来指定存取内存中的字节数。

Go中汇编语言寄存器名称无位数之分,如AX寄存器没有什么RAX、EAX之类的名字,汇编代码中统一使用AX,如需存取内存,则需将操作码加上如B(8位)、W(16位)、D(32位)、Q(64位)的后缀。

最后来聊聊函数的定义

还是以Go的runtime中的一个叫gogo的函数为例:

// func gogo(buf *gobuf)// restore state from Gobuf; longjmpTEXT runtime·gogo(SB), NOSPLIT, $16-8

说明如下:

  1. TEXT runtime·gogo(SB):意为代码区定义了一名为gogo的全局函数,该函数属于runtime包。

  2. NOSPLIT:意为编译器不要在此函数中插入检查栈是否溢出的代码。

  3. $16-8:16表示此函数栈帧大小为16字节,8说明此函数返回值只需占用8字节内存。因为这里gogo没有返回值,只有一指针参数,对于AMD64平台来说指针就是8字节。

Go函数调用的参数和返回值都是放在栈上的,而这部分内存是由调用者负责预留的,不是被调用者,所以在定义函数的时候需要说明需在调用者栈帧中预留多少内存空间。

本文到这里就结束了,下文来介绍Go和C的函数调用过程,喜欢就来个三连击吧。

扫码关注公众号,获取更多优质内容。

  

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

luyaran

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值