Go語言探索第一天,學習筆記

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

        已經在大數字做了三年的windows C++開發了,坦白的講,自己現在還是個小碼農。深深的感到自己是個loser。如今,大家回家後鮮有開啟電腦玩電腦的人,與09年我剛

上大學那會兒乃至13年剛入職的時候相比,堪稱滄海桑田~互連網節奏太快了,windows終端目測已經淪陷,轉瞬間就變成了移動端的天下。想起之前學習彙編,windows PE

檔案,hook,線程注入等各種windows技能,對新技術的嗤之以鼻,如今對自己感到了呵呵。期間自己學過了PHP,JS,甚至安卓SDK NDK。學了不實踐,兩天忘光光。作為一個小碼農,如今感到一絲彷徨迷茫,竟不知未來何去何從。

       經過自己兩天輾轉反折的思考,感覺自己應該學習點服務端的知識,這個方面好友早就提醒過我多次,之前的我竟然執迷不悟。

我們部門的服務端開發語言百花齊放,lua,PHP,python,GO,四大陣營,這個也歸結於領導的包容並收。聽人說GO效率要比C\C++高,我聽到了差點沒笑掉大牙。但我深

深的知道,GO是個很牛逼的東西。決定在業餘時間探索一下這個東西。   GO大道至簡,開發環境搭建也就是解壓縮,配置環境變數兩個步驟而已。對了據說他吸收了各種語言的優點,摒棄了各種語言的缺點。到底是不是這麼回事呢?我們來一點點探索吧~


系統變數名:

GOROOT

值:

Go的安裝位置


系統變數名:

Path

追加值:

;%GOROOT%\bin







開發環境安裝包在此 https://yunpan.cn/cRzWuKqjn9MIV  訪問密碼 a41e。



cmd 輸入go   列印出如下一大堆資訊,那麼恭喜你,環境搭建成功了。然後讓我們開始寫自己的第一個GO程式吧~




package main


import "fmt"


func main() {


fmt.Printf("HelloWorld!")


}


代碼注意:

func main(){

不可以寫成

func main()

{

這個不僅僅是代碼規範,Go為了統一編碼風格的文法。


儲存檔案名稱為 gofirst.go


編譯 go build gofirst.go


這個時候你會在gofirst.go目錄下發現多了一個檔案


拖入cmd黑框框執行,。

唔?產生的檔案竟然有1942KB這麼大!!!為啥子檔案會這麼大?難道Go會不再沿用windows PE結構?答案是否定的。

UE看了下Go交叉編譯器產生的二進位檔案,標準的win PE檔案,很顯然,程式碼片段和資源段增加了不少內容。瑕不掩瑜,這可能是Google為瞭解決某種問題不得不這麼做的吧。




IDA看了看,顯然,為了輸出一個hello world   Go在初始化的時候做了不少工作。


沒錯,至少在輸出Hello World方面。GO語言應該會比C語言慢個幾十倍。  但它不是生來輸出Hello World的。另外他是一種編譯型語言,而且產生windows的標準WinPE檔案。同理 *nix的標準執行檔案。我們有理由相信,在大型項目上,拋開記憶體記憶體回收機制不講,(語言自動管理記憶體回收機制,勢必會對速度有一丁點影響)Go完全有理由媲美C、C++,還會大大降低開發的難度,我們有好多理由去好好瞭解下這麼語言。



為了給大家展示一下Go語言媲美C語言的能力,我們寫一個Go語言的   Windows MessBox程式。代碼如下,唔~第一天寫go程式,這段代碼是copy自網路哦。為的是證明C能做到的,GO同樣能做到,效率還不會太低哦。


package main
import (
       "syscall"
       "unsafe"
       "fmt"
)
func abort(funcname string, err int) {
       panic(funcname + " failed: " + syscall.Errno(err).Error())
}
var (
       kernel32, _ = syscall.LoadLibrary("kernel32.dll")
       getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
       user32, _ = syscall.LoadLibrary("user32.dll")
       messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")
)
const (
       MB_OK                      = 0x00000000
       MB_OKCANCEL                = 0x00000001
       MB_ABORTRETRYIGNORE        = 0x00000002
       MB_YESNOCANCEL             = 0x00000003
       MB_YESNO                   = 0x00000004
       MB_RETRYCANCEL             = 0x00000005
       MB_CANCELTRYCONTINUE       = 0x00000006
       MB_ICONHAND                = 0x00000010
       MB_ICONQUESTION            = 0x00000020
       MB_ICONEXCLAMATION         = 0x00000030
       MB_ICONASTERISK            = 0x00000040
       MB_USERICON                = 0x00000080
       MB_ICONWARNING             = MB_ICONEXCLAMATION
       MB_ICONERROR               = MB_ICONHAND
       MB_ICONINFORMATION         = MB_ICONASTERISK
       MB_ICONSTOP                = MB_ICONHAND
       MB_DEFBUTTON1              = 0x00000000
       MB_DEFBUTTON2              = 0x00000100
       MB_DEFBUTTON3              = 0x00000200
       MB_DEFBUTTON4              = 0x00000300
)
func MessageBox(caption, text string, style uintptr) (result int) {
       // var hwnd HWND
       ret, _, callErr := syscall.Syscall6(uintptr(messageBox), 4,
               0, // HWND
               uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), // Text
               uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))), // Caption
               style, // type
               0,
               0)
       if callErr != 0 {
               abort("Call MessageBox", int(callErr))
       }
       result = int(ret)
       return
}
func main() {
       defer syscall.FreeLibrary(kernel32)
       defer syscall.FreeLibrary(user32)
       fmt.Printf("Retern: %d\n", MessageBox("Done Title", "This test is Done.", MB_YESNOCANCEL))
}
func init() {
       fmt.Print("Starting Up\n")
}


