agiledragon / gomonkey

gomonkey is a library to make monkey patching in unit tests easy
MIT License
2k stars 179 forks source link

mac m1 used gomockey: undefined: buildJmpDirective #38

Closed JoanWu5 closed 2 years ago

JoanWu5 commented 3 years ago

my system is mac m1 when I used gomonkey, it reports:

github.com/agiledragon/gomonkey

../../../../pkg/mod/github.com/agiledragon/gomonkey@v2.0.1+incompatible/patch.go:160:10: undefined: buildJmpDirective can you help to solve this issue?

fran96 commented 3 years ago

same issue for me on M1.

LoveScotty commented 3 years ago

Is that finish?

YangAidi commented 3 years ago

me too

YangAidi commented 3 years ago

A temporary solution is to change the name ofjmp_amd64.go to jmp.go, but it is not known if the instructions in it will work properly on the ARM platform

agiledragon commented 3 years ago

add go file jmp_arm64.go. It is more complex than amd64. The length of the arm64 instruction is only 32 bits, and the instruction cannot store such a large immediate value. You must first load the parameter from the stack to the r27 register, and then b r27. Remember to replace instructions with instruction codes.

itart-top commented 3 years ago

So is the issue solved now?

chenxu2048 commented 3 years ago

A workaround: GOARCH=amd64 go test -gcflags='-N -l' . or GOARCH=amd64 go test -exec='arch -x86_64' -gcflags='-N -l' .

M1 can run x86_64 binary via arch -x86_64.

Have tested on my M1.

chenxu2048 commented 3 years ago

add go file jmp_arm64.go. It is more complex than amd64. The length of the arm64 instruction is only 32 bits, and the instruction cannot store such a large immediate value. You must first load the parameter from the stack to the r27 register, and then b r27. Remember to replace instructions with instruction codes.

@agiledragon any detail about go calling conversion in arm64?

I found that reflect.makeFunc in amd64 is:

TEXT ·makeFuncStub<ABIInternal>(SB),(NOSPLIT|WRAPPER),$32
    NO_LOCAL_POINTERS
    MOVQ    DX, 0(SP)
    LEAQ    argframe+0(FP), CX
    MOVQ    CX, 8(SP)
    MOVB    $0, 24(SP)
    LEAQ    24(SP), AX
    MOVQ    AX, 16(SP)
    CALL    ·callReflect<ABIInternal>(SB)
    RET

which in arm64 is:

TEXT ·makeFuncStub(SB),(NOSPLIT|WRAPPER),$40
    NO_LOCAL_POINTERS
    MOVD    R26, 8(RSP)
    MOVD    $argframe+0(FP), R3
    MOVD    R3, 16(RSP)
    MOVB    $0, 32(RSP)
    ADD $32, RSP, R3
    MOVD    R3, 24(RSP)
    BL  ·callReflect(SB)
    RET

And gomonckey patch function with some code like:

MOV rdx, double
JMP [rdx]

So, I replace hooked function with some code like:

// double = d3 d2 d1 d0
MOVK R26, d0
MOVK R26, d1, LSL 16
MOVK R26, d2, LSL 32
MOVK R26, d3, LSL 48
LDR R0, [R26]
BR R0

In some test case it works but others failed. It seems x0 register was broken in some case, but I'm not sure. Is there any instruct like JMP [rdx] in ARM64 or other usable register in this context?

agiledragon commented 3 years ago

Arm64 is fully supported in the v2.2.0, please try it.

Rambatino commented 2 years ago

Getting:

> go get github.com/agiledragon/gomonkey
go: downloading github.com/agiledragon/gomonkey v2.0.2+incompatible
# github.com/agiledragon/gomonkey
../../go/pkg/mod/github.com/agiledragon/gomonkey@v2.0.2+incompatible/patch.go:163:10: undefined: buildJmpDirective
librant commented 2 years ago

the same as @Rambatino, M1 questions;

zhongyuanjia commented 2 years ago

@Rambatino @librant please try gomonkey@v2.2.0 or higher version