tallegro-internals.txt - clic - Clic is an command line interactive client for … | |
git clone git://bitreich.org/clic/ git://hg6vgqziawt5s4dj.onion/clic/ | |
Log | |
Files | |
Refs | |
Tags | |
LICENSE | |
--- | |
tallegro-internals.txt (5245B) | |
--- | |
1 July 2005 | |
2 These details were kindly provided by Duane Rettig of Franz. | |
3 | |
4 Regarding the following snippet of the macro expansion of | |
5 FF:DEF-FOREIGN-CALL: | |
6 | |
7 (SYSTEM::FF-FUNCALL | |
8 (LOAD-TIME-VALUE (EXCL::DETERMINE-FOREIGN-ADDRESS | |
9 '("foo" :LANGUAGE :C) 2 NIL)) | |
10 '(:INT (INTEGER * *)) ARG1 | |
11 '(:DOUBLE (DOUBLE-FLOAT * *)) ARG2 | |
12 '(:INT (INTEGER * *))) | |
13 | |
14 " | |
15 ... in Allegro CL, if you define a foreign call FOO with C entry point | |
16 "foo" and with :call-direct t in the arguments, and if other things are | |
17 satisfied, then if a lisp function BAR is compiled which has a call to | |
18 FOO, that call will not go through ff-funcall (and thus a large amount | |
19 of argument manipulation and processing) but will instead set up its | |
20 arguments directly on the stack, and will then perform the "call" more | |
21 or less directly, through the "entry vec" (a small structure which | |
22 keeps track of a foreign entry's address and status)." | |
23 | |
24 This is the code that generates what the compiler expects to see: | |
25 | |
26 (setq call-direct-form | |
27 (if* call-direct | |
28 then `(setf (get ',lispname 'sys::direct-ff-call) | |
29 (list ',external-name | |
30 ,callback | |
31 ,convention | |
32 ',returning | |
33 ',arg-types | |
34 ,arg-checking | |
35 ,entry-vec-flags)) | |
36 else `(remprop ',lispname 'sys::direct-ff-call))) | |
37 | |
38 Thus generating something like: | |
39 | |
40 (EVAL-WHEN (COMPILE LOAD EVAL) | |
41 (SETF (GET 'FOO 'SYSTEM::DIRECT-FF-CALL) | |
42 (LIST '("foo" :LANGUAGE :C) T :C | |
43 '(:INT (INTEGER * *)) | |
44 '((:INT (INTEGER * *)) | |
45 (:FLOAT (SINGLE-FLOAT * *))) | |
46 T | |
47 2 ; this magic value is explained later | |
48 ))) | |
49 | |
50 " | |
51 (defun determine-foreign-address (name &optional (flags 0) method-index) | |
52 ;; return an entry-vec struct suitable for the foreign-call of name. | |
53 ;; | |
54 ;; name is either a string, which is taken without conversion, or | |
55 ;; a list consisting of a string to convert or a conversion function | |
56 ;; call. | |
57 ;; flags is an integer representing the flags to place into the entry-… | |
58 ;; method-index, if non-nil, is a word-index into a vtbl (virtual tabl… | |
59 ;; If method-index is true, then the name must be a string uniquely | |
60 ;; represented by the index and by the flags field. | |
61 | |
62 Note that not all architectures implement the :method-index argument | |
63 to def-foreign-call, but your interface likely won't support it | |
64 anyway, so just leave it nil. As for the flags, they are constants | |
65 stored into the entry-vec returned by d-f-a and are given here: | |
66 | |
67 (defconstant ep-flag-call-semidirect 1) ; Real address stored in alt-add… | |
68 (defconstant ep-flag-never-release 2) ; Never release the heap | |
69 (defconstant ep-flag-always-release 4) ; Always release the heap | |
70 (defconstant ep-flag-release-when-ok 8) ; Release the heap unless withou… | |
71 | |
72 (defconstant ep-flag-tramp-calls #x70) ; Make calls through special tram… | |
73 (defconstant ep-flag-tramp-shift 4) | |
74 | |
75 (defconstant ep-flag-variable-address #x100) ; Entry-point contains addr… | |
76 (defconstant ep-flag-strings-convert #x200) ; Convert strings au… | |
77 | |
78 (defconstant ep-flag-get-errno #x1000) ;; [rfe5060]: Get errno valu… | |
79 (defconstant ep-flag-get-last-error #x2000) ;; [rfe5060]: call GetLastEr… | |
80 ;; Leave #x4000 and #x8000 open for expansion | |
81 | |
82 Mostly, you'll give the value 2 (never release the heap), but if you | |
83 give 4 or 8, then d-f-a will automatically set the 1 bit as well, | |
84 which takes the call through a heap-release/reacquire process. | |
85 | |
86 Some docs for entry-vec are: | |
87 | |
88 ;; -- entry vec -- | |
89 ;; An entry-vec is an entry-point descriptor, usually a pointer into | |
90 ;; a shared-library. It is represented as a 5-element struct of type | |
91 ;; foreign-vector. The reason for this represntation is | |
92 ;; that it allows the entry point to be stored in a table, called | |
93 ;; the .saved-entry-points. table, and to be used by a foreign | |
94 ;; function. When the location of the foreign function to which the ent… | |
95 ;; point refers changes, it is simply a matter of changing the value in … | |
96 ;; point vector and the foreign call code sees it immediately. There is | |
97 ;; even an address that can be put in the entry point vector that denotes | |
98 ;; a missing foreign function, thus lookup can happen dynamically. | |
99 | |
100 (defstruct (entry-vec | |
101 (:type (vector excl::foreign (*))) | |
102 (:constructor make-entry-vec-boa ())) | |
103 name ; entry point name | |
104 (address 0) ; jump address for foreign code | |
105 (handle 0) ; shared-lib handle | |
106 (flags 0) ; ep-* flags | |
107 (alt-address 0) ; sometimes holds the real func addr | |
108 ) | |
109 | |
110 [...] | |
111 " | |
112 | |
113 Regarding the arguments to SYSTEM::FF-FUNCALL: | |
114 '(:int (integer * *)) argN | |
115 | |
116 "The type-spec is as it is given in the def-foreign-call | |
117 syntax, with a C type optionally followed by a lisp type, | |
118 followed optionally by a user-conversion function name[...]" | |
119 | |
120 | |
121 Getting the alignment: | |
122 | |
123 CL-USER(2): (ff:get-foreign-type :int) | |
124 #S(FOREIGN-FUNCTIONS::IFOREIGN-TYPE | |
125 :ATTRIBUTES NIL | |
126 :SFTYPE | |
127 #S(FOREIGN-FUNCTIONS::SIZED-FTYPE-PRIM | |
128 :KIND :INT | |
129 :WIDTH 4 | |
130 :OFFSET 0 | |
131 :ALIGN 4) | |
132 ...) |