summaryrefslogtreecommitdiff
path: root/rts/linker
diff options
context:
space:
mode:
authorBen Gamari <ben@smart-cactus.org>2020-11-21 11:17:27 -0500
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-11-30 19:48:53 -0500
commit6ac3db5fefbac6bea6c8fd0ac64daf036d9a8e60 (patch)
tree4e7b1a67545901ffa4d61b4594d5e6d65c9edbba /rts/linker
parent490aa14dbc98e4713f913c4417d454e53b8b278a (diff)
downloadhaskell-6ac3db5fefbac6bea6c8fd0ac64daf036d9a8e60.tar.gz
rts/linker: Move shared library loading logic into Elf.c
Diffstat (limited to 'rts/linker')
-rw-r--r--rts/linker/Elf.c142
-rw-r--r--rts/linker/Elf.h2
-rw-r--r--rts/linker/PEi386Types.h4
3 files changed, 144 insertions, 4 deletions
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
index 8a8480018c..bcf7556bc1 100644
--- a/rts/linker/Elf.c
+++ b/rts/linker/Elf.c
@@ -15,15 +15,20 @@
#include "RtsUtils.h"
#include "RtsSymbolInfo.h"
+#include "CheckUnload.h"
+#include "LinkerInternals.h"
#include "linker/Elf.h"
#include "linker/CacheFlush.h"
#include "linker/M32Alloc.h"
#include "linker/SymbolExtras.h"
+#include "ForeignExports.h"
+#include "Profiling.h"
#include "sm/OSMem.h"
#include "GetEnv.h"
#include "linker/util.h"
#include "linker/elf_util.h"
+#include <link.h>
#include <stdlib.h>
#include <string.h>
#if defined(HAVE_SYS_STAT_H)
@@ -1970,6 +1975,143 @@ int ocRunInit_ELF( ObjectCode *oc )
}
/*
+ * Shared object loading
+ */
+
+static int loadNativeObjCb_(struct dl_phdr_info *info,
+ size_t _size GNUC3_ATTRIBUTE(__unused__), void *data) {
+ ObjectCode* nc = (ObjectCode*) data;
+
+ // This logic mimicks _dl_addr_inside_object from glibc
+ // For reference:
+ // int
+ // internal_function
+ // _dl_addr_inside_object (struct link_map *l, const ElfW(Addr) addr)
+ // {
+ // int n = l->l_phnum;
+ // const ElfW(Addr) reladdr = addr - l->l_addr;
+ //
+ // while (--n >= 0)
+ // if (l->l_phdr[n].p_type == PT_LOAD
+ // && reladdr - l->l_phdr[n].p_vaddr >= 0
+ // && reladdr - l->l_phdr[n].p_vaddr < l->l_phdr[n].p_memsz)
+ // return 1;
+ // return 0;
+ // }
+
+ if ((void*) info->dlpi_addr == nc->l_addr) {
+ int n = info->dlpi_phnum;
+ while (--n >= 0) {
+ if (info->dlpi_phdr[n].p_type == PT_LOAD) {
+ NativeCodeRange* ncr =
+ stgMallocBytes(sizeof(NativeCodeRange), "loadNativeObjCb_");
+ ncr->start = (void*) ((char*) nc->l_addr + info->dlpi_phdr[n].p_vaddr);
+ ncr->end = (void*) ((char*) ncr->start + info->dlpi_phdr[n].p_memsz);
+
+ ncr->next = nc->nc_ranges;
+ nc->nc_ranges = ncr;
+ }
+ }
+ }
+ return 0;
+}
+
+static void copyErrmsg(char** errmsg_dest, char* errmsg) {
+ if (errmsg == NULL) errmsg = "loadNativeObj_ELF: unknown error";
+ *errmsg_dest = stgMallocBytes(strlen(errmsg)+1, "loadNativeObj_ELF");
+ strcpy(*errmsg_dest, errmsg);
+}
+
+// need dl_mutex
+void freeNativeCode_ELF (ObjectCode *nc) {
+ dlclose(nc->dlopen_handle);
+
+ NativeCodeRange *ncr = nc->nc_ranges;
+ while (ncr) {
+ NativeCodeRange* last_ncr = ncr;
+ ncr = ncr->next;
+ stgFree(last_ncr);
+ }
+}
+
+void * loadNativeObj_ELF (pathchar *path, char **errmsg)
+{
+ ObjectCode* nc;
+ void *hdl, *retval;
+
+ IF_DEBUG(linker, debugBelch("loadNativeObj_ELF %" PATH_FMT "\n", path));
+
+ retval = NULL;
+ ACQUIRE_LOCK(&dl_mutex);
+
+ /* Loading the same object multiple times will lead to chaos
+ * as we will have two ObjectCodes but one underlying dlopen
+ * handle. Fail if this happens.
+ */
+ if (getObjectLoadStatus_(path) != OBJECT_NOT_LOADED) {
+ copyErrmsg(errmsg, "loadNativeObj_ELF: Already loaded");
+ goto dlopen_fail;
+ }
+
+ nc = mkOc(DYNAMIC_OBJECT, path, NULL, 0, true, NULL, 0);
+
+ foreignExportsLoadingObject(nc);
+ hdl = dlopen(path, RTLD_NOW|RTLD_LOCAL);
+ foreignExportsFinishedLoadingObject();
+ if (hdl == NULL) {
+ /* dlopen failed; save the message in errmsg */
+ copyErrmsg(errmsg, dlerror());
+ goto dlopen_fail;
+ }
+
+ struct link_map *map;
+ if (dlinfo(hdl, RTLD_DI_LINKMAP, &map) == -1) {
+ /* dlinfo failed; save the message in errmsg */
+ copyErrmsg(errmsg, dlerror());
+ goto dlinfo_fail;
+ }
+
+ nc->l_addr = (void*) map->l_addr;
+ nc->dlopen_handle = hdl;
+ hdl = NULL; // pass handle ownership to nc
+
+ dl_iterate_phdr(loadNativeObjCb_, nc);
+ if (!nc->nc_ranges) {
+ copyErrmsg(errmsg, "dl_iterate_phdr failed to find obj");
+ goto dl_iterate_phdr_fail;
+ }
+
+ insertOCSectionIndices(nc);
+
+ nc->next_loaded_object = loaded_objects;
+ loaded_objects = nc;
+
+ retval = nc->dlopen_handle;
+
+#if defined(PROFILING)
+ // collect any new cost centres that were defined in the loaded object.
+ refreshProfilingCCSs();
+#endif
+
+ goto success;
+
+dl_iterate_phdr_fail:
+ // already have dl_mutex
+ freeNativeCode_ELF(nc);
+dlinfo_fail:
+ if (hdl) dlclose(hdl);
+dlopen_fail:
+success:
+
+ RELEASE_LOCK(&dl_mutex);
+
+ IF_DEBUG(linker, debugBelch("loadNativeObj_ELF result=%p\n", retval));
+
+ return retval;
+}
+
+
+/*
* PowerPC & X86_64 ELF specifics
*/
diff --git a/rts/linker/Elf.h b/rts/linker/Elf.h
index 30c993b98c..a16255abba 100644
--- a/rts/linker/Elf.h
+++ b/rts/linker/Elf.h
@@ -14,5 +14,7 @@ int ocGetNames_ELF ( ObjectCode* oc );
int ocResolve_ELF ( ObjectCode* oc );
int ocRunInit_ELF ( ObjectCode* oc );
int ocAllocateExtras_ELF ( ObjectCode *oc );
+void freeNativeCode_ELF ( ObjectCode *nc );
+void *loadNativeObj_ELF ( pathchar *path, char **errmsg );
#include "EndPrivate.h"
diff --git a/rts/linker/PEi386Types.h b/rts/linker/PEi386Types.h
index 67ea34345f..ec53ec800b 100644
--- a/rts/linker/PEi386Types.h
+++ b/rts/linker/PEi386Types.h
@@ -7,10 +7,6 @@
#include <stdint.h>
#include <stdio.h>
-/* Some forward declares. */
-struct Section;
-
-
struct SectionFormatInfo {
char* name;
size_t alignment;