From 6674c94d15e8bdf2d6d3d53d73acb28bd0b10c36 Mon Sep 17 00:00:00 2001
From: csmoe <csmoe@msn.com>
Date: Mon, 25 Jul 2022 05:20:23 +0000
Subject: [PATCH] feat: impl export-executable-symbols

---
 compiler/rustc_codegen_ssa/src/back/link.rs     |  7 ++++++-
 compiler/rustc_codegen_ssa/src/back/linker.rs   | 17 +++++++++++++----
 compiler/rustc_interface/src/tests.rs           |  1 +
 compiler/rustc_session/src/options.rs           |  2 ++
 .../run-make/export-executable-symbols/Makefile | 11 +++++++++++
 .../run-make/export-executable-symbols/main.rs  |  8 ++++++++
 src/test/rustdoc-ui/z-help.stdout               |  1 +
 7 files changed, 42 insertions(+), 5 deletions(-)
 create mode 100644 src/test/run-make/export-executable-symbols/Makefile
 create mode 100644 src/test/run-make/export-executable-symbols/main.rs

diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index 878a670cba3ef..48d24ecf41280 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -2082,7 +2082,12 @@ fn add_order_independent_options(
         // sections to ensure we have all the data for PGO.
         let keep_metadata =
             crate_type == CrateType::Dylib || sess.opts.cg.profile_generate.enabled();
-        cmd.gc_sections(keep_metadata);
+        if crate_type != CrateType::Executable || !sess.opts.unstable_opts.export_executable_symbols
+        {
+            cmd.gc_sections(keep_metadata);
+        } else {
+            cmd.no_gc_sections();
+        }
     }
 
     cmd.set_output_kind(link_output_kind, out_filename);
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index d4a9db4af23a2..8e5ac9da4ac50 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -640,9 +640,14 @@ impl<'a> Linker for GccLinker<'a> {
 
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
         // Symbol visibility in object files typically takes care of this.
-        if crate_type == CrateType::Executable && self.sess.target.override_export_symbols.is_none()
-        {
-            return;
+        if crate_type == CrateType::Executable {
+            let should_export_executable_symbols =
+                self.sess.opts.unstable_opts.export_executable_symbols;
+            if self.sess.target.override_export_symbols.is_none()
+                && !should_export_executable_symbols
+            {
+                return;
+            }
         }
 
         // We manually create a list of exported symbols to ensure we don't expose any more.
@@ -969,7 +974,11 @@ impl<'a> Linker for MsvcLinker<'a> {
     fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType, symbols: &[String]) {
         // Symbol visibility takes care of this typically
         if crate_type == CrateType::Executable {
-            return;
+            let should_export_executable_symbols =
+                self.sess.opts.unstable_opts.export_executable_symbols;
+            if !should_export_executable_symbols {
+                return;
+            }
         }
 
         let path = tmpdir.join("lib.def");
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index d07e17f679251..0a0eb99cd9266 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -733,6 +733,7 @@ fn test_unstable_options_tracking_hash() {
     tracked!(debug_macros, true);
     tracked!(dep_info_omit_d_target, true);
     tracked!(drop_tracking, true);
+    tracked!(export_executable_symbols, true);
     tracked!(dual_proc_macros, true);
     tracked!(dwarf_version, Some(5));
     tracked!(emit_thin_lto, false);
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 1b583417ca089..28e2e0db89a1f 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -1282,6 +1282,8 @@ options! {
         "emit a section containing stack size metadata (default: no)"),
     emit_thin_lto: bool = (true, parse_bool, [TRACKED],
         "emit the bc module with thin LTO info (default: yes)"),
+    export_executable_symbols: bool = (false, parse_bool, [TRACKED],
+        "export symbols from executables, as if they were dynamic libraries"),
     fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
         "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
         (default: no)"),
diff --git a/src/test/run-make/export-executable-symbols/Makefile b/src/test/run-make/export-executable-symbols/Makefile
new file mode 100644
index 0000000000000..5006f9cb8cfea
--- /dev/null
+++ b/src/test/run-make/export-executable-symbols/Makefile
@@ -0,0 +1,11 @@
+-include ../../run-make-fulldeps/tools.mk
+
+# ignore-wasm32
+# ignore-wasm64
+# ignore-none no-std is not supported
+# only-linux
+
+all:
+	$(RUSTC) -Zexport-executable-symbols  main.rs --target $(TARGET) --crate-type=bin
+	nm $(TMPDIR)/main | $(CGREP) exported_symbol
+
diff --git a/src/test/run-make/export-executable-symbols/main.rs b/src/test/run-make/export-executable-symbols/main.rs
new file mode 100644
index 0000000000000..c498381a33f64
--- /dev/null
+++ b/src/test/run-make/export-executable-symbols/main.rs
@@ -0,0 +1,8 @@
+// edition:2018
+
+fn main() {}
+
+#[no_mangle]
+pub fn exported_symbol() -> i8 {
+    42
+}
diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout
index bcf323e1cab89..86e42440bd0bc 100644
--- a/src/test/rustdoc-ui/z-help.stdout
+++ b/src/test/rustdoc-ui/z-help.stdout
@@ -37,6 +37,7 @@
     -Z                           dwarf-version=val -- version of DWARF debug information to emit (default: 2 or 4, depending on platform)
     -Z                        emit-stack-sizes=val -- emit a section containing stack size metadata (default: no)
     -Z                           emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes)
+    -Z               export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries
     -Z                             fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no)
     -Z              force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no)
     -Z                                    fuel=val -- set the optimization fuel quota for a crate