分享
  1. 首页
  2. 文章

2018年08月08日

myonlyzzy · · 1053 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

go 汇编

编译一个最简单的go执行程序

package main
import "fmt"
func main(){
 fmt.Println("helloworld")
}

go build -gcflags "-N -l" test.go

使用go tool objdump 反汇编

go tool objdump test >test.asm

gdb test

goasm1.png

我们看到汇编的入口地址位于0x452100,打开test.asm

TEXT _rt0_amd64_linux(SB) /usr/local/go/src/runtime/rt0_linux_amd64.s
 rt0_linux_amd64.s:8 0x452100 488d742408 LEAQ 0x8(SP), SI 
 rt0_linux_amd64.s:9 0x452105 488b3c24 MOVQ 0(SP), DI 
 rt0_linux_amd64.s:10 0x452109 488d0510000000 LEAQ 0x10(IP), AX 
 rt0_linux_amd64.s:11 0x452110 ffe0 JMP AX 

可以看到入口为rto_linux_amd64.s (当然了不同平台的入口文件肯定不一样),

rto_linux_amd64.s

#include "textflag.h"
TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
 LEAQ 8(SP), SI // argv
 MOVQ 0(SP), DI // argc
 MOVQ $main(SB), AX
 JMP AX
// When building with -buildmode=c-shared, this symbol is called when the shared
// library is loaded.
// Note: This function calls external C code, which might required 16-byte stack
// alignment after cmd/internal/obj applies its transformations.
TEXT _rt0_amd64_linux_lib(SB),NOSPLIT,0ドルx50
 MOVQ SP, AX
 ANDQ $-16, SP
 MOVQ BX, 0x10(SP)
 MOVQ BP, 0x18(SP)
 MOVQ R12, 0x20(SP)
 MOVQ R13, 0x28(SP)
 MOVQ R14, 0x30(SP)
 MOVQ R15, 0x38(SP)
 MOVQ AX, 0x40(SP)
 MOVQ DI, _rt0_amd64_linux_lib_argc<>(SB)
 MOVQ SI, _rt0_amd64_linux_lib_argv<>(SB)
 // Synchronous initialization.
 MOVQ $runtime·libpreinit(SB), AX
 CALL AX
 // Create a new thread to do the runtime initialization and return.
 MOVQ _cgo_sys_thread_create(SB), AX
 TESTQ AX, AX
 JZ nocgo
 MOVQ $_rt0_amd64_linux_lib_go(SB), DI
 MOVQ 0,ドル SI
 CALL AX
 JMP restore
nocgo:
 MOVQ 8388608,ドル 0(SP) // stacksize
 MOVQ $_rt0_amd64_linux_lib_go(SB), AX
 MOVQ AX, 8(SP) // fn
 MOVQ $runtime·newosproc0(SB), AX
 CALL AX
restore:
 MOVQ 0x10(SP), BX
 MOVQ 0x18(SP), BP
 MOVQ 0x20(SP), R12
 MOVQ 0x28(SP), R13
 MOVQ 0x30(SP), R14
 MOVQ 0x38(SP), R15
 MOVQ 0x40(SP), SP
 RET
TEXT _rt0_amd64_linux_lib_go(SB),NOSPLIT,0ドル
 MOVQ _rt0_amd64_linux_lib_argc<>(SB), DI
 MOVQ _rt0_amd64_linux_lib_argv<>(SB), SI
 MOVQ $runtime·rt0_go(SB), AX
 JMP AX
DATA _rt0_amd64_linux_lib_argc<>(SB)/8, 0ドル
GLOBL _rt0_amd64_linux_lib_argc<>(SB),NOPTR, 8ドル
DATA _rt0_amd64_linux_lib_argv<>(SB)/8, 0ドル
GLOBL _rt0_amd64_linux_lib_argv<>(SB),NOPTR, 8ドル
TEXT main(SB),NOSPLIT,$-8
 MOVQ $runtime·rt0_go(SB), AX
 JMP AX

上面的是go1.9.2 的rto_linux_amd64.s 文件内容.

但是我对汇编完全是半懂,只能半看半猜了,更何况这种go的汇编指令有些以前都没有看到过.好在有伟大的google,另外gdb里面的汇编单步调试提供了很多方便。

TEXT rt0amd64_linux(SB),NOSPLIT,$-8
 LEAQ 8(SP), SI // argv
 MOVQ 0(SP), DI // argc
 MOVQ $main(SB), AX
 JMP AX
 
TEXT main(SB),NOSPLIT,$-8
 MOVQ $runtime·rt0_go(SB), AX
 JMP AX

这是rto_linux_asm64.s 的前几行,第4行跳到了main(SB)这里. main(SB)有跳到了runtime·rt0_go(SB) 但是runtime·rt0_go(SB)在那里呢。这里有2种方式可以找到,一种我们可以搜索runtime 目录下的所有汇编文件。另外一种方式是使用gdb的汇编单步调试看它跳到那里

这是使用gdb单步调试的内容,关于gdb汇编单步调试就2指令ni si.

Breakpoint 1, _rt0_amd64_linux () at /usr/local/go/src/runtime/rt0_linux_amd64.s:8
8 LEAQ 8(SP), SI // argv
(gdb) ni
9 MOVQ 0(SP), DI // argc
(gdb) ni
Breakpoint 2, _rt0_amd64_linux () at /usr/local/go/src/runtime/rt0_linux_amd64.s:10
10 MOVQ $main(SB), AX
(gdb) ni
11 JMP AX
(gdb) ni
Stopped due to shared library event
(gdb) si
74 JMP AX
(gdb) si
runtime.rt0_go () at /usr/local/go/src/runtime/asm_amd64.s:12
12 MOVQ DI, AX // argc
(gdb) ni
13 MOVQ SI, BX // argv
(gdb) 

我们看到是跳到了asm_amd64.s:12的12行执行,这里的代码我们可以通过旁边的注释大概了解做了什么事情

 // create istack out of the given (operating system) stack.
 // _cgo_init may update stackguard.
 MOVQ $runtime·g0(SB), DI
 LEAQ (-64*1024+104)(SP), BX
 MOVQ BX, g_stackguard0(DI)
 MOVQ BX, g_stackguard1(DI)
 MOVQ BX, (g_stack+stack_lo)(DI)
 MOVQ SP, (g_stack+stack_hi)(DI)
 // find out information about the processor we're on
 MOVL 0,ドル AX
 CPUID
 MOVL AX, SI
 CMPL AX, 0ドル
 JE nocpuinfo
 
 
 MOVL 16(SP), AX // copy argc
 MOVL AX, 0(SP)
 MOVQ 24(SP), AX // copy argv
 MOVQ AX, 8(SP)
 CALL runtime·args(SB)
 CALL runtime·osinit(SB)
 CALL runtime·schedinit(SB)

主要就是获取初始化的一些事情,包括runtime.osinit runtime.schedinit 等.

 // create a new goroutine to start program
 MOVQ $runtime·mainPC(SB), AX // entry
 PUSHQ AX
 PUSHQ 0ドル // arg size
 CALL runtime·newproc(SB)
 POPQ AX
 POPQ AX

这里把main函数入栈,然后调用newproc创建协程.

小结

这篇主要介绍了使用go tool he gdb简单的分析golang程序的启动引导过程,一些细节例如 newproc和mstart 在后面的文章中介绍.


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:myonlyzzy

查看原文:2018年08月08日

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1053 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