Re: Calling Lisp from C (SBCL as a shared object) on Windows

Stas Boukarev <[email protected]> Thu, 27 Mar 2025 21:36:47 +0300
Newsgroups gmane.lisp.steel-bank.general
Message-ID <CAF63=12ExFc0u1MhjrvFO0XK9QVhwAHEOMsPYvhZAK0vvh=iMQ@mail.gmail.com>
Or rather try this

On Thu, Mar 27, 2025 at 9:15 PM Stas Boukarev <[email protected]> wrote:
>
> Try this
>
> On Thu, Mar 27, 2025 at 6:07 PM Stas Boukarev <[email protected]> wrote:
> >
> > os_dlsym_default is probably to blame.
> >
> > On Thu, Mar 27, 2025 at 4:14 PM Uģis Lācis <[email protected]> wrote:
> > >
> > > Dear SBCL community,
> > >
> > >
> > >
> > > I am trying to use SBCL to define a LISP function I should be able to call from C. My working platform is Windows 11. I have gone through the information I could find on the topic, but can not make a basic example work. I have found discussions around this topic (with similar error traces as I am getting), but without a solution that would work for me. So what I am trying to do now:
> > >
> > >
> > >
> > > I have found an example (Re: [Sbcl-help] Calling Lisp from C (SBCL as a shared object) | Steel Bank Common Lisp) that should be working for exporting a callable LISP function.
> > > I have saved the LISP code as-is in a “test1.lsp” file.
> > > To check that I can produce a valid core, I do:
> > >
> > > sbcl.exe --script "test1.lsp" --noinform
> > > sbcl.exe --core libsum.core
> > >
> > >
> > >
> > > After these steps I get the error, which is attached at the end of this message (I have also seen it in the thread I referenced above). I have tried these steps both in pre-built Windows installation downloaded from SBCL home page (SBCL 2.5.1) and also in compiled version from the git source (SBCL 2.5.2.155-1d476f1e0). I get the same output if I load the core as written above or via linking to compiled libsbcl.so shared library.
> > >
> > >
> > >
> > > Has anyone gotten this functionality to work on Windows? Any suggestions about how to get this working would be highly appreciated.
> > >
> > >
> > >
> > > Best wishes,
> > > Ugis
> > >
> > >
> > >
> > > -------------------------------------
> > >
> > > ------------------------ ERROR
> > > -------------------------------------
> > > Unhandled SB-KERNEL::UNDEFINED-ALIEN-VARIABLE-ERROR in thread #<SB-THREAD:THREAD tid=47068 "main thread" RUNNING
> > >
> > >                                                                  {1100BA8003}>:
> > >
> > >   Attempt to access an undefined alien variable.
> > >
> > >
> > >
> > > Backtrace for: #<SB-THREAD:THREAD tid=47068 "main thread" RUNNING {1100BA8003}>
> > >
> > > 0: (SB-DEBUG::DEBUGGER-DISABLED-HOOK #<SB-KERNEL::UNDEFINED-ALIEN-VARIABLE-ERROR {1100B9E613}> #<unused argument> :QUIT T)
> > >
> > > 1: (SB-DEBUG::RUN-HOOK *INVOKE-DEBUGGER-HOOK* #<SB-KERNEL::UNDEFINED-ALIEN-VARIABLE-ERROR {1100B9E613}>)
> > >
> > > 2: (INVOKE-DEBUGGER #<SB-KERNEL::UNDEFINED-ALIEN-VARIABLE-ERROR {1100B9E613}>)
> > >
> > > 3: (ERROR SB-KERNEL::UNDEFINED-ALIEN-VARIABLE-ERROR)
> > >
> > > 4: (SB-KERNEL::UNDEFINED-ALIEN-VARIABLE-ERROR)
> > >
> > > 5: ("foreign function: #x140046D35")
> > >
> > > 6: ("foreign function: #x140046E00")
> > >
> > > 7: ((SETF SB-SYS:SAP-REF-SAP) :INVALID-VALUE-FOR-UNESCAPED-REGISTER-STORAGE :INVALID-VALUE-FOR-UNESCAPED-REGISTER-STORAGE :INVALID-VALUE-FOR-UNESCAPED-REGISTER-STORAGE)
> > >
> > > 8: (SB-EVAL::EVAL-PROGN ((SETF (SB-SYS:SAP-REF-SAP SB-ALIEN::SAP (/ SB-ALIEN::OFFSET SB-VM:N-BYTE-BITS)) SB-ALIEN::VALUE) (SB-ALIEN-INTERNALS:NATURALIZE SB-ALIEN::VALUE (QUOTE #<ALIEN-TYPE (* T)>))) #<SB-EVAL::ENV {1100B9E1F3}>)
> > >
> > > 9: ((SETF SB-ALIEN-INTERNALS:%ALIEN-VALUE) #<SB-ALIEN-INTERNALS:ALIEN-VALUE :SAP #X20010CC0 :TYPE (* T)> #.(SB-SYS:INT-SAP #X001D0000) 0 #<ALIEN-TYPE (* T)>)
> > >
> > > 10: (SB-IMPL::%START-LISP)
> > >
> > > 11: ("foreign function: #x140046D35")
> > >
> > > 12: ("foreign function: #x14000A160")
> > >
> > > _______________________________________________
> > > Sbcl-help mailing list
> > > [email protected]
> > > https://lists.sourceforge.net/lists/listinfo/sbcl-help

_______________________________________________
Sbcl-help mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/sbcl-help
dlsym.diff (application/octet-stream, 3 KB)
diff --git a/src/code/win32-foreign-load.lisp b/src/code/win32-foreign-load.lisp
index 08332cfa6..bf5af8d23 100644
--- a/src/code/win32-foreign-load.lisp
+++ b/src/code/win32-foreign-load.lisp
@@ -23,6 +23,9 @@
   (handle hinstance)
   (symbol c-string))
 
+(define-alien-routine os-dlsym-default sb-win32:int-ptr
+  (symbol c-string))
+
 (define-alien-routine ("SetStdHandle" set-std-handle)
    void
  (id int)
@@ -76,25 +79,7 @@
     (setf (shared-object-handle obj) nil)))
 
 (defun find-dynamic-foreign-symbol-address (symbol)
-  ;; On real ELF & dlsym platforms the EXTERN-ALIEN-NAME is a no-op,
-  ;; but on platforms where dlsym is simulated we use the mangled name.
-  ;; Win32 is a special case. It needs EXTERN-ALIEN-NAME to mangle the
-  ;; name for static linkage, but also needs unmangled symbols for
-  ;; GetProcAddress(). So we coerce to base-string instead.
-  ;; Oh, and we assume that all runtime symbols are static-linked.
-  ;; No *runtime-dlhandle* for us.
-  ;; Also, GetProcAddress doesn't call SetLastError(0) on success,
-  ;; and GetLastError() doesn't either. For now, we assume that
-  ;; GetProcAddress() won't return NULL on success.
-  (let* ((extern (coerce symbol 'base-string))
-         (result nil))
-    (dolist (handle
-              (cons *runtime-dlhandle*
-                    (mapcar #'shared-object-handle *shared-objects*)))
-      (when handle
-        (setf result (sap-int (getprocaddress handle extern)))
-        (when (not (zerop result))
-          (return result))))))
+  (os-dlsym-default (coerce symbol 'base-string)))
 
 (defun runtime-exported-symbols ()
   ;; TODO: reimplement for x86-64. Not so hard.
diff --git a/src/runtime/win32-os.c b/src/runtime/win32-os.c
index d63214bbe..1e1e863dd 100644
--- a/src/runtime/win32-os.c
+++ b/src/runtime/win32-os.c
@@ -422,19 +422,28 @@ uint32_t os_get_build_time_shared_libraries(uint32_t excl_maximum,
 static uint32_t buildTimeImageCount = 0;
 static void* buildTimeImages[16];
 
+BOOL K32EnumProcessModules(HANDLE  hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded);
+
 /* Resolve symbols against the executable and its build-time dependencies */
 void* os_dlsym_default(char* name)
 {
     unsigned int i;
     void* result = 0;
-    buildTimeImages[0] = (void*)runtime_module_handle;
-    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);
+
+    if ((result = GetProcAddress(GetModuleHandle(NULL), name)))
+        return result;
+
+    HANDLE process = GetCurrentProcess();
+    HMODULE modules[1024];
+    DWORD needed;
+    
+    if (K32EnumProcessModules(process, modules, sizeof(modules), &needed))
+    {
+        for ( i = 0; i < (needed / sizeof(HMODULE)); i++ )
+        {
+            if ((result = GetProcAddress(modules[i], name)))
+                return result;
+        }
     }
     return result;
 }