This page is intended to track efforts for golang support. If you're looking for how to use it, please refer to TBD.
Support golang binary without modification with graphene(-SGX). Here golang binary means one created by gc toolchain. Not gccgo, not go-llvm nor other implementations. The target user is normal go developer who has already binary. We'd like tell them, bring your binary as is.
categoary | item | status | PRs/Issues |
---|---|---|---|
Static binary | trap-and-emulate syscall instruction | merged | |
%gs for PAL/LibOS tls | https://github.com/oscarlab/graphene/pull/555 https://github.com/oscarlab/graphene/pull/556 https://github.com/oscarlab/graphene/pull/601 | ||
binary patch | |||
dedicated stack for LibOS | |||
signal emulation | nested signal | discussion on-going. respin PR | https://github.com/oscarlab/graphene/issues/348 https://github.com/oscarlab/graphene/pull/347 |
sigaltstack | |||
host signal handling | fp registers to PAL_CONTEXT | https://github.com/oscarlab/graphene/pull/397 | |
PAL/Linux-SGX dedicated stack for host signal | RFC:code needs to be improved | https://github.com/oscarlab/graphene/pull/632 | |
multiple signal(PAL, LibOS) | |||
Pal/Linux-SGX ocall and signal | |||
syscall/instruction emulation | rdtsc | https://github.com/oscarlab/graphene/pull/424 | |
probably more to come | |||
test | regression test for golang | ||
regression test for static binary | |||
misc | vDSO | https://github.com/oscarlab/graphene/pull/318 https://github.com/oscarlab/graphene/pull/319 | |
stack protector | https://github.com/oscarlab/graphene/pull/774 |
There are several challenges with go binary.
golang doesn't use libc. But it has its own runtime library written in go(self hosting). glibc modification doesn't help. golang prefers static link and go runtime is always statically linked. (recent go support dynamic link to use shared library. CGO. However go runtime is always statically linked) So the trick to replace shared library isn't usable. Current graphene uses modified shared glibc to hook system call instruction for function call.
small memory(e.g. 2KB) is assigned to goroutine on start and stack size is increased on demand. sigaltstack is used due to small stack size and for stability. Currently sigaltstack isn't supported. It would be an issue for graphene to directly invoking user signal handler within LibOS. It may cause SEGV due to stack overflow.
trap-and-emulate is slow. optimization for performance is needed to avoid the overhead. One way is to edit loaded text area. Editing text area is tricky and fragile. Also it's hard to debug. There are several possible options. We should support easiest one and make it solid and then move on to further tricks(more complex and more fragile) if necessary. Because we have trap-and-emulate as fallback, the solutions don't have to be perfect. (at the cost of performance.)
There are two major points. How to identify syscall instruction and How to replace syscall instruction with function call. It is observed that functions in golang runtime for system call are leaf function without referencing any symbols. a sort of simple wrapper function. It only swaps registers to adjust ABI difference between function call and Linux system call, issues syscall instruction and checks return value. (Please remember -errno trick.) (Actually many of glibc syscall functions are so. so actually the solution discussed here could be applied to glibc.)
replace leaf function as a whole: The assumption is that static symbol is usable. So all the symbol names of syscall functions(of given specific version of golang). So replacing functions can be prepared as a shared library and jump instruction can be put on the beginning of each symbols of the original go binary to replacing functions when target binary is loaded into memory.
scan instruction to find syscall instruction and replace it somehow: The assumption is static symbol isn't available. This will be very tricky and bunch of heuristics. Please remember that x86-64 instruction has variable length. we have to play with instruction length. Linux paravirt ops uses padding with nop. But golang upstream won't adapt such nop trick to allocate space for text editing.
find syscall by SIGILL on runtime. This requires synchronization to stop all the thread, modify the text area, icache flush and resume threads. This is too complex. So for now this is out of choice.
Now discussion is on-going. Right now host signal handling of Pal/Linux-SGX seems broken. a lot of clean ups are necessary before actual sigaltstack support.
The stack can be very small. So the dedicated stack for signal handling is needed. Pal/Linux uses sigaltstack. Pal/Linux-SGX has to implement something similar itself because sigaltstack isn't usable. PAL ABI related to host signal needs to be clarified.
The question is, do we want to support host job control? to what extent?
Use case.
Feedback:
golang gc runtime requires much memory. SGX2 is desired for good performance.
TBD