Posted on 2015-04-24 08:55:17 golang
摘要:在Golang汇编快速指南这篇博客中,简单介绍了Golang中汇编的简单语法以及特殊之处。下面介绍Golang中的内置函数和相关操作代码的汇编实现,可以作为上篇博客的补充和实践。
汇编中过程调用的参数是通过栈来传递的,在栈上的布局如下:
参数3
参数2
参数1 <-FP
保存PC <-SP
...
...
package main
import (
"fmt"
)
type new_int int
var (
gobal_1 = "this is global var"
)
func main() {
auto_1 := "this is auto_1"
s0 := new(new_int)
s1 := make([]int, 10)
s2 := make([]int, 10)
append(s2, 9999)
fmt.Println(s1, s2)
fmt.Println(s0)
}
下面是汇编代码:
"".main t=1 size=1936 value=0 args=0x0 locals=0x128
// 定义函数main,栈帧大小为296字节,0字节的参数(无参数)
0x0000 00000 (builtin.go:13) TEXT "".main+0(SB),$296-0
// 将线程本地存储(thread local storage)传送到CX
0x0000 00000 (builtin.go:13) MOVQ (TLS),CX
// 下面是检查栈帧的大小是否超过目前分配的小
0x0009 00009 (builtin.go:13) LEAQ -168(SP),AX
0x0011 00017 (builtin.go:13) CMPQ AX,16(CX)
0x0015 00021 (builtin.go:13) JHI ,30
// 如果超过调用runtime.morestack_noctxt
0x0017 00023 (builtin.go:13) CALL ,runtime.morestack_noctxt(SB)
0x001c 00028 (builtin.go:13) JMP ,0
// 扩大栈帧
0x001e 00030 (builtin.go:13) SUBQ $296,SP
0x0025 00037 (builtin.go:13) FUNCDATA $0,gclocals·e14c7473fe07b0ccdc0fdfa1a770087b+0(SB)
0x0025 00037 (builtin.go:13) FUNCDATA $1,gclocals·7a70fcb413ec620f2a7a8c3ba5f394c1+0(SB)
// 局部变量auto_1
0x0025 00037 (builtin.go:14) LEAQ go.string."this is auto_1"+0(SB),BX
// string在golang中是由数据本身和其长度组成的
// 将数据的地址移动到BP
0x002c 00044 (builtin.go:14) MOVQ (BX),BP
// 移动BP到栈指针152字节的位置
0x002f 00047 (builtin.go:14) MOVQ BP,"".auto_1+152(SP)
// 将字符串长度移动到BP
0x0037 00055 (builtin.go:14) MOVQ 8(BX),BP
// 移动BP到栈指针160字节的位置
0x003b 00059 (builtin.go:14) MOVQ BP,"".auto_1+160(SP)
// new_int类型的初始化
// 将类型本身移动到BX
0x0043 00067 (builtin.go:17) MOVQ $type."".new_int+0(SB),BX
// 将BX移动到栈顶
0x004a 00074 (builtin.go:17) MOVQ BX,(SP)
0x004e 00078 (builtin.go:17) PCDATA $0,$1
// 调用runtime.newobject
0x004e 00078 (builtin.go:17) CALL ,runtime.newobject(SB)
// 将返回的结果移动到BX
0x0053 00083 (builtin.go:17) MOVQ 8(SP),BX
// 移动BP到栈指针80字节的位置
0x0058 00088 (builtin.go:17) MOVQ BX,"".s1+80(SP)
0x005d 00093 (builtin.go:17) NOP ,
// 创建slice s1
// 将类型移动到BX
0x005d 00093 (builtin.go:18) MOVQ $type.[]int+0(SB),BX
// 将BX(类型)移动到栈顶
0x0064 00100 (builtin.go:18) MOVQ BX,(SP)
// 将长度参数len移动到相对于栈顶8字节的位置
0x0068 00104 (builtin.go:18) MOVQ $10,8(SP)
// 将容量参数cap移动到相对于栈顶16字节的位置
0x0071 00113 (builtin.go:18) MOVQ $10,16(SP)
0x007a 00122 (builtin.go:18) PCDATA $0,$2
// 调用runtime.makeslice
0x007a 00122 (builtin.go:18) CALL ,runtime.makeslice(SB)
// 创建出的s1的参数分别保存在相对栈顶24, 32, 40字节的位置
0x007f 00127 (builtin.go:18) MOVQ 24(SP),DX
0x0084 00132 (builtin.go:18) MOVQ 32(SP),CX
0x0089 00137 (builtin.go:18) MOVQ 40(SP),BX
// CX中保存的是slice的len参数
0x008e 00142 (builtin.go:20) MOVQ CX,"".s2_len+64(SP)
0x0093 00147 (builtin.go:20) NOP ,
// 将slice的array, len, cap传送给s2
0x0093 00147 (builtin.go:21) MOVQ DX,"".s2+168(SP)
0x009b 00155 (builtin.go:21) MOVQ CX,"".s2+176(SP)
0x00a3 00163 (builtin.go:21) MOVQ BX,"".s2+184(SP)
0x00ab 00171 (builtin.go:21) MOVQ BX,AX
// 从BX中减去CX的值,结果保存在BX
0x00ae 00174 (builtin.go:21) SUBQ CX,BX
0x00b1 00177 (builtin.go:21) CMPQ BX,$1
0x00b5 00181 (builtin.go:21) JGE ,262
// 将类型传送到栈顶
0x00b7 00183 (builtin.go:21) MOVQ $type.[]int+0(SB),BX
0x00be 00190 (builtin.go:21) MOVQ BX,(SP)
// 将旧的slice传送到栈的第二个参数
0x00c2 00194 (builtin.go:21) MOVQ DX,"".autotmp_0001+240(SP)
0x00ca 00202 (builtin.go:21) MOVQ DX,8(SP)
// 将长度传送到栈上第三个参数(s2的长度)
0x00cf 00207 (builtin.go:21) MOVQ CX,"".autotmp_0001+248(SP)
0x00d7 00215 (builtin.go:21) MOVQ CX,16(SP)
// 将33行的BX的值重新保存到24(SP),即s2的array
0x00dc 00220 (builtin.go:21) MOVQ AX,"".autotmp_0001+256(SP)
0x00e4 00228 (builtin.go:21) MOVQ AX,24(SP)
// 将s2的长度置为1
0x00e9 00233 (builtin.go:21) MOVQ $1,32(SP)
// 调用growslice
0x00f2 00242 (builtin.go:21) PCDATA $0,$2
0x00f2 00242 (builtin.go:21) CALL ,runtime.growslice(SB)
// 3个返回值(sliceStruct)
0x00f7 00247 (builtin.go:21) MOVQ 40(SP),DX
0x00fc 00252 (builtin.go:21) MOVQ 48(SP),CX
0x0101 00257 (builtin.go:21) MOVQ 56(SP),AX
// 增加返回的结构中len参数长度,增加1
0x0106 00262 (builtin.go:21) MOVQ CX,SI
0x0109 00265 (builtin.go:21) INCQ ,SI
// 变址寻址,DX+CX*8
0x010c 00268 (builtin.go:21) LEAQ (DX)(CX*8),BX
// 将立即数9999传递到(BX)的内存位置
0x0110 00272 (builtin.go:21) MOVQ $9999,(BX)
0x0117 00279 (builtin.go:21) NOP ,
0x0117 00279 (builtin.go:21) MOVQ DX,"".autotmp_0001+240(SP)
0x011f 00287 (builtin.go:21) MOVQ SI,"".autotmp_0001+248(SP)
0x0127 00295 (builtin.go:21) MOVQ AX,"".autotmp_0001+256(SP)
// 将新的slice的参数传递给s2
0x012f 00303 (builtin.go:21) MOVQ DX,"".s2+168(SP)
0x0137 00311 (builtin.go:21) MOVQ SI,"".s2+176(SP)
0x013f 00319 (builtin.go:21) MOVQ AX,"".s2+184(SP)
0x0147 00327 (builtin.go:21) NOP ,
阅读全文
Posted on 2015-04-23 15:40:07 golang
摘要:这篇文档是对于Go编译器套件(6g, 8g, etc.)中不常用的汇编语言的快速预览,涵盖面不是很广泛。
Go的汇编语言基于Plan 9的汇编,Plan 9网站的页面上有详细描述。如果你想编写汇编语言,你应该读这篇文档,虽然它是Plan 9相关的。这边文档总结了汇编的语法,并且描述了使用汇编语言和Go程序交互时的特殊之处。
有一点是很重要的是,Go的汇编中没有直接体现出底层的机器。有些汇编细节能直接对应到机器,但有些不是。这是因为编译器套件在常规过程中不需要汇编语言。取而代之的是,编译器产生二进制的不完整的汇编指令集,链接器会完成它。实际上,链接器做了汇编指令的选择,所以当你看到类似于MOV这样的指令,链接器的实际操作可能不是一个移动指令,也许是清除或者载入。或者可能会根据指令的名字对应到真实的机器指令。总体上,机器相关的指令操作趋向于体现出真实的机器指令,但是一些通用的概念类似于移动内存数据、调用子例程、返回等操作就更抽象了。具体的细节和架构相关,我们为这种不精确性道歉。
阅读全文