@@ -7,6 +7,7 @@ use rustc_errors::{ErrorGuaranteed, Handler};
7
7
use rustc_fs_util:: fix_windows_verbatim_for_gcc;
8
8
use rustc_hir:: def_id:: CrateNum ;
9
9
use rustc_middle:: middle:: dependency_format:: Linkage ;
10
+ use rustc_middle:: middle:: exported_symbols:: SymbolExportKind ;
10
11
use rustc_session:: config:: { self , CFGuard , CrateType , DebugInfo , LdImpl , Strip } ;
11
12
use rustc_session:: config:: { OutputFilenames , OutputType , PrintRequest , SplitDwarfKind } ;
12
13
use rustc_session:: cstore:: DllImport ;
@@ -1655,6 +1656,67 @@ fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor
1655
1656
}
1656
1657
}
1657
1658
1659
+ /// Add a synthetic object file that contains reference to all symbols that we want to expose to
1660
+ /// the linker.
1661
+ ///
1662
+ /// Background: we implement rlibs as static library (archives). Linkers treat archives
1663
+ /// differently from object files: all object files participate in linking, while archives will
1664
+ /// only participate in linking if they can satisfy at least one undefined reference (version
1665
+ /// scripts doesn't count). This causes `#[no_mangle]` or `#[used]` items to be ignored by the
1666
+ /// linker, and since they never participate in the linking, using `KEEP` in the linker scripts
1667
+ /// can't keep them either. This causes #47384.
1668
+ ///
1669
+ /// To keep them around, we could use `--whole-archive` and equivalents to force rlib to
1670
+ /// participate in linking like object files, but this proves to be expensive (#93791). Therefore
1671
+ /// we instead just introduce an undefined reference to them. This could be done by `-u` command
1672
+ /// line option to the linker or `EXTERN(...)` in linker scripts, however they does not only
1673
+ /// introduce an undefined reference, but also make them the GC roots, preventing `--gc-sections`
1674
+ /// from removing them, and this is especially problematic for embedded programming where every
1675
+ /// byte counts.
1676
+ ///
1677
+ /// This method creates a synthetic object file, which contains undefined references to all symbols
1678
+ /// that are necessary for the linking. They are only present in symbol table but not actually
1679
+ /// used in any sections, so the linker will therefore pick relevant rlibs for linking, but
1680
+ /// unused `#[no_mangle]` or `#[used]` can still be discard by GC sections.
1681
+ fn add_linked_symbol_object (
1682
+ cmd : & mut dyn Linker ,
1683
+ sess : & Session ,
1684
+ tmpdir : & Path ,
1685
+ symbols : & [ ( String , SymbolExportKind ) ] ,
1686
+ ) {
1687
+ if symbols. is_empty ( ) {
1688
+ return ;
1689
+ }
1690
+
1691
+ let Some ( mut file) = super :: metadata:: create_object_file ( sess) else {
1692
+ return ;
1693
+ } ;
1694
+
1695
+ for ( sym, kind) in symbols. iter ( ) {
1696
+ file. add_symbol ( object:: write:: Symbol {
1697
+ name : sym. clone ( ) . into ( ) ,
1698
+ value : 0 ,
1699
+ size : 0 ,
1700
+ kind : match kind {
1701
+ SymbolExportKind :: Text => object:: SymbolKind :: Text ,
1702
+ SymbolExportKind :: Data => object:: SymbolKind :: Data ,
1703
+ SymbolExportKind :: Tls => object:: SymbolKind :: Tls ,
1704
+ } ,
1705
+ scope : object:: SymbolScope :: Unknown ,
1706
+ weak : false ,
1707
+ section : object:: write:: SymbolSection :: Undefined ,
1708
+ flags : object:: SymbolFlags :: None ,
1709
+ } ) ;
1710
+ }
1711
+
1712
+ let path = tmpdir. join ( "symbols.o" ) ;
1713
+ let result = std:: fs:: write ( & path, file. write ( ) . unwrap ( ) ) ;
1714
+ if let Err ( e) = result {
1715
+ sess. fatal ( & format ! ( "failed to write {}: {}" , path. display( ) , e) ) ;
1716
+ }
1717
+ cmd. add_object ( & path) ;
1718
+ }
1719
+
1658
1720
/// Add object files containing code from the current crate.
1659
1721
fn add_local_crate_regular_objects ( cmd : & mut dyn Linker , codegen_results : & CodegenResults ) {
1660
1722
for obj in codegen_results. modules . iter ( ) . filter_map ( |m| m. object . as_ref ( ) ) {
@@ -1798,6 +1860,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
1798
1860
// Sanitizer libraries.
1799
1861
add_sanitizer_libraries ( sess, crate_type, cmd) ;
1800
1862
1863
+ add_linked_symbol_object (
1864
+ cmd,
1865
+ sess,
1866
+ tmpdir,
1867
+ & codegen_results. crate_info . linked_symbols [ & crate_type] ,
1868
+ ) ;
1869
+
1801
1870
// Object code from the current crate.
1802
1871
// Take careful note of the ordering of the arguments we pass to the linker
1803
1872
// here. Linkers will assume that things on the left depend on things to the
0 commit comments