[prev in list] [next in list] [prev in thread] [next in thread]
List: sbcl-devel
Subject: [Sbcl-devel] [PATCH 2/4] Prefill the linkage table using references resolved at link time
From: Eric Timmons <etimmons () mit ! edu>
Date: 2020-07-13 20:02:34
Message-ID: 20200713200236.22507-3-etimmons () mit ! edu
[Download RAW message or body]
The second genesis produces a c file that populates lisp_linkage_values with
references to foreign data and functions referenced in cold init. This
autodetection can be augmented by providing --extra-linkage-table-entries to
make-config.sh.
The system linker then resolves those references for us at link time, avoiding
the need to call into dlsym to resolve them ourselves.
os_dlsym_default is then no longer needed.
---
.gitignore | 1 +
make-config.sh | 21 ++-
make-genesis-2.lisp | 5 +-
make-target-1.sh | 5 +-
src/compiler/generic/genesis.lisp | 49 ++++-
src/runtime/GNUmakefile | 7 +-
src/runtime/coreparse.c | 26 +--
src/runtime/os-common.c | 78 ++++----
src/runtime/runtime.h | 2 -
src/runtime/win32-os.c | 296 ------------------------------
10 files changed, 116 insertions(+), 374 deletions(-)
diff --git a/.gitignore b/.gitignore
index 2ea1e4263..848ef25a5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,6 +35,7 @@ src/runtime/target-lispregs.h
src/runtime/target-os.h
src/runtime/ppc-linux-mcontext.h
src/runtime/sparc-funcdef.h
+src/runtime/linkage-table-prefill-info.c
tests/test-status.lisp-expr
tests/test.log
tests/*.so
diff --git a/make-config.sh b/make-config.sh
index 518f33282..9dc4972ce 100755
--- a/make-config.sh
+++ b/make-config.sh
@@ -88,7 +88,10 @@ do
;;
--without)
WITHOUT_FEATURES="$WITHOUT_FEATURES :$optarg"
- ;;
+ ;;
+ --extra-linkage-table-entries=)
+ $optarg_ok && SBCL_EXTRA_LINKAGE_TABLE_ENTRIES=$optarg
+ ;;
--fancy)
WITH_FEATURES="$WITH_FEATURES $FANCY_FEATURES"
# Lower down we add :sb-thread for platforms where it can be built.
@@ -213,6 +216,17 @@ Options:
Transfer the files to/from directory /home/user/sbcl
on host-machine.
+ --extra-linkage-table-entries=<path> Specify extra C symbols to include in
+ the linkage table
+
+ Path to a file specifying symbols that must be included in the
+ SBCL linkage table. Useful for statically linking libraries
+ into the runtime and ensuring the linker does not remove them.
+ The file must contain a single list of two element lists. Each
+ sublist must have a string naming a C symbol as its first
+ element and NIL or T (if the symbol names a variable) as its
+ second element.
+
EOF
exit 1
fi
@@ -254,6 +268,11 @@ find_gnumake
./generate-version.sh
+# Copy the extra linkage entries to output folder for Genesis to find.
+if [ -n "$SBCL_EXTRA_LINKAGE_TABLE_ENTRIES" ] && [ -f \
"$SBCL_EXTRA_LINKAGE_TABLE_ENTRIES" ]; then + cp \
"$SBCL_EXTRA_LINKAGE_TABLE_ENTRIES" output/extra-linkage-table-entries.lisp-expr +fi
+
# Now that we've done our option parsing and found various
# dependencies, write them out to a file to be sourced by other
# scripts.
diff --git a/make-genesis-2.lisp b/make-genesis-2.lisp
index cb17160e1..a4a58e308 100644
--- a/make-genesis-2.lisp
+++ b/make-genesis-2.lisp
@@ -24,7 +24,10 @@
:core-file-name "output/cold-sbcl.core"
;; The map file is not needed by the system, but can be
;; very handy when debugging cold init problems.
- :map-file-name "output/cold-sbcl.map")
+ :map-file-name "output/cold-sbcl.map"
+ :linkage-table-prefill-info-c-name \
"src/runtime/linkage-table-prefill-info.c" + :extra-linkage-table-entries \
(when (probe-file "output/extra-linkage-table-entries.lisp-expr") + \
(read-from-file "output/extra-linkage-table-entries.lisp-expr"))) #+cmu (ext:quit)
#+clisp (ext:quit)
#+abcl (ext:quit)
diff --git a/make-target-1.sh b/make-target-1.sh
index 3d2e0cf41..b7cde9503 100755
--- a/make-target-1.sh
+++ b/make-target-1.sh
@@ -31,8 +31,9 @@ fi
# Build the runtime system and symbol table (.nm) file.
#
-# This C build has to come after the first genesis in order to get
-# the sbcl.h the C build needs.
+# This C build has to come after the first genesis in order to get the
+# sbcl.h the C build needs. This also needs to come after the second
+# genesis to get the symbol prelink table needed by the runtime.
echo //building runtime system and symbol table file
# The clean is needed for Darwin's readonlyspace hack.
diff --git a/src/compiler/generic/genesis.lisp b/src/compiler/generic/genesis.lisp
index bd5c890ec..baf8b0d0f 100644
--- a/src/compiler/generic/genesis.lisp
+++ b/src/compiler/generic/genesis.lisp
@@ -2255,6 +2255,45 @@ (defun foreign-symbols-to-core ()
(cold-cons (cold-intern (first rtn)) (make-fixnum-descriptor (cdr \
rtn)))) '*!initial-assembler-routines*)))
+(defun foreign-symbols-to-c (output-pathname)
+ (with-open-file (output output-pathname
+ :direction :output
+ :if-exists :supersede)
+ (let ((sorted-pairs (sort (%hash-table-alist *cold-foreign-symbol-table*) #'< \
:key #'cdr))) + ;; Needed for uintptr_t. We use the raw uintptr_t as we don't \
want to have + ;; to include any SBCL headers just to get at lispobj.
+ (format output "#include <stdint.h>~%~%")
+
+ ;; Write out the extern definitions. Everything is a void function (even
+ ;; variables) because compilers don't like void variables. Remove
+ ;; lisp_linkage_values as we need to write to it, so we should use the
+ ;; actual type.
+ (format output "extern void ~{~A()~^, ~};~%~%"
+ (remove "lisp_linkage_values"
+ (mapcar (lambda (x)
+ (if (listp (car x))
+ (caar x)
+ (car x)))
+ sorted-pairs)
+ :test #'equal))
+
+ ;; Write out the linkage values. Make this weak on ELF targets so that
+ ;; shrinkwrapping can supersede it.
+ #+elf
+ (format output "uintptr_t __attribute__((weak)) lisp_linkage_values[] = {~%")
+ #-elf
+ (format output "uintptr_t lisp_linkage_values[] = {~%")
+
+ (format output " ~D,~%" (length sorted-pairs))
+ (dolist (pair sorted-pairs)
+ (when (listp (car pair))
+ ;; This is data, put -1 in to indicate that.
+ (format output " (uintptr_t)-1,~%"))
+ (format output " (uintptr_t)&~A,~%" (if (listp (car pair))
+ (caar pair)
+ (car pair))))
+ (format output "};~%"))))
+
;;;; general machinery for cold-loading FASL files
@@ -3589,10 +3628,14 @@ (defun write-initial-core-file (filename verbose)
;;; CORE-FILE-NAME gets a Lisp core.
;;; C-HEADER-DIR-NAME gets the path in which to place generated headers
;;; MAP-FILE-NAME gets the name of the textual 'cold-sbcl.map' file
+;;; LINKAGE-TABLE-PREFILL-INFO-C-NAME gets a .c file used to store the
+;;; data used to link the runtime before entering Lisp.
(defun sb-cold:genesis (&key object-file-names tls-init
defstruct-descriptions
core-file-name c-header-dir-name map-file-name
- symbol-table-file-name (verbose t))
+ symbol-table-file-name (verbose t)
+ linkage-table-prefill-info-c-name
+ extra-linkage-table-entries)
(declare (ignorable symbol-table-file-name))
(when verbose
@@ -3611,6 +3654,8 @@ (defun sb-cold:genesis (&key object-file-names tls-init
;; Prefill some linkage table entries perhaps
(loop for (name datap) in sb-vm::*linkage-space-predefined-entries*
do (linkage-table-note-symbol name datap))
+ (loop for (name datap) in extra-linkage-table-entries
+ do (linkage-table-note-symbol name datap))
#-(or linkage-table crossbuild-test)
(when core-file-name
(if symbol-table-file-name
@@ -3786,6 +3831,8 @@ (defun sb-cold:genesis (&key object-file-names tls-init
(resolve-deferred-known-funs)
(resolve-static-call-fixups)
(foreign-symbols-to-core)
+ (when linkage-table-prefill-info-c-name
+ (foreign-symbols-to-c linkage-table-prefill-info-c-name))
#+(or x86 immobile-space)
(dolist (pair (sort (%hash-table-alist *code-fixup-notes*) #'< :key #'car))
(write-wordindexed (make-random-descriptor (car pair))
diff --git a/src/runtime/GNUmakefile b/src/runtime/GNUmakefile
index d9ad52f82..993566cac 100644
--- a/src/runtime/GNUmakefile
+++ b/src/runtime/GNUmakefile
@@ -73,8 +73,8 @@ endif
COMMON_SRC = alloc.c backtrace.c breakpoint.c coalesce.c coreparse.c \
dynbind.c funcall.c gc-common.c globals.c hopscotch.c \
- interr.c interrupt.c largefile.c main.c \
- monitor.c murmur_hash.c os-common.c parse.c print.c \
+ interr.c interrupt.c largefile.c linkage-table-prefill-info.c \
+ main.c monitor.c murmur_hash.c os-common.c parse.c print.c \
purify.c pthread-futex.c regnames.c runtime.c \
safepoint.c save.c sc-offset.c search.c thread.c time.c \
validate.c var-io.c vars.c wrap.c
@@ -118,6 +118,9 @@ unit-tests: gc-unit-tests.o libsbcl.a
sbcl.o: $(OBJS)
$(LD) $(__LDFLAGS__) -r -o $@ $^
+linkage-table-prefill-info.o: linkage-table-prefill-info.c
+ $(CC) $(CFLAGS) $(CPPFLAGS) -Wno-builtin-declaration-mismatch -c -o $@ $<
+
libsbcl.a: $(OBJS)
rm -f $@ ; ar rcs $@ $^
diff --git a/src/runtime/coreparse.c b/src/runtime/coreparse.c
index 8371ae416..6fd2c0ad7 100644
--- a/src/runtime/coreparse.c
+++ b/src/runtime/coreparse.c
@@ -93,7 +93,7 @@ open_binary(char *filename, int mode)
int lisp_code_in_elf() { return 0; }
#else
extern __attribute__((weak)) lispobj
- lisp_code_start, lisp_jit_code, lisp_code_end, lisp_linkage_values;
+ lisp_code_start, lisp_jit_code, lisp_code_end;
int lisp_code_in_elf() { return &lisp_code_start != 0; }
#endif
@@ -743,30 +743,6 @@ process_directory(int count, struct ndir_entry *entry,
(uword_t)&lisp_code_start, (uword_t)&lisp_code_end,
varyobj_free_pointer);
#endif
- // Prefill the Lisp linkage table so that shrinkwrapped executables which \
link in
- // all their C library dependencies can avoid linking with -ldl.
- // All data references are potentially needed because aliencomp doesn't emit
- // SAP-REF-n in a way that admits elision of the linkage entry. e.g.
- // MOV RAX, [#x20200AA0] ; some_c_symbol
- // MOV RAX, [RAX]
- // might be rendered as
- // MOV RAX, some_c_symbol(%rip)
- // but that's more of a change to the asm instructions than I'm comfortable \
making;
- // whereas "CALL linkage_entry_for_f" -> "CALL f" is quite straightforward.
- // (Rarely would a jmp indirection be used; maybe for newly compiled code?)
- lispobj* ptr = &lisp_linkage_values;
- gc_assert(ptr);
- int entry_index = 0;
- int count;
- extern int lisp_linkage_table_n_prelinked;
- count = lisp_linkage_table_n_prelinked = *ptr++;
- for ( ; count-- ; entry_index++ ) {
- boolean datap = *ptr == (lispobj)-1; // -1 can't be a function address
- if (datap)
- ++ptr;
- arch_write_linkage_table_entry(entry_index, (void*)*ptr++, datap);
- }
-
// unprotect the pages
os_protect((void*)VARYOBJ_SPACE_START, varyobj_space_size, OS_VM_PROT_ALL);
} else
diff --git a/src/runtime/os-common.c b/src/runtime/os-common.c
index 4926e3e2d..10604cf04 100644
--- a/src/runtime/os-common.c
+++ b/src/runtime/os-common.c
@@ -8,7 +8,6 @@
* provided with absolutely no warranty. See the COPYING and CREDITS
* files for more information.
*/
-# define _GNU_SOURCE /* needed for RTLD_DEFAULT from dlfcn.h */
#include <stdio.h>
#include <errno.h>
#include <string.h>
@@ -28,9 +27,6 @@
#include "arch.h"
#include "interr.h"
#include "immobile-space.h"
-#if defined(LISP_FEATURE_OS_PROVIDES_DLOPEN) && !defined(LISP_FEATURE_WIN32)
-# include <dlfcn.h>
-#endif
/*
* historically, this used sysconf to select the runtime page size
@@ -147,59 +143,53 @@ os_sem_destroy(os_sem_t *sem)
*
* Before any code in lisp image can be called, we have to resolve all
* references to runtime foreign symbols that used to be static, adding linkage
- * table entry for each element of REQUIRED_FOREIGN_SYMBOLS.
+ * table entry for each element of lisp_linkage_values.
*/
-#if defined(LISP_FEATURE_LINKAGE_TABLE) && !defined(LISP_FEATURE_WIN32)
-void *
-os_dlsym_default(char *name)
-{
- void *frob = dlsym(RTLD_DEFAULT, name);
- return frob;
-}
+int lisp_linkage_table_n_prelinked;
+
+#if defined(LISP_FEATURE_ELF)
+// Weak only works on ELF targets and we'd like this to be weak on those
+// targets for shrinkwrapping.
+extern __attribute__((weak)) lispobj lisp_linkage_values;
+#else
+extern lispobj lisp_linkage_values;
#endif
-int lisp_linkage_table_n_prelinked;
void os_link_runtime()
{
- // There is a potentially better technique we could use which would simplify
- // this function, rendering REQUIRED_FOREIGN_SYMBOLS unnecessary, namely:
- // all we need are two prefilled entries: one for dlsym() itself, and one
- // for the allocation region overflow handler ("alloc" or "alloc_tramp").
- // Lisp can fill in the linkage table as the very first action on startup.
+
+ // There is a potentially better technique we could use which would
+ // simplify this function on platforms with dlopen/dlsym, namely: all we
+ // need are two prefilled entries: one for dlsym() itself, and one for the
+ // allocation region overflow handler ("alloc" or "alloc_tramp"). Lisp can
+ // fill in the linkage table as the very first action on startup.
#ifdef LISP_FEATURE_LINKAGE_TABLE
int entry_index = 0;
- lispobj symbol_name;
- char *namechars;
- boolean datap;
- void* result;
- int j;
-
- if (lisp_linkage_table_n_prelinked)
- return; // Linkage was already performed by coreparse
-
- struct vector* symbols = VECTOR(SymbolValue(REQUIRED_FOREIGN_SYMBOLS,0));
- lisp_linkage_table_n_prelinked = fixnum_value(symbols->length);
- for (j = 0 ; j < lisp_linkage_table_n_prelinked ; ++j)
- {
- lispobj item = symbols->data[j];
- datap = listp(item);
- symbol_name = datap ? CONS(item)->car : item;
- namechars = (void*)(intptr_t)(VECTOR(symbol_name)->data);
- result = os_dlsym_default(namechars);
+ // Prefill the Lisp linkage table using references stored in
+ // lisp_linkage_values. This array has an interesting format. The first
+ // entry is interpreted as how many references to symbols are found in the
+ // array. Each subsequent entry is either a reference or -1 (an invalid
+ // funciton pointer). A -1 indicates that the following reference is a
+ // reference to data instead of a function.
+ lispobj *ptr = &lisp_linkage_values;
+
+ if (&lisp_linkage_values) {
+ int count;
+ count = lisp_linkage_table_n_prelinked = *ptr++;
+ for ( ; count-- ; entry_index++ ) {
if (entry_index == 0) {
#ifdef LISP_FEATURE_WIN32
- os_validate_recommit(LINKAGE_TABLE_SPACE_START, os_vm_page_size);
+ os_validate_recommit(LINKAGE_TABLE_SPACE_START, os_vm_page_size);
#endif
}
- if (result) {
- arch_write_linkage_table_entry(entry_index, result, datap);
- } else { // startup might or might not work. ymmv
- fprintf(stderr, "Missing required foreign symbol '%s'\n", namechars);
- }
-
- ++entry_index;
+ boolean datap = *ptr == (lispobj)-1; // -1 can't be a function address
+ if (datap)
+ ++ptr;
+ arch_write_linkage_table_entry(entry_index, (void*)*ptr++, datap);
+ }
+ return;
}
#endif /* LISP_FEATURE_LINKAGE_TABLE */
}
diff --git a/src/runtime/runtime.h b/src/runtime/runtime.h
index c24dd1697..4f865cfd2 100644
--- a/src/runtime/runtime.h
+++ b/src/runtime/runtime.h
@@ -497,8 +497,6 @@ extern char *copied_string (char *string);
# define GENCGC_IS_PRECISE 0
#endif
-void *os_dlsym_default(char *name);
-
struct lisp_startup_options {
boolean noinform;
};
diff --git a/src/runtime/win32-os.c b/src/runtime/win32-os.c
index 964386baa..ba27724d3 100644
--- a/src/runtime/win32-os.c
+++ b/src/runtime/win32-os.c
@@ -309,302 +309,6 @@ void unmap_gc_page()
#endif
-#if defined(LISP_FEATURE_LINKAGE_TABLE)
-/* This feature has already saved me more development time than it
- * took to implement. In its current state, ``dynamic RT<->core
- * linking'' is a protocol of initialization of C runtime and Lisp
- * core, populating SBCL linkage table with entries for runtime
- * "foreign" symbols that were referenced in cross-compiled code.
- *
- * How it works: a sketch
- *
- * Last Genesis (resulting in cold-sbcl.core) binds foreign fixups in
- * x-compiled lisp-objs to sequential addresses from the beginning of
- * linkage-table space; that's how it ``resolves'' foreign references.
- * Obviously, this process doesn't require pre-built runtime presence.
- *
- * When the runtime loads the core (cold-sbcl.core initially,
- * sbcl.core later), runtime should do its part of the protocol by (1)
- * traversing a list of ``runtime symbols'' prepared by Genesis and
- * dumped as a static symbol value, (2) resolving each name from this
- * list to an address (stubbing unresolved ones with
- * undefined_alien_address or undefined_alien_function), (3) adding an
- * entry for each symbol somewhere near the beginning of linkage table
- * space (location is provided by the core).
- *
- * The implementation of the part described in the last paragraph
- * follows. C side is currently more ``hackish'' and less clear than
- * the Lisp code; OTOH, related Lisp changes are scattered, and some
- * of them play part in complex interrelations -- beautiful but taking
- * much time to understand --- but my subset of PE-i386 parser below
- * is in one place (here) and doesn't have _any_ non-trivial coupling
- * with the rest of the Runtime.
- *
- * What do we gain with this feature, after all?
- *
- * One things that I have to do rather frequently: recompile and
- * replace runtime without rebuilding the core. Doubtlessly, slam.sh
- * was a great time-saver here, but relinking ``cold'' core and bake a
- * ``warm'' one takes, as it seems, more than 10x times of bare
- * SBCL.EXE build time -- even if everything is recompiled, which is
- * now unnecessary. Today, if I have a new idea for the runtime,
- * getting from C-x C-s M-x ``compile'' to fully loaded SBCL
- * installation takes 5-15 seconds.
- *
- * Another thing (that I'm not currently using, but obviously
- * possible) is delivering software patches to remote system on
- * customer site. As you are doing minor additions or corrections in
- * Lisp code, it doesn't take much effort to prepare a tiny ``FASL
- * bundle'' that rolls up your patch, redumps and -- presto -- 100MiB
- * program is fixed by sending and loading a 50KiB thingie.
- *
- * However, until LISP_FEATURE_LINKAGE_TABLE, if your bug were fixed
- * by modifying two lines of _C_ sources, a customer described above
- * had to be ready to receive and reinstall a new 100MiB
- * executable. With the aid of code below, deploying such a fix
- * requires only sending ~300KiB (when stripped) of SBCL.EXE.
- *
- * But there is more to it: as the common linkage-table is used for
- * DLLs and core, its entries may be overridden almost without a look
- * into SBCL internals. Therefore, ``patching'' C runtime _without_
- * restarting target systems is also possible in many situations
- * (it's not as trivial as loading FASLs into a running daemon, but
- * easy enough to be a viable alternative if any downtime is highly
- * undesirable).
- *
- * During my (rather limited) commercial Lisp development experience
- * I've already been through a couple of situations where such
- * ``deployment'' issues were important; from my _total_ programming
- * experience I know -- _sometimes_ they are a two orders of magnitude
- * more important than those I observed.
- *
- * The possibility of entire runtime ``hot-swapping'' in running
- * process is not purely theoretical, as it could seem. There are 2-3
- * problems whose solution is not obvious (call stack patching, for
- * instance), but it's literally _nothing_ if compared with
- * e.g. LISP_FEATURE_SB_AUTO_FPU_SWITCH. By the way, one of the
- * problems with ``hot-swapping'', that could become a major one in
- * many other environments, is nonexistent in SBCL: we already have a
- * ``global quiesce point'' that is generally required for this kind
- * of worldwide revolution -- around collect_garbage.
- *
- * What's almost unnoticeable from the C side (where you are now, dear
- * reader): using the same style for all linking is beautiful. I tried
- * to leave old-style linking code in place for the sake of
- * _non-linkage-table_ platforms (they probably don't have -ldl or its
- * equivalent, like LL/GPA, at all) -- but i did it usually by moving
- * the entire `old style' code under #-linkage-table and
- * refactoring the `new style' branch, instead of cutting the tail
- * piecemeal and increasing #+-ifdeffery amount & the world enthropy.
- *
- * If we look at the majority of the ``new style'' code units, it's a
- * common thing to observe how #+-ifdeffery _vanishes_ instead of
- * multiplying: #-sb-xc, #+sb-xc-host and #-sb-xc-host end up
- * needing the same code. Runtime checks of static v. dynamic symbol
- * disappear even faster. STDCALL mangling and leading underscores go
- * out of scope (and GCed, hopefully) instead of surfacing here and
- * there as a ``special case for core static symbols''. What I like
- * the most about CL development in general is a frequency of solving
- * problems and fixing bugs by simplifying code and dropping special
- * cases.
- *
- * Last important thing about the following code: besides resolving
- * symbols provided by the core itself, it detects runtime's own
- * build-time prerequisite DLLs. Any symbol that is unresolved against
- * the core is looked up in those DLLs (normally kernel32, msvcrt,
- * ws2_32... I could forget something). This action (1) resembles
- * implementation of foreign symbol lookup in SBCL itself, (2)
- * emulates shared library d.l. facilities of OSes that use flat
- * dynamic symbol namespace (or default to it). Anyone concerned with
- * portability problems of this PE-i386 stuff below will be glad to
- * hear that it could be ported to most modern Unices _by deletion_:
- * raw dlsym() with null handle usually does the same thing that i'm
- * trying to squeeze out of MS Windows by the brute force.
- *
- * My reason for _desiring_ flat symbol namespace, populated from
- * link-time dependencies, is avoiding any kind of ``requested-by-Lisp
- * symbol lists to be linked statically'', providing core v. runtime
- * independence in both directions. Minimizing future maintenance
- * effort is very important; I had gone for it consistently, starting
- * by turning "CloseHandle@4" into a simple "CloseHandle", continuing
- * by adding intermediate Genesis resulting in autogenerated symbol
- * list (farewell, void scratch(); good riddance), going to take
- * another great step for core/runtime independence... and _without_
- * flat namespace emulation, the ghosts and spirits exiled at the
- * first steps would come and take revenge: well, here are the symbols
- * that are really in msvcrt.dll.. hmm, let's link statically against
- * them, so the entry is pulled from the import library.. and those
- * entry has mangled names that we have to map.. ENOUGH, I though
- * here: fed up with stuff like that.
- *
- * Now here we are, without import libraries, without mangled symbols,
- * and without nm-generated symbol tables. Every symbol exported by
- * the runtime is added to SBCL.EXE export directory; every symbol
- * requested by the core is looked up by GetProcAddress for SBCL.EXE,
- * falling back to GetProcAddress for MSVCRT.dll, etc etc.. All ties
- * between SBCL's foreign symbols with object file symbol tables,
- * import libraries and other pre-linking symbol-resolving entities
- * _having no representation in SBCL.EXE_ were teared.
- *
- * This simplistic approach proved to work well; there is only one
- * problem introduced by it, and rather minor: in real MSVCRT.dll,
- * what's used to be available as open() is now called _open();
- * similar thing happened to many other `lowio' functions, though not
- * every one, so it's not a kind of name mangling but rather someone's
- * evil creative mind in action.
- *
- * When we look up any of those poor `uglified' functions in CRT
- * reference on MSDN, we can see a notice resembling this one:
- *
- * `unixishname()' is obsolete and provided for backward
- * compatibility; new standard-compliant function, `_unixishname()',
- * should be used instead. Sentences of that kind were there for
- * several years, probably even for a decade or more (a propos,
- * MSVCRT.dll, as the name to link against, predates year 2000, so
- * it's actually possible). Reasoning behing it (what MS people had in
- * mind) always seemed strange to me: if everyone uses open() and that
- * `everyone' is important to you, why rename the function? If no one
- * uses open(), why provide or retain _open() at all? <kidding>After
- * all, names like _open() are entirely non-informative and just plain
- * ugly; compare that with CreateFileW() or InitCommonControlsEx(),
- * the real examples of beauty and clarity.</kidding>
- *
- * Anyway, if the /standard/ name on Windows is _open() (I start to
- * recall, vaguely, that it's because of _underscore names being
- * `reserved to system' and all other ones `available for user', per
- * ANSI/ISO C89) -- well, if the /standard/ name is _open, SBCL should
- * use it when it uses MSVCRT and not some ``backward-compatible''
- * stuff. Deciding this way, I added a hack to SBCL's syscall macros,
- * so "[_]open" as a syscall name is interpreted as a request to link
- * agains "_open" on win32 and "open" on every other system.
- *
- * Of course, this name-parsing trick lacks conceptual clarity; we're
- * going to get rid of it eventually. */
-
-u32 os_get_build_time_shared_libraries(u32 excl_maximum,
- void* opt_root,
- void** opt_store_handles,
- const char *opt_store_names[])
-{
- void* base = opt_root ? opt_root : (void*)runtime_module_handle;
- /* base defaults to 0x400000 with GCC/mingw32. If you dereference
- * that location, you'll see 'MZ' bytes */
- void* base_magic_location =
- base + ((IMAGE_DOS_HEADER*)base)->e_lfanew;
-
- /* dos header provided the offset from `base' to
- * IMAGE_FILE_HEADER where PE-i386 really starts */
-
- void* check_duplicates[excl_maximum];
-
- if ((*(u32*)base_magic_location)!=0x4550) {
- /* We don't need this DLL thingie _that_ much. If the world
- * has changed to a degree where PE magic isn't found, let's
- * silently return `no libraries detected'. */
- return 0;
- } else {
- /* We traverse PE-i386 structures of SBCL.EXE in memory (not
- * in the file). File and memory layout _surely_ differ in
- * some places and _may_ differ in some other places, but
- * fortunately, those places are irrelevant to the task at
- * hand. */
-
- IMAGE_FILE_HEADER* image_file_header = (base_magic_location + 4);
- IMAGE_OPTIONAL_HEADER* image_optional_header =
- (void*)(image_file_header + 1);
- IMAGE_DATA_DIRECTORY* image_import_direntry =
- &image_optional_header->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
- IMAGE_IMPORT_DESCRIPTOR* image_import_descriptor =
- base + image_import_direntry->VirtualAddress;
- u32 nlibrary, j;
-
- for (nlibrary=0u; nlibrary < excl_maximum
- && image_import_descriptor->FirstThunk;
- ++image_import_descriptor)
- {
- HMODULE hmodule;
- odxprint(runtime_link, "Now should know DLL: %s",
- (char*)(base + image_import_descriptor->Name));
- /* Code using image thunk data to get its handle was here, with a
- * number of platform-specific tricks (like using VirtualQuery for
- * old OSes lacking GetModuleHandleEx).
- *
- * It's now replaced with requesting handle by name, which is
- * theoretically unreliable (with SxS, multiple modules with same
- * name are quite possible), but good enough to find the
- * link-time dependencies of our executable or DLL. */
-
- hmodule = (HMODULE)
- GetModuleHandle(base + image_import_descriptor->Name);
-
- if (hmodule)
- {
- /* We may encouncer some module more than once while
- traversing import descriptors (it's usually a
- result of non-trivial linking process, like doing
- ld -r on some groups of files before linking
- everything together.
-
- Anyway: using a module handle more than once will
- do no harm, but it slows down the startup (even
- now, our startup time is not a pleasant topic to
- discuss when it comes to :linkage-table; there is
- an obvious direction to go for speed, though --
- instead of resolving symbols one-by-one, locate PE
- export directories -- they are sorted by symbol
- name -- and merge them, at one pass, with sorted
- list of required symbols (the best time to sort the
- latter list is during Genesis -- that's why I don't
- proceed with memory copying, qsort() and merge
- right here)). */
-
- for (j=0; j<nlibrary; ++j)
- {
- if(check_duplicates[j] == hmodule)
- break;
- }
- if (j<nlibrary) continue; /* duplicate => skip it in
- * outer loop */
-
- check_duplicates[nlibrary] = hmodule;
- if (opt_store_handles) {
- opt_store_handles[nlibrary] = hmodule;
- }
- if (opt_store_names) {
- opt_store_names[nlibrary] = (const char *)
- (base + image_import_descriptor->Name);
- }
- odxprint(runtime_link, "DLL detection: %u, base %p: %s",
- nlibrary, hmodule,
- (char*)(base + image_import_descriptor->Name));
- ++ nlibrary;
- }
- }
- return nlibrary;
- }
-}
-
-static u32 buildTimeImageCount = 0;
-static void* buildTimeImages[16];
-
-/* Resolve symbols against the executable and its build-time dependencies */
-void* os_dlsym_default(char* name)
-{
- unsigned int i;
- void* result = 0;
- if (buildTimeImageCount == 0) {
- buildTimeImageCount =
- 1 + os_get_build_time_shared_libraries(15u,
- NULL, 1+(void**)buildTimeImages, NULL);
- }
- for (i = 0; i<buildTimeImageCount && (!result); ++i) {
- result = GetProcAddress(buildTimeImages[i], name);
- }
- return result;
-}
-
-#endif /* LINKAGE_TABLE */
-
#if defined(LISP_FEATURE_SB_THREAD)
/* We want to get a slot in TIB that (1) is available at constant
offset, (2) is our private property, so libraries wouldn't legally
--
2.27.0
_______________________________________________
Sbcl-devel mailing list
Sbcl-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/sbcl-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic