pkujhd / goloader

load and run golang code at runtime.
Apache License 2.0
497 stars 58 forks source link

你好, 请问这个项目是怎么保持跟随 Go 最新版本的呢 #73

Closed fumeboy closed 1 year ago

fumeboy commented 1 year ago

目前我知道 goloader 是借用了 go plugin 的接口, 通过构造 moduledata 并注册到链表来动态接入 Go Runtime

但是这块的资料网上非常少, 怎么判断每次 Go 更新后, 这个项目要不要更新, 以及更新哪些补丁呢

pkujhd commented 1 year ago

@fumeboy , 基本只能测试,如果有问题就适配新版本。 这方面基本没有资料,只能读golang自己的linker的代码来处理

fumeboy commented 1 year ago

@pkujhd 你好, 我五一认真看了一下 go 链接器源码(的一部分), 发觉 goloader 可能有一个场景不太好处理, 就是动态链接的 object file 不能 import 第三方包对吗

pkujhd commented 1 year ago

@pkujhd 你好, 我五一认真看了一下 go 链接器源码(的一部分), 发觉 goloader 可能有一个场景不太好处理, 就是动态链接的 object file 不能 import 第三方包对吗

可以,如果你的loader里边没有使用这个包,那么你在加载的时候也要加载这个包才能使用

eh-steve commented 1 year ago

FYI, this fork https://github.com/eh-steve/goloader#example-usage attempts to address this automatically by building and loading any missing dependencies recursively

fumeboy commented 1 year ago

在阅读您的 goloader 源代码前, 我只知道卸载需要从 moduledata 链中移除, 没想到还需要 removeitabs 我们怎么才能知道卸载一个 object file 需要处理哪些 runtime 的 global variable?

pkujhd commented 1 year ago

这个基本都是按照add的过程的逆向操作,大部分都是测试后发现有问题然后读源代码补充的. 另外如果你想解决依赖性问题,可以使用eh-steve的分支,他的分支会自动解决依赖性.

fumeboy commented 1 year ago

你好, 在 Go 链接器源代码 link/internal/ld 中, 重定位类型 objabi.R_CALL 和 objabi.R_PCREL 是统一处理的, 但是在 goloader 中relocatePCREL 函数实现比起 relocateCALL 更复杂, 请问为什么 relocatePCREL 要关心用了哪些汇编指令呢

eh-steve commented 1 year ago

In the standard linker, relocations are guaranteed to be within a 32 bit distance and so it's quite straightforward to write PCREL/CALL offsets as a 4 byte uint32. In Goloader, the mmapped code might be further than 32-bits (though not in my fork), and might have relocations which point at firstmodule symbols, (and strings are always stored in the heap which is definitely further than 32 bits away).

To get around this, goloader rewrites certain instructions which assume a 32-bit immediate value, replacing them with a jump to equivalent instructions but allowing for 64 bit offsets.

fumeboy commented 1 year ago

@eh-steve Thank you, and maybe use GOT and PLT will be more safe to handle 64bit address?

eh-steve commented 1 year ago

@eh-steve Thank you, and maybe use GOT and PLT will be more safe to handle 64bit address?

That would require JIT packages to be compiled with the still experimental gcflag -dynlink (which may be fine if we control the compilation), but I'm not sure that a statically linked host binary even includes a GOT/PLT... Currently goloader can load JIT code in fully static binaries.

I might look into the feasibility of this approach at some point though.

fumeboy commented 1 year ago

@eh-steve @pkujhd I may have found the right approach to solve this problem by go tool compile -dynlink

if without -dynlink, the compiler write asm as:

  _make_object_file.go:15       0x1f07                  488b1d00000000          MOVQ 0(IP), BX          [3:7]R_PCREL:<unlinkable>.a     
  _make_object_file.go:15       0x1f0e                  488b1500000000          MOVQ 0(IP), DX          [3:7]R_PCREL:<unlinkable>.a+8  

if with -dynlink, the compiler write asm as:

  _make_object_file.go:15       0x1a98                  4c8b3d00000000          MOVQ 0(IP), R15         [3:7]R_GOTPCREL:<unlinkable>.a  
  _make_object_file.go:15       0x1a9f                  498b1f                  MOVQ 0(R15), BX         
  _make_object_file.go:15       0x1aa2                  4c8b3d00000000          MOVQ 0(IP), R15         [3:7]R_GOTPCREL:<unlinkable>.a  
  _make_object_file.go:15       0x1aa9                  498b5708                MOVQ 0x8(R15), DX 
fumeboy commented 1 year ago

In addition, it seems that PLT is implemented through "trampoline" in the source code.

https://github.com/golang/go/blob/3e35df5edbb02ecf8efd6dd6993aabd5053bfc66/src/cmd/link/internal/arm64/asm.go#L1284

fumeboy commented 1 year ago

In addition, it seems that PLT is implemented through "trampoline" in the source code.

https://github.com/golang/go/blob/3e35df5edbb02ecf8efd6dd6993aabd5053bfc66/src/cmd/link/internal/arm64/asm.go#L1284

哦, 原来 x86amd64JMPLcode 就是 PLT 的实现