Skip to content

Commit fcf787f

Browse files
committed
Auto merge of #140176 - dpaoliello:arm64ecdec, r=<try>
Fix linking statics on Arm64EC Arm64EC builds recently started to fail due to the linker not finding a symbol: ``` symbols.o : error LNK2001: unresolved external symbol #_ZN3std9panicking11EMPTY_PANIC17hc8d2b903527827f1E (EC Symbol) C:\Code\hello-world\target\arm64ec-pc-windows-msvc\debug\deps\hello_world.exe : fatal error LNK1120: 1 unresolved externals ``` It turns out that `EMPTY_PANIC` is a new static variable that was being exported then imported from the standard library, but when exporting LLVM didn't prepend the name with `#` (as only functions are prefixed with this character), whereas Rust was prefixing with `#` when attempting to import it. The fix is to have Rust not prefix statics with `#` when importing. Adding tests discovered another issue: we need to correctly mark static exported from dylibs with `DATA`, otherwise MSVC's linker assumes they are functions and complains that there is no exit thunk for them. Fixes #138541 --- try-job: dist-aarch64-msvc try-job: dist-x86_64-msvc try-job: x86_64-msvc-1 try-job: x86_64-msvc-2
2 parents f242d6c + 7370c5c commit fcf787f

File tree

8 files changed

+181
-50
lines changed

8 files changed

+181
-50
lines changed

compiler/rustc_codegen_ssa/src/back/linker.rs

+90-30
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,12 @@ pub(crate) trait Linker {
337337
fn debuginfo(&mut self, strip: Strip, natvis_debugger_visualizers: &[PathBuf]);
338338
fn no_crt_objects(&mut self);
339339
fn no_default_libraries(&mut self);
340-
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]);
340+
fn export_symbols(
341+
&mut self,
342+
tmpdir: &Path,
343+
crate_type: CrateType,
344+
symbols: &[(String, SymbolExportKind)],
345+
);
341346
fn subsystem(&mut self, subsystem: &str);
342347
fn linker_plugin_lto(&mut self);
343348
fn add_eh_frame_header(&mut self) {}
@@ -770,7 +775,12 @@ impl<'a> Linker for GccLinker<'a> {
770775
}
771776
}
772777

