1- //! Support for "weak linkage" to symbols on Unix
2- //!
3- //! Some I/O operations we do in std require newer versions of OSes but we need
4- //! to maintain binary compatibility with older releases for now. In order to
5- //! use the new functionality when available we use this module for detection.
6- //!
7- //! One option to use here is weak linkage, but that is unfortunately only
8- //! really workable with ELF. Otherwise, use dlsym to get the symbol value at
9- //! runtime. This is also done for compatibility with older versions of glibc,
10- //! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
11- //! we've been dynamically linked to the library the symbol comes from, but that
12- //! is currently always the case for things like libpthread/libc.
13- //!
14- //! A long time ago this used weak linkage for the __pthread_get_minstack
15- //! symbol, but that caused Debian to detect an unnecessarily strict versioned
16- //! dependency on libc6 (#23628) because it is GLIBC_PRIVATE. We now use `dlsym`
17- //! for a runtime lookup of that symbol to avoid the ELF versioned dependency.
18-
19- // There are a variety of `#[cfg]`s controlling which targets are involved in
20- // each instance of `weak!` and `syscall!`. Rather than trying to unify all of
21- // that, we'll just allow that some unix targets don't use this module at all.
22- #![ allow( dead_code, unused_macros) ]
23- #![ forbid( unsafe_op_in_unsafe_fn) ]
24-
251use crate :: ffi:: { CStr , c_char, c_void} ;
262use crate :: marker:: { FnPtr , PhantomData } ;
273use crate :: sync:: atomic:: { Atomic , AtomicPtr , Ordering } ;
284use crate :: { mem, ptr} ;
295
30- // We currently only test `dlsym!`, but that doesn't work on all platforms, so
31- // we gate the tests to only the platforms where it is actually used.
32- //
33- // FIXME(joboet): add more tests, reorganise the whole module and get rid of
34- // `#[allow(dead_code, unused_macros)]`.
35- #[ cfg( any(
36- target_vendor = "apple" ,
37- all( target_os = "linux" , target_env = "gnu" ) ,
38- target_os = "freebsd" ,
39- ) ) ]
406#[ cfg( test) ]
7+ #[ path = "./tests.rs" ]
418mod tests;
429
43- // We can use true weak linkage on ELF targets.
44- #[ cfg( all( unix, not( target_vendor = "apple" ) ) ) ]
4510pub ( crate ) macro weak {
4611 ( fn $name: ident( $( $param: ident : $t: ty) , * $( , ) ?) -> $ret: ty; ) => (
47- let ref $name: ExternWeak <unsafe extern "C" fn ( $( $t) , * ) -> $ret> = {
48- unsafe extern "C" {
49- #[ linkage = "extern_weak" ]
50- static $name: Option <unsafe extern "C" fn ( $( $t) , * ) -> $ret>;
51- }
52- #[ allow( unused_unsafe) ]
53- ExternWeak :: new ( unsafe { $name } )
54- } ;
55- )
56- }
57-
58- // On non-ELF targets, use the dlsym approximation of weak linkage.
59- #[ cfg( target_vendor = "apple" ) ]
60- pub ( crate ) use self :: dlsym as weak;
61-
62- pub ( crate ) struct ExternWeak < F : Copy > {
63- weak_ptr : Option < F > ,
64- }
65-
66- impl < F : Copy > ExternWeak < F > {
67- #[ inline]
68- pub ( crate ) fn new ( weak_ptr : Option < F > ) -> Self {
69- ExternWeak { weak_ptr }
70- }
71-
72- #[ inline]
73- pub ( crate ) fn get ( & self ) -> Option < F > {
74- self . weak_ptr
75- }
76- }
77-
78- pub ( crate ) macro dlsym {
79- ( fn $name: ident( $( $param: ident : $t: ty) , * $( , ) ?) -> $ret: ty; ) => (
80- dlsym ! (
12+ weak ! (
8113 #[ link_name = stringify!( $name) ]
8214 fn $name( $( $param : $t) , * ) -> $ret;
8315 ) ;
@@ -116,7 +48,7 @@ impl<F: FnPtr> DlsymWeak<F> {
11648 /// If the signature of `F` does not match the signature of the symbol (if
11749 /// it exists), calling the function pointer returned by `get()` is
11850 /// undefined behaviour.
119- pub ( crate ) const unsafe fn new ( name : & ' static CStr ) -> Self {
51+ pub const unsafe fn new ( name : & ' static CStr ) -> Self {
12052 DlsymWeak {
12153 name : name. as_ptr ( ) ,
12254 func : AtomicPtr :: new ( ptr:: without_provenance_mut ( 1 ) ) ,
@@ -125,7 +57,7 @@ impl<F: FnPtr> DlsymWeak<F> {
12557 }
12658
12759 #[ inline]
128- pub ( crate ) fn get ( & self ) -> Option < F > {
60+ pub fn get ( & self ) -> Option < F > {
12961 // The caller is presumably going to read through this value
13062 // (by calling the function we've dlsymed). This means we'd
13163 // need to have loaded it with at least C11's consume
@@ -179,47 +111,3 @@ impl<F: FnPtr> DlsymWeak<F> {
179111
180112unsafe impl < F > Send for DlsymWeak < F > { }
181113unsafe impl < F > Sync for DlsymWeak < F > { }
182-
183- #[ cfg( not( any( target_os = "linux" , target_os = "android" ) ) ) ]
184- pub ( crate ) macro syscall {
185- ( fn $name: ident( $( $param: ident : $t: ty) , * $( , ) ?) -> $ret: ty; ) => (
186- unsafe fn $name( $( $param: $t) , * ) -> $ret {
187- weak ! ( fn $name( $( $param: $t) , * ) -> $ret; ) ;
188-
189- if let Some ( fun) = $name. get ( ) {
190- unsafe { fun ( $( $param) , * ) }
191- } else {
192- super :: os:: set_errno ( libc:: ENOSYS ) ;
193- -1
194- }
195- }
196- )
197- }
198-
199- #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
200- pub ( crate ) macro syscall {
201- (
202- fn $name: ident( $( $param: ident : $t: ty) , * $( , ) ?) -> $ret: ty;
203- ) => (
204- unsafe fn $name( $( $param: $t) , * ) -> $ret {
205- weak ! ( fn $name( $( $param: $t) , * ) -> $ret; ) ;
206-
207- // Use a weak symbol from libc when possible, allowing `LD_PRELOAD`
208- // interposition, but if it's not found just use a raw syscall.
209- if let Some ( fun) = $name. get ( ) {
210- unsafe { fun ( $( $param) , * ) }
211- } else {
212- unsafe { libc:: syscall ( libc:: ${ concat ( SYS_ , $name) } , $( $param) , * ) as $ret }
213- }
214- }
215- )
216- }
217-
218- #[ cfg( any( target_os = "linux" , target_os = "android" ) ) ]
219- pub ( crate ) macro raw_syscall {
220- ( fn $name: ident( $( $param: ident : $t: ty) , * $( , ) ?) -> $ret: ty ; ) => (
221- unsafe fn $name( $( $param: $t) , * ) -> $ret {
222- unsafe { libc:: syscall ( libc:: ${ concat ( SYS_ , $name) } , $( $param) , * ) as $ret }
223- }
224- )
225- }
0 commit comments