pkujhd / goloader

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

unexpected return pc 0x0 #87

Closed pkujhd closed 1 year ago

pkujhd commented 1 year ago

on windows exec ./loader -o schedule.o -times 100 panic

log:

all start
begin
.\loader.exe : runtime: g 21393: unexpected return pc for main.main.func2 called from 0x0
所在位置 行:1 字符: 1
+ .\loader.exe -o .\schedule.o -times 100
    + CategoryInfo          : NotSpecified: (runtime: g 2139...called from 0x0:String) [], RemoteException
    + FullyQualifiedErrorId : NativeCommandError

stack: frame={sp:0xc00b61df78, fp:0xc00b61dfd8} stack=[0xc00b61c000,0xc00b61e000)
0x000000c00b61de78:  0x0000000000000000  0x000000c00917f380 
0x000000c00b61de88:  0x000000c00917f520  0x000000c00917fa00 
0x000000c00b61de98:  0x000000c00917fba0  0x000000c0091589c0 
0x000000c00b61dea8:  0x000000c009158b60  0x000000c00917f520 
0x000000c00b61deb8:  0x000000c00917f6c0  0x000000c00917f860 
0x000000c00b61dec8:  0x000000c00917fa00  0x000000c00917fba0 
0x000000c00b61ded8:  0x000000c00917fd40  0x000000c0091a4000 
0x000000c00b61dee8:  0x000000c0091a41a0  0x000000c0091a4340 
0x000000c00b61def8:  0x000000c0091a44e0  0x000000c0091a4680 
0x000000c00b61df08:  0x000000c0091a4820  0x000000c0091a49c0 
0x000000c00b61df18:  0x000000c0091a4b60  0x000000c0091a4d00 
0x000000c00b61df28:  0x000000c0091a4ea0  0x000000c003d8da00 
0x000000c00b61df38:  0x000000c003d8dba0  0x000000c003d8dd40 
0x000000c00b61df48:  0x000000c003920000  0x0000000000000000 
0x000000c00b61df58:  0x0000000000000000  0x0000000000000246 
0x000000c00b61df68:  0x000000c00b61dfd0  0x00000299b7f7029b <main.main.func2+0x000000000000010b> 
0x000000c00b61df78: <0x00000299b7f7021a <main.main.func2+0x000000000000008a>  0x000000c00b61dfb8 
0x000000c00b61df88:  0x0000000000000001  0x0000000000000001 
0x000000c00b61df98:  0x0168616861686168  0x0000000000000048 
0x000000c00b61dfa8:  0x000000c0000875c0  0x000000c00029a700 
0x000000c00b61dfb8:  0x0000000000897020  0x00000299b7f80178 
0x000000c00b61dfc8:  0x00000299b7f80170 !0x0000000000000000 
0x000000c00b61dfd8: >0x0000000000645101 <runtime.goexit+0x0000000000000001>  0x6168616861686168 
0x000000c00b61dfe8:  0x6168616861686168  0x6168616861686168 
0x000000c00b61dff8:  0x6168616861686168 
fatal error: unknown caller pc
pkujhd commented 1 year ago

need rewrite R_CALL and R_PCREL_CALL

with ASM code JMPNear(0xE9, 0x00, 0x00, 0x00, 0x00) => CALL(0xFF, 0x15, 0x00, 0x00, 0x00, 0x00) => JMPNear(0xE9, 0x00, 0x00, 0x00, 0x00)

eh-steve commented 1 year ago

I can't seem to reproduce with this branch... Does this new test reproduce the failure for you?

pkujhd commented 1 year ago

I can't seem to reproduce with this branch... Does this new test reproduce the failure for you?

This bug is probabilistic. i think golang runtime switch stack when exec 'call' instruction will lead to this panic I haven't figured out why, but use jmpnear -> far call -> jmpnear instruction can avoid it

eh-steve commented 1 year ago

Ah, I think the reason the x86 case was a problem was because the CALL was to a PC in the epilogue (which aimed to JMP straight into the target function). The return PC is pushed to the stack (as the frame's "virtual" link register), but if a traceback happens while we're still in the epilogue (but before the jump), the _func for this PC would be the original caller, and not match the actual final call target (i.e. it would look like the function called itself, because the link register _func and current PC _func would be the same).

Your fix is correct (to first jump to the epilogue, so LR and current PC are consistent, then to CALL to the destination directly (so LR points to the epilogue, then jump back)