Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

draft PR for gaining insight into what is needed for Go 1.17 calling conventions; DO NOT MERGE #104

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

mewmew
Copy link
Contributor

@mewmew mewmew commented Feb 12, 2022

For context, see the detailed commit messages of:

  • 8cdbd4f: kernel: invoke sseInit and initFakeFS from rt0 to handle function wrappers of Go 1.17
  • ef26ff1: kernel: skip return address of function wrapper in trapret before IRET instruction

NOTE: this is a draft PR to gain intuition into the problem domain and is not intended to be commited into eggos. DO NOT MERGE.

NOTE: commit ef26ff1 is incompatible with Go versions prior to Go 1.17. In particular, it will not work with Go 1.16. A proper solution should handle both!

Updates #100.

…ed> function wrappers of Go 1.17

In Go 1.17, when invoking Go functions from asm, <autogenerated>
function wrappers are generated to handle the conversion from the
old Go ABI (abi0) which is stack based to the new internal
register-based Go ABI (abi1).

The problem is that the <autogenerated> function wrapper assumes
that we are already running in a fully initialized Go environment,
with support for SSE instructions and with a configured %fs segment
register to handle TLS of G.

For context, see the autogenerated function wrapper which is invoked
when calling the Go kernel.preinit function from the asm rt0 function.

	Dump of assembler code for function github.com/icexin/eggos/kernel.preinit<autogenerated>:
		0x00000000002bbe40 <+0>:	sub    $0x18,%rsp
		0x00000000002bbe44 <+4>:	mov    %rbp,0x10(%rsp)
		0x00000000002bbe49 <+9>:	lea    0x10(%rsp),%rbp
		0x00000000002bbe4e <+14>:	mov    0x20(%rsp),%rax
		0x00000000002bbe53 <+19>:	mov    0x28(%rsp),%rbx
	=> 0x00000000002bbe58 <+24>:	xorps  %xmm15,%xmm15
		0x00000000002bbe5c <+28>:	mov    %fs:0xfffffffffffffff8,%r14
		0x00000000002bbe65 <+37>:	call   0x2b6c40 <github.com/icexin/eggos/kernel.preinit>
		0x00000000002bbe6a <+42>:	mov    0x10(%rsp),%rbp
		0x00000000002bbe6f <+47>:	add    $0x18,%rsp
		0x00000000002bbe73 <+51>:	ret

As visible in the disassembly of kernel.preinit<autogenerated>,
the XMM15 register is set to zero using XOR (see offset +24),
which requires SSE instructions to be initialized.

Also, on offset +28, the R14 register is moved into TLS by
using the %fs segment register. R14 store G in Go 1.17.

To handle this case, we need to initialize %fs to a valid memory
location; we use a fake memory location, as no Go routines are
running at this point, and later on %fs will be set when the first
goroutine is started by thread0Init.

Note, this is just a preliminary work to better understand what
we must support to handle Go 1.17. We are most likely _not_ going
to use this code for the final commit to eggos. This is just to
get more intuition into the problem domain.

Updates icexin#100.
…apret before IRET instruction

NOTE: this commit will ONLY work for Go 1.17, it is not backwards
compatible with Go 1.16. We should probably find a way to handle
both (e.g. build tags or a general approach).

To give context, an <autogenerated> function wrapper is generated
in Go 1.17 for kernel.trapret.

	Dump of assembler code for function github.com/icexin/eggos/kernel.trapret<autogenerated>:
	=> 0x00000000002bbf60 <+0>:   call   0x2b9e40 <github.com/icexin/eggos/kernel.trapret>
		0x00000000002bbf65 <+5>:   xorps  %xmm15,%xmm15
		0x00000000002bbf69 <+9>:   mov    %fs:0xfffffffffffffff8,%r14
		0x00000000002bbf72 <+18>:  ret

In this autogenerated function, a call to the real kernel.trapret
is made, which places a return address on the stack. However, the
trapret function will use IRET to return, so to handle this case,
we skip the return address pushed onto the stack by the autogenerated
function by adding 8 (ptr size) to rsp.

We should definitely try to find a better way to handle this situation
as it seems very fragile and may break in the future if Go changes
their autogenerated functions.

So, once more, this is mostly to get intuition into the problem domain,
it is not meant as a solution that should be merged into eggos.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant