Files
Paweł Marczewski 2cfdd510dc [LibOS] Remove dynamic linking
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>
2021-02-18 02:48:02 +01:00

169 lines
4.1 KiB
C

/* SPDX-License-Identifier: LGPL-3.0-or-later */
/* Copyright (C) 2014 Stony Brook University */
#ifndef _SHIM_UTILS_H_
#define _SHIM_UTILS_H_
#include "api.h"
#include "list.h"
#include "pal.h"
#include "shim_handle.h"
#include "shim_internal.h"
#include "toml.h"
struct shim_handle;
/* quick hash function based on Robert Jenkins' hash algorithm */
static inline uint64_t hash64(uint64_t key) {
key = (~key) + (key << 21);
key = key ^ (key >> 24);
key = (key + (key << 3)) + (key << 8);
key = key ^ (key >> 14);
key = (key + (key << 2)) + (key << 4);
key = key ^ (key >> 28);
key = key + (key << 31);
return key;
}
/* string object */
struct shim_str* get_str_obj(void);
int free_str_obj(struct shim_str* str);
int init_str_mgr(void);
/* qstring object */
#define QSTR_INIT \
{ .len = 0, .oflow = NULL }
static inline const char* qstrgetstr(const struct shim_qstr* qstr) {
return qstr->oflow ? qstr->oflow->str : qstr->name;
}
static inline void qstrfree(struct shim_qstr* qstr) {
if (qstr->oflow) {
free_str_obj(qstr->oflow);
qstr->oflow = NULL;
}
qstr->name[0] = 0;
qstr->len = 0;
}
static inline char* qstrsetstr(struct shim_qstr* qstr, const char* str, size_t size) {
if (!str) {
qstrfree(qstr);
return NULL;
}
if (size >= STR_SIZE)
return NULL;
char* buf = qstr->name;
if (size >= QSTR_SIZE) {
if (!qstr->oflow) {
qstr->oflow = get_str_obj();
if (!qstr->oflow)
return NULL;
}
buf = qstr->oflow->str;
} else {
if (qstr->oflow) {
free_str_obj(qstr->oflow);
qstr->oflow = NULL;
}
}
memcpy(buf, str, size);
buf[size] = 0;
qstr->len = size;
return buf;
}
static inline char* qstrsetstrs(struct shim_qstr* qstr, int nstrs, const char** strs,
size_t* sizes) {
size_t total_size = 0;
for (int i = 0; i < nstrs; i++) {
total_size += sizes[i];
}
if (total_size >= STR_SIZE)
return NULL;
char* buf = qstr->name;
if (total_size >= QSTR_SIZE) {
if (!qstr->oflow) {
// TODO: alloc proper size.
qstr->oflow = get_str_obj();
if (!qstr->oflow)
return NULL;
}
buf = qstr->oflow->str;
}
char* ptr = buf;
qstr->len = 0;
for (int i = 0; i < nstrs; i++) {
int size = sizes[i];
memcpy(ptr, strs[i], size);
ptr[size] = 0;
qstr->len += size;
ptr += size;
}
return buf;
}
static inline int qstrempty(const struct shim_qstr* qstr) {
return qstr->len == 0;
}
static inline void qstrcopy(struct shim_qstr* to, const struct shim_qstr* from) {
qstrsetstr(to, qstrgetstr(from), from->len);
to->hash = from->hash;
}
static inline int qstrcmpstr(const struct shim_qstr* qstr, const char* str, size_t size) {
if (qstr->len != size)
return 1;
return memcmp(qstrgetstr(qstr), str, size);
}
/* heap allocation functions */
int init_slab(void);
void* malloc(size_t size);
void free(void* mem);
void* malloc_copy(const void* mem, size_t size);
/* ELF binary loading */
int check_elf_object(struct shim_handle* file);
int load_elf_object(struct shim_handle* file);
int load_elf_interp(struct shim_handle* exec);
int free_elf_interp(void);
noreturn void execute_elf_object(struct shim_handle* exec, void* argp, elf_auxv_t* auxp);
int remove_loaded_libraries(void);
/* gdb debugging support */
void remove_r_debug(void* addr);
void append_r_debug(const char* uri, void* addr);
void clean_link_map_list(void);
/* create unique files/pipes */
int create_pipe(char* name, char* uri, size_t size, PAL_HANDLE* hdl, struct shim_qstr* qstr,
bool use_vmid_for_name);
/* Asynchronous event support */
int init_async(void);
int64_t install_async_event(PAL_HANDLE object, unsigned long time,
void (*callback)(IDTYPE caller, void* arg), void* arg);
struct shim_thread* terminate_async_helper(void);
extern toml_table_t* g_manifest_root;
#endif /* _SHIM_UTILS_H */