1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! Public names for the four entry points whose bodies must be C.
//!
//! # Why this file exists
//!
//! Four entry points cannot be written in Rust on stable: three take C
//! varargs (`c_variadic` is unstable) and one returns `_Float16` (`f16` is
//! unstable). Their bodies live in `shim.c`.
//!
//! The obvious arrangement -- let the C definitions carry the public names --
//! does not survive linking. rustc gives a `cdylib` its own version script
//! listing the Rust `#[no_mangle]` symbols and ending `local: *`, so a symbol
//! defined in C is hidden from the finished library. Every way of adding them
//! back is worse than it looks:
//!
//! - A second `--version-script` works on some GNU ld builds and not others:
//! "anonymous version tag cannot be combined with other version tags". It
//! also stamps a version tag onto the symbols, which upstream's are without,
//! so a program linked against one library and run against the other meets a
//! version mismatch that need not exist.
//! - `--export-dynamic-symbol` and `--dynamic-list` both lose to the version
//! script's `local: *`. Measured, not assumed.
//! - Mach-O has no version script at all, so on macOS the symbols were simply
//! absent, and upstream's own `test-error` suite failed to link against us.
//!
//! What does work is giving rustc the symbol. A `#[naked]` function *is* a
//! `#[no_mangle]` Rust item, so it lands in rustc's export list on every
//! platform, and its body is a single jump.
//!
//! # Why a jump is ABI-transparent
//!
//! A tail `jmp`/`b` transfers control without touching a register, the stack,
//! or the return address, so the callee sees exactly the state the caller
//! established. That is what makes it safe for signatures Rust cannot even
//! spell: the varargs registers, x86-64's `al` vector-register count, and the
//! `_Float16` return in `xmm0` all pass through untouched, because nothing
//! here observes them.
//!
//! The Rust signatures below are therefore fiction -- deliberately so. They
//! take no arguments because a naked body cannot read arguments anyway, and
//! declaring the real ones would suggest a Rust caller could use these. None
//! can; the true signatures are in the vendored headers, which is what C
//! compiles against.
use naked_asm;
/// One public symbol, defined as a jump to its `asdf_shim_*` implementation.
///
/// The implementations are hidden (`ASDF_LOCAL`), so they bind locally and
/// the jump is direct rather than through the PLT.
trampoline!
trampoline!
trampoline!
trampoline!