@@ -5,14 +5,18 @@ use std::path::{Path, PathBuf};
55use std:: { env, io, iter, mem, str} ;
66
77use cc:: windows_registry;
8+ use object:: read:: archive:: ArchiveFile ;
9+ use rustc_data_structures:: fx:: { FxHashSet , FxIndexMap , FxIndexSet } ;
10+ use rustc_data_structures:: memmap:: Mmap ;
811use rustc_hir:: def_id:: { CrateNum , LOCAL_CRATE } ;
912use rustc_metadata:: {
1013 find_native_static_library, try_find_native_dynamic_library, try_find_native_static_library,
1114} ;
1215use rustc_middle:: bug;
1316use rustc_middle:: middle:: dependency_format:: Linkage ;
14- use rustc_middle:: middle:: exported_symbols;
15- use rustc_middle:: middle:: exported_symbols:: { ExportedSymbol , SymbolExportInfo , SymbolExportKind } ;
17+ use rustc_middle:: middle:: exported_symbols:: {
18+ self , ExportedSymbol , SymbolExportInfo , SymbolExportKind ,
19+ } ;
1620use rustc_middle:: ty:: TyCtxt ;
1721use rustc_session:: Session ;
1822use rustc_session:: config:: { self , CrateType , DebugInfo , LinkerPluginLto , Lto , OptLevel , Strip } ;
@@ -21,6 +25,7 @@ use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, Lld};
2125use tracing:: { debug, warn} ;
2226
2327use super :: command:: Command ;
28+ use super :: link:: are_upstream_rust_objects_already_included;
2429use super :: symbol_export;
2530use crate :: errors;
2631
@@ -1753,17 +1758,15 @@ impl<'a> Linker for AixLinker<'a> {
17531758fn for_each_exported_symbols_include_dep < ' tcx > (
17541759 tcx : TyCtxt < ' tcx > ,
17551760 crate_type : CrateType ,
1756- mut callback : impl FnMut ( ExportedSymbol < ' tcx > , SymbolExportInfo , CrateNum ) ,
1761+ mut callback : impl FnMut ( & ' tcx [ ( ExportedSymbol < ' tcx > , SymbolExportInfo ) ] , CrateNum ) ,
17571762) {
17581763 let formats = tcx. dependency_formats ( ( ) ) ;
17591764 let deps = & formats[ & crate_type] ;
17601765
17611766 for ( cnum, dep_format) in deps. iter_enumerated ( ) {
17621767 // For each dependency that we are linking to statically ...
17631768 if * dep_format == Linkage :: Static {
1764- for & ( symbol, info) in tcx. exported_symbols ( cnum) . iter ( ) {
1765- callback ( symbol, info, cnum) ;
1766- }
1769+ callback ( tcx. exported_symbols ( cnum) , cnum) ;
17671770 }
17681771 }
17691772}
@@ -1783,12 +1786,14 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
17831786fn exported_symbols_for_non_proc_macro ( tcx : TyCtxt < ' _ > , crate_type : CrateType ) -> Vec < String > {
17841787 let mut symbols = Vec :: new ( ) ;
17851788 let export_threshold = symbol_export:: crates_export_threshold ( & [ crate_type] ) ;
1786- for_each_exported_symbols_include_dep ( tcx, crate_type, |symbol, info, cnum| {
1787- if info. level . is_below_threshold ( export_threshold) {
1788- symbols. push ( symbol_export:: exporting_symbol_name_for_instance_in_crate (
1789- tcx, symbol, cnum,
1790- ) ) ;
1791- symbol_export:: extend_exported_symbols ( & mut symbols, tcx, symbol, cnum) ;
1789+ for_each_exported_symbols_include_dep ( tcx, crate_type, |exported_symbols, cnum| {
1790+ for & ( symbol, info) in exported_symbols {
1791+ if info. level . is_below_threshold ( export_threshold) {
1792+ symbols. push ( symbol_export:: exporting_symbol_name_for_instance_in_crate (
1793+ tcx, symbol, cnum,
1794+ ) ) ;
1795+ symbol_export:: extend_exported_symbols ( & mut symbols, tcx, symbol, cnum) ;
1796+ }
17921797 }
17931798 } ) ;
17941799
@@ -1808,30 +1813,97 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
18081813 vec ! [ proc_macro_decls_name, metadata_symbol_name]
18091814}
18101815
1811- pub ( crate ) fn linked_symbols (
1816+ fn add_linked_objects (
1817+ archive_path : & Path ,
1818+ linked_symbols : & mut FxHashSet < String > ,
1819+ ) -> Option < FxIndexSet < u64 > > {
1820+ let archive_map = unsafe { Mmap :: map ( File :: open ( & archive_path) . unwrap ( ) ) . unwrap ( ) } ;
1821+ let archive = ArchiveFile :: parse ( & * archive_map)
1822+ . map_err ( |err| io:: Error :: new ( io:: ErrorKind :: InvalidData , err) )
1823+ . unwrap ( ) ;
1824+ let Some ( archive_symbols) = archive. symbols ( ) . unwrap ( ) else {
1825+ return None ;
1826+ } ;
1827+ let mut offsets = FxIndexSet :: default ( ) ;
1828+ for symbol in archive_symbols {
1829+ let symbol = symbol. unwrap ( ) ;
1830+ let name = std:: str:: from_utf8 ( symbol. name ( ) ) . unwrap ( ) ;
1831+ if linked_symbols. remove ( name) {
1832+ offsets. insert ( symbol. offset ( ) . 0 ) ;
1833+ }
1834+ }
1835+ Some ( offsets)
1836+ }
1837+
1838+ pub ( crate ) fn linked_objects (
18121839 tcx : TyCtxt < ' _ > ,
18131840 crate_type : CrateType ,
1814- ) -> Vec < ( String , SymbolExportKind ) > {
1841+ linked_symbols : & mut Vec < ( String , SymbolExportKind ) > ,
1842+ ) -> FxIndexMap < CrateNum , FxIndexSet < u64 > > {
18151843 match crate_type {
18161844 CrateType :: Executable | CrateType :: Cdylib | CrateType :: Dylib => ( ) ,
18171845 CrateType :: Staticlib | CrateType :: ProcMacro | CrateType :: Rlib => {
1818- return Vec :: new ( ) ;
1846+ return FxIndexMap :: default ( ) ;
18191847 }
18201848 }
18211849
1822- let mut symbols = Vec :: new ( ) ;
1823-
1850+ let mut objects = FxIndexMap :: default ( ) ;
1851+ let upstream_rust_objects_already_included =
1852+ are_upstream_rust_objects_already_included ( tcx. sess ) ;
18241853 let export_threshold = symbol_export:: crates_export_threshold ( & [ crate_type] ) ;
1825- for_each_exported_symbols_include_dep ( tcx, crate_type, |symbol, info, cnum| {
1826- if info. level . is_below_threshold ( export_threshold) || info. used {
1827- symbols. push ( (
1828- symbol_export:: linking_symbol_name_for_instance_in_crate ( tcx, symbol, cnum) ,
1829- info. kind ,
1830- ) ) ;
1854+ for_each_exported_symbols_include_dep ( tcx, crate_type, |exported_symbols, cnum| {
1855+ if cnum == LOCAL_CRATE {
1856+ // We don't know here if the symbols are undefined, so we add them all.
1857+ // Since the local crate is always linked directly to object files, `#[used]` works as expected.
1858+ linked_symbols. extend (
1859+ exported_symbols
1860+ . iter ( )
1861+ . filter ( |( _, info) | {
1862+ info. level . is_below_threshold ( export_threshold) || info. used
1863+ } )
1864+ . map ( |& ( symbol, info) | {
1865+ (
1866+ symbol_export:: linking_symbol_name_for_instance_in_crate (
1867+ tcx, symbol, cnum,
1868+ ) ,
1869+ info. kind ,
1870+ )
1871+ } ) ,
1872+ ) ;
1873+ return ;
1874+ }
1875+ // TODO: let lto = upstream_rust_objects_already_included && !ignored_for_lto(tcx.sess, &codegen_results.crate_info, cnum);
1876+ let lto = upstream_rust_objects_already_included;
1877+ if lto {
1878+ return ;
1879+ }
1880+ let symbols: Vec < _ > = exported_symbols
1881+ . iter ( )
1882+ . filter ( |( _, info) | info. level . is_below_threshold ( export_threshold) || info. used )
1883+ . map ( |& ( symbol, info) | {
1884+ (
1885+ symbol_export:: linking_symbol_name_for_instance_in_crate ( tcx, symbol, cnum) ,
1886+ info. kind ,
1887+ )
1888+ } )
1889+ . collect ( ) ;
1890+ if symbols. is_empty ( ) {
1891+ return ;
18311892 }
1893+ let used_crate_source = tcx. used_crate_source ( cnum) ;
1894+ let cratepath = & used_crate_source. rlib . as_ref ( ) . unwrap ( ) . 0 ;
1895+ let mut crate_linked_symbols: FxHashSet < _ > =
1896+ symbols. iter ( ) . map ( |( symbol, _) | symbol. to_string ( ) ) . collect ( ) ;
1897+ if let Some ( archive_offsets) = add_linked_objects ( cratepath, & mut crate_linked_symbols) {
1898+ objects. insert ( cnum, archive_offsets) ;
1899+ }
1900+ // Unresolved symbols may come from external libraries.
1901+ linked_symbols. extend (
1902+ symbols. into_iter ( ) . filter ( |( symbol, _) | crate_linked_symbols. contains ( symbol) ) ,
1903+ ) ;
18321904 } ) ;
18331905
1834- symbols
1906+ objects
18351907}
18361908
18371909/// Much simplified and explicit CLI for the NVPTX linker. The linker operates
0 commit comments