欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

圖文詳解Go程序如何編譯并運行起來的

 更新時間:2024年05月30日 11:00:36   作者:RdrB1te  
Go語言這兩年在語言排行榜上的上升勢頭非常猛,Go語言雖然是靜態(tài)編譯型語言,但是它卻擁有腳本化的語法,下面這篇文章主要給大家介紹了關(guān)于Go程序如何編譯并運行起來的相關(guān)資料,需要的朋友可以參考下

Go程序是如何編譯的

從hello RdrB1te開始

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

不實際編譯它,只輸出它的編譯過程:

go build -n

簡單的編譯過程分析:

上面的過程確認了兩個事情:

  • Runtime會永遠隨著用戶代碼一起編譯
  • 在windows平臺上編譯出來了一個exe的可執(zhí)行文件

Go 編譯過程

詞法分析

  • 將源代碼翻譯成Token
  • Token是代碼中的最小語義結(jié)構(gòu)(如變量名、關(guān)鍵字、運算符等不可拆分的最小單元)

句法分析

  • Token序列經(jīng)過處理,變成語法樹

語義分析

  • 類型檢查
  • 類型推斷
  • 查看類型是否匹配
  • 函數(shù)調(diào)用內(nèi)聯(lián)
  • 逃逸分析

中間碼生成:

  • 為了處理不同平臺的差異,先生成中間代碼(SSA)

查看從代碼到中間碼(SSA)生成的整個過程

$env:GOSSAFUNC="main" # windows powershell
export GOSSAFUNC=main # linux
go build

會看到如下輸出:

用瀏覽器打開ssa.html文件:

sources就是你的源代碼,AST就是生成的語法樹,genssa就是生成的與平臺無關(guān)的中間碼SSA,當(dāng)然中間還有很多的其它步驟,這里不再列舉,可以點擊展開查看

機器碼生成:

  • 先生成Plan9匯編代碼(與平臺相關(guān))
  • 最后編譯為機器碼
  • 輸出的機器碼為.a文件

查看Plan9匯編代碼

go build -gcflags -S main.go

鏈接:

  • 將各個包進行鏈接,包括runtime,最終生成可執(zhí)行文件

Go程序是如何運行起來的

Go程序的入口?

是下面的main方法嗎?當(dāng)然不是

func main() {  
   fmt.Println("hello RdrB1te")  
}

是runtime包下面的rt0_xxx.s文件,下面以Linux x86芯片架構(gòu)上面運行的rt0_linux-amd64.s舉例:

TEXT _rt0_amd64_linux(SB),NOSPLIT,$-8
	JMP	_rt0_amd64(SB)

只要用了x86芯片架構(gòu)都要進入到_rt0_amd64這個方法中去,這個方法調(diào)到了哪里呢,選中雙擊shift,打開在文件中查找:找到下面這行

asm_amd64.s這個文件中的這段代碼:

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

意思是讀取命令行參數(shù),復(fù)制參數(shù)數(shù)量argc和參數(shù)值argv到棧上,然后調(diào)用了runtime·rt0_go這個方法,這方法的位置就在這個文件的下面:

TEXT runtime·rt0_go(SB),NOSPLIT|TOPFRAME,$0  
   // copy arguments forward on an even stack  
   MOVQ   DI, AX    // argc  
   MOVQ   SI, BX    // argv  
   SUBQ   $(5*8), SP    // 3args 2auto  
   ANDQ   $~15, SP  
   MOVQ   AX, 24(SP)  
   MOVQ   BX, 32(SP)  
  
   // create istack out of the given (operating system) stack.  
   // _cgo_init may update stackguard.   MOVQ   $runtime·g0(SB), DI

上面這段的意思時初始化g0執(zhí)行棧,g0是為了調(diào)度協(xié)程而產(chǎn)生的協(xié)程,g0是每個Go程序的第一個協(xié)程。繼續(xù)往下面看,找到下面這段:

	CALL	runtime·check(SB)

這行是第一次調(diào)用的go語言方法,要找到這個方法可以選中雙擊shift,找到下面這行:

進入:

func check(){

}

check方法主要是做運行時檢測:

  • 檢查各種類型的長度
  • 檢查指針操作
  • 檢查結(jié)構(gòu)體字段的偏移量
  • 檢查atomic原子操作
  • 檢查CAS操作
  • 檢查棧大小是否是2的冪次

繼續(xù)往下看,可以通過Ctrl+Alt+左右箭頭進行快速跳轉(zhuǎn)回退或前進,退到這個位置:

CALL    runtime·check(SB)  
  
MOVL   24(SP), AX    // copy argc  
MOVL   AX, 0(SP)  
MOVQ   32(SP), AX    // copy argv  
MOVQ   AX, 8(SP)  
CALL   runtime·args(SB)  
CALL   runtime·osinit(SB)  
CALL   runtime·schedinit(SB)  
  
// create a new goroutine to start program  
MOVQ   $runtime·mainPC(SB), AX       // entry  
PUSHQ  AX  
CALL   runtime·newproc(SB)  
POPQ   AX

runtime·args(SB):參數(shù)初始化runtime.args,對命令行中的參數(shù)進行處理,參數(shù)數(shù)量賦值給argc int32,參數(shù)值復(fù)制給argv **byteruntime·osinit:判斷操作系統(tǒng),執(zhí)行相應(yīng)的初始化組件,供調(diào)度器初始化所用
runtime·schedinit: 初始化Go調(diào)度器。初始化調(diào)度器會做哪些事情:

  • 全局??臻g內(nèi)存分配
  • 加載命令行參數(shù)到 os.Args
  • 堆內(nèi)存空間的初始化
  • 加載操作系統(tǒng)環(huán)境變量
  • 初始化當(dāng)前系統(tǒng)線程
  • 垃圾回收器的參數(shù)初始化
  • 算法初始化(map、hash)
  • 設(shè)置 process 數(shù)量

