@@ -460,6 +460,101 @@ fn link_staticlib<'a, B: ArchiveBuilder<'a>>(sess: &'a Session,
460
460
}
461
461
}
462
462
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
+
463
558
// Create a dynamic library or executable
464
559
//
465
560
// 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,
476
571
// The invocations of cc share some flags across platforms
477
572
let ( pname, mut cmd) = get_linker ( sess, & linker, flavor) ;
478
573
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
+
479
577
if let Some ( args) = sess. target . target . options . pre_link_args . get ( & flavor) {
480
578
cmd. args ( args) ;
481
579
}
0 commit comments