Closed
Conversation
The dynlib pragma hard-coded a library path and resolved it via dlopen() at
runtime, preventing static linking and forcing a specific load-time path.
Using bare {.importc.} lets consumers choose: link liblibchat dynamically
at link time (--passL:-llibchat) or link it statically into their binary.
Nim's code generator transforms function signatures involving large structs
in two ways that conflict with the standard C ABI:
- Return values of large structs (> register size): Nim emits a void
function with an explicit out-pointer appended as the *last* argument.
The standard x86-64 SysV ABI passes the hidden return pointer in RDI
(before the real arguments); ARM64 aapcs64 uses X8. Calling Rust
directly from Nim therefore puts the pointer in the wrong register /
stack slot on both architectures, causing crashes.
- Large struct parameters (> ~24 bytes): Nim passes a pointer rather
than copying bytes on the stack / into registers as the C ABI expects.
This commit introduces a thin C shim (nim_shims.c) that acts as a
translation layer:
- Each nim_* wrapper is declared with a Nim-compatible signature, so
Nim calls it correctly by its own rules.
- Inside the wrapper the C compiler calls the real Rust-exported
function using the standard C ABI, inserting the correct hidden-
pointer placement and stack-copy behaviour for the current platform.
As a result:
- The Rust API stays standard C ABI (return T by value; destroy takes
*mut T, which is pointer-sized and matches Nim's large-param transform).
- Other language bindings (C, Swift, Go, …) call Rust directly without
any shim — the standard ABI is preserved for them.
- The fix is correct on both x86-64 and ARM64 without any
architecture-specific code in Nim or Rust.
Changes:
- nim-bindings/src/nim_shims.c: C bridge with nim_* wrappers for all
create/handle/installation_name and destroy functions
- nim-bindings/src/bindings.nim: {.compile: "nim_shims.c"}, proc
signatures use natural return-by-value form, importc names point to
the nim_* shims
- nim-bindings/src/libchat.nim: call sites use natural let binding form;
destroy calls pass addr res (ptr T)
- conversations/src/api.rs: destroy functions take *mut T so Nim's
large-param-to-pointer transform is satisfied without a stack copy
2c84caf to
8d172f0
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Test pingpong against main, as #64 points to different branch.