來來來,儲存為messagebox.go

執行命令go build messagebox.go



同樣檔案不小,也許是包含了調試資訊?  這個我們之後再進行探索。運行結果如下



注意,我們調用了

 kernel32, _ = syscall.LoadLibrary("kernel32.dll")
       getModuleHandle, _ = syscall.GetProcAddress(kernel32, "GetModuleHandleW")
       user32, _ = syscall.LoadLibrary("user32.dll")
       messageBox, _ = syscall.GetProcAddress(user32, "MessageBoxW")


看出來沒,這和C\C++調用一個微軟的Api如出一轍。都是擷取了MessageBox在記憶體的地址,然後

func MessageBox(caption, text string, style uintptr) (result int) {
       // var hwnd HWND
       ret, _, callErr := syscall.Syscall6(uintptr(messageBox), 4,
               0, // HWND
               uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(text))), // Text
               uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(caption))), // Caption
               style, // type
               0,
               0)
       if callErr != 0 {
               abort("Call MessageBox", int(callErr))
       }
       result = int(ret)
       return
}



關看代碼就可以知道GO調用MessageBox,和C、c++進行了完全一樣的步驟。syscall.Syscall6到底做了點什麼~  想必也就是簡單的擷取syscall.Syscall6的第一個參數 messbox在windows記憶體中位置(二進位程式碼片段的位置),擷取第二個參數,這個表明了被調用的MessageBox有四個參數,也就是push四次,然後分別取出後面的四個參數進行壓杖,最後call

push style

push caption

push text

push 0

CALL messageBox




不過我好奇的是,我簡單的彈一個messagebox,但是這個進程卻啟動了6個線程




拋開搜狗IME注入可能啟動的線程不說,起碼在·GO編譯出來的代碼中,也就是

記憶體位移 messagebox.exe+0X4af80和messagebox.exe+0X4b240這個地方的線程,理論上講是Go語言產生的。

莫非這幾個線程就是為了Go語言高並發設計的線程池?

我們以後慢慢來深入學習,看看Go語言葫蘆裡到底有什麼藥。

       





相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.