Skip to content

figure out some mechanism to alias symbols #70

Open
@japaric

Description

@japaric

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?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions