@@ -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,73 @@ 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
+ // NOTE(nbdd0121): MSVC will hang if the input object file contains no sections,
1696
+ // so add an empty section.
1697
+ if file. format ( ) == object:: BinaryFormat :: Coff {
1698
+ file. add_section ( Vec :: new ( ) , ".text" . into ( ) , object:: SectionKind :: Text ) ;
1699
+ }
1700
+
1701
+ for ( sym, kind) in symbols. iter ( ) {
1702
+ file. add_symbol ( object:: write:: Symbol {
1703
+ name : sym. clone ( ) . into ( ) ,
1704
+ value : 0 ,
1705
+ size : 0 ,
1706
+ kind : match kind {
1707
+ SymbolExportKind :: Text => object:: SymbolKind :: Text ,
1708
+ SymbolExportKind :: Data => object:: SymbolKind :: Data ,
1709
+ SymbolExportKind :: Tls => object:: SymbolKind :: Tls ,
1710
+ } ,
1711
+ scope : object:: SymbolScope :: Unknown ,
1712
+ weak : false ,
1713
+ section : object:: write:: SymbolSection :: Undefined ,
1714
+ flags : object:: SymbolFlags :: None ,
1715
+ } ) ;
1716
+ }
1717
+
1718
+ let path = tmpdir. join ( "symbols.o" ) ;
1719
+ let result = std:: fs:: write ( & path, file. write ( ) . unwrap ( ) ) ;
1720
+ if let Err ( e) = result {
1721
+ sess. fatal ( & format ! ( "failed to write {}: {}" , path. display( ) , e) ) ;
1722
+ }
1723
+ cmd. add_object ( & path) ;
1724
+ }
1725
+
1658
1726
/// Add object files containing code from the current crate.
1659
1727
fn add_local_crate_regular_objects ( cmd : & mut dyn Linker , codegen_results : & CodegenResults ) {
1660
1728
for obj in codegen_results. modules . iter ( ) . filter_map ( |m| m. object . as_ref ( ) ) {
@@ -1795,6 +1863,13 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
1795
1863
// Pre-link CRT objects.
1796
1864
add_pre_link_objects ( cmd, sess, link_output_kind, crt_objects_fallback) ;
1797
1865
1866
+ add_linked_symbol_object (
1867
+ cmd,
1868
+ sess,
1869
+ tmpdir,
1870
+ & codegen_results. crate_info . linked_symbols [ & crate_type] ,
1871
+ ) ;
1872
+
1798
1873
// Sanitizer libraries.
1799
1874
add_sanitizer_libraries ( sess, crate_type, cmd) ;
1800
1875
0 commit comments