Golang内置函数和过程调用汇编代码分析

Comments(169)


Posted on 2015-04-24 08:55:17 golang


Golang汇编快速指南这篇博客中,简单介绍了Golang中汇编的简单语法以及特殊之处。下面介绍Golang中的内置函数和相关操作代码的汇编实现,可以作为上篇博客的补充和实践。

汇编中过程调用的参数是通过栈来传递的,在栈上的布局如下:

参数3
参数2
参数1  <-FP
保存PC <-SP
...
...

内置函数: new, make, append

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 ,

内置函数: copy

package main

import (
    "fmt"
)

func main() {
    s1 := make([]int, 10)
    s2 := make([]int, 10)

    copy(s1, s2)
    fmt.Println(s1, s2)
}

下面是汇编代码:

"".main t=1 size=624 value=0 args=0x0 locals=0x108
    0x0000 00000 (builtin.go:7) TEXT    "".main+0(SB),$264-0
    0x0000 00000 (builtin.go:7) MOVQ    (TLS),CX
    0x0009 00009 (builtin.go:7) LEAQ    -136(SP),AX
    0x0011 00017 (builtin.go:7) CMPQ    AX,16(CX)
    0x0015 00021 (builtin.go:7) JHI ,30
    0x0017 00023 (builtin.go:7) CALL    ,runtime.morestack_noctxt(SB)
    0x001c 00028 (builtin.go:7) JMP ,0
    0x001e 00030 (builtin.go:7) SUBQ    $264,SP
    0x0025 00037 (builtin.go:7) FUNCDATA    $0,gclocals·7c13896baab3273e10662a9a37b348ce+0(SB)
    0x0025 00037 (builtin.go:7) FUNCDATA    $1,gclocals·978d33e7717760c8870a69548dc9a2fb+0(SB)

    // 创建切片s1
    0x0025 00037 (builtin.go:8) MOVQ    $type.[]int+0(SB),BX
    0x002c 00044 (builtin.go:8) MOVQ    BX,(SP)
    0x0030 00048 (builtin.go:8) MOVQ    $10,8(SP)
    0x0039 00057 (builtin.go:8) MOVQ    $10,16(SP)
    0x0042 00066 (builtin.go:8) PCDATA  $0,$0
    0x0042 00066 (builtin.go:8) CALL    ,runtime.makeslice(SB)
    0x0047 00071 (builtin.go:8) MOVQ    24(SP),DX
    0x004c 00076 (builtin.go:8) MOVQ    32(SP),CX
    0x0051 00081 (builtin.go:8) MOVQ    40(SP),AX
    0x0056 00086 (builtin.go:8) MOVQ    DX,"".s1+88(SP)
    0x005b 00091 (builtin.go:8) MOVQ    CX,"".s1+96(SP)
    0x0060 00096 (builtin.go:8) MOVQ    AX,"".s1+104(SP)

    // 创建切片s2
    0x0065 00101 (builtin.go:9) MOVQ    $type.[]int+0(SB),BX
    0x006c 00108 (builtin.go:9) MOVQ    BX,(SP)
    0x0070 00112 (builtin.go:9) MOVQ    $10,8(SP)
    0x0079 00121 (builtin.go:9) MOVQ    $10,16(SP)
    0x0082 00130 (builtin.go:9) PCDATA  $0,$1
    0x0082 00130 (builtin.go:9) CALL    ,runtime.makeslice(SB)
    0x0087 00135 (builtin.go:9) MOVQ    24(SP),DX
    0x008c 00140 (builtin.go:9) MOVQ    32(SP),CX
    0x0091 00145 (builtin.go:9) MOVQ    40(SP),AX

    // 将s1的数据保存到SI, BP, BX
    0x0096 00150 (builtin.go:11)    MOVQ    "".s1+88(SP),SI
    0x009b 00155 (builtin.go:11)    MOVQ    "".s1+96(SP),BP
    0x00a0 00160 (builtin.go:11)    MOVQ    "".s1+104(SP),BX

    // 将BX保存到224(SP)
    0x00a5 00165 (builtin.go:11)    MOVQ    BX,"".autotmp_0005+224(SP)

    // 将s2的数据保存到栈上
    0x00ad 00173 (builtin.go:11)    MOVQ    DX,"".s2+64(SP)
    0x00b2 00178 (builtin.go:11)    MOVQ    CX,"".s2+72(SP)
    0x00b7 00183 (builtin.go:11)    MOVQ    AX,"".s2+80(SP)

    // 将AX保存到152(SP)
    0x00bc 00188 (builtin.go:11)    MOVQ    AX,"".autotmp_0006+152(SP)
    // 将BP保存到216(SP)
    0x00c4 00196 (builtin.go:11)    MOVQ    BP,"".autotmp_0000+216(SP)

    // 从204到220是比较s1和s2的长度
    // 哪个比较大就用它作为参数
    // 复制BP到AX, BP保存的是s1的len
    0x00cc 00204 (builtin.go:11)    MOVQ    BP,AX
    // 将CX保存到144(SP)
    0x00cf 00207 (builtin.go:11)    MOVQ    CX,"".autotmp_0006+144(SP)
    // 比较s2的长度(CX)和s1的长度(BP)
    // 如果小于0则跳转到223
    // 否则执行220
    0x00d7 00215 (builtin.go:11)    CMPQ    CX,BP
    0x00da 00218 (builtin.go:11)    JGE ,223

    0x00dc 00220 (builtin.go:11)    MOVQ    CX,AX
    
    // 将s1的array作为第一个参数
    0x00df 00223 (builtin.go:11)    MOVQ    SI,"".autotmp_0000+208(SP)
    0x00e7 00231 (builtin.go:11)    MOVQ    SI,(SP)
    // 将s2的array作为第二个参数
    0x00eb 00235 (builtin.go:11)    MOVQ    DX,"".autotmp_0006+136(SP)
    0x00f3 00243 (builtin.go:11)    MOVQ    DX,8(SP)

    // AX中保存的是s2的长度
    0x00f8 00248 (builtin.go:11)    MOVQ    AX,BX
    // shl 左移位操作, 左移3位
    0x00fb 00251 (builtin.go:11)    SHLQ    $3,BX
    // 将BX作为第三个参数
    0x00ff 00255 (builtin.go:11)    MOVQ    BX,16(SP)
    0x0104 00260 (builtin.go:11)    PCDATA  $0,$2
    0x0104 00260 (builtin.go:11)    CALL    ,runtime.memmove(SB)

