                    do (unless (eq arg :void) (princ "0")))
           (princ "w")
           (princ (1- (length signature)))
-          (princ "Co")
+          (princ "C")
           (ffi-write ffi (buffer-string))
-          (setf (gethash signature (ffi-cifs ffi)) (ffi-read ffi))))))
+          (setf (gethash signature (ffi-cifs ffi)) (ffi-pop ffi))))))
 
 (defun ffi-dlopen (ffi name)
   "Fetch a handle (pointer) by library NAME."
   (or (gethash name (ffi-libs ffi))
       (progn
-        (ffi-write ffi (format "w%dM%sOo" (length name) name))
-        (setf (gethash name (ffi-libs ffi)) (ffi-read ffi)))))
+        (ffi-push ffi :pointer name)
+        (ffi-write ffi "O")
+        (setf (gethash name (ffi-libs ffi)) (ffi-pop ffi)))))
 
 (defun ffi-dlsym (ffi library name)
   "Fetch a handle for NAME from LIRBARY in FFI."
   (or (gethash name (ffi-syms ffi))
       (progn
-        (ffi-write ffi (format "p%sw%dM%sSo" (or library 0) (length name) name))
-        (setf (gethash name (ffi-syms ffi)) (ffi-read ffi)))))
+        (ffi-push ffi :pointer (or library 0))
+        (ffi-push ffi :pointer name)
+        (ffi-write ffi "S")
+        (setf (gethash name (ffi-syms ffi)) (ffi-pop ffi)))))
 
 (defun ffi-call (library symbol signature &rest args)
   "Call SYMBOL from LIBRARY with ARGS using SIGNATURE.


(cl-defstruct (ffi (:constructor ffi--create))
  (process nil)
  (log nil)
  (cifs (make-hash-table :test 'equal))
  (libs (make-hash-table :test 'equal))
  (syms (make-hash-table :test 'equal)))

  "Push VALUE onto FFI's stack."
  (cond ((null value) (ffi-write ffi "p0"))
        ((eq type :void) (ffi-write ffi "V"))
        ((stringp value) (ffi-write ffi (format "w%dM%s" (length value) value)))
        ((ffi-write ffi (get type 'ffi-code) (prin1-to-string value) " "))))

(defun ffi-pop (ffi)
  "Return value from the top of FFI's stack."
