Skip to content

Commit 3dadabc

Browse files
Auto merge of #142568 - bjorn3:windows_symbols_o_export, r=<try>
Use the .drectve section for exporting symbols from dlls on Windows While it would be reasonable to expect the Windows linker to handle linker args in the .drectve section identical to cli arguments, as it turns out exporting weak symbols only works when the /EXPORT is in the .drectve section, not when it is a linker argument or when a .DEF file is used. Necessary for and extracted out of #142366. Thanks `@dpaoliello` for figuring out this weird quirk of link.exe! try-job: x86_64-msvc-1 try-job: x86_64-msvc-2
2 parents d9ca9bd + c353c7d commit 3dadabc

File tree

4 files changed

+118
-47
lines changed

4 files changed

+118
-47
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1976,9 +1976,10 @@ fn add_linked_symbol_object(
19761976
cmd: &mut dyn Linker,
19771977
sess: &Session,
19781978
tmpdir: &Path,
1979-
symbols: &[(String, SymbolExportKind)],
1979+
linked_symbols: &[(String, SymbolExportKind)],
1980+
exported_symbols: &[(String, SymbolExportKind)],
19801981
) {
1981-
if symbols.is_empty() {
1982+
if linked_symbols.is_empty() {
19821983
return;
19831984
}
19841985

@@ -2015,7 +2016,7 @@ fn add_linked_symbol_object(
20152016
None
20162017
};
20172018

2018-
for (sym, kind) in symbols.iter() {
2019+
for (sym, kind) in linked_symbols.iter() {
20192020
let symbol = file.add_symbol(object::write::Symbol {
20202021
name: sym.clone().into(),
20212022
value: 0,
@@ -2073,6 +2074,29 @@ fn add_linked_symbol_object(
20732074
}
20742075
}
20752076

2077+
if sess.target.is_like_msvc {
2078+
// Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
2079+
// export symbols from a dynamic library. When building a dynamic library,
2080+
// however, we're going to want some symbols exported, so this adds a
2081+
// `.drectve` section which lists all the symbols using /EXPORT arguments.
2082+
//
2083+
// The linker will read these arguments from the `.drectve` section and
2084+
// export all the symbols from the dynamic library. Note that this is not
2085+
// as simple as just exporting all the symbols in the current crate (as
2086+
// specified by `codegen.reachable`) but rather we also need to possibly
2087+
// export the symbols of upstream crates. Upstream rlibs may be linked
2088+
// statically to this dynamic library, in which case they may continue to
2089+
// transitively be used and hence need their symbols exported.
2090+
let drectve = exported_symbols
2091+
.into_iter()
2092+
.map(|(sym, _kind)| format!(" /EXPORT:\"{sym}\""))
2093+
.collect::<Vec<_>>()
2094+
.join("");
2095+
2096+
let section = file.add_section(vec![], b".drectve".to_vec(), object::SectionKind::Linker);
2097+
file.append_section_data(section, drectve.as_bytes(), 1);
2098+
}
2099+
20762100
let path = tmpdir.join("symbols.o");
20772101
let result = std::fs::write(&path, file.write().unwrap());
20782102
if let Err(error) = result {
@@ -2248,6 +2272,7 @@ fn linker_with_args(
22482272
sess,
22492273
tmpdir,
22502274
&codegen_results.crate_info.linked_symbols[&crate_type],
2275+
&codegen_results.crate_info.exported_symbols[&crate_type],
22512276
);
22522277

22532278
// Sanitizer libraries.

compiler/rustc_codegen_ssa/src/back/linker.rs

Lines changed: 87 additions & 41 deletions
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,7 +824,7 @@ 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, _) in symbols {
818828
debug!(" _{symbol}");
819829
// Quote the name in case it's reserved by linker in some way
820830
// (this accounts for names with dots in particular).
@@ -831,7 +841,7 @@ impl<'a> Linker for GccLinker<'a> {
831841
writeln!(f, "{{")?;
832842
if !symbols.is_empty() {
833843
writeln!(f, " global:")?;
834-
for sym in symbols {
844+
for (sym, _) in symbols {
835845
debug!(" {sym};");
836846
writeln!(f, " {sym};")?;
837847
}
@@ -1086,19 +1096,15 @@ impl<'a> Linker for MsvcLinker<'a> {
10861096
}
10871097
}
10881098

1089-
// Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
1090-
// export symbols from a dynamic library. When building a dynamic library,
1091-
// however, we're going to want some symbols exported, so this function
1092-
// generates a DEF file which lists all the symbols.
1093-
//
1094-
// The linker will read this `*.def` file and export all the symbols from
1095-
// the dynamic library. Note that this is not as simple as just exporting
1096-
// all the symbols in the current crate (as specified by `codegen.reachable`)
1097-
// but rather we also need to possibly export the symbols of upstream
1098-
// crates. Upstream rlibs may be linked statically to this dynamic library,
1099-
// in which case they may continue to transitively be used and hence need
1100-
// their symbols exported.
1101-
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
1099+
fn export_symbols(
1100+
&mut self,
1101+
tmpdir: &Path,
1102+
crate_type: CrateType,
1103+
_symbols: &[(String, SymbolExportKind)],
1104+
) {
1105+
// We already add /EXPORT arguments to the .drectve section of symbols.o. We generate
1106+
// a .DEF file here anyway as it might prevent auto-export of some symbols.
1107+
11021108
// Symbol visibility takes care of this typically
11031109
if crate_type == CrateType::Executable {
11041110
let should_export_executable_symbols =
@@ -1116,10 +1122,6 @@ impl<'a> Linker for MsvcLinker<'a> {
11161122
// straight to exports.
11171123
writeln!(f, "LIBRARY")?;
11181124
writeln!(f, "EXPORTS")?;
1119-
for symbol in symbols {
1120-
debug!(" _{symbol}");
1121-
writeln!(f, " {symbol}")?;
1122-
}
11231125
};
11241126
if let Err(error) = res {
11251127
self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error });
@@ -1259,14 +1261,19 @@ impl<'a> Linker for EmLinker<'a> {
12591261
self.cc_arg("-nodefaultlibs");
12601262
}
12611263

1262-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1264+
fn export_symbols(
1265+
&mut self,
1266+
_tmpdir: &Path,
1267+
_crate_type: CrateType,
1268+
symbols: &[(String, SymbolExportKind)],
1269+
) {
12631270
debug!("EXPORTED SYMBOLS:");
12641271

12651272
self.cc_arg("-s");
12661273

12671274
let mut arg = OsString::from("EXPORTED_FUNCTIONS=");
12681275
let encoded = serde_json::to_string(
1269-
&symbols.iter().map(|sym| "_".to_owned() + sym).collect::<Vec<_>>(),
1276+
&symbols.iter().map(|(sym, _)| "_".to_owned() + sym).collect::<Vec<_>>(),
12701277
)
12711278
.unwrap();
12721279
debug!("{encoded}");
@@ -1428,8 +1435,13 @@ impl<'a> Linker for WasmLd<'a> {
14281435

14291436
fn no_default_libraries(&mut self) {}
14301437

1431-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1432-
for sym in symbols {
1438+
fn export_symbols(
1439+
&mut self,
1440+
_tmpdir: &Path,
1441+
_crate_type: CrateType,
1442+
symbols: &[(String, SymbolExportKind)],
1443+
) {
1444+
for (sym, _) in symbols {
14331445
self.link_args(&["--export", sym]);
14341446
}
14351447

@@ -1563,7 +1575,7 @@ impl<'a> Linker for L4Bender<'a> {
15631575
self.cc_arg("-nostdlib");
15641576
}
15651577

1566-
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) {
1578+
fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[(String, SymbolExportKind)]) {
15671579
// ToDo, not implemented, copy from GCC
15681580
self.sess.dcx().emit_warn(errors::L4BenderExportingSymbolsUnimplemented);
15691581
}
@@ -1720,12 +1732,17 @@ impl<'a> Linker for AixLinker<'a> {
17201732

17211733
fn no_default_libraries(&mut self) {}
17221734

1723-
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
1735+
fn export_symbols(
1736+
&mut self,
1737+
tmpdir: &Path,
1738+
_crate_type: CrateType,
1739+
symbols: &[(String, SymbolExportKind)],
1740+
) {
17241741
let path = tmpdir.join("list.exp");
17251742
let res: io::Result<()> = try {
17261743
let mut f = File::create_buffered(&path)?;
17271744
// FIXME: use llvm-nm to generate export list.
1728-
for symbol in symbols {
1745+
for (symbol, _) in symbols {
17291746
debug!(" _{symbol}");
17301747
writeln!(f, " {symbol}")?;
17311748
}
@@ -1769,9 +1786,15 @@ fn for_each_exported_symbols_include_dep<'tcx>(
17691786
}
17701787
}
17711788

1772-
pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1789+
pub(crate) fn exported_symbols(
1790+
tcx: TyCtxt<'_>,
1791+
crate_type: CrateType,
1792+
) -> Vec<(String, SymbolExportKind)> {
17731793
if let Some(ref exports) = tcx.sess.target.override_export_symbols {
1774-
return exports.iter().map(ToString::to_string).collect();
1794+
return exports
1795+
.iter()
1796+
.map(|sym| (sym.to_string(), SymbolExportKind::Text /* FIXME */))
1797+
.collect();
17751798
}
17761799

17771800
if let CrateType::ProcMacro = crate_type {
@@ -1781,16 +1804,20 @@ pub(crate) fn exported_symbols(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<St
17811804
}
17821805
}
17831806

1784-
fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -> Vec<String> {
1807+
fn exported_symbols_for_non_proc_macro(
1808+
tcx: TyCtxt<'_>,
1809+
crate_type: CrateType,
1810+
) -> Vec<(String, SymbolExportKind)> {
17851811
let mut symbols = Vec::new();
17861812
let export_threshold = symbol_export::crates_export_threshold(&[crate_type]);
17871813
for_each_exported_symbols_include_dep(tcx, crate_type, |symbol, info, cnum| {
17881814
// Do not export mangled symbols from cdylibs and don't attempt to export compiler-builtins
17891815
// from any cdylib. The latter doesn't work anyway as we use hidden visibility for
17901816
// compiler-builtins. Most linkers silently ignore it, but ld64 gives a warning.
17911817
if info.level.is_below_threshold(export_threshold) && !tcx.is_compiler_builtins(cnum) {
1792-
symbols.push(symbol_export::exporting_symbol_name_for_instance_in_crate(
1793-
tcx, symbol, cnum,
1818+
symbols.push((
1819+
symbol_export::exporting_symbol_name_for_instance_in_crate(tcx, symbol, cnum),
1820+
info.kind,
17941821
));
17951822
symbol_export::extend_exported_symbols(&mut symbols, tcx, symbol, cnum);
17961823
}
@@ -1799,7 +1826,7 @@ fn exported_symbols_for_non_proc_macro(tcx: TyCtxt<'_>, crate_type: CrateType) -
17991826
symbols
18001827
}
18011828

1802-
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
1829+
fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<(String, SymbolExportKind)> {
18031830
// `exported_symbols` will be empty when !should_codegen.
18041831
if !tcx.sess.opts.output_types.should_codegen() {
18051832
return Vec::new();
@@ -1809,7 +1836,10 @@ fn exported_symbols_for_proc_macro_crate(tcx: TyCtxt<'_>) -> Vec<String> {
18091836
let proc_macro_decls_name = tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id);
18101837
let metadata_symbol_name = exported_symbols::metadata_symbol_name(tcx);
18111838

1812-
vec![proc_macro_decls_name, metadata_symbol_name]
1839+
vec![
1840+
(proc_macro_decls_name, SymbolExportKind::Data),
1841+
(metadata_symbol_name, SymbolExportKind::Data),
1842+
]
18131843
}
18141844

18151845
pub(crate) fn linked_symbols(
@@ -1906,7 +1936,13 @@ impl<'a> Linker for PtxLinker<'a> {
19061936

19071937
fn ehcont_guard(&mut self) {}
19081938

1909-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, _symbols: &[String]) {}
1939+
fn export_symbols(
1940+
&mut self,
1941+
_tmpdir: &Path,
1942+
_crate_type: CrateType,
1943+
_symbols: &[(String, SymbolExportKind)],
1944+
) {
1945+
}
19101946

19111947
fn subsystem(&mut self, _subsystem: &str) {}
19121948

@@ -1975,10 +2011,15 @@ impl<'a> Linker for LlbcLinker<'a> {
19752011

19762012
fn ehcont_guard(&mut self) {}
19772013

1978-
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
2014+
fn export_symbols(
2015+
&mut self,
2016+
_tmpdir: &Path,
2017+
_crate_type: CrateType,
2018+
symbols: &[(String, SymbolExportKind)],
2019+
) {
19792020
match _crate_type {
19802021
CrateType::Cdylib => {
1981-
for sym in symbols {
2022+
for (sym, _) in symbols {
19822023
self.link_args(&["--export-symbol", sym]);
19832024
}
19842025
}
@@ -2052,11 +2093,16 @@ impl<'a> Linker for BpfLinker<'a> {
20522093

20532094
fn ehcont_guard(&mut self) {}
20542095

2055-
fn export_symbols(&mut self, tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) {
2096+
fn export_symbols(
2097+
&mut self,
2098+
tmpdir: &Path,
2099+
_crate_type: CrateType,
2100+
symbols: &[(String, SymbolExportKind)],
2101+
) {
20562102
let path = tmpdir.join("symbols");
20572103
let res: io::Result<()> = try {
20582104
let mut f = File::create_buffered(&path)?;
2059-
for sym in symbols {
2105+
for (sym, _) in symbols {
20602106
writeln!(f, "{sym}")?;
20612107
}
20622108
};

compiler/rustc_codegen_ssa/src/back/symbol_export.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,7 @@ pub(crate) fn exporting_symbol_name_for_instance_in_crate<'tcx>(
753753
/// Add it to the symbols list for all kernel functions, so that it is exported in the linked
754754
/// object.
755755
pub(crate) fn extend_exported_symbols<'tcx>(
756-
symbols: &mut Vec<String>,
756+
symbols: &mut Vec<(String, SymbolExportKind)>,
757757
tcx: TyCtxt<'tcx>,
758758
symbol: ExportedSymbol<'tcx>,
759759
instantiating_crate: CrateNum,
@@ -767,7 +767,7 @@ pub(crate) fn extend_exported_symbols<'tcx>(
767767
let undecorated = symbol_name_for_instance_in_crate(tcx, symbol, instantiating_crate);
768768

769769
// Add the symbol for the kernel descriptor (with .kd suffix)
770-
symbols.push(format!("{undecorated}.kd"));
770+
symbols.push((format!("{undecorated}.kd"), SymbolExportKind::Data));
771771
}
772772

773773
fn maybe_emutls_symbol_name<'tcx>(

compiler/rustc_codegen_ssa/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ pub struct CrateInfo {
218218
pub target_cpu: String,
219219
pub target_features: Vec<String>,
220220
pub crate_types: Vec<CrateType>,
221-
pub exported_symbols: UnordMap<CrateType, Vec<String>>,
221+
pub exported_symbols: UnordMap<CrateType, Vec<(String, SymbolExportKind)>>,
222222
pub linked_symbols: FxIndexMap<CrateType, Vec<(String, SymbolExportKind)>>,
223223
pub local_crate_name: Symbol,
224224
pub compiler_builtins: Option<CrateNum>,

0 commit comments

Comments
 (0)