函数调用

package main

import (
    "fmt"
)

func f1(a int) int {
    fmt.Println(a)
    return a + 123
}

func main() {
    b := f1(123)
    fmt.Println(b)
}

下面是汇编代码:

"".f1 t=1 size=240 value=0 args=0x10 locals=0x70
    0x0000 00000 (builtin.3.go:7)   TEXT    "".f1+0(SB),$112-16
    0x0000 00000 (builtin.3.go:7)   MOVQ    (TLS),CX
    0x0009 00009 (builtin.3.go:7)   CMPQ    SP,16(CX)
    0x000d 00013 (builtin.3.go:7)   JHI ,22
    0x000f 00015 (builtin.3.go:7)   CALL    ,runtime.morestack_noctxt(SB)
    0x0014 00020 (builtin.3.go:7)   JMP ,0
    0x0016 00022 (builtin.3.go:7)   SUBQ    $112,SP
    0x001a 00026 (builtin.3.go:7)   FUNCDATA    $0,gclocals·480b8f52e76ecc554a5236babfd9a6e5+0(SB)
    0x001a 00026 (builtin.3.go:7)   FUNCDATA    $1,gclocals·403a8d79fd24b295e8557f6970497aa3+0(SB)

    // 因为栈帧的大小是112字节
    // 所以在120(FP)处保存的是第一个参数
    0x001a 00026 (builtin.3.go:8)   MOVQ    "".a+120(FP),BX

    // 下面的代码将a转换为接口类型
    // 因为fmt.Println需要的是空接口类型的参数
    0x001f 00031 (builtin.3.go:8)   MOVQ    BX,"".autotmp_0001+48(SP)
    0x0024 00036 (builtin.3.go:8)   LEAQ    "".autotmp_0000+72(SP),BX
    0x0029 00041 (builtin.3.go:8)   MOVQ    $0,(BX)
    0x0030 00048 (builtin.3.go:8)   MOVQ    $0,8(BX)
    0x0038 00056 (builtin.3.go:8)   LEAQ    "".autotmp_0000+72(SP),BX
    0x003d 00061 (builtin.3.go:8)   CMPQ    BX,$0
    0x0041 00065 (builtin.3.go:8)   JEQ $1,226
    0x0047 00071 (builtin.3.go:8)   MOVQ    $1,DX
    0x004e 00078 (builtin.3.go:8)   MOVQ    $1,CX
    0x0055 00085 (builtin.3.go:8)   MOVQ    BX,"".autotmp_0002+88(SP)
    0x005a 00090 (builtin.3.go:8)   MOVQ    DX,"".autotmp_0002+96(SP)
    0x005f 00095 (builtin.3.go:8)   MOVQ    CX,"".autotmp_0002+104(SP)
    0x0064 00100 (builtin.3.go:8)   MOVQ    $type.int+0(SB),BX
    0x006b 00107 (builtin.3.go:8)   MOVQ    BX,(SP)
    0x006f 00111 (builtin.3.go:8)   LEAQ    "".autotmp_0001+48(SP),BX
    0x0074 00116 (builtin.3.go:8)   MOVQ    BX,8(SP)
    0x0079 00121 (builtin.3.go:8)   PCDATA  $0,$1
    0x0079 00121 (builtin.3.go:8)   CALL    ,runtime.convT2E(SB)
    0x007e 00126 (builtin.3.go:8)   MOVQ    16(SP),CX
    0x0083 00131 (builtin.3.go:8)   MOVQ    24(SP),AX
    0x0088 00136 (builtin.3.go:8)   MOVQ    "".autotmp_0002+88(SP),BX
    0x008d 00141 (builtin.3.go:8)   MOVQ    BX,(SP)
    0x0091 00145 (builtin.3.go:8)   MOVQ    CX,"".autotmp_0004+56(SP)
    0x0096 00150 (builtin.3.go:8)   MOVQ    CX,8(SP)
    0x009b 00155 (builtin.3.go:8)   MOVQ    AX,"".autotmp_0004+64(SP)
    0x00a0 00160 (builtin.3.go:8)   MOVQ    AX,16(SP)
    0x00a5 00165 (builtin.3.go:8)   PCDATA  $0,$1
    0x00a5 00165 (builtin.3.go:8)   CALL    ,runtime.writebarrieriface(SB)
    // 传递参数给fmt.Println,并调用
    0x00aa 00170 (builtin.3.go:8)   MOVQ    "".autotmp_0002+88(SP),BX
    0x00af 00175 (builtin.3.go:8)   MOVQ    BX,(SP)
    0x00b3 00179 (builtin.3.go:8)   MOVQ    "".autotmp_0002+96(SP),BX
    0x00b8 00184 (builtin.3.go:8)   MOVQ    BX,8(SP)
    0x00bd 00189 (builtin.3.go:8)   MOVQ    "".autotmp_0002+104(SP),BX
    0x00c2 00194 (builtin.3.go:8)   MOVQ    BX,16(SP)
    0x00c7 00199 (builtin.3.go:8)   PCDATA  $0,$2
    0x00c7 00199 (builtin.3.go:8)   CALL    ,fmt.Println(SB)

    // 将a加上123,并返回
    0x00cc 00204 (builtin.3.go:9)   MOVQ    "".a+120(FP),BX
    0x00d1 00209 (builtin.3.go:9)   ADDQ    $123,BX
    0x00d5 00213 (builtin.3.go:9)   MOVQ    BX,"".~r1+128(FP)
    0x00dd 00221 (builtin.3.go:9)   ADDQ    $112,SP
    0x00e1 00225 (builtin.3.go:9)   RET ,
    0x00e2 00226 (builtin.3.go:8)   MOVL    AX,(BX)
    0x00e4 00228 (builtin.3.go:8)   JMP ,71
    
    
    "".main t=1 size=240 value=0 args=0x0 locals=0x70
    0x0000 00000 (builtin.3.go:12)  TEXT    "".main+0(SB),$112-0
    0x0000 00000 (builtin.3.go:12)  MOVQ    (TLS),CX
    0x0009 00009 (builtin.3.go:12)  CMPQ    SP,16(CX)
    0x000d 00013 (builtin.3.go:12)  JHI ,22
    0x000f 00015 (builtin.3.go:12)  CALL    ,runtime.morestack_noctxt(SB)
    0x0014 00020 (builtin.3.go:12)  JMP ,0
    // 将SP减去112(栈的大小),栈向下增长
    0x0016 00022 (builtin.3.go:12)  SUBQ    $112,SP
    0x001a 00026 (builtin.3.go:12)  FUNCDATA    $0,gclocals·73423680ca5f2d7df4fe760a82d507fb+0(SB)
    0x001a 00026 (builtin.3.go:12)  FUNCDATA    $1,gclocals·403a8d79fd24b295e8557f6970497aa3+0(SB)
    // 将123放在栈顶
    0x001a 00026 (builtin.3.go:13)  MOVQ    $123,(SP)
    0x0022 00034 (builtin.3.go:13)  PCDATA  $0,$0
    // 调用f1
    0x0022 00034 (builtin.3.go:13)  CALL    ,"".f1(SB)
    // 将结果8(SP)存入BX
    0x0027 00039 (builtin.3.go:13)  MOVQ    8(SP),BX
    0x002c 00044 (builtin.3.go:13)  NOP ,

    // 将BX存放到48(SP), 是一个临时变量,BX中保存的是f1的调用结果
    0x002c 00044 (builtin.3.go:14)  MOVQ    BX,"".autotmp_0010+48(SP)
前一篇: Golang汇编快速指南 后一篇: Golang网络库中socket阻塞调度源码剖析

Captcha:
验证码

Email:

Content: (Support Markdown Syntax)


enlilinna  2023-01-27 18:31:11 From 127.0.0.1

Search terms were bipolar, mania, trial, and names of individual antipsychotic, anticonvulsant, or other drugs buy priligy online Tel 44 121 414 3797 Fax 44 121 414 3700 Email aTTom bham


Fereofs  2023-02-01 05:11:26 From 127.0.0.1

how much is 100mg of clomid Overall survival was defined as the time from the date of randomization to the date of death from any cause; patients last known to be alive were censored at the date of last contact


Сайтапродвижение  2023-02-11 00:00:55 From 127.0.0.1

продвижение сайтов харьков

Продвижение сайта — этто цепь мероприятий, погнанных на привлечение мотивированных юзеров и шлифовка свойства трафика. Я пас через слово под сим определением по умолчанию подразумевают исключительно оптимизацию веб-ресурса под условия поисковых порядков (SEO). продвижение сайтов харьков


plapyKarl  2023-02-19 04:57:25 From 127.0.0.1

DrugMerge performance on COVID 19 data without FDA approval restriction buy cialis cheap Thus, EDS, though often taught to be a disorder of impaired collagen production to medical students, is significantly more diverse and mechanistically much more complicated