繼續(xù)往下看:

    // create a new goroutine to start program  
   MOVQ   $runtime·mainPC(SB), AX       // entry  
   PUSHQ  AX  
   CALL   runtime·newproc(SB)  
   POPQ   AX  
  
   // start this M  
   CALL   runtime·mstart(SB)  
  
   CALL   runtime·abort(SB)  // mstart should never return  
   RET  
  
// mainPC is a function value for runtime.main, to be passed to newproc.  
// The reference to runtime.main is made via ABIInternal, since the  
// actual function (not the ABI0 wrapper) is needed by newproc.  
DATA   runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB)

MOVQ $runtime·mainPC(SB):取mainPC的地址,這個mainPC的地址就是runtime·main這個方法的地址
CALL runtime·newproc:創(chuàng)建一個新的協(xié)程(主協(xié)程),執(zhí)行runtime·main這個方法(主函數(shù)),放入調(diào)度器等待調(diào)度
CALL runtime·mstart(SB):初始化一個M,用來調(diào)度主協(xié)程,主協(xié)程開始執(zhí)行主函數(shù)。

看下runtime·main這個方法里面干了什么,選中雙擊shift,找到下面這行:

進入:

// The main goroutine.
func main() {  
   doInit(&runtime_inittask) // 執(zhí)行runtime包中的init方法
   gcenable() // 啟動GC垃圾回收器
   doInit(&main_inittask) //執(zhí)行用戶包依賴的init方法
   fn := main_main // 執(zhí)行用戶主函數(shù)main.mian() 
   fn()
}

按住ctrl進入main_main:

//go:linkname main_main main.main
func main_main()

主協(xié)程執(zhí)行主函數(shù):

  • 執(zhí)行runtime包中的init方法
  • 啟動GC垃圾回收器
  • 執(zhí)行用戶包依賴的init方法
  • 執(zhí)行用戶主函數(shù)main.mian()

總結(jié)

  • Go啟動時經(jīng)歷了檢查、各種初始化、初始化協(xié)程調(diào)度的過程
  • main.main()也是在協(xié)程中運行的

到此這篇關(guān)于Go程序如何編譯并運行起來的文章就介紹到這了,更多相關(guān)Go編譯運行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語句與表達式案例手冊深度解析

    Go語句與表達式案例手冊深度解析

    這篇文章主要為大家介紹了Go語句與表達式案例手冊深度解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-09-09
  • Golang實現(xiàn)反向代理的示例代碼

    Golang實現(xiàn)反向代理的示例代碼

    這篇文章主要為大家學(xué)習(xí)介紹了如何利用Golang實現(xiàn)反向代理,文中的示例代碼講解詳細,具有一定的學(xué)習(xí)價值,感興趣的小伙伴可以跟隨小編一起了解一下
    2023-07-07
  • go?map搬遷的實現(xiàn)

    go?map搬遷的實現(xiàn)

    本文主要介紹了go?map搬遷的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • Go Gorm 示例詳解

    Go Gorm 示例詳解

    Gorm是一款高性能的Golang ORM庫,便于開發(fā)人員提高效率,本文介紹了Gorm的基本概念、數(shù)據(jù)庫連接、基本操作(創(chuàng)建表、新增記錄、查詢記錄、修改記錄、刪除記錄)等,本文介紹Go Gorm的相關(guān)知識,感興趣的朋友一起看看吧
    2025-01-01
  • CGO編程基礎(chǔ)快速入門

    CGO編程基礎(chǔ)快速入門

    這篇文章主要為大家介紹了CGO編程基礎(chǔ)快速入門示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 詳解Golang中Context的原理和使用技巧

    詳解Golang中Context的原理和使用技巧

    Golang?的?Context?包,中文可以稱之為“上下文”,是用來在?goroutine?協(xié)程之間進行上下文信息傳遞的,這些上下文信息包括?kv?數(shù)據(jù)、取消信號、超時時間、截止時間等。本文主要介紹了Context的原理和使用技巧,希望對大家有所幫助
    2022-11-11
  • Go打印結(jié)構(gòu)體提升代碼調(diào)試效率實例詳解

    Go打印結(jié)構(gòu)體提升代碼調(diào)試效率實例詳解

    這篇文章主要介紹了Go打印結(jié)構(gòu)體提升代碼調(diào)試效率實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2024-02-02
  • Golang中指針的使用詳解

    Golang中指針的使用詳解

    Golang是一門支持指針的編程語言,指針是一種特殊的變量,存儲了其他變量的地址。通過指針,可以在程序中直接訪問和修改變量的值,避免了不必要的內(nèi)存拷貝和傳遞。Golang中的指針具有高效、安全的特點,在并發(fā)編程和底層系統(tǒng)開發(fā)中得到廣泛應(yīng)用
    2023-04-04
  • GoLang sync.Pool簡介與用法

    GoLang sync.Pool簡介與用法

    這篇文章主要介紹了GoLang sync.Pool簡介與用法,Pool是可伸縮、并發(fā)安全的臨時對象池,用來存放已經(jīng)分配但暫時不用的臨時對象,通過對象重用機制,緩解GC壓力,提高程序性能
    2023-01-01
  • Go?Excelize?API源碼閱讀Close及NewSheet方法示例解析

    Go?Excelize?API源碼閱讀Close及NewSheet方法示例解析

    這篇文章主要為大家介紹了Go?Excelize?API源碼閱讀Close及NewSheet方法示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08

最新評論