Description
The problem
Some symbols, like the __aeabi_*
ones, are defined as "aliases" of others in the C implementation of compiler-rt. For example: __aeabi_dadd
is an alias of __adddf3
. This means that both symbols, the original and its alias, refer to the same routine and use of either will result in a call to the same routine.
Rust doesn't have a mechanism for aliasing symbols and right now we are "emulating" aliases like this:
#[no_mangle]
pub extern fn __aeabi_dadd(a: f64, b: f64) -> f64 {
__adddf3(a, b)
}
Although this works (calling that "alias" does the right thing), it also incurrs in an extra function call everytime the alias is used:
00000a8c <__aeabi_dadd>:
a8c: ea00001a b afc <__adddf3>
Attempted solutions
Use #[link_args]
to ask the linker to duplicate the symbol. See #39. Sadly, this didn't work because #[link_args]
is not propagated through crates and also that feature is slated for removal so we can't rely on it anyway.
Possible non-ideal solutions
export_name
Most (all?) ARM builtins have the form __aeabi_*
. compiler-rt
implements them as aliases to the non-aeabi symbols. For example: __aeabi_dadd
is an alias of __adddf3
and both symbols appear in libcompiler-rt.a
. Given that ARM executables never use the non-aeabi symbols, we could simply expose the __adddf3
routine as the __aeabi_dadd
symbol without providing the __adddf3
symbol. In Rust code this would look like this:
#[cfg_attr(target = "arm", export_name = "__aeabi_dadd")]
#[cfg_attr(not(target = "arm"), no_mangle)]
pub extern fn __adddf3(a: f64, b: f64) -> f64 { ... }
The result would be:
rustc_builtins
on x86 exposes the__adddf3
symbolrustc_builtins
on ARM exposes the__aeabi_dadd
symbol
In contrast, libcompiler-rt.a
on ARM exposes both the __adddf3
and the __aeabi_dadd
symbols
This approach can only be used if the implementation resides in rustc-builtins
. For instance, we can't use this to expose the __aeabi_memcpy*
symbols which are all aliases to memcpy
.
Just duplicate the routine
#[no_mangle]
pub extern fn __adddf3(a: f64, b: f64) -> f64 { impl!() }
#[no_mangle]
pub extern fn __aeabi_dadd(a: f64, b: f64) -> f64 { impl!() }
This would get rid of the extra function call in the "alias" but would probably result in duplicate code/instructions in the final executable (unless LLVM is smart enough to deduplicate two routines that have the same instructions)
Anyone has any other idea about how to solve this?