Amberlyelmr  2023-02-19 18:24:45 From 127.0.0.1

singles in women best online dating sites connecting singles online members


Josephnug  2023-02-23 19:05:55 From 127.0.0.1

You actually expressed it terrifically. essaywritingserviceahrefs.com essay help websites


Vivan  2023-03-01 09:57:25 From 127.0.0.1

Equipos para el manejo y almacenamiento de materiales se utilizan para sujetar los plegadores durante la tejeduría. Los plegadores se componen de plegadores de pulpa y plegadores de urdimbre que se enhebran con lizos y se utilizan junto con la máquina correspondiente para tejer el tejido. Los camiones de haces pueden transportar los haces, y el uso del camión de haces puede reducir el coste del transporte de los y reducir el daño de los haces en el proceso de transporte.


mkrvtbskv  2023-03-04 21:43:01 From 127.0.0.1

mkrvtbskv

На теперешний день существует чертова гибель многообразных микроавтобусов. Собрали шкала наихороших, чтоб угощение вам улучить транспорт. У многих автомобилистов … mkrvtbskv


Gellak  2023-03-07 22:56:20 From 127.0.0.1

Gel lak na nehty

Gel laky na nehty jsou oblibenym produktem, ktery si vybiraji zacatecnici i zkuseni remeslnici. Toto je alternativa ke starsi metode pouzivani prekryvnych vrstev. Gel lak na nehty


Инвестор  2023-03-13 12:38:17 From 127.0.0.1

Найти инвестора в Москве

Если язык тебя есть новичок, то твоя милость имеешь возможность принять участие равным образом поселиться сверху нашей доске объявлений. Этто шара (а) также твоя милость имеешь возможность отыскать вклады очень легко. Найти инвестора в Москве