773-
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
778+
fn export_symbols(
779+
&mut self,
780+
tmpdir: &Path,
781+
crate_type: CrateType,
782+
symbols: &[(String, SymbolExportKind)],
783+
) {
774784
// Symbol visibility in object files typically takes care of this.
775785
if crate_type == CrateType::Executable {
776786
let should_export_executable_symbols =
@@ -799,7 +809,7 @@ impl<'a> Linker for GccLinker<'a> {
799809
// Write a plain, newline-separated list of symbols
800810
let res: io::Result<()> = try {
801811
let mut f = File::create_buffered(&path)?;
802-
for sym in symbols {
812+
for (sym, _) in symbols {
803813
debug!(" _{sym}");
804814
writeln!(f, "_{sym}")?;
805815
}
@@ -814,9 +824,10 @@ impl<'a> Linker for GccLinker<'a> {
814824
// .def file similar to MSVC one but without LIBRARY section
815825
// because LD doesn't like when it's empty
816826
writeln!(f, "EXPORTS")?;
817-
for symbol in symbols {
827+
for (symbol, kind) in symbols {
828+
let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
818829
debug!(" _{symbol}");
819-
writeln!(f, " {symbol}")?;
830+
writeln!(f, " {symbol}{kind_marker}")?;
820831
}
821832
};
822833
if let Err(error) = res {
@@ -829,7 +840,7 @@ impl<'a> Linker for GccLinker<'a> {
829840
writeln!(f, "{{")?;
830841
if !symbols.is_empty() {
831842
writeln!(f, " global:")?;
832-
for sym in symbols {
843+
for (sym, _) in symbols {
833844
debug!(" {sym};");
834845
writeln!(f, " {sym};")?;
835846
}
@@ -1096,7 +1107,12 @@ impl<'a> Linker for MsvcLinker<'a> {
10961107
// crates. Upstream rlibs may be linked statically to this dynamic library,
10971108
// in which case they may continue to transitively be used and hence need
10981109
// their symbols exported.
1099-
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
1110+
fn export_symbols(
1111+
&mut self,
1112+
tmpdir: &Path,
1113+
crate_type: CrateType,
1114+
symbols: &[(String, SymbolExportKind)],
1115+
) {
11001116
// Symbol visibility takes care of this typically
11011117
if crate_type == CrateType::Executable {
11021118
let should_export_executable_symbols =
@@ -1114,9 +1130,10 @@ impl<'a> Linker for MsvcLinker<'a> {
11141130
// straight to exports.
11151131
writeln!(f, "LIBRARY")?;
11161132
writeln!(f, "EXPORTS")?;
1117-
for symbol in symbols {
1133+
for (symbol, kind) in symbols {
1134+
let kind_marker = if *kind == SymbolExportKind::Data { " DATA" } else { "" };
11181135
debug!(" _{symbol}");
1119-
writeln!(f, " {symbol}")?;
1136+
writeln!(f, " {symbol}{kind_marker}")?;
11201137
}
11211138
};
11221139
if let Err(error) = res {
@@ -1257,14 +1274,19 @@ impl<'a> Linker for EmLinker<'a> {
12571274
self.cc_arg("-nodefaultlibs");
12581275
}
12591276

1260-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1277+
fn export_symbols(
1278+
&mut self,
1279+
_tmpdir: &Path,
1280+
_crate_type: CrateType,
1281+
symbols: &[(String, SymbolExportKind)],
1282+
) {
12611283
debug!("EXPORTED SYMBOLS:");
12621284

12631285
self.cc_arg("-s");
12641286

12651287
let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
12661288
let encoded = serde_json::to_string(
1267-
&symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
1289+
&symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
12681290
)
12691291
.unwrap();
12701292
debug!("{encoded}");
@@ -1426,8 +1448,13 @@ impl<'a> Linker for WasmLd<'a> {
14261448

14271449
fn no_default_libraries(&mut self) {}
14281450

1429-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1430-
for sym in symbols {
1451+
fn export_symbols(
1452+
&mut self,
1453+
_tmpdir: &Path,
1454+
_crate_type: CrateType,
1455+
symbols: &[(String, SymbolExportKind)],
1456+
) {
1457+
for (sym, _) in symbols {
14311458
self.link_args(&["--export", sym]);
14321459
}
14331460

@@ -1561,7 +1588,7 @@ impl<'a> Linker for L4Bender<'a> {
15611588
self.cc_arg("-nostdlib");
15621589
}
15631590

1564-
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
1591+
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) {
15651592
// ToDo, not implemented, copy from GCC
15661593
self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
15671594
}
@@ -1718,12 +1745,17 @@ impl<'a> Linker for AixLinker<'a> {
17181745

17191746
fn no_default_libraries(&mut self) {}
17201747

1721-
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1748+
fn export_symbols(
1749+
&mut self,
1750+
tmpdir: &Path,
1751+
_crate_type: CrateType,
1752+
symbols: &[(String, SymbolExportKind)],
1753+
) {
17221754
let path = tmpdir.join("list.exp");
17231755
let res: io::Result<()> = try {
17241756
let mut f = File::create_buffered(&path)?;
17251757
// FIXME: use llvm-nm to generate export list.
1726-
for symbol in symbols {
1758+
for (symbol, _) in symbols {
17271759
debug!(" _{symbol}");
17281760
writeln!(f, " {symbol}")?;
17291761
}
@@ -1767,9 +1799,12 @@ fn for_each_exported_symbols_include_dep<'tcx>(
17671799
}
17681800
}
17691801

1770-
pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1802+
pub(crate) fn exported_symbols(
1803+
tcx: TyCtxt<'_>,
1804+
crate_type: CrateType,
1805+
) -> Vec<(String, SymbolExportKind)> {
17711806
if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1772-
return exports.iter().map(ToString::to_string).collect();
1807+
return exports.iter().map(|name| (name.to_string(), SymbolExportKind::Text)).collect();
17731808
}
17741809

17751810
if let CrateType::ProcMacro = crate_type {
@@ -1779,25 +1814,29 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
17791814
}
17801815
}
17811816

1782-
fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1817+
fn exported_symbols_for_non_proc_macro(
1818+
tcx: TyCtxt<'_>,
1819+
crate_type: CrateType,
1820+
) -> Vec<(String, SymbolExportKind)> {
17831821
let mut symbols = Vec::new();
17841822
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
17851823
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
17861824
// Do not export mangled symbols from cdylibs and don't attempt to export compiler-builtins
17871825
// from any cdylib. The latter doesn't work anyway as we use hidden visibility for
17881826
// compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning.
17891827
if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
1790-
symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
1791-
tcx, symbol, cnum,
1828+
symbols.push((
1829+
symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1830+
info.kind,
17921831
));
1793-
symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
1832+
symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, info, cnum);
17941833
}
17951834
});
17961835

17971836
symbols
17981837
}
17991838

1800-
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
1839+
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
18011840
// `exported_symbols` will be empty when !should_codegen.
18021841
if !tcx.sess.opts.output_types.should_codegen() {
18031842
return Vec::new();
@@ -1807,7 +1846,10 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
18071846
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
18081847
let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
18091848

1810-
vec![proc_macro_decls_name, metadata_symbol_name]
1849+
vec![
1850+
(proc_macro_decls_name, SymbolExportKind::Text),
1851+
(metadata_symbol_name, SymbolExportKind::Text),
1852+
]
18111853
}
18121854

18131855
pub(crate) fn linked_symbols(
@@ -1829,7 +1871,9 @@ pub(crate) fn linked_symbols(
18291871
|| info.used
18301872
{
18311873
symbols.push((
1832-
symbol_export::linking_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1874+
symbol_export::linking_symbol_name_for_instance_in_crate(
1875+
tcx, symbol, info.kind, cnum,
1876+
),
18331877
info.kind,
18341878
));
18351879
}
@@ -1904,7 +1948,13 @@ impl<'a> Linker for PtxLinker<'a> {
19041948

19051949
fn ehcont_guard(&mut self) {}
19061950

1907-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
1951+
fn export_symbols(
1952+
&mut self,
1953+
_tmpdir: &Path,
1954+
_crate_type: CrateType,
1955+
_symbols: &[(String, SymbolExportKind)],
1956+
) {
1957+
}
19081958

19091959
fn subsystem(&mut self, _subsystem: &str) {}
19101960

@@ -1973,10 +2023,15 @@ impl<'a> Linker for LlbcLinker<'a> {
19732023

19742024
fn ehcont_guard(&mut self) {}
19752025

1976-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
2026+
fn export_symbols(
2027+
&mut self,
2028+
_tmpdir: &Path,
2029+
_crate_type: CrateType,
2030+
symbols: &[(String, SymbolExportKind)],
2031+
) {
19772032
match _crate_type {
19782033
CrateType::Cdylib => {
1979-
for sym in symbols {
2034+
for (sym, _) in symbols {
19802035
self.link_args(&["--export-symbol", sym]);
19812036
}
19822037
}
@@ -2050,11 +2105,16 @@ impl<'a> Linker for BpfLinker<'a> {
20502105

20512106
fn ehcont_guard(&mut self) {}
20522107

2053-
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
2108+
fn export_symbols(
2109+
&mut self,
2110+
tmpdir: &Path,
2111+
_crate_type: CrateType,
2112+
symbols: &[(String, SymbolExportKind)],
2113+
) {
20542114
let path = tmpdir.join("symbols");
20552115
let res: io::Result<()> = try {
20562116
let mut f = File::create_buffered(&path)?;
2057-
for sym in symbols {
2117+
for (sym, _) in symbols {
20582118
writeln!(f, "{sym}")?;
20592119
}
20602120
};

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

+7-4
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ fn calling_convention_for_symbol<'tcx>(
645645
pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
646646
tcx: TyCtxt<'tcx>,
647647
symbol: ExportedSymbol<'tcx>,
648+
export_kind: SymbolExportKind,
648649
instantiating_crate: CrateNum,
649650
) -> String {
650651
let mut undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
@@ -665,8 +666,9 @@ pub(crate) fn linking_symbol_name_for_instance_in_crate<'tcx>(
665666
let prefix = match &target.arch[..] {
666667
"x86" => Some('_'),
667668
"x86_64" => None,
668-
"arm64ec" => Some('#'),
669-
// Only x86/64 use symbol decorations.
669+
// Only functions are decorated for arm64ec.
670+
"arm64ec" if export_kind == SymbolExportKind::Text => Some('#'),
671+
// Only x86/64 and arm64ec use symbol decorations.
670672
_ => return undecorated,
671673
};
672674

@@ -706,9 +708,10 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>(
706708
/// Add it to the symbols list for all kernel functions, so that it is exported in the linked
707709
/// object.
708710
pub(crate) fn extend_exported_symbols<'tcx>(
709-
symbols: &mut Vec<String>,
711+
symbols: &mut Vec<(String, SymbolExportKind)>,
710712
tcx: TyCtxt<'tcx>,
711713
symbol: ExportedSymbol<'tcx>,
714+
info: SymbolExportInfo,
712715
instantiating_crate: CrateNum,
713716
) {
714717
let (conv, _) = calling_convention_for_symbol(tcx, symbol);
@@ -720,7 +723,7 @@ pub(crate) fn extend_exported_symbols<'tcx>(
720723
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
721724

722725
// Add the symbol for the kernel descriptor (with .kd suffix)
723-
symbols.push(format!("{undecorated}.kd"));
726+
symbols.push((format!("{undecorated}.kd"), info.kind));
724727
}
725728

726729
fn maybe_emutls_symbol_name<'tcx>(

0 commit comments

Comments
 (0)