Skip to content

Tracking issue for the linkage feature #29603

Open

Description

@aturon

View all comments

Tracks stabilization for the linkage attribute.

Note that this has peculiar semantics, see #156468.
In particular, unlike normal statics, the local global variable we generate for this indirection does not have a globally unique address (rust-lang/miri#5015, #156467).

Activity

  1. added
    T-langRelevant to the language team
    B-unstableBlocker: Implemented in the nightly compiler and unstable.
    on Nov 5, 2015
  2. aturon commented on Nov 5, 2015

    @aturon
    ContributorAuthor
  3. alexcrichton commented on Nov 5, 2015

    @alexcrichton
    Member

    Currently this translates to the various linkage models of LLVM, for example the values of the attribute can be:

    match name {                                                         
        "appending" => Some(llvm::AppendingLinkage),                     
        "available_externally" => Some(llvm::AvailableExternallyLinkage),
        "common" => Some(llvm::CommonLinkage),                           
        "extern_weak" => Some(llvm::ExternalWeakLinkage),                
        "external" => Some(llvm::ExternalLinkage),                       
        "internal" => Some(llvm::InternalLinkage),                       
        "linkonce" => Some(llvm::LinkOnceAnyLinkage),                    
        "linkonce_odr" => Some(llvm::LinkOnceODRLinkage),                
        "private" => Some(llvm::PrivateLinkage),                         
        "weak" => Some(llvm::WeakAnyLinkage),                            
        "weak_odr" => Some(llvm::WeakODRLinkage),                        
        _ => None,                                                       
    }                                                                    

    Some worries about this are:

    • These are very LLVM specific, it's unclear how applicable they are to other backends.
    • Beyond external or weak, I've never seen a reason to use the other attributes.
    • These linkage methods are platform-specific and aren't guaranteed to work everywhere.

    That being said, it's the only way to do weak symbols on Linux and it's also convenient for exporting a known symbol without worrying about privacy on the Rust side of things. I would personally want to reduce the set of accepted linkage types and then state "well of course linkage is platform-specific!"

  4. aturon commented on Nov 5, 2015

    @aturon
    ContributorAuthor
  5. mahkoh commented on Jan 11, 2016

    @mahkoh
    Contributor

    This feature is fundamentally broken. Consider the following code:

    static unsigned long B = 0;
    unsigned long *A = &B;
    void f(void) { }
    #![feature(linkage)]
    
    #[link_name = "c_part"]
    extern {
        #[linkage = "extern_weak"] static A: *const usize;
        fn f();
    }
    
    fn main() {
        unsafe {
            f();
            println!("{:x} @ {:x} @ {:p}", *(*A as *const usize), *A, A);
        }
    }

    Which prints 0 @ 5617765adaa8 @ 0x5617765ad890 meaning that the A seen by the rust code contains the address of A and not A itself. It's also easy to get LLVM to abort with this.

  6. mahkoh commented on Jan 11, 2016

    @mahkoh
    Contributor

    This attribute is also used incorrectly here.

  7. added
    T-dev-toolsRelevant to the dev-tools subteam, which will review and decide on the PR/issue.
    and removed on May 24, 2017
  8. brson commented on Jun 1, 2017

    @brson
    Contributor

    #18804 needs to be resolved before stabilization.

  9. removed
    T-dev-toolsRelevant to the dev-tools subteam, which will review and decide on the PR/issue.
    on Jun 1, 2017
  10. added
    C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFC
    on Jul 22, 2017
  11. nagisa commented on Jan 6, 2018

    @nagisa
    Member

    I think we should at least work on stabilising the weak and extern_weak linkage. Both are very useful and a fairly widespread linkage options that seem to be supported (unlike many other options currently exposed) by at least all of the tier 1 targets.

    To give an example of a use-case for weak linkage in Rust code (I need weak linkage for libloading), one would be for global statics unique even between multiple versions of the same crate. Consider that, currently, if a binary links log = ^0.3 and log = ^0.4 some way, or another, it will end up having two distinct global loggers. This could trivially be resolved with some use of the weak linkage option (as it ensures – at link time – only one instance of global with the same name).

    That being said, #[linkage] should always infect whatever it applies to with unsafety. Consider for example these two crates:

    // crate older version
    #[linkage="weak"]
    static mut FOO: u32 = !0;
    // crate newer version
    #[linkage="weak"]
    static mut FOO: char = 'a';

    when linked together, all uses of FOO as seen from the newer-version crate would be UB if the linker happened to choose to link-in the value from the older version. This is functionally a transmute without size checks.

  12. mahkoh commented on Jan 13, 2018

    @mahkoh
    Contributor

    extern_weak is broken in such a dubious way that even though I pointed out two years ago that it was being used incorrectly in the stdlib, the bug still hasn't been fixed.

    ~$ cat strong.rs 
    extern {
        static __progname: *const u8;
    }
    
    fn main() {
        unsafe {
            println!("  __progname:\t\t{:?}", __progname);
            println!(" &__progname:\t\t{:?}", &__progname as *const _);
            if !__progname.is_null() {
                println!(" *__progname:\t\t{:?}", *__progname as char);
            }
        }
    }
    ~$ cat weak.rs 
    #![feature(linkage)]
    
    extern {
        #[linkage = "extern_weak"]
        static __progname: *mut *const u8;
    }
    
    fn main() {
        unsafe {
            println!("  __progname:\t\t{:?}", __progname);
            println!(" &__progname:\t\t{:?}", &__progname as *const _);
            if !__progname.is_null() {
                println!(" *__progname:\t\t{:?}", *__progname);
                if !(*__progname).is_null() {
                    println!("**__progname:\t\t{:?}", **__progname as char);
                }
            }
        }
    }
    ~$ rustc strong.rs 
    ~$ rustc weak.rs 
    ~$ ./strong 
      __progname:		0x7ffdfc7438ac
     &__progname:		0x7f10560a5360
     *__progname:		's'
    ~$ ./weak 
      __progname:		0x7f730b21f360
     &__progname:		0x5574a33bb008
     *__progname:		0x7fffe4ca38b2
    **__progname:		'w'
    

    gcc and clang handle this attribute correctly.

    PS: The address of __dso_handle isn't actually too significant in __cxa_thread_atexit_impl and &__dso_handle is only a few bytes off.

    PSS: Wow, looks like I already explained this above (also two years ago). Maybe the NSA is trying to keep this potential remote code execution unfixed. 🤔

  13. 38 remaining items

  14. added a commit that references this issue on Sep 28, 2026
  15. tgross35 commented on Sep 28, 2026

    @tgross35
    Member
  16. added a commit that references this issue on Sep 29, 2026
  17. added 2 commits that reference this issue on Sep 29, 2026
  18. added 4 commits that reference this issue on Sep 30, 2026
  19. added 2 commits that reference this issue on Oct 1, 2026
  20. added a commit that references this issue on Oct 1, 2026
  21. added a commit that references this issue on Oct 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-FFIArea: Foreign function interface (FFI)A-attributesArea: Attributes (`#[…]`, `#![…]`)A-linkageArea: linking into static, shared libraries and binariesB-unstableBlocker: Implemented in the nightly compiler and unstable.C-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCF-linkage#![feature(linkage)]`S-tracking-perma-unstableStatus: The feature will stay unstable indefinitely.T-langRelevant to the language team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions