Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

figure out some mechanism to alias symbols #70

Open
japaric opened this issue Sep 22, 2016 · 4 comments
Open

figure out some mechanism to alias symbols #70

japaric opened this issue Sep 22, 2016 · 4 comments

Comments

@japaric
Copy link
Member

japaric commented Sep 22, 2016

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 symbol
  • rustc_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?

@est31
Copy link
Member

est31 commented Feb 4, 2017

Just an idea: one could add a perma-unstable feature to rust that gives you support to add aliases. This worked great for "unadjusted" and i128.

@japaric
Copy link
Member Author

japaric commented Feb 22, 2017

Just an idea: one could add a perma-unstable feature to rust that gives you support to add aliases.

LLVM has IR for this so we could implement it. The issue, I think, is picking a syntax. In C, one writes:

void __aeabi_memcpy2() {}

void __aeabi_memcpy4() __attribute__((alias("__aeabi_memcpy2")));

But in Rust we don't have syntax for function declarations (without definition). Perhaps we could implement a reverse syntax like this:

#[aliases(__aeabi_memcpy2, __aeabi_mecpy4)]
fn memcpy() { .. }

@alexcrichton
Copy link
Member

I'm likely going to have to figure out something to handle this on #166 as the tests aren't passing (lots of duplicate symbols) if this isn't handled. Right now my current strategy is to use a macro to deal with the ABI switches between __aeabi and the non-prefixed version, define both symbols, and basically "duplicate the routine". The routine is only defined in one place but LLVM's likely to inline it into both anyway.

@nox
Copy link

nox commented Oct 12, 2020

Another interesting thing is being able to replace a symbol by a different one if a third symbol is used in the final program, and I have no idea how we would model that in Rust. To take an example, AFAIU there is 2 translation units in musl to support syscalls that are cancellation points, the first one defines __syscall_cp_c as a weak alias to sccp, which is just a dumb wrapper around __syscall, and the second one actually defines __syscall_cp_c as a function that can handle thread cancellation during syscalls properly. That latter definition is used only if the translation unit that contains it is used in the final program, that is if pthread_cancel is actually used.

Or is my understanding of this stuff completely wrong?

If I'm correct, how would do this dance in Rust?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants