go语言魔法技能go:linkname

我们在看Go语言的源码时,经常会看到一些特别的注释,比如:

//go:build
//go:linkname
//go:nosplit
//go:noescape
//go:uintptrescapes
//go:noinline
//go:nowritebarrierrec

等等,这些特别的注释其实是Go编译器的指示指令。这里介绍一下go:linkname指令其及用法,并给出各种用法的完整实例,网上很少有各种用法的完整实例的。

go:linkname的指令格式为:

//go:linkname localname [importpath.name]
  • localname为本包中的名字
  • importpath.name为引入包的路径及其名字,可省略。

在使用该指令前,需要import unsafe包。

该指令写在localname上,但localname可以是importpath.name的别名,也可以是它的实现,即可以是在本包中定义,也可以不是定义。下面就以具体例子来说明:

一、localname函数在本包未实现,相当于是别名

可以看Go源码中time包的runtimeNano函数,如下图:
在这里插入图片描述
runtimeNano函数在此并未实现,只是提供了一个声明,使用//go:linkname runtimeNano runtime.nanotime来告诉编译器该函数使用runtime包中的nanotime函数实现,这里相当于只是一个别名。该函数的定义如下图所示,但是分为nofakefake两种版本:

在这里插入图片描述

在这里插入图片描述

这种用法比较容易理解,定义好一个函数后,可以在其它包中进行多次go:linkname创建别名。

二、localname函数在本包实现

细心的读者应该发现了上图中time_now函数了,即通过//go:linkname time_now time.now指示time包中的now函数使用本包(runtime包)中的time_now函数,当然time包中还是需要有一个now函数的声明,就在前面nanotime函数的上方:

在这里插入图片描述
可以看到now函数上面的注释没有任何编译器指令。

这种用法比较容易出错,很容易出现missing function body错误,这是因为Go在编译时会添加-complete将该包作为一个纯Go包来编译,即该包中不包括非Go组件。
在这里插入图片描述

遇到这种情况,有两种方式解决:

  • 在该包中添加一个空的.s文件,随便取一个名字,比如empty.s
  • 在函数前添加//go:linkname localname格式的指令,注意没有importpath.name

三、实例

新建一个目录demo,使用VSCode打开,其目录结构如下:

$ tree -a
.
├── .vscode
│   ├── launch.json
│   └── tasks.json
├── case3
│   ├── case3.go
│   ├── empty.s
│   └── internal
│       └── priv.go
├── go.mod
├── main.go
├── outer
│   ├── internal
│   │   └── inter.go
│   └── outer.go
├── private
│   └── private.go
└── public└── public.go8 directories, 11 files

在这里插入图片描述

main.go

package mainimport ("demo/outer""demo/public"
)func main() {public.Demo()outer.Outer()
}

go.mod

module demogo 1.22.0

public.go

package publicimport (_ "demo/private"_ "unsafe"
)//go:linkname foo demo/private.foo
func foo()func Demo() {foo()
}

private.go

package privateimport ("fmt"
)func foo() {fmt.Println("Private foo")
}

outer.go

package outerimport (_ "demo/outer/internal"_ "unsafe"
)//go:linkname Outer
func Outer()

inter.go

package internalimport ("fmt"_ "unsafe"
)//go:linkname inter demo/outer.Outer
func inter() {fmt.Println("internal.inter")
}

case3.go

package case3import _ "demo/case3/internal"func Foo()

empty.s是一个空文件,用于告诉编译器,本包不是一个纯Go组件包

priv.go

package internalimport ("fmt"_ "unsafe"
)//go:linkname f demo/case3.Foo
func f() {fmt.Println("internal.f")
}

tasks.json

{"version": "2.0.0","tasks": [{"type": "go","label": "go: build workspace","command": "build","args": ["./..."],"problemMatcher": ["$go"],"group": {"kind": "build","isDefault": true},"detail": "cd d:\\go; go build ./..."}]
}

launch.json

{// 使用 IntelliSense 了解相关属性。 // 悬停以查看现有属性的描述。// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387"version": "0.2.0","configurations": [{"name": "Launch Package","type": "go","request": "launch","mode": "auto","program": "${workspaceFolder}","preLaunchTask": "go: build workspace"}]
}

如果对你有帮助,欢迎点赞收藏!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/710255.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

VUE实现Office文档在线编辑,支持doc/docx、xls/xlsx、ppt/pptx、pdf等

1.微软提供的在线Office预览(只能预览,不能编辑) https://view.officeapps.live.com/op/view.aspx?src服务器上文档地址(http开头) 2.国内在线Office方案: 腾讯文档、石墨文档、飞书 优势:跨…

掌握 Vue3 中的 setup 函数

Vue.js 经历了从 Vue 2 到 Vue 3 的重大变革,带来了许多引人注目的新特性和性能优化。其中,setup函数无疑是最引人瞩目的新星之一。 一、概览 setup函数是 Vue 3 引入的一个新的组件选项,作为组合式 API 中心,它允许开发者在一个…

Unity生命周期函数解析

本文由 简悦 SimpRead 转码, 原文地址 mp.weixin.qq.com Unity生命周期函数解析 Unity 生命周期函数是在游戏对象的不同阶段被调用的方法,通过这些函数,我们可以在不同的时刻执行特定的代码。在这篇文章中,我们将一步步解析 Unit…

Linux红帽rhce认证多少钱?考个RHCE难不难?

Linux作为开源操作系统的佼佼者,已经广泛应用于各个领域。红帽认证工程师(Red Hat Certified Engineer,简称RHCE)作为Linux领域权威的认证之一,自然成为了众多IT从业者追求的目标。那么,RHCE认证的培训费用是多少?考取这一认证又…

ElasticSearch仿京东搜索

一:爬取京东数据 package com.esjd.Utils;import lombok.SneakyThrows; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.jsoup.select.Elements;import java.net.MalformedURLException; import java.net.…

Linux的条件变量

条件变量 条件变量本身不是锁,但是它可以造成线程阻塞。通常于互斥锁配合使用。给多线程提供一个会和的场合。 使用互斥量保护共享数据使用条件变量可以造成线程阻塞,等待某个条件的发生,当条件满足的时候解除阻塞。 条件变量的两个动作&a…

python 基础知识点(蓝桥杯python科目个人复习计划55)

今日复习内容:做题 例题1:体育健将 问题描述: 小蓝作为班级里的体育健将,他被安排在校运会时参加n个体育项目,第i个体育项目参赛需要耗时ai分钟,赛后休息需要bi分钟(这意味着当他参加完这场比…

【AIGC大模型】InstantID 赏析

论文地址:https://arxiv.org/abs/2401.07519 InstantID 主页:https://instantid.github.io/ Demo :https://huggingface.co/spaces/InstantX/InstantID code: InstantID/InstantID: InstantID : Zero-shot Identity-Preserving…

计算机组成原理-第一/二章 概述和数据的表示和运算【期末复习|考研复习】

文章目录 前言第一章 计算机组成原理 概述及各种码1.1 计算机硬件的基本组成1.1.1 存储器1.1.2 运算器1.1.3 控制器 1.2 计算机的工作过程1.3 计算机的性能指标1.4 各个字长区别与联系 第二章 数据的表示与运算2.1 ASCII码2.2 各种码2.3 浮点数 总结 前言 给大家整理了一下计算…

网络安全与代理技术:解密 SOCKS5、代理IP 和 HTTP

在当今数字化的世界中,网络安全问题备受关注。作为网络安全的重要组成部分,代理技术在保护个人隐私和网络安全方面发挥着关键作用。本文将以教授的身份,简明扼要地介绍 SOCKS5 代理、代理IP、HTTP 代理等关键词,帮助读者了解这些技…

雅特力AT32L021首款低功耗MCU震撼登场

雅特力于2月28日正式发布AT32L021首款入门级低功耗MCU,搭配不同容量Flash、SRAM,提供7种封装类型共21个型号选择,最小封装面积仅3x3mm。为降低能耗,延长设备运作时间,AT32L021系列支持多种能耗模式和休眠模式&#xff…

spark中dataframe起别名对join过程的影响

toDF().as("a").join(df2,Seq("seq1"),"right") .filter($"a.seq1".isNotNull)toDF().as("a").join(df2,Seq("seq1"),"right") .filter($"seq1".isNotNull)今天之前我认为这里不应该用别名&a…

2.29文件IO-进程 作业

1.要求将当前路径下&#xff0c;所有文件的权限及最后一次的访问时间提取出来&#xff0c;写入到file.txt中! !提示: opendir readir stat-->提取出来的数据写入到file.xt中 #include <stdio.h> #include <sys/types.h> #include <dirent.h> #include &l…

详解kubernetes中的Pod生命周期

目录 1.1 Pod生命周期概述 1.2 创建和终止 1.2.1 Pod的创建过程 1.2.2 Pod的终止过程 1.3 初始化容器 1.3.1 案例 1.4 容器探测 1.4.1 Exec示例 1.5 重启策略 1.1 Pod生命周期概述 Pod中的生命周期主要包含以下过程&#xff1a; pod创建过程 运行初始化容器&#xff…

Mysql Day07

存储过程 -- 存储过程基本语法 -- 创建 create procedure p1() begin select count(*) from student; end; -- 调用 call p1(); -- 查看 select * from information_schema.ROUTINES where ROUTINE_SCHEMA itcast; show create procedure p1; -- 删除 drop procedure if exis…

weak 的实现原理

iOS 在运行时维护着一个全局的弱引用表&#xff0c;该表是一个 hash 表&#xff0c;hash表的 key 是 weak 对象的地址&#xff0c;value 是指向该对象的所有 weak 指针的地址数组。 /**全局的弱引用表&#xff0c;本质是一个hash结构&#xff0c;object作为key, weak_entry_…

npm 设置取消代理

npm 设置淘宝镜像源&#xff1a;npm install -g cnpm --registryhttps://registry.npm.taobao.org npm 查看当前配置信息 npm config listnpm 设置代理 npm config set proxy 127.0.0.1:7890 npm config set https-proxy 127.0.0.1:7890删除代理信息 npm config delete pro…

TCP/UDP模型:2024/2/29

作业1&#xff1a;TCP模型 服务器端&#xff1a; #include <myhead.h> #define SER_IP "192.168.199.129" #define SER_PORT 8899int main(int argc, const char *argv[]) {//1.创建用于连接的套接字文件int sfdsocket(AF_INET,SOCK_STREAM,0);if(sfd-1){per…

【蓝桥杯】赢球票(模拟、枚举、搜索)

一.题目描述 某机构举办球票大奖赛。获奖选手有机会赢得若干张球票。 主持人拿出 N 张卡片&#xff08;上面写着 1~N 的数字&#xff09;&#xff0c;打乱顺序&#xff0c;排成一个圆圈。你可以从任意一张 卡片开始顺时针数数: 1,2,3..... 如果数到的数字刚好和卡片上的数字…

深入理解nginx的https alpn机制

目录 1. 概述2. alpn协议的简要理解2.1 ssl的握手过程2.2 通过抓包看一下alpn的细节3. nginx源码分析3.1 给ssl上下文设置alpn回调3.2 连接初始化3.3 处理alpn协议回调3.4 握手完成,启用http协议4.4 总结阅读姊妹篇:深入理解nginx的https alpn机制 1. 概述 应用层协议协商(…