91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何使用go:linkname指令

發布時間:2021-10-13 11:37:07 來源:億速云 閱讀:363 作者:iii 欄目:編程語言

這篇文章主要介紹“如何使用go:linkname指令”,在日常操作中,相信很多人在如何使用go:linkname指令問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何使用go:linkname指令”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

 如何使用go:linkname指令

01 格式

//go:linkname local remote

remote 可以沒有,此時 remote 使用 local 的值,效果就是 local 被導出。

02 local 和 remote 同時為函數

local 作為占位符,remote 作為實現者

標準庫中的例子:

// 來自 time 包 //go:linkname runtimeNano runtime.nanotime func runtimeNano() int64  // 來自 runtime 包 //go:nosplit func nanotime() int64 {  return nanotime1() }

此時二進制文件中并沒有runtimeNano,直接轉化為對runtime.nanotime的調用。

local 作為實現者,remote 作為占位符

同樣來自標準庫。這里存在函數沒有函數體,但是被反向引用。

// 在標準庫的一個 internal 中 //go:linkname runtime_cmpstring runtime.cmpstring func runtime_cmpstring(a, b string) int {  l := len(a)  if len(b) < l {   l = len(b)  }  for i := 0; i < l; i++ {   c1, c2 := a[i], b[i]   if c1 < c2 {    return -1   }   if c1 > c2 {    return +1   }  }  if len(a) < len(b) {   return -1  }  if len(a) > len(b) {   return +1  }  return 0 }  // 來自 runtime func cmpstring(string, string) int

此時二進制文件中并沒有runtime_cmpstring,對應的函數已經被命名為runtime.cmpstring。也就是說,實現在 internal  包,但最終通過 runtime.cmpstring 來引用。

一個占位符+一個匯編函數

// 在標準庫的一個 internal 中 //go:linkname abigen_runtime_memequal runtime.memequal func abigen_runtime_memequal(a, b unsafe.Pointer, size uintptr) bool

注意runtime.memequal的實現并不在runtime包中,使用匯編實現的話并不要求必須在相應的包中。

# memequal(a, b unsafe.Pointer, size uintptr) bool TEXT runtime&middot;memequal(SB),NOSPLIT,$0-25     MOVQ    a+0(FP), SI     MOVQ    b+8(FP), DI     CMPQ    SI, DI     JEQ eq     MOVQ    size+16(FP), BX     LEAQ    ret+24(FP), AX     JMP memeqbody<>(SB) eq:     MOVB    $1, ret+24(FP)     RET

03 local 和 remote 同時為變量

兩個常規變量

//go:linkname overflowError runtime.overflowError var overflowError error  //go:linkname divideError runtime.divideError var divideError error  //go:linkname zeroVal runtime.zeroVal var zeroVal [maxZero]byte  //go:linkname _iscgo runtime.iscgo var _iscgo bool = true  //go:cgo_import_static x_cgo_setenv //go:linkname x_cgo_setenv x_cgo_setenv //go:linkname _cgo_setenv runtime._cgo_setenv var x_cgo_setenv byte var _cgo_setenv = &x_cgo_setenv  //go:cgo_import_static x_cgo_unsetenv //go:linkname x_cgo_unsetenv x_cgo_unsetenv //go:linkname _cgo_unsetenv runtime._cgo_unsetenv var x_cgo_unsetenv byte var _cgo_unsetenv = &x_cgo_unsetenv

一個占位符+一個偽符號

//go:linkname runtime_inittask runtime..inittask var runtime_inittask initTask  //go:linkname main_inittask main..inittask var main_inittask initTask

注意是..inittask不是.inittask,而且.inittask只存在于編譯階段,任何包中都無法聲明該變量。

這里額外解釋下 ..inittask 為什么兩個點。第一個點就是普通的 runtime. 這種調用方式,第二個點和 inittask  一起構成一個符號(變量)。注意,Go 中的變量是不允許以 . 開頭的,所以,這個叫偽符號,只在不編譯階段存在。

04 一個例子

研究 //go:linkname 是因為如下的背景:

Java 里有 InheritableThreadLocal,SpringWeb 在 ServletActionContext  里使用它,達到在任何地方都能方便的獲取HttpServletRequest。

Go 并沒有提供類似的機制,即使通過 stack 找到 goroutine id(99% 的文章都是這么介紹的),再配合  sync.Map,也只是實現了一個比較粗糙的 ThreadLocal,在子協程里仍然獲取不到父協程的內容。

g.label 雖然不是給這種場景準備的,但它具備了 InheritableThreadLocal 的一切要求,只要我們能夠訪問到 label  私有字段,我們就有了完整版的 InheritableThreadLocal。

下面這個例子是作者真實項目中用的。

在 runtime 和 runtime/pprof 包中有兩個函數:runtime_setProfLabel 和  runtime_getProfLabel。其中,runtime 包中的提供了實現,而 pprof 中的沒有提供實現。如果基于它們創建另外的函數,如下:

//go:linkname SetPointer runtime/pprof.runtime_setProfLabel func SetPointer(ptr unsafe.Pointer)  //go:linkname GetPointer runtime/pprof.runtime_getProfLabel func GetPointer() unsafe.Pointer

根據前面的分析,雖然runtime.runtime_setProfLabel/runtime.runtime_getProfLabel提供了函數實現,但是二進制文件中并不會出現(見下方代碼),此時想要調用必須通過runtime/pprof.runtime_setProfLabel/runtime/pprof.runtime_getProfLabel,這也是上面linkname到pprof而不是runtime的根本原因。

// 來自 runtime 包 //go:linkname runtime_setProfLabel runtime/pprof.runtime_setProfLabel func runtime_setProfLabel(labels unsafe.Pointer) {  if raceenabled {   racereleasemerge(unsafe.Pointer(&labelSync))  }  getg().labels = labels }  // 來自 runtime/pprof 包 func runtime_setProfLabel(labels unsafe.Pointer)  // 來自 runtime 包 //go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel func runtime_getProfLabel() unsafe.Pointer {  return getg().labels }  // 來自 runtime/pprof 包 func runtime_getProfLabel() unsafe.Pointer

到此,關于“如何使用go:linkname指令”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

go
AI

治多县| 新乐市| 黑龙江省| 师宗县| 黑水县| 泸定县| 宣恩县| 芜湖县| 尉犁县| 阳谷县| 大兴区| 赤壁市| 阜康市| 天镇县| 新野县| 夹江县| 漳平市| 古蔺县| 太白县| 阜新| 大同市| 扎鲁特旗| 新沂市| 启东市| 调兵山市| 安丘市| 玛纳斯县| 贡山| 巴中市| 仙游县| 金门县| 时尚| 福海县| 南漳县| 鹿泉市| 林口县| 永新县| 缙云县| 会泽县| 阳高县| 星子县|