After this change, LibOS will no longer perform dynamic linking.
The ELF loading code executes load commands and passes control to
interpreter (ld.so), which handles necessary relocations and
loading additional libraries. In this way, the code resembles what
Linux kernel does when executing a new program.
Before, dynamic linking was necessary for making LibOS entry point
(syscalldb function) available for applications. However, that meant
duplicating the work already done by ld.so, and introduced a lot of
unnecessary complexity. After changing LibOS entry API to use the
GS register, it's possible to omit dynamic linking entirely.
The main function (__load_elf_object()) still needs cleanup and
possibly rewriting from scratch. However, this change prepares
ground for that rewrite.
Summary of changes:
- Remove dynamic relocation step (DO_DYNAMIC_RELOCATE()).
- Don't call __load_elf_object() again for ELFs reported
via register_library(). We only need to notify GDB about these.
- Remove fields related to dynamic linking from link_map (dynamic
section address, hashes, etc.), and setup for these fields.
- need_interp(): To check if we need an interpreter, check only if
the binary requests one (PT_INTERP), instead of traversing the
dynamic section (before, we ignored dynamic dependencies on LibOS
itself, but now there shouldn't be any).
- RELOCATE(): always adjust addresses, instead of checking if
they're already inside the mapped range. I think the previous
behaviour was a workaround to make repeated relocations work.
- Get rid of load modes that are no longer used (OBJECT_REMAP,
OBJECT_USER).
- Remove the workaround for repeated relocation in glibc patches
(R_X86_64_NONE).
Signed-off-by: Paweł Marczewski <pawel@invisiblethingslab.com>
Instead of depending on dynamic linking for LibOS entry point
(syscalldb), we pass a pointer in the shim_tcb structure, so that
the patched code can enter syscall using 'jmp *%gs:<offset>'.
The same applies to the vDSO syscall code that previously needed
an up-to-date pointer to syscalldb function. Now, there is no
need to adjust the values inside the vDSO page.
In addition, this change removes the other two instances where we
import a symbol directly from LibOS: register_library (can be also
done through GS register) and glibc_version (not important because
we build Graphene and glibc together).
This simplifies things because the dynamic linking necessary to
make the syscalldb function available had to be performed by LibOS
itself (in many cases, effectively doing a second pass of dynamic
linking after ld.so). After this change, there will be no need for
LibOS to perform dynamic linking, and the ELF loading code can be
simplified.
Signed-off-by: Paweł Marczewski <pawel@invisiblethingslab.com>
Change log (most important only):
- unify CPU context structures - now we have only one version -
`PAL_CONTEXT` - which is shared between LibOS and PALs and it should
depend only on the host architecture (not OS),
- syscalls emulation changed:
- dedicated LibOS stack is now used for syscalls emulation,
- removed one indirection level in syscalls table - now it stores
`shim_do_*` functions directly,
- signal handling - completely rewritten:
- all signal queues use proper locking schemes now,
- signals are handled *only* when returning to the user app from LibOS
or PAL,
- nested signals are now possible,
- the app is allowed to jump out of signal handler with the same
sematics as on normal Linux,
- signal altstack is now fully supported,
- syscall restarting is now supported,
- doing a backtrace from the signal handler works properly,
- disallow injecting host-level signals, with one exception, see
`sys.enable_sigterm_injection` manifest option for more details.
This commit additionally replaces all `while (true) {}` inf loops with
`die_or_inf_loop` which either crashes the process or loops infinitely
and is not an undefined behavior like the original one (C disallows inf
loops without side effects).
Previously, LibOS (shim) layer of Graphene didn't support XSAVE area.
The XSAVE area stores FP, XMM, YMM, ZMM, etc. registers and control
states and is handled via FXSAVE/XSAVE and FXRSTOR/XRSTOR x86-64
instructions. This commit is the first step towards adding full-
fledged XSAVE support to LibOS. It adds XSAVE related structs and
functions to LibOS code, and propagates XSAVE regs/states from
parent to child on thread creation via clone() (though not really
correctly). New test `fp_multithread` is added to LibOS regression.
Future commits will add correct XSAVE handling on syscall transitions
and arriving signals.
I don't know any reason why would stating the file name we're in be
helpful for anything. Moreover, this information was incorrect in a few
cases (copy-paste bugs, probably).
Additionally, a few minor type/formatting fixes included.
When compiling against v5.8 (or later) kernel headers, we encounter
compilation errors such as:
In file included from /usr/include/asm/unistd.h:13,
from shim_parser.c:11:
shim_parser.c:408:10: error: array index in initializer exceeds array bounds
[__NR_io_uring_setup] = {.slow = 0, .parser = {NULL}},
The remedy is to extend `syscall_parser_table` by modyfing the
definition of LIBOS_SYSCALL_BOUND so the offending system calls fit in
the table.
While at it, also fix the actual values for syscall numbers in
"shim_syscalls.h" (the numbers are not sequential, there is an
intentional gap between the numers).
Previously Graphene delivered each signal to all threads instead of
one. This was additionally abused to quit the application. Now each
signal is delivered to only one arbitrary thread. This commit
additionally cleans the signal and exiting code.
Use the ucontext from PAL instead. LibOS now has access to the inline
functions for copying PAL_CONTEXT to ucontext and vice versa and we use
them where possible.
We need to introduce a ucontext.h for Skeleton. It does need ucontext
to be defined for being able to compile shim_signal.c. The easiest way
to achieve this is to rely on Linux's ucontext.h.
SGX can reuse Linux's ucontext.h and sigcontext.h.
Implement shim_regs_to_ucontext to copy shim_regs to ucontext.
Leave a FIXME in the inline function pointing out missing registers
in shim_regs and the order of the registers in shim_regs.