千家信息网

go tool objdump怎么用

发表于:2026-11-01 作者:千家信息网编辑
千家信息网最后更新 2026年11月01日,本篇内容主要讲解"go tool objdump怎么用",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"go tool objdump怎么用"吧!1.用go
千家信息网最后更新 2026年11月01日go tool objdump怎么用

本篇内容主要讲解"go tool objdump怎么用",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"go tool objdump怎么用"吧!

1.用go tool objdump,可以看到任意函数的机器码、汇编指令、偏移。(go源码下面有一个cmd/internal/goobj包,可以读到.o文件的重定向信息,更好。)

2.修改里面的golang内部函数的相对跳转,指向加载者相同的函数的地址(仍然可以用go tool objdump看到函数的初始地址),常见的有runtime.newobject、runtime.convT2Eslice、runtime.panicindex、runtime.morestack_noctxt等runtime系列函数。

3.修改golang类型指针偏移(当对象转换成interface{}时候,需要一个类型指针),指向加载者相同的类型。

4.修改指向字符串,全局变量,自定义函数的偏移(一般都是相对偏移)。

5.写入mmap,并执行。

整体思路是,通过修改偏移,复用加载者所用到的函数、golang内部函数、golang类型信息等。

缺点:

1.可以自定义类型,但是不能将这些类型的对象赋值到interface{}(加载者已定义的类型可以),比如使用fmt.Println打印这些对象(但是可以打印这些对象的成员)。因为golang内部的一些全局变量(比如golang类型)可能存在指针,而且开始就初始化了。

2.不能在函数外初始化全局变量。(可能的解决方法:定义一个入口函数,在里面初始化,或者读取main.init函数,取出初始化代码。)

优点:

仍然使用golang和golang编译工具。

速度极快,体积极小。相当于复用了golang内部的调度器、内存分配器、类型系统等。

可以自定义。golang函数内的汇编足够简单,可以开发自己的工具来实现上面的思路。

golang本质就是GPM三个实体实现的调度。

G对应每个任务,P对应每个processor概念(就是会包含一堆的G,比如先执行G1,在执行G2)M对应系统线程,M(还包含系统栈之类的概念)绑定一个P之后就开始逐个运行P里面的G。

最基本的流程图就是雨痕给的

后面雨痕对于GPM三者的解释也很到位。我这里不抄袭了。

2.初始化

首先介绍的就是schedinit()里面主要是procresize函数。

这个procresize()就是调整系统里面P的数量。一般就是系统的cpu内核的数量,初始化时也实行多退少补的原则,只是退的时候要注意是否退出的P包含了当前P,如果是就需要一大堆的细节上的处理。

这里还有个所有P的管理结构

var allp [_MaxGomaxprocs + 1]*p

type schedt struct {

pidle puintptr // P

npidle uint32 // P

}

还有个提示,如果调用手动调用并修改runtime.GOMAXPROCS就会引发stopTheWorld以及startTheWorld,这两个动作本身是比较好耗时的,之后在startTheWorld执行的procresize()也是比较耗时的。

3.任务 G/P

先举了个栗子,通过

go build -o test test.go

go tool objdump -s "main\.main" test

go add(x, y)会被汇编成类似

CALL runtime.newproc(SB)

这种代码

然后就去runtime找了。

newproc(获取pc/ip地址以及入参等重要信息后)->newproc1

之后登场的G的数据结构

type g struct {

stack stack //执行栈

sched gobuf //用于保存执行现场

goid int64 //唯一序号

gopc uintptr //调用者 PC/IP

startpc uintptr //任务函数

}

newproc1一开始就处理各种处理创建G,测试G,对齐地址,拷贝栈,保存现场的各种杂活儿。然后一个runqput(p, newg, true),被put进去了。

runqput有可能把g作为P.runnext,也可能放在末尾,也有可能丢到全局队列。

稍微介绍了g通过p然后进行二级缓存复用的逻辑,类似cache/object,central的做法。分别对应gfget, gfput两个函数。

所有的g 还有个全局应用allgs/allg,用来索引所有的G方便回收和shrinkstack。

补充了个细节只有本地的P队列堆满了才会丢到全局队列,而且一次会丢本地队列长度的一半,保证效率和多核均匀调度。

4.线程 M

当结束runqput之后,开始wakep了,

wake->startm->newm创建/或者notewakeup(&mp.park)

newm->newosproc->linux调用

clone(cloneFlags,stk,unsafe.Pointer(mp),unsafe.Pointer(mp.g0),unsafe.Pointer(funcPC(mstart))) 开启系统线程,并且入口函数是mstart

所有m会被添加到allm链表,不会被释放,超过10000崩溃。

最后补充了两个细节1:m也是有复用的,mput&mget使用1级缓存。

然后说不要创建太多m啊,time.Sleep比C.sleep(1)要好,之类的。

5.执行

上面说到newm的时候会注册系统线程并把mstart作为入口函数。

然后这里就讲mstart

mstart ->

mstart1 aquirep绑定p ->

schedule()兼顾帮助垃圾回收标记之类的各种杂活,findrunable,->

调用execute->

各种准备好栈JMP入函数入口地址PC->

各种调用结束后RET指令把预先压入的goexit地址恢复到PC/IP->

将G返回服用链表->

重新schedule()

然后介绍了一下findrunable的主干:

1.通过runqget拿本地的P的东西,

2.globrunqget

3.检查netpoll任务

4.尝试偷取其他P的任务。(基于CAS和atomicset弄的Work-Stealing算法)

…

5.这后还会进行各种尝试,如果实在没有就stopm了。

Lockedg

这是cgo的一个特定调用方式,会把当前的g和m绑定,而且只有在结束调用的时候才会松开。

一个m在调用schedule() 如果发现它是被某个G绑定的则会暂时休息。如果发现自己将要调用的G,是被别的m绑定的,则会将它唤醒,然后自己休眠。

所以每个cgo routine在调用完成之前都会有自己专属的一个G调用。cgo因此会产生大量的m。

到此,相信大家对"go tool objdump怎么用"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

函数 类型 系统 全局 地址 就是 任务 偏移 入口 对象 时候 线程 队列 复用 两个 信息 变量 指向 指针 细节 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网科技 互联网科技公司起名 重庆互联网络科技 互联网 科技创业 北京互联网络科技有限公司 顺网科技2021年互联网排名 成都仁贤领冠互联网科技有限公司 昭通云南众福互联网科技有限公司 天津腾达互联网科技有限公司 如何创新互联网科技 互联网行业科技股 卓翼科技产业互联网合作 元气玛特互联网科技公司是外包吗 信承诺互联网科技有限公司 全球科技与互联网公司市值变化 北京天晋互联网科技有限公司 求路客互联网科技电话 三亚科技创新互联网基地 互联网金融金融科技 互联网科技创业有什么好项目 什么是科技互联网 合肥互联网科技公司 开启互联网科技时代小说 移动互联网科技公司 速维有品互联网信息科技(苏州)有限公司 哈尔滨屹滨互联网科技有限公司 互联网科技大赛获奖感言 郑州欣桑互联网科技有限公司 互联网的黑科技实验室 互联网科技企业文化
0