Giter Club home page Giter Club logo

Comments (19)

pkujhd avatar pkujhd commented on August 18, 2024

@devanwang 因为你编译的t.go不是一个main包,所以go build -x -n -v t.go 2>&1 | sed -n "/^# import config/,/EOF$/p" |grep -v EOF > importcfg 这个得到的信息是错的.

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

正确的信息是类似这样的

# import config
packagefile fmt=/Users/pkujhd/programs/go/pkg/darwin_amd64/fmt.a
packagefile github.com/pkujhd/goloader/examples/p=/Users/pkujhd/Library/Caches/go-build/90/903b1feecaa67440b2c6c3b2edee39fffec4ad91db2874c894b6213cc3975991-d
packagefile runtime=/Users/pkujhd/programs/go/pkg/darwin_amd64/runtime.a

from goloader.

devanwang avatar devanwang commented on August 18, 2024

@pkujhd 大佬,我把t.go的package改了main,cat importcfg结果如下:

# import config
packagefile fmt=/usr/local/go/pkg/linux_amd64/fmt.a
packagefile github.com/pkujhd/goloader/examples/p=/root/.cache/go-build/7c/7ca25758e4aed09361504e8dfac5576615f44fefc3d1960788eab0500ed48243-d
packagefile runtime=/usr/local/go/pkg/linux_amd64/runtime.a

然后重新编译t.o,执行loader还是同样的报错

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

给下你的运行环境和golang的版本

from goloader.

devanwang avatar devanwang commented on August 18, 2024

Linux version 5.4.119-1-tlinux4-0005 (root@VM_197_173_centos) (gcc version 8.3.1 20191121 (Red Hat 8.3.1-5)
go version go1.18.3 linux/amd64

from goloader.

devanwang avatar devanwang commented on August 18, 2024

如果在t.go里调用reflect

package main

import (
	"fmt"
	"reflect"

	"github.com/pkujhd/goloader/examples/p"
)

func Test(param p.Intf) p.Intf {
	fmt.Println(reflect.TypeOf(param))
	return param
}

会报错 Load error: unresolve external:reflect.(*rtype).FieldByIndex

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

如果在t.go里调用reflect

package main

import (
	"fmt"
	"reflect"

	"github.com/pkujhd/goloader/examples/p"
)

func Test(param p.Intf) p.Intf {
	fmt.Println(reflect.TypeOf(param))
	return param
}

会报错 Load error: unresolve external:reflect.(*rtype).FieldByIndex

你的case可以在loader中注册掉这个interface暂时避免

var x p.Intf = &p.Stru{}
goloader.RegTypes(symPtr, x, x.Print)

from goloader.

devanwang avatar devanwang commented on August 18, 2024
var x p.Intf = &p.Stru{}
goloader.RegTypes(symPtr, x, x.Print)

加了这个不会报linker bug了,unresolve external:reflect.xxx还是会有

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

reflect

var x p.Intf = &p.Stru{}
goloader.RegTypes(symPtr, x, x.Print)

加了这个不会报linker bug了,unresolve external:reflect.xxx还是会有

这个reflect的函数loader里没有使用,你需要注册

from goloader.

devanwang avatar devanwang commented on August 18, 2024

在t.go里只加了一行reflect.TypeOf(param),每次都报不同的错,没法加啊
Load error: unresolve external:reflect.(*rtype).Implements
Load error: unresolve external:reflect.(*rtype).FieldByNameFunc
Load error: unresolve external:reflect.(*rtype).ConvertibleTo
Load error: unresolve external:reflect.(*rtype).FieldAlign
Load error: unresolve external:reflect.(*rtype).MethodByName
Load error: unresolve external:reflect.(*rtype).FieldByIndex

我看原理会解析loader bin的symbols, 我在loader里同样加了reflect.TypeOf(param)代码,还是不行

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

Refelect 包会用到一系列的函数,都要注册,或者就在你的加载器里有类似的代码,会移动处理加载器里的符号

from goloader.

devanwang avatar devanwang commented on August 18, 2024

不是很懂,大佬能不能给个具体例子,针对t.go里的reflect.TypeOf函数,我要在loader写什么?

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

fmt.Println(reflect.TypeOf(param))

就是你在loader里也调用过相应的函数,就会自动注册
就是在loader里加一行
fmt.Println(reflect.TypeOf(param))

from goloader.

devanwang avatar devanwang commented on August 18, 2024

这个不行,在loader里加了同样的reflect.TypeOf(param)还是会报如下错误:
Load error: unresolve external:reflect.(*rtype).Implements
Load error: unresolve external:reflect.(*rtype).FieldByNameFunc
Load error: unresolve external:reflect.(*rtype).ConvertibleTo
Load error: unresolve external:reflect.(*rtype).FieldAlign
Load error: unresolve external:reflect.(*rtype).MethodByName
Load error: unresolve external:reflect.(*rtype).FieldByIndex

大佬你那边可以试下

from goloader.

devanwang avatar devanwang commented on August 18, 2024

@pkujhd 查nm找到原因了,loader里的reflect.TypeOf被内联优化了,t.o的没有被内联,加上-gcflags -l就可以了,但这样编译器就禁止内联了,不知道有啥好办法没有

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

@pkujhd 查nm找到原因了,loader里的reflect.TypeOf被内联优化了,t.o的没有被内联,加上-gcflags -l就可以了,但这样编译器就禁止内联了,不知道有啥好办法没有

这个没啥办法,内联了要么你loader的时候重新提供一份,要么loader就是禁止inline的

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

@devanwang ,这个问题查了下,是因为loader中产生的type,由于连接优化,剔除了Intf.Print, 因此上在加载一个扩展的时候,两边的类型虽然名字相同但是实际类型却不一样,无法正确运行,如果你需要在runtime和dynamic library之间传递interface,那么需要使得两边的类型一致(即需要手动注册相应的函数,保证runtime里边产生的type是一样的).
故此问题只能和inline一样. 编写时规避

from goloader.

pkujhd avatar pkujhd commented on August 18, 2024

记录下这个case的调试信息:

relocateType symbolName relocateSymbolName address
5 main.Test.stkobj runtime.gcbits.02 1094664412
1 main..stmp_0 go.string."done!" 1107140612
24 main.Test type.github.com/pkujhd/goloader/examples/p.Intf 7043456
23 main.Test type.string 6948512
23 main.Test type.*os.File 7288448
14 main.Test go.string."Intf" 1107140608
10 main.Test  1094664360
14 main.Test type.string 6948512
14 main.Test main..stmp_0 1094664448
14 main.Test os.Stdout 9954648
14 main.Test go.itab.*os.File,io.Writer 7911456
7 main.Test fmt.Fprintln 4919424
7 main.Test runtime.morestack_noctxt 4594432
1 go.itab.*os.File,io.Writer type.io.Writer 7044224
1 go.itab.*os.File,io.Writer type.*os.File 7288448
32769 go.itab.*os.File,io.Writer os.(*File).Write 4893696

以上是这个case所有需要relocate的列表, main.Test需要重定向type.github.com/pkujhd/goloader/examples/p.Intf,这个type已经在load中存在,但是对应的stuc.Print不存在,就会导致运行错误

记录信息:

可以采用-dynlink作为编译参数,这个参数是golang为plugin的模式添加的编译参数,会产生一个go.plugin.tabs的symbol来储存需要导出的函数,plugin模式用它来初始化moduledata的ptabEntry, 然后plugin模块读取这个array来产生导出的符号列表,
这是一个interface{]的array,所以当把interface转成func()时,会导入相应的符号,就不会产生上述才问题.

但是这个问题在goversion>=1.12的schedule这个case的时候会导致找不到符号runtime.gosched_m·f, 这个符号在runtime.a里,但是生成的loader里边没有,生成的.o里也没有,暂时无法处理;而不包含-dynlink的编译成的.o,runtime.gosched_m·f,这个符号就在当前的.o里.

now blocking...

from goloader.

eh-steve avatar eh-steve commented on August 18, 2024

I think this is an artefact of the main loader's go compiler/linker setting some of the method offsets in the uncommon type of the *p.Stru to -1 as part of its reachability analysis (since no code in loader.go explicitly calls (*p.Stru).Print()). These "unreachable" method offsets are then baked into the firstmodule's itabs (go.itab.*github.com/pkujhd/goloader/examples/p.Stru,github.com/pkujhd/goloader/examples/p.Intf) during the first itab init and the method text pointers are set to point at the address of runtime.unreachableMethod, and when the method is later called from a dynamic module, it is indeed unreachable (from the first module's perspective).

PR #66 adds a functionality to patch the first module's itabs to point at newly included method offsets if they're now available in a dynamic module, which prevents these fatal error: unreachable method called. linker bug? errors.

I've made a separate branch here with this commit eh-steve@78fc98a demonstrating the solution.

If you check out that branch and run either:

cd ./examples/jit
go build .
./jit

or (using old loader)

cd ./examples/issue55/t/
go build -o t.o .
cd ../p/
go build -o p.o .
cd ../../loader
go build .
 ./loader -o ../issue55/t/t.o -o ../issue55/p/p.o -run "github.com/pkujhd/goloader/examples/issue55/t.Test"

It should be working (without the main binary having registered any extra types!)

from goloader.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.