Golang-support.md 7.1 KB

Golang support

This page is intended to track efforts for golang support. If you're looking for how to use it, please refer to TBD.

Goal

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.

Summary

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

Challenges with golang binary

There are several challenges with go binary.

no libc and static link

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.

goroutine with small stack size and signal stack

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.

Issues and proposed solutions

syscall to function call of syscalldb

  • trap SIGILL/SIGSYS and emulate: status: working locally. soon to send PR. This is fallback for corner cases.
  • binary patch to replace syscall instruction with function call

binary patch

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.

emulation of signal and sigaltstack

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.

host signal handling and PAL ABI

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.

  • stack: the current stack is used or the dedicated stack is used (sigaltstack). For stability, the dedicated stack is preferable
  • FP registers: The currently only regular register is defined in PAL_CONTEXT. FP registers needs to be included and its format should be defined. We can adapt Linux format. Other platform PAL can emulate it.

host signal handling and host job control

The question is, do we want to support host job control? to what extent?

Use case.

Feedback:

memory size and SGX2

golang gc runtime requires much memory. SGX2 is desired for good performance.

related PR's and issues

TBD