Line | Count | Source |
1 | | /* ----------------------------------------------------------------------- |
2 | | tramp.c - Copyright (c) 2020 Madhavan T. Venkataraman |
3 | | Copyright (c) 2022 Anthony Green |
4 | | |
5 | | API and support functions for managing statically defined closure |
6 | | trampolines. |
7 | | |
8 | | Permission is hereby granted, free of charge, to any person obtaining |
9 | | a copy of this software and associated documentation files (the |
10 | | ``Software''), to deal in the Software without restriction, including |
11 | | without limitation the rights to use, copy, modify, merge, publish, |
12 | | distribute, sublicense, and/or sell copies of the Software, and to |
13 | | permit persons to whom the Software is furnished to do so, subject to |
14 | | the following conditions: |
15 | | |
16 | | The above copyright notice and this permission notice shall be included |
17 | | in all copies or substantial portions of the Software. |
18 | | |
19 | | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
20 | | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
21 | | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
22 | | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
23 | | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
24 | | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
25 | | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
26 | | DEALINGS IN THE SOFTWARE. |
27 | | ----------------------------------------------------------------------- */ |
28 | | |
29 | | #include <fficonfig.h> |
30 | | |
31 | | #ifdef FFI_EXEC_STATIC_TRAMP |
32 | | |
33 | | /* -------------------------- Headers and Definitions ---------------------*/ |
34 | | /* |
35 | | * Add support for other OSes later. For now, it is just Linux and Cygwin. |
36 | | */ |
37 | | |
38 | | #if defined (__linux__) || defined (__CYGWIN__) |
39 | | #ifdef __linux__ |
40 | | #define _GNU_SOURCE 1 |
41 | | #endif |
42 | | |
43 | | #include <ffi.h> |
44 | | #include <ffi_common.h> |
45 | | |
46 | | #include <stdio.h> |
47 | | #include <unistd.h> |
48 | | #include <stdlib.h> |
49 | | #include <stdint.h> |
50 | | #include <fcntl.h> |
51 | | #include <pthread.h> |
52 | | #include <sys/mman.h> |
53 | | #include <tramp.h> |
54 | | #ifdef __linux__ |
55 | | #include <linux/limits.h> |
56 | | #include <linux/types.h> |
57 | | #endif |
58 | | #ifdef __CYGWIN__ |
59 | | #include <limits.h> |
60 | | #endif |
61 | | #endif |
62 | | |
63 | | /* |
64 | | * Each architecture defines static code for a trampoline code table. The |
65 | | * trampoline code table is mapped into the address space of a process. |
66 | | * |
67 | | * The following architecture specific function returns: |
68 | | * |
69 | | * - the address of the trampoline code table in the text segment |
70 | | * - the size of each trampoline in the trampoline code table |
71 | | * - the size of the mapping for the whole trampoline code table |
72 | | */ |
73 | | void __attribute__((weak)) *ffi_tramp_arch (size_t *tramp_size, |
74 | | size_t *map_size); |
75 | | |
76 | | /* ------------------------- Trampoline Data Structures --------------------*/ |
77 | | |
78 | | struct tramp; |
79 | | |
80 | | /* |
81 | | * Trampoline table. Manages one trampoline code table and one trampoline |
82 | | * parameter table. |
83 | | * |
84 | | * prev, next Links in the global trampoline table list. |
85 | | * code_table Trampoline code table mapping. |
86 | | * parm_table Trampoline parameter table mapping. |
87 | | * array Array of trampolines malloced. |
88 | | * free List of free trampolines. |
89 | | * nfree Number of free trampolines. |
90 | | */ |
91 | | struct tramp_table |
92 | | { |
93 | | struct tramp_table *prev; |
94 | | struct tramp_table *next; |
95 | | void *code_table; |
96 | | void *parm_table; |
97 | | struct tramp *array; |
98 | | struct tramp *free; |
99 | | int nfree; |
100 | | }; |
101 | | |
102 | | /* |
103 | | * Parameters for each trampoline. |
104 | | * |
105 | | * data |
106 | | * Data for the target code that the trampoline jumps to. |
107 | | * target |
108 | | * Target code that the trampoline jumps to. |
109 | | */ |
110 | | struct tramp_parm |
111 | | { |
112 | | void *data; |
113 | | void *target; |
114 | | }; |
115 | | |
116 | | /* |
117 | | * Trampoline structure for each trampoline. |
118 | | * |
119 | | * prev, next Links in the trampoline free list of a trampoline table. |
120 | | * table Trampoline table to which this trampoline belongs. |
121 | | * code Address of this trampoline in the code table mapping. |
122 | | * parm Address of this trampoline's parameters in the parameter |
123 | | * table mapping. |
124 | | */ |
125 | | struct tramp |
126 | | { |
127 | | struct tramp *prev; |
128 | | struct tramp *next; |
129 | | struct tramp_table *table; |
130 | | void *code; |
131 | | struct tramp_parm *parm; |
132 | | }; |
133 | | |
134 | | enum tramp_globals_status { |
135 | | TRAMP_GLOBALS_UNINITIALIZED = 0, |
136 | | TRAMP_GLOBALS_PASSED, |
137 | | TRAMP_GLOBALS_FAILED, |
138 | | }; |
139 | | |
140 | | /* |
141 | | * Trampoline globals. |
142 | | * |
143 | | * fd |
144 | | * File descriptor of binary file that contains the trampoline code table. |
145 | | * offset |
146 | | * Offset of the trampoline code table in that file. |
147 | | * text |
148 | | * Address of the trampoline code table in the text segment. |
149 | | * map_size |
150 | | * Size of the trampoline code table mapping. |
151 | | * size |
152 | | * Size of one trampoline in the trampoline code table. |
153 | | * ntramp |
154 | | * Total number of trampolines in the trampoline code table. |
155 | | * free_tables |
156 | | * List of trampoline tables that contain free trampolines. |
157 | | * nfree_tables |
158 | | * Number of trampoline tables that contain free trampolines. |
159 | | * status |
160 | | * Initialization status. |
161 | | */ |
162 | | struct tramp_globals |
163 | | { |
164 | | int fd; |
165 | | off_t offset; |
166 | | void *text; |
167 | | size_t map_size; |
168 | | size_t size; |
169 | | int ntramp; |
170 | | struct tramp_table *free_tables; |
171 | | int nfree_tables; |
172 | | enum tramp_globals_status status; |
173 | | }; |
174 | | |
175 | | static struct tramp_globals tramp_globals; |
176 | | |
177 | | /* --------------------- Trampoline File Initialization --------------------*/ |
178 | | |
179 | | /* |
180 | | * The trampoline file is the file used to map the trampoline code table into |
181 | | * the address space of a process. There are two ways to get this file: |
182 | | * |
183 | | * - From the OS. E.g., on Linux, /proc/<pid>/maps lists all the memory |
184 | | * mappings for <pid>. For file-backed mappings, maps supplies the file name |
185 | | * and the file offset. Using this, we can locate the mapping that maps |
186 | | * libffi and get the path to the libffi binary. And, we can compute the |
187 | | * offset of the trampoline code table within that binary. |
188 | | * |
189 | | * - Else, if we can create a temporary file, we can write the trampoline code |
190 | | * table from the text segment into the temporary file. |
191 | | * |
192 | | * The first method is the preferred one. If the OS security subsystem |
193 | | * disallows mapping unsigned files with PROT_EXEC, then the second method |
194 | | * will fail. |
195 | | * |
196 | | * If an OS allows the trampoline code table in the text segment to be |
197 | | * directly remapped (e.g., MACH vm_remap ()), then we don't need the |
198 | | * trampoline file. |
199 | | */ |
200 | | static int tramp_table_alloc (void); |
201 | | |
202 | | #if defined (__linux__) || defined (__CYGWIN__) |
203 | | |
204 | | static int |
205 | | ffi_tramp_get_libffi (void) |
206 | 0 | { |
207 | 0 | FILE *fp; |
208 | 0 | char file[PATH_MAX], line[PATH_MAX+100], perm[10], dev[10]; |
209 | 0 | unsigned long start, end, offset, inode; |
210 | 0 | uintptr_t addr = (uintptr_t) tramp_globals.text; |
211 | 0 | int nfields, found; |
212 | 0 | int open_flags = O_RDONLY; |
213 | |
|
214 | 0 | #ifdef O_CLOEXEC |
215 | 0 | open_flags |= O_CLOEXEC; |
216 | 0 | #endif |
217 | |
|
218 | 0 | snprintf (file, PATH_MAX, "/proc/%d/maps", getpid()); |
219 | 0 | fp = fopen (file, "r"); |
220 | 0 | if (fp == NULL) |
221 | 0 | return 0; |
222 | | |
223 | 0 | found = 0; |
224 | 0 | while (feof (fp) == 0) { |
225 | 0 | if (fgets (line, sizeof (line), fp) == 0) |
226 | 0 | break; |
227 | | |
228 | 0 | nfields = sscanf (line, "%lx-%lx %9s %lx %9s %ld %s", |
229 | 0 | &start, &end, perm, &offset, dev, &inode, file); |
230 | 0 | if (nfields != 7) |
231 | 0 | continue; |
232 | | |
233 | 0 | if (addr >= start && addr < end) { |
234 | 0 | tramp_globals.offset = offset + (addr - start); |
235 | 0 | found = 1; |
236 | 0 | break; |
237 | 0 | } |
238 | 0 | } |
239 | 0 | fclose (fp); |
240 | |
|
241 | 0 | if (!found) |
242 | 0 | return 0; |
243 | | |
244 | 0 | tramp_globals.fd = open (file, open_flags); |
245 | 0 | if (tramp_globals.fd == -1) |
246 | 0 | return 0; |
247 | | |
248 | | /* |
249 | | * Allocate a trampoline table just to make sure that the trampoline code |
250 | | * table can be mapped. |
251 | | */ |
252 | 0 | if (!tramp_table_alloc ()) |
253 | 0 | { |
254 | 0 | close (tramp_globals.fd); |
255 | 0 | tramp_globals.fd = -1; |
256 | 0 | return 0; |
257 | 0 | } |
258 | 0 | return 1; |
259 | 0 | } |
260 | | |
261 | | #endif /* defined (__linux__) || defined (__CYGWIN__) */ |
262 | | |
263 | | #if defined (__linux__) || defined (__CYGWIN__) |
264 | | |
265 | | static int |
266 | | ffi_tramp_get_temp_file (void) |
267 | 0 | { |
268 | 0 | ssize_t count; |
269 | |
|
270 | 0 | tramp_globals.offset = 0; |
271 | 0 | tramp_globals.fd = open_temp_exec_file (); |
272 | | |
273 | | /* |
274 | | * Write the trampoline code table into the temporary file and allocate a |
275 | | * trampoline table to make sure that the temporary file can be mapped. |
276 | | */ |
277 | 0 | count = write(tramp_globals.fd, tramp_globals.text, tramp_globals.map_size); |
278 | 0 | if (count >=0 && (size_t)count == tramp_globals.map_size && tramp_table_alloc ()) |
279 | 0 | return 1; |
280 | | |
281 | 0 | close (tramp_globals.fd); |
282 | 0 | tramp_globals.fd = -1; |
283 | 0 | return 0; |
284 | 0 | } |
285 | | |
286 | | #endif /* defined (__linux__) || defined (__CYGWIN__) */ |
287 | | |
288 | | /* ------------------------ OS-specific Initialization ----------------------*/ |
289 | | |
290 | | #if defined (__linux__) || defined (__CYGWIN__) |
291 | | |
292 | | static int |
293 | | ffi_tramp_init_os (void) |
294 | 0 | { |
295 | 0 | if (ffi_tramp_get_libffi ()) |
296 | 0 | return 1; |
297 | 0 | return ffi_tramp_get_temp_file (); |
298 | 0 | } |
299 | | |
300 | | #endif /* defined (__linux__) || defined (__CYGWIN__) */ |
301 | | |
302 | | /* --------------------------- OS-specific Locking -------------------------*/ |
303 | | |
304 | | #if defined (__linux__) || defined (__CYGWIN__) |
305 | | |
306 | | static pthread_mutex_t tramp_globals_mutex = PTHREAD_MUTEX_INITIALIZER; |
307 | | |
308 | | static void |
309 | | ffi_tramp_lock(void) |
310 | 0 | { |
311 | 0 | pthread_mutex_lock (&tramp_globals_mutex); |
312 | 0 | } |
313 | | |
314 | | static void |
315 | | ffi_tramp_unlock(void) |
316 | 0 | { |
317 | 0 | pthread_mutex_unlock (&tramp_globals_mutex); |
318 | 0 | } |
319 | | |
320 | | #endif /* defined (__linux__) || defined (__CYGWIN__) */ |
321 | | |
322 | | /* ------------------------ OS-specific Memory Mapping ----------------------*/ |
323 | | |
324 | | /* |
325 | | * Create a trampoline code table mapping and a trampoline parameter table |
326 | | * mapping. The two mappings must be adjacent to each other for PC-relative |
327 | | * access. |
328 | | * |
329 | | * For each trampoline in the code table, there is a corresponding parameter |
330 | | * block in the parameter table. The size of the parameter block is the same |
331 | | * as the size of the trampoline. This means that the parameter block is at |
332 | | * a fixed offset from its trampoline making it easy for a trampoline to find |
333 | | * its parameters using PC-relative access. |
334 | | * |
335 | | * The parameter block will contain a struct tramp_parm. This means that |
336 | | * sizeof (struct tramp_parm) cannot exceed the size of a parameter block. |
337 | | */ |
338 | | |
339 | | #if defined (__linux__) || defined (__CYGWIN__) |
340 | | |
341 | | static int |
342 | | tramp_table_map (struct tramp_table *table) |
343 | 0 | { |
344 | 0 | char *addr; |
345 | | |
346 | | /* |
347 | | * Create an anonymous mapping twice the map size. The top half will be used |
348 | | * for the code table. The bottom half will be used for the parameter table. |
349 | | */ |
350 | 0 | addr = mmap (NULL, tramp_globals.map_size * 2, PROT_READ | PROT_WRITE, |
351 | 0 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
352 | 0 | if (addr == MAP_FAILED) |
353 | 0 | return 0; |
354 | | |
355 | | /* |
356 | | * Replace the top half of the anonymous mapping with the code table mapping. |
357 | | */ |
358 | 0 | table->code_table = mmap (addr, tramp_globals.map_size, PROT_READ | PROT_EXEC, |
359 | 0 | MAP_PRIVATE | MAP_FIXED, tramp_globals.fd, tramp_globals.offset); |
360 | 0 | if (table->code_table == MAP_FAILED) |
361 | 0 | { |
362 | 0 | (void) munmap (addr, tramp_globals.map_size * 2); |
363 | 0 | return 0; |
364 | 0 | } |
365 | 0 | table->parm_table = table->code_table + tramp_globals.map_size; |
366 | 0 | return 1; |
367 | 0 | } |
368 | | |
369 | | static void |
370 | | tramp_table_unmap (struct tramp_table *table) |
371 | 0 | { |
372 | 0 | (void) munmap (table->code_table, tramp_globals.map_size); |
373 | 0 | (void) munmap (table->parm_table, tramp_globals.map_size); |
374 | 0 | } |
375 | | |
376 | | #endif /* defined (__linux__) || defined (__CYGWIN__) */ |
377 | | |
378 | | /* ------------------------ Trampoline Initialization ----------------------*/ |
379 | | |
380 | | /* |
381 | | * Initialize the static trampoline feature. |
382 | | */ |
383 | | static int |
384 | | ffi_tramp_init (void) |
385 | 0 | { |
386 | 0 | long page_size; |
387 | |
|
388 | 0 | if (tramp_globals.status == TRAMP_GLOBALS_PASSED) |
389 | 0 | return 1; |
390 | | |
391 | 0 | if (tramp_globals.status == TRAMP_GLOBALS_FAILED) |
392 | 0 | return 0; |
393 | | |
394 | 0 | if (ffi_tramp_arch == NULL) |
395 | 0 | { |
396 | 0 | tramp_globals.status = TRAMP_GLOBALS_FAILED; |
397 | 0 | return 0; |
398 | 0 | } |
399 | | |
400 | 0 | tramp_globals.free_tables = NULL; |
401 | 0 | tramp_globals.nfree_tables = 0; |
402 | | |
403 | | /* |
404 | | * Get trampoline code table information from the architecture. |
405 | | */ |
406 | 0 | tramp_globals.text = ffi_tramp_arch (&tramp_globals.size, |
407 | 0 | &tramp_globals.map_size); |
408 | 0 | tramp_globals.ntramp = tramp_globals.map_size / tramp_globals.size; |
409 | |
|
410 | 0 | page_size = sysconf (_SC_PAGESIZE); |
411 | 0 | if (page_size >= 0 && (size_t)page_size > tramp_globals.map_size) |
412 | 0 | return 0; |
413 | | |
414 | 0 | if (ffi_tramp_init_os ()) |
415 | 0 | { |
416 | 0 | tramp_globals.status = TRAMP_GLOBALS_PASSED; |
417 | 0 | return 1; |
418 | 0 | } |
419 | | |
420 | 0 | tramp_globals.status = TRAMP_GLOBALS_FAILED; |
421 | 0 | return 0; |
422 | 0 | } |
423 | | |
424 | | /* ---------------------- Trampoline Table functions ---------------------- */ |
425 | | |
426 | | /* This code assumes that malloc () is available on all OSes. */ |
427 | | |
428 | | static void tramp_add (struct tramp *tramp); |
429 | | |
430 | | /* |
431 | | * Allocate and initialize a trampoline table. |
432 | | */ |
433 | | static int |
434 | | tramp_table_alloc (void) |
435 | 0 | { |
436 | 0 | struct tramp_table *table; |
437 | 0 | struct tramp *tramp_array, *tramp; |
438 | 0 | size_t size; |
439 | 0 | char *code, *parm; |
440 | 0 | int i; |
441 | | |
442 | | /* |
443 | | * If we already have tables with free trampolines, there is no need to |
444 | | * allocate a new table. |
445 | | */ |
446 | 0 | if (tramp_globals.nfree_tables > 0) |
447 | 0 | return 1; |
448 | | |
449 | | /* |
450 | | * Allocate a new trampoline table structure. |
451 | | */ |
452 | 0 | table = malloc (sizeof (*table)); |
453 | 0 | if (table == NULL) |
454 | 0 | return 0; |
455 | | |
456 | | /* |
457 | | * Allocate new trampoline structures. |
458 | | */ |
459 | 0 | tramp_array = malloc (sizeof (*tramp) * tramp_globals.ntramp); |
460 | 0 | if (tramp_array == NULL) |
461 | 0 | goto free_table; |
462 | | |
463 | | /* |
464 | | * Map a code table and a parameter table into the caller's address space. |
465 | | */ |
466 | 0 | if (!tramp_table_map (table)) |
467 | 0 | { |
468 | | /* |
469 | | * Failed to map the code and parameter tables. |
470 | | */ |
471 | 0 | goto free_tramp_array; |
472 | 0 | } |
473 | | |
474 | | /* |
475 | | * Initialize the trampoline table. |
476 | | */ |
477 | 0 | table->array = tramp_array; |
478 | 0 | table->free = NULL; |
479 | 0 | table->nfree = 0; |
480 | | |
481 | | /* |
482 | | * Populate the trampoline table free list. This will also add the trampoline |
483 | | * table to the global list of trampoline tables. |
484 | | */ |
485 | 0 | size = tramp_globals.size; |
486 | 0 | code = table->code_table; |
487 | 0 | parm = table->parm_table; |
488 | 0 | for (i = 0; i < tramp_globals.ntramp; i++) |
489 | 0 | { |
490 | 0 | tramp = &tramp_array[i]; |
491 | 0 | tramp->table = table; |
492 | 0 | tramp->code = code; |
493 | 0 | tramp->parm = (struct tramp_parm *) parm; |
494 | 0 | tramp_add (tramp); |
495 | |
|
496 | 0 | code += size; |
497 | 0 | parm += size; |
498 | 0 | } |
499 | | /* Success */ |
500 | 0 | return 1; |
501 | | |
502 | | /* Failure */ |
503 | 0 | free_tramp_array: |
504 | 0 | free (tramp_array); |
505 | 0 | free_table: |
506 | 0 | free (table); |
507 | 0 | return 0; |
508 | 0 | } |
509 | | |
510 | | /* |
511 | | * Free a trampoline table. |
512 | | */ |
513 | | static void |
514 | | tramp_table_free (struct tramp_table *table) |
515 | 0 | { |
516 | 0 | tramp_table_unmap (table); |
517 | 0 | free (table->array); |
518 | 0 | free (table); |
519 | 0 | } |
520 | | |
521 | | /* |
522 | | * Add a new trampoline table to the global table list. |
523 | | */ |
524 | | static void |
525 | | tramp_table_add (struct tramp_table *table) |
526 | 0 | { |
527 | 0 | table->next = tramp_globals.free_tables; |
528 | 0 | table->prev = NULL; |
529 | 0 | if (tramp_globals.free_tables != NULL) |
530 | 0 | tramp_globals.free_tables->prev = table; |
531 | 0 | tramp_globals.free_tables = table; |
532 | 0 | tramp_globals.nfree_tables++; |
533 | 0 | } |
534 | | |
535 | | /* |
536 | | * Delete a trampoline table from the global table list. |
537 | | */ |
538 | | static void |
539 | | tramp_table_del (struct tramp_table *table) |
540 | 0 | { |
541 | 0 | tramp_globals.nfree_tables--; |
542 | 0 | if (table->prev != NULL) |
543 | 0 | table->prev->next = table->next; |
544 | 0 | if (table->next != NULL) |
545 | 0 | table->next->prev = table->prev; |
546 | 0 | if (tramp_globals.free_tables == table) |
547 | 0 | tramp_globals.free_tables = table->next; |
548 | 0 | } |
549 | | |
550 | | /* ------------------------- Trampoline functions ------------------------- */ |
551 | | |
552 | | /* |
553 | | * Add a trampoline to its trampoline table. |
554 | | */ |
555 | | static void |
556 | | tramp_add (struct tramp *tramp) |
557 | 0 | { |
558 | 0 | struct tramp_table *table = tramp->table; |
559 | |
|
560 | 0 | tramp->next = table->free; |
561 | 0 | tramp->prev = NULL; |
562 | 0 | if (table->free != NULL) |
563 | 0 | table->free->prev = tramp; |
564 | 0 | table->free = tramp; |
565 | 0 | table->nfree++; |
566 | |
|
567 | 0 | if (table->nfree == 1) |
568 | 0 | tramp_table_add (table); |
569 | | |
570 | | /* |
571 | | * We don't want to keep too many free trampoline tables lying around. |
572 | | */ |
573 | 0 | if (table->nfree == tramp_globals.ntramp && |
574 | 0 | tramp_globals.nfree_tables > 1) |
575 | 0 | { |
576 | 0 | tramp_table_del (table); |
577 | 0 | tramp_table_free (table); |
578 | 0 | } |
579 | 0 | } |
580 | | |
581 | | /* |
582 | | * Remove a trampoline from its trampoline table. |
583 | | */ |
584 | | static void |
585 | | tramp_del (struct tramp *tramp) |
586 | 0 | { |
587 | 0 | struct tramp_table *table = tramp->table; |
588 | |
|
589 | 0 | table->nfree--; |
590 | 0 | if (tramp->prev != NULL) |
591 | 0 | tramp->prev->next = tramp->next; |
592 | 0 | if (tramp->next != NULL) |
593 | 0 | tramp->next->prev = tramp->prev; |
594 | 0 | if (table->free == tramp) |
595 | 0 | table->free = tramp->next; |
596 | |
|
597 | 0 | if (table->nfree == 0) |
598 | 0 | tramp_table_del (table); |
599 | 0 | } |
600 | | |
601 | | /* ------------------------ Trampoline API functions ------------------------ */ |
602 | | |
603 | | int |
604 | | ffi_tramp_is_supported(void) |
605 | 0 | { |
606 | 0 | int ret; |
607 | |
|
608 | 0 | ffi_tramp_lock(); |
609 | 0 | ret = ffi_tramp_init (); |
610 | 0 | ffi_tramp_unlock(); |
611 | 0 | return ret; |
612 | 0 | } |
613 | | |
614 | | /* |
615 | | * Allocate a trampoline and return its opaque address. |
616 | | */ |
617 | | void * |
618 | | ffi_tramp_alloc (int flags) |
619 | 0 | { |
620 | 0 | struct tramp *tramp; |
621 | |
|
622 | 0 | ffi_tramp_lock(); |
623 | |
|
624 | 0 | if (!ffi_tramp_init () || flags != 0) |
625 | 0 | { |
626 | 0 | ffi_tramp_unlock(); |
627 | 0 | return NULL; |
628 | 0 | } |
629 | | |
630 | 0 | if (!tramp_table_alloc ()) |
631 | 0 | { |
632 | 0 | ffi_tramp_unlock(); |
633 | 0 | return NULL; |
634 | 0 | } |
635 | | |
636 | 0 | tramp = tramp_globals.free_tables->free; |
637 | 0 | tramp_del (tramp); |
638 | |
|
639 | 0 | ffi_tramp_unlock(); |
640 | |
|
641 | 0 | return tramp; |
642 | 0 | } |
643 | | |
644 | | /* |
645 | | * Set the parameters for a trampoline. |
646 | | */ |
647 | | void |
648 | | ffi_tramp_set_parms (void *arg, void *target, void *data) |
649 | 0 | { |
650 | 0 | struct tramp *tramp = arg; |
651 | |
|
652 | 0 | ffi_tramp_lock(); |
653 | 0 | tramp->parm->target = target; |
654 | 0 | tramp->parm->data = data; |
655 | 0 | ffi_tramp_unlock(); |
656 | 0 | } |
657 | | |
658 | | /* |
659 | | * Get the invocation address of a trampoline. |
660 | | */ |
661 | | void * |
662 | | ffi_tramp_get_addr (void *arg) |
663 | 0 | { |
664 | 0 | struct tramp *tramp = arg; |
665 | 0 | void *addr; |
666 | |
|
667 | 0 | ffi_tramp_lock(); |
668 | 0 | addr = tramp->code; |
669 | 0 | ffi_tramp_unlock(); |
670 | |
|
671 | 0 | return addr; |
672 | 0 | } |
673 | | |
674 | | /* |
675 | | * Free a trampoline. |
676 | | */ |
677 | | void |
678 | | ffi_tramp_free (void *arg) |
679 | 0 | { |
680 | 0 | struct tramp *tramp = arg; |
681 | |
|
682 | 0 | ffi_tramp_lock(); |
683 | 0 | tramp_add (tramp); |
684 | 0 | ffi_tramp_unlock(); |
685 | 0 | } |
686 | | |
687 | | /* ------------------------------------------------------------------------- */ |
688 | | |
689 | | #else /* !FFI_EXEC_STATIC_TRAMP */ |
690 | | |
691 | | #include <stddef.h> |
692 | | |
693 | | int |
694 | | ffi_tramp_is_supported(void) |
695 | | { |
696 | | return 0; |
697 | | } |
698 | | |
699 | | void * |
700 | | ffi_tramp_alloc (int flags) |
701 | | { |
702 | | return NULL; |
703 | | } |
704 | | |
705 | | void |
706 | | ffi_tramp_set_parms (void *arg, void *target, void *data) |
707 | | { |
708 | | } |
709 | | |
710 | | void * |
711 | | ffi_tramp_get_addr (void *arg) |
712 | | { |
713 | | return NULL; |
714 | | } |
715 | | |
716 | | void |
717 | | ffi_tramp_free (void *arg) |
718 | | { |
719 | | } |
720 | | |
721 | | #endif /* FFI_EXEC_STATIC_TRAMP */ |