Skip to content

Commit fb4a3ff

Browse files
Rollup merge of rust-lang#158294 - AsakuraMizu:windows-drectve-export, r=oli-obk
Use .drectve for MSVC DLL exports This is a continuation of rust-lang#142568. This fixes the i686 MSVC issue mentioned there: `.def` files accept undecorated names, but `.drectve` `/EXPORT` needs decorated symbol names. The public export name is preserved with `EXPORTAS`. It's worth noting that EII with defaults now also works on MSVC.
2 parents df75cf3 + 4051560 commit fb4a3ff

6 files changed

Lines changed: 182 additions & 140 deletions

File tree

compiler/rustc_codegen_ssa/src/back/link.rs

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ use super::metadata::{MetadataPosition, create_wrapper_file};
6262
use super::rpath::{self, RPathConfig};
6363
use super::{apple, rmeta_link, versioned_llvm_target};
6464
use crate::base::needs_allocator_shim_for_linking;
65-
use crate::{CodegenLintLevelSpecs, CompiledModule, CompiledModules, CrateInfo, NativeLib, errors};
65+
use crate::{
66+
CodegenLintLevelSpecs, CompiledModule, CompiledModules, CrateInfo, NativeLib, SymbolExport,
67+
errors,
68+
};
6669

6770
pub fn ensure_removed(dcx: DiagCtxtHandle<'_>, path: &Path) {
6871
if let Err(e) = fs::remove_file(path) {
@@ -588,7 +591,7 @@ fn link_staticlib(
588591
crate_info
589592
.exported_symbols
590593
.get(&CrateType::StaticLib)
591-
.map(|symbols| symbols.iter().map(|(s, _)| s.clone()).collect())
594+
.map(|symbols| symbols.iter().map(|symbol| symbol.name.clone()).collect())
592595
}
593596
} else {
594597
None
@@ -2189,9 +2192,15 @@ fn add_linked_symbol_object(
21892192
cmd: &mut dyn Linker,
21902193
sess: &Session,
21912194
tmpdir: &Path,
2192-
symbols: &[(String, SymbolExportKind)],
2195+
crate_type: CrateType,
2196+
linked_symbols: &[(String, SymbolExportKind)],
2197+
exported_symbols: &[SymbolExport],
21932198
) {
2194-
if symbols.is_empty() {
2199+
let should_export_symbols = sess.target.is_like_msvc
2200+
&& !exported_symbols.is_empty()
2201+
&& (crate_type != CrateType::Executable
2202+
|| sess.opts.unstable_opts.export_executable_symbols);
2203+
if linked_symbols.is_empty() && !should_export_symbols {
21952204
return;
21962205
}
21972206

@@ -2228,7 +2237,7 @@ fn add_linked_symbol_object(
22282237
None
22292238
};
22302239

2231-
for (sym, kind) in symbols.iter() {
2240+
for (sym, kind) in linked_symbols.iter() {
22322241
let symbol = file.add_symbol(object::write::Symbol {
22332242
name: sym.clone().into(),
22342243
value: 0,
@@ -2286,6 +2295,37 @@ fn add_linked_symbol_object(
22862295
}
22872296
}
22882297

2298+
if should_export_symbols {
2299+
// Currently the compiler doesn't use `dllexport` (an LLVM attribute) to
2300+
// export symbols from a dynamic library. When building a dynamic library,
2301+
// however, we're going to want some symbols exported, so this adds a
2302+
// `.drectve` section which lists all the symbols using /EXPORT arguments.
2303+
//
2304+
// The linker will read these arguments from the `.drectve` section and
2305+
// export all the symbols from the dynamic library. Note that this is not
2306+
// as simple as just exporting all the symbols in the current crate (as
2307+
// specified by `codegen.reachable`) but rather we also need to possibly
2308+
// export the symbols of upstream crates. Upstream rlibs may be linked
2309+
// statically to this dynamic library, in which case they may continue to
2310+
// transitively be used and hence need their symbols exported.
2311+
fn msvc_drectve_export(symbol: &SymbolExport) -> String {
2312+
let data = if symbol.kind == SymbolExportKind::Data { ",DATA" } else { "" };
2313+
2314+
if let Some(link_name) = symbol.link_name.as_deref() {
2315+
// The first name is the decorated symbol used by the import library, while
2316+
// EXPORTAS gives the public name written to the DLL export table.
2317+
format!(" /EXPORT:\"{link_name}\"{data},EXPORTAS,\"{}\"", symbol.name)
2318+
} else {
2319+
format!(" /EXPORT:\"{}\"{data}", symbol.name)
2320+
}
2321+
}
2322+
2323+
let drectve = exported_symbols.iter().map(msvc_drectve_export).collect::<String>();
2324+
2325+
let section = file.add_section(vec![], b".drectve".to_vec(), object::SectionKind::Linker);
2326+
file.append_section_data(section, drectve.as_bytes(), 1);
2327+
}
2328+
22892329
let path = tmpdir.join("symbols.o");
22902330
let result = std::fs::write(&path, file.write().unwrap());
22912331
if let Err(error) = result {
@@ -2416,7 +2456,7 @@ fn add_rpath_args(
24162456
fn add_c_staticlib_symbols(
24172457
sess: &Session,
24182458
lib: &NativeLib,
2419-
out: &mut Vec<(String, SymbolExportKind)>,
2459+
out: &mut Vec<SymbolExport>,
24202460
) -> io::Result<()> {
24212461
let file_path = find_native_static_library(lib.name.as_str(), lib.verbatim, sess);
24222462

@@ -2469,9 +2509,9 @@ fn add_c_staticlib_symbols(
24692509
_ => continue,
24702510
};
24712511

2472-
// FIXME:The symbol mangle rules are slightly different in Windows(32-bit) and Apple.
2473-
// Need to be resolved.
2474-
out.push((name.to_string(), export_kind));
2512+
// Names read from the object file are already linker-visible.
2513+
// Do not apply symbol decoration again here.
2514+
out.push(SymbolExport::new(name.to_string(), export_kind));
24752515
}
24762516
}
24772517

@@ -2550,7 +2590,14 @@ fn linker_with_args(
25502590
// Pre-link CRT objects.
25512591
add_pre_link_objects(cmd, sess, flavor, link_output_kind, self_contained_crt_objects);
25522592

2553-
add_linked_symbol_object(cmd, sess, tmpdir, &crate_info.linked_symbols[&crate_type]);
2593+
add_linked_symbol_object(
2594+
cmd,
2595+
sess,
2596+
tmpdir,
2597+
crate_type,
2598+
&crate_info.linked_symbols[&crate_type],
2599+
&export_symbols,
2600+
);
25542601

25552602
// Sanitizer libraries.
25562603
add_sanitizer_libraries(sess, flavor, crate_type, cmd);

0 commit comments

Comments
 (0)