@@ -460,6 +460,101 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
460460 }
461461}
462462
463+
464+ /// rust-lang/rust#61539: bugs in older versions of GNU `ld` cause problems that
465+ /// are readily exposed under our default setting of disabling PLT (PR
466+ /// rust-lang/rust#54592). Heuristically detect and warn about this.
467+ fn check_for_buggy_ld_version ( sess : & Session ,
468+ program_name : & Path ,
469+ flavor : LinkerFlavor ,
470+ crate_type : config:: CrateType ) {
471+ debug ! ( "check_for_buggy_ld_version: \
472+ program_name: {:?} flavor: {:?} crate_type: {:?}",
473+ program_name, flavor, crate_type) ;
474+
475+ match crate_type {
476+ config:: CrateType :: Dylib |
477+ config:: CrateType :: ProcMacro => ( ) ,
478+
479+ // FIXME: should we include CrateType::Cdylib in the warning? It is not
480+ // clear why we haven't seen it there.
481+ config:: CrateType :: Cdylib => return ,
482+
483+ // Static objects won't run into this (unless they load a dynamic
484+ // object, which this heuristic is not attempting to detect).
485+ config:: CrateType :: Executable |
486+ config:: CrateType :: Rlib |
487+ config:: CrateType :: Staticlib => return ,
488+ } ;
489+
490+ let mut version_cmd = Command :: new ( program_name) ;
491+ match flavor {
492+ LinkerFlavor :: Gcc => {
493+ // run `gcc -v -Xlinker --version` to query gcc for version info of underlying linker
494+ version_cmd. args ( & [ "-v" , "-Xlinker" , "--version" ] ) ;
495+ }
496+ LinkerFlavor :: Ld => {
497+ // run `ld --version`
498+ version_cmd. args ( & [ "--version" ] ) ;
499+ }
500+ LinkerFlavor :: Msvc |
501+ LinkerFlavor :: Em |
502+ LinkerFlavor :: Lld ( ..) |
503+ LinkerFlavor :: PtxLinker => {
504+ // Not GNU ld, so don't bother inspecting version.
505+ return ;
506+ }
507+ }
508+ let version_check_invocation = format ! ( "{:?}" , & version_cmd) ;
509+ debug ! ( "check_for_buggy_ld_version version_check_invocation: {:?}" ,
510+ version_check_invocation) ;
511+ let output = match version_cmd. output ( ) {
512+ Err ( _) => {
513+ sess. warn ( & format ! ( "Linker version inspection failed to execute: `{}`" ,
514+ version_check_invocation) ) ;
515+ return ;
516+ }
517+ Ok ( output) => output,
518+ } ;
519+ let out = String :: from_utf8_lossy ( & output. stdout ) ;
520+
521+ debug ! ( "check_for_buggy_ld_version out: {:?}" , out) ;
522+
523+ let parse = |first_line : & str | -> Option < ( u32 , u32 ) > {
524+ let suffix = first_line. splitn ( 2 , "GNU ld version " ) . last ( ) ?;
525+ let version_components: Vec < _ > = suffix. split ( '.' ) . collect ( ) ;
526+ let major: u32 = version_components. get ( 0 ) ?. parse ( ) . ok ( ) ?;
527+ let minor: u32 = version_components. get ( 1 ) ?. parse ( ) . ok ( ) ?;
528+ Some ( ( major, minor) )
529+ } ;
530+
531+ let first_line = out. lines ( ) . next ( ) ;
532+
533+ debug ! ( "check_for_buggy_ld_version first_line: {:?}" , first_line) ;
534+
535+ let ( major, minor) = match first_line. and_then ( parse) {
536+ None => {
537+ sess. warn ( & format ! ( "Linker version inspection failed to parse: `{}`, output: {}" ,
538+ version_check_invocation, out) ) ;
539+ return ;
540+ }
541+ Some ( version) => version,
542+ } ;
543+ debug ! ( "check_for_buggy_ld_version (major, minor): {:?}" , ( major, minor) ) ;
544+
545+ let is_old_buggy_version = major < 2 || ( major == 2 && minor < 29 ) ;
546+
547+ if is_old_buggy_version {
548+ let diag = sess. diagnostic ( ) ;
549+ diag. warn ( & format ! ( "Using linker `{}` with Rust dynamic libraries has known bugs." ,
550+ first_line. unwrap( ) ) ) ;
551+ diag. note_without_error (
552+ "Consider upgrading to GNU ld version 2.29 or newer, or using a different linker." ) ;
553+ diag. note_without_error (
554+ "For more information, see https://github.com/rust-lang/rust/issues/61539" ) ;
555+ }
556+ }
557+
463558// Create a dynamic library or executable
464559//
465560// This will invoke the system linker/cc to create the resulting file. This
@@ -476,6 +571,9 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
476571 // The invocations of cc share some flags across platforms
477572 let ( pname, mut cmd) = get_linker ( sess, & linker, flavor) ;
478573
574+ // rust-lang/rust#61539: heuristically inspect ld version to warn about bugs
575+ check_for_buggy_ld_version ( sess, & pname, flavor, crate_type) ;
576+
479577 if let Some ( args) = sess. target . target . options . pre_link_args . get ( & flavor) {
480578 cmd. args ( args) ;
481579 }
0 commit comments