Repository: davidlattimore/wild (rust)

Issue:
--export-dynamic: thread 'main' panicked at libwild/src/layout.rs:289:14:
@mati865 I noticed the following panic in one of the Mold tests after 0c5cd7e74bdcec6ee815fb5bff3fac8e601dd217:
```
$ cp ~/Programming/wild/ld mold && ../test/export-dynamic.sh
...
+ ./mold -o out/test/x86_64/export-dynamic/exe out/test/x86_64/export-dynamic/a.o out/test/x86_64/export-dynamic/b.so --export-dynamic

thread 'main' panicked at libwild/src/layout.rs:289:14:
Dynamic symbol definitions should start > 0: TryFromIntError(())
```

Pull request description:
Output dynamic executable when the executable depends on shared objects
Fixes #836

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 26d8f70..c54f578 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -8,7 +8,7 @@ version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
 dependencies = [
- "gimli",
+ "gimli 0.31.1",
 ]
 
 [[package]]
@@ -296,7 +296,7 @@ version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "fde0e0ec90c9dfb3b4b1a0891a7dcd0e2bffde2f7efed5fe7c9bb00e5bfb915e"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -449,7 +449,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
 dependencies = [
  "libc",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -472,7 +472,7 @@ checksum = "0ce92ff622d6dadf7349484f42c93271a0d49b7cc4d466a936405bacbe10aa78"
 dependencies = [
  "cfg-if",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -552,6 +552,12 @@ name = "gimli"
 version = "0.31.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
+
+[[package]]
+name = "gimli"
+version = "0.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe"
 dependencies = [
  "fallible-iterator",
  "indexmap",
@@ -716,7 +722,7 @@ dependencies = [
  "crossbeam-utils",
  "flate2",
  "foldhash",
- "gimli",
+ "gimli 0.32.0",
  "hashbrown",
  "hex",
  "itertools",
@@ -758,7 +764,7 @@ dependencies = [
  "clap",
  "colored",
  "fallible-iterator",
- "gimli",
+ "gimli 0.32.0",
  "iced-x86",
  "itertools",
  "linker-layout",
@@ -1184,7 +1190,7 @@ dependencies = [
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1386,7 +1392,7 @@ dependencies = [
  "getrandom",
  "once_cell",
  "rustix",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
diff --git a/Cargo.toml b/Cargo.toml
index cc47289..d286e18 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -37,7 +37,7 @@ fallible-iterator = "0.3.0"
 fd-lock = "4.0.0"
 flate2 = { version = "1.1.0", features = ["zlib-rs"] }
 foldhash = "0.1.0"
-gimli = "0.31.0"
+gimli = "0.32.0"
 hashbrown = "0.15.1"
 hex = "0.4.0"
 iced-x86 = { version = "1.17.0", default-features = false, features = [
diff --git a/libwild/src/aarch64.rs b/libwild/src/aarch64.rs
index 29edda7..8b2ea81 100644
--- a/libwild/src/aarch64.rs
+++ b/libwild/src/aarch64.rs
@@ -4,6 +4,7 @@ use crate::ensure;
 use crate::error;
 use crate::error::Result;
 use crate::layout::Layout;
+use crate::layout::PropertyClass;
 use linker_utils::aarch64::DEFAULT_AARCH64_PAGE_IGNORED_MASK;
 use linker_utils::aarch64::DEFAULT_AARCH64_PAGE_MASK;
 use linker_utils::aarch64::DEFAULT_AARCH64_PAGE_SIZE;
@@ -16,6 +17,7 @@ use linker_utils::elf::RelocationKindInfo;
 use linker_utils::elf::aarch64_rel_type_to_string;
 use linker_utils::elf::shf;
 use linker_utils::relaxation::RelocationModifier;
+use object::elf::GNU_PROPERTY_AARCH64_FEATURE_1_AND;
 
 pub(crate) struct AArch64;
 
@@ -92,6 +94,13 @@ impl crate::arch::Arch for AArch64 {
     fn tp_offset_start(layout: &Layout<'_>) -> u64 {
         layout.tls_start_address_aarch64()
     }
+
+    fn get_property_class(property_type: u32) -> Option<PropertyClass> {
+        match property_type {
+            GNU_PROPERTY_AARCH64_FEATURE_1_AND => Some(PropertyClass::And),
+            _ => None,
+        }
+    }
 }
 
 #[derive(Debug, Clone)]
diff --git a/libwild/src/arch.rs b/libwild/src/arch.rs
index e0ca55d..e010b9a 100644
--- a/libwild/src/arch.rs
+++ b/libwild/src/arch.rs
@@ -4,6 +4,7 @@ use crate::args::OutputKind;
 use crate::bail;
 use crate::error::Result;
 use crate::layout::Layout;
+use crate::layout::PropertyClass;
 use crate::resolution::ValueFlags;
 use linker_utils::elf::DynamicRelocationKind;
 use linker_utils::elf::RelocationKindInfo;
@@ -45,6 +46,9 @@ pub(crate) trait Arch {
     // a different place based on the following article:
     // https://maskray.me/blog/2021-02-14-all-about-thread-local-storage#tls-variants
     fn tp_offset_start(layout: &Layout) -> u64;
+
+    // Classify a GNU property note.
+    fn get_property_class(property_type: u32) -> Option<PropertyClass>;
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
diff --git a/libwild/src/args.rs b/libwild/src/args.rs
index e2216e6..68aaca9 100644
--- a/libwild/src/args.rs
+++ b/libwild/src/args.rs
@@ -27,7 +27,9 @@ use std::path::Path;
 use std::path::PathBuf;
 use std::str::FromStr;
 use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
 use std::sync::atomic::AtomicI64;
+use std::sync::atomic::Ordering;
 
 pub struct Args {
     pub(crate) arch: Architecture,
@@ -88,7 +90,7 @@ pub struct Args {
     pub(crate) relax: bool,
 
     output_kind: Option<OutputKind>,
-    is_dynamic_executable: bool,
+    pub(crate) is_dynamic_executable: AtomicBool,
     relocation_model: RelocationModel,
 }
 
@@ -230,7 +232,7 @@ impl Default for Args {
             lib_search_path: Vec::new(),
             inputs: Vec::new(),
             output: Arc::from(Path::new("a.out")),
-            is_dynamic_executable: false,
+            is_dynamic_executable: AtomicBool::new(false),
             dynamic_linker: None,
             output_kind: None,
             time_phases: false,
@@ -415,10 +417,10 @@ pub(crate) fn parse<F: Fn() -> I, S: AsRef<str>, I: Iterator<Item = S>>(input: F
                 .map(|a| Arc::from(Path::new(a.as_ref())))
                 .context("Missing argument to -o")?;
         } else if long_arg_eq("dynamic-linker") {
-            args.is_dynamic_executable = true;
+            args.is_dynamic_executable.store(true, Ordering::Relaxed);
             args.dynamic_linker = input.next().map(|a| Box::from(Path::new(a.as_ref())));
         } else if let Some(rest) = long_arg_split_prefix("dynamic-linker=") {
-            args.is_dynamic_executable = true;
+            args.is_dynamic_executable.store(true, Ordering::Relaxed);
             args.dynamic_linker = Some(Box::from(Path::new(rest)));
         } else if long_arg_eq("no-dynamic-linker") {
             args.dynamic_linker = None;
@@ -794,7 +796,7 @@ impl Args {
 
     pub(crate) fn output_kind(&self) -> OutputKind {
         self.output_kind.unwrap_or({
-            if self.is_dynamic_executable {
+            if self.is_dynamic_executable.load(Ordering::Relaxed) {
                 OutputKind::DynamicExecutable(self.relocation_model)
             } else {
                 OutputKind::StaticExecutable(self.relocation_model)
diff --git a/libwild/src/layout.rs b/libwild/src/layout.rs
index 4e7aa43..84fe7a9 100644
--- a/libwild/src/layout.rs
+++ b/libwild/src/layout.rs
@@ -79,13 +79,6 @@ use linker_utils::elf::shf;
 use linker_utils::relaxation::RelocationModifier;
 use object::LittleEndian;
 use object::SectionIndex;
-use object::elf::GNU_PROPERTY_AARCH64_FEATURE_1_AND;
-use object::elf::GNU_PROPERTY_X86_UINT32_AND_HI;
-use object::elf::GNU_PROPERTY_X86_UINT32_AND_LO;
-use object::elf::GNU_PROPERTY_X86_UINT32_OR_AND_HI;
-use object::elf::GNU_PROPERTY_X86_UINT32_OR_AND_LO;
-use object::elf::GNU_PROPERTY_X86_UINT32_OR_HI;
-use object::elf::GNU_PROPERTY_X86_UINT32_OR_LO;
 use object::elf::Rela64;
 use object::elf::gnu_hash;
 use object::read::elf::Dyn as _;
@@ -145,7 +138,7 @@ pub fn compute<'data, A: Arch>(
 
     finalise_copy_relocations(&mut group_states, &symbol_db, &symbol_resolution_flags)?;
     merge_dynamic_symbol_definitions(&mut group_states)?;
-    merge_gnu_property_notes(&mut group_states)?;
+    merge_gnu_property_notes::<A>(&mut group_states)?;
 
     finalise_all_sizes(
         &symbol_db,
@@ -354,7 +347,7 @@ fn merge_dynamic_symbol_definitions(group_states: &mut [GroupState]) -> Result {
     Ok(())
 }
 
-enum PropertyClass {
+pub(crate) enum PropertyClass {
     // A bit in the output pr_data is set if it is set in any relocatable input.
     // If all bits in the output pr_data field are zero, this property should be removed from output.
     Or,
@@ -368,20 +361,8 @@ enum PropertyClass {
     AndOr,
 }
 
-fn get_property_class(property_type: u32) -> Option<PropertyClass> {
-    match property_type {
-        GNU_PROPERTY_X86_UINT32_AND_LO..=GNU_PROPERTY_X86_UINT32_AND_HI => Some(PropertyClass::And),
-        GNU_PROPERTY_AARCH64_FEATURE_1_AND => Some(PropertyClass::And),
-        GNU_PROPERTY_X86_UINT32_OR_LO..=GNU_PROPERTY_X86_UINT32_OR_HI => Some(PropertyClass::Or),
-        GNU_PROPERTY_X86_UINT32_OR_AND_LO..=GNU_PROPERTY_X86_UINT32_OR_AND_HI => {
-            Some(PropertyClass::AndOr)
-        }
-        _ => None,
-    }
-}
-
 #[tracing::instrument(skip_all, name = "Merge GNU property notes")]
-fn merge_gnu_property_notes(group_states: &mut [GroupState]) -> Result {
+fn merge_gnu_property_notes<A: Arch>(group_states: &mut [GroupState]) -> Result {
     let properties_per_file = group_states
         .iter()
         .flat_map(|group| {
@@ -395,23 +376,23 @@ fn merge_gnu_property_notes(group_states: &mut [GroupState]) -> Result {
         })
         .collect_vec();
 
-    // Merge bits of each property type based on type: OR or AND operation. When a property type
-    // is newly added to the map, we start either with zero or all bits-set (PropertyClass::And).
+    // Merge bits of each property type based on type: OR or AND operation.
     let mut property_map = HashMap::new();
+
     for file_props in &properties_per_file {
         for prop in *file_props {
-            let property_class = get_property_class(prop.ptype)
+            let property_class = A::get_property_class(prop.ptype)
                 .ok_or_else(|| crate::error!("unclassified property type {}", prop.ptype))?;
             property_map
                 .entry(prop.ptype)
-                .and_modify(|e| {
+                .and_modify(|entry: &mut (u32, PropertyClass)| {
                     if matches!(property_class, PropertyClass::And) {
-                        *e &= prop.data;
+                        entry.0 &= prop.data;
                     } else {
-                        *e |= prop.data;
+                        entry.0 |= prop.data;
                     }
                 })
-                .or_insert_with(|| prop.data);
+                .or_insert_with(|| (prop.data, property_class));
         }
     }
 
@@ -419,8 +400,7 @@ fn merge_gnu_property_notes(group_states: &mut [GroupState]) -> Result {
     let output_properties = property_map
         .into_iter()
         .sorted_by_key(|x| x.0)
-        .filter_map(|(property_type, property_value)| {
-            let property_class = get_property_class(property_type).unwrap();
+        .filter_map(|(property_type, (property_value, property_class))| {
             let type_present_in_all = properties_per_file.iter().all(|props_per_file| {
                 props_per_file
                     .iter()
@@ -3760,7 +3740,8 @@ impl<'data> ObjectLayoutState<'data> {
 
         if resources.symbol_db.args.output_kind() == OutputKind::SharedObject
             && (!resources.symbol_db.args.exclude_libs || !self.input.has_archive_semantics())
-            || resources.symbol_db.args.explicitly_export_dynamic
+            || resources.symbol_db.args.needs_dynsym()
+                && resources.symbol_db.args.explicitly_export_dynamic
         {
             self.load_non_hidden_symbols::<A>(common, resources, queue)?;
         }
diff --git a/libwild/src/lib.rs b/libwild/src/lib.rs
index 1a519a6..0ba1f41 100644
--- a/libwild/src/lib.rs
+++ b/libwild/src/lib.rs
@@ -57,6 +57,7 @@ use input_data::InputFile;
 use input_data::InputLinkerScript;
 use layout_rules::LayoutRules;
 use output_section_id::OutputSections;
+use std::sync::atomic::Ordering;
 pub use subprocess::run_in_subprocess;
 use tracing_subscriber::EnvFilter;
 use tracing_subscriber::fmt;
@@ -187,6 +188,14 @@ impl Linker {
         let inputs = archive_splitter::split_archives(input_data)?;
         let mut output_sections = OutputSections::with_base_address(args.base_address());
 
+        if args.output_kind().is_static_executable()
+            && inputs
+                .iter()
+                .any(|input| input.kind == crate::file_kind::FileKind::ElfDynamic)
+        {
+            args.is_dynamic_executable.store(true, Ordering::Relaxed);
+        }
+
         let (parsed_inputs, layout_rules) = parsing::parse_input_files(
             &inputs,
             &input_data.linker_scripts,
diff --git a/libwild/src/riscv64.rs b/libwild/src/riscv64.rs
index d7c4159..b9de088 100644
--- a/libwild/src/riscv64.rs
+++ b/libwild/src/riscv64.rs
@@ -79,6 +79,10 @@ impl crate::arch::Arch for RiscV64 {
     fn tp_offset_start(layout: &crate::layout::Layout) -> u64 {
         layout.tls_start_address()
     }
+
+    fn get_property_class(_property_type: u32) -> Option<crate::layout::PropertyClass> {
+        None
+    }
 }
 
 #[derive(Debug, Clone)]
diff --git a/libwild/src/x86_64.rs b/libwild/src/x86_64.rs
index bc327b1..e79f026 100644
--- a/libwild/src/x86_64.rs
+++ b/libwild/src/x86_64.rs
@@ -7,6 +7,7 @@ use crate::args::OutputKind;
 use crate::elf::PLT_ENTRY_SIZE;
 use crate::error;
 use crate::error::Result;
+use crate::layout::PropertyClass;
 use crate::resolution::ValueFlags;
 use linker_utils::elf::DynamicRelocationKind;
 use linker_utils::elf::RelocationKindInfo;
@@ -16,6 +17,12 @@ use linker_utils::elf::x86_64_rel_type_to_string;
 use linker_utils::relaxation::RelocationModifier;
 use linker_utils::x86_64::RelaxationKind;
 use linker_utils::x86_64::relocation_from_raw;
+use object::elf::GNU_PROPERTY_X86_UINT32_AND_HI;
+use object::elf::GNU_PROPERTY_X86_UINT32_AND_LO;
+use object::elf::GNU_PROPERTY_X86_UINT32_OR_AND_HI;
+use object::elf::GNU_PROPERTY_X86_UINT32_OR_AND_LO;
+use object::elf::GNU_PROPERTY_X86_UINT32_OR_HI;
+use object::elf::GNU_PROPERTY_X86_UINT32_OR_LO;
 
 pub(crate) struct X86_64;
 
@@ -74,6 +81,21 @@ impl crate::arch::Arch for X86_64 {
     fn tp_offset_start(layout: &crate::layout::Layout) -> u64 {
         layout.tls_end_address()
     }
+
+    fn get_property_class(property_type: u32) -> Option<crate::layout::PropertyClass> {
+        match property_type {
+            GNU_PROPERTY_X86_UINT32_AND_LO..=GNU_PROPERTY_X86_UINT32_AND_HI => {
+                Some(PropertyClass::And)
+            }
+            GNU_PROPERTY_X86_UINT32_OR_LO..=GNU_PROPERTY_X86_UINT32_OR_HI => {
+                Some(PropertyClass::Or)
+            }
+            GNU_PROPERTY_X86_UINT32_OR_AND_LO..=GNU_PROPERTY_X86_UINT32_OR_AND_HI => {
+                Some(PropertyClass::AndOr)
+            }
+            _ => None,
+        }
+    }
 }
 
 macro_rules! rel_info_from_type {


Test patch:
diff --git a/wild/tests/integration_tests.rs b/wild/tests/integration_tests.rs
index f49d47b..c5a231d 100644
--- a/wild/tests/integration_tests.rs
+++ b/wild/tests/integration_tests.rs
@@ -483,15 +483,18 @@ enum RustcChannel {
     Nightly,
 }
 
-#[derive(Clone, Copy, PartialEq, Eq)]
-struct DirectConfig {
-    is_static: bool,
+#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumString, Default)]
+#[strum(serialize_all = "snake_case")]
+enum Mode {
+    Dynamic,
+    #[default]
+    Static,
+    Unspecified,
 }
 
-impl Default for DirectConfig {
-    fn default() -> Self {
-        Self { is_static: true }
-    }
+#[derive(Clone, Copy, PartialEq, Eq, Default)]
+struct DirectConfig {
+    mode: Mode,
 }
 
 impl Config {
@@ -767,7 +770,7 @@ fn parse_configs(src_filename: &Path, test_config: &TestConfig) -> Result<Vec<Co
                     .assertions
                     .contains_strings
                     .push(arg.trim().to_owned()),
-                "Static" => config.linker_driver.direct_mut()?.is_static = arg.parse()?,
+                "Mode" => config.linker_driver.direct_mut()?.mode = arg.parse()?,
                 "DiffIgnore" => config.diff_ignore.push(arg.trim().to_owned()),
                 "DiffEnabled" => {
                     config.should_diff = arg.parse().context("Invalid bool for DiffEnabled")?
@@ -1577,12 +1580,16 @@ impl LinkCommand {
                         command.arg("-m").arg(arch.emulation_name());
                     }
 
-                    if direct_config.is_static {
-                        command.arg("-static");
-                    } else {
-                        command
-                            .arg("-dynamic-linker")
-                            .arg(dynamic_linker_path(cross_arch));
+                    match direct_config.mode {
+                        Mode::Dynamic => {
+                            command
+                                .arg("-dynamic-linker")
+                                .arg(dynamic_linker_path(cross_arch));
+                        }
+                        Mode::Static => {
+                            command.arg("-static");
+                        }
+                        Mode::Unspecified => {}
                     }
 
                     if let Some(version_script) = &config.version_script {
@@ -2379,7 +2386,8 @@ fn integration_test(
         "duplicate_strong_symbols.c",
         "preinit-array.c",
         "exception.cc",
-        "z-defs.c"
+        "z-defs.c",
+        "export-dynamic.c"
     )]
     program_name: &'static str,
     #[allow(unused_variables)] setup_symlink: (),
diff --git a/wild/tests/sources/basic-comdat.s b/wild/tests/sources/basic-comdat.s
index 0359cf0..6d2450c 100644
--- a/wild/tests/sources/basic-comdat.s
+++ b/wild/tests/sources/basic-comdat.s
@@ -1,7 +1,7 @@
 /* For some reason, GAS on riscv64 does not support '//' comments.
 //#Object:basic-comdat-1.s
 //#RunEnabled:false
-//#Static:false
+//#Mode:dynamic
 //#LinkArgs:-shared -z now
 //#DiffIgnore:section.got
 //#DiffIgnore:segment.GNU_STACK.alignment
diff --git a/wild/tests/sources/copy-relocations.c b/wild/tests/sources/copy-relocations.c
index 3b571b0..9c4689c 100644
--- a/wild/tests/sources/copy-relocations.c
+++ b/wild/tests/sources/copy-relocations.c
@@ -1,6 +1,6 @@
 //#Object:runtime.c
 //#EnableLinker:lld
-//#Static:false
+//#Mode:dynamic
 //#CompSoArgs:-fPIC
 //#LinkArgs:-z now
 //#Shared:copy-relocations-2.c
diff --git a/wild/tests/sources/data-pointers.c b/wild/tests/sources/data-pointers.c
index 32eb1f7..7d0e03a 100644
--- a/wild/tests/sources/data-pointers.c
+++ b/wild/tests/sources/data-pointers.c
@@ -1,6 +1,6 @@
 //#Shared:runtime.c
 //#EnableLinker:lld
-//#Static:false
+//#Mode:dynamic
 //#LinkArgs:-z now
 //#Shared:data-pointers-2.c
 //#EnableLinker:lld
diff --git a/wild/tests/sources/empty.c b/wild/tests/sources/empty.c
new file mode 100644
index 0000000..e69de29
diff --git a/wild/tests/sources/exclude-libs.c b/wild/tests/sources/exclude-libs.c
index aac6f8b..142fae4 100644
--- a/wild/tests/sources/exclude-libs.c
+++ b/wild/tests/sources/exclude-libs.c
@@ -1,5 +1,5 @@
 //#LinkArgs:-z now -Bshareable --exclude-libs ALL
-//#Static:false
+//#Mode:dynamic
 //#Archive:exclude-libs-archive.c
 //#RunEnabled:false
 // We optimise away the GOT, but GNU ld doesn't.
diff --git a/wild/tests/sources/export-dynamic.c b/wild/tests/sources/export-dynamic.c
new file mode 100644
index 0000000..7dbaf3a
--- /dev/null
+++ b/wild/tests/sources/export-dynamic.c
@@ -0,0 +1,23 @@
+// Adding shared libraries should yield dynamic executables: #836
+//#Config:shared-input
+//#LinkArgs:-z now --export-dynamic 
+//#ExpectDynSym:foo
+//#Shared:empty.c
+//#Mode:unspecified
+//#EnableLinker:lld
+//#Cross:false
+// We're linking different .so files, so this is expected.
+//#DiffIgnore:.dynamic.DT_NEEDED
+//#DiffIgnore:section.got
+//#RunEnabled:false
+
+// Do not export symbols for static executables: #836
+//#Config:static-exe
+//#Mode:static
+//#LinkArgs:-z now --export-dynamic 
+//#RunEnabled:false
+//#DoesNotContain:.dynamic
+
+void foo(void) {};
+
+void _start() {}
diff --git a/wild/tests/sources/linker-script.c b/wild/tests/sources/linker-script.c
index 9d999d8..c24d689 100644
--- a/wild/tests/sources/linker-script.c
+++ b/wild/tests/sources/linker-script.c
@@ -1,5 +1,5 @@
 //#LinkerScript:linker-script.ld
-//#Static:false
+//#Mode:dynamic
 //#LinkArgs:-shared -z now
 //#RunEnabled:false
 //#DiffIgnore:section.got
diff --git a/wild/tests/sources/mixed-verdef-verneed.c b/wild/tests/sources/mixed-verdef-verneed.c
index 9f803d3..d65212f 100644
--- a/wild/tests/sources/mixed-verdef-verneed.c
+++ b/wild/tests/sources/mixed-verdef-verneed.c
@@ -1,6 +1,6 @@
 // Makes sure that having both verdef and verneed doesn't cause problems.
 
-//#Static:false
+//#Mode:dynamic
 //#Object:runtime.c
 //#VersionScript:mixed-verdef-verneed.map
 //#Shared:mixed-verdef-verneed-2.c
diff --git a/wild/tests/sources/preinit-array.c b/wild/tests/sources/preinit-array.c
index 28db58b..ffabaf8 100644
--- a/wild/tests/sources/preinit-array.c
+++ b/wild/tests/sources/preinit-array.c
@@ -8,7 +8,7 @@
 //#DiffIgnore:.dynamic.DT_RELAENT
 //#Arch: x86_64
 //#RequiresGlibc:true
-//#Static:false
+//#Mode:dynamic
 
 #include "runtime.h"
 
diff --git a/wild/tests/sources/shared-priority.c b/wild/tests/sources/shared-priority.c
index 9191560..2346006 100644
--- a/wild/tests/sources/shared-priority.c
+++ b/wild/tests/sources/shared-priority.c
@@ -4,7 +4,7 @@
 //#AbstractConfig:default
 //#CompArgs:-fPIC
 //#Object:runtime.c
-//#Static:false
+//#Mode:dynamic
 //#DiffIgnore:.dynamic.DT_NEEDED
 //#DiffIgnore:.dynamic.DT_RELA
 //#DiffIgnore:.dynamic.DT_RELAENT
diff --git a/wild/tests/sources/shared.c b/wild/tests/sources/shared.c
index 80ad851..2981b92 100644
--- a/wild/tests/sources/shared.c
+++ b/wild/tests/sources/shared.c
@@ -7,7 +7,7 @@
 //#Config:default
 //#RunEnabled:false
 //#LinkArgs:-shared -z now
-//#Static:false
+//#Mode:dynamic
 // TODO: https://rust-lang.zulipchat.com/#narrow/channel/421156-gsoc/topic/Project.3A.20Improve.20Wild.20linker.20test.20suites/near/521482968
 //#Cross:false
 //#Archive:shared-a1.c,shared-a2.c
diff --git a/wild/tests/sources/shlib-undefined.c b/wild/tests/sources/shlib-undefined.c
index 04abf0f..4b05ac5 100644
--- a/wild/tests/sources/shlib-undefined.c
+++ b/wild/tests/sources/shlib-undefined.c
@@ -1,6 +1,6 @@
 //#AbstractConfig:default
 //#Object:runtime.c
-//#Static:false
+//#Mode:dynamic
 //#Shared:shlib-undefined-2.c
 //#DiffIgnore:.dynamic.DT_RELA
 //#DiffIgnore:.dynamic.DT_RELAENT
diff --git a/wild/tests/sources/trivial-dynamic.c b/wild/tests/sources/trivial-dynamic.c
index 566ed7a..e4620a5 100644
--- a/wild/tests/sources/trivial-dynamic.c
+++ b/wild/tests/sources/trivial-dynamic.c
@@ -1,7 +1,7 @@
 //#Config:default
 //#Object:runtime.c
 //#EnableLinker:lld
-//#Static:false
+//#Mode:dynamic
 //#LinkArgs:-z now
 //#Shared:trivial-dynamic-2.c
 //#EnableLinker:lld
@@ -25,12 +25,6 @@
 //#DiffIgnore:.dynamic.DT_FLAGS.SYMBOLIC
 //#DiffIgnore:.dynamic.DT_SYMBOLIC
 
-//#Config:export-dynamic:default
-//#LinkArgs:-z now --export-dynamic 
-//#ExpectDynSym: runtime_init
-// Ld is acting weird and comparing to LLD is not possible right when when cross compiling: #804
-//#Cross:false
-
 #include "runtime.h"
 
 int foo(void);
diff --git a/wild/tests/sources/visibility-merging.c b/wild/tests/sources/visibility-merging.c
index bc9ecb5..98f0183 100644
--- a/wild/tests/sources/visibility-merging.c
+++ b/wild/tests/sources/visibility-merging.c
@@ -1,4 +1,4 @@
-//#Static:false
+//#Mode:dynamic
 //#LinkArgs:-shared -z now
 //#Object:visibility-merging-1.c
 //#RunEnabled:false
diff --git a/wild/tests/sources/z-defs.c b/wild/tests/sources/z-defs.c
index b549f33..279c377 100644
--- a/wild/tests/sources/z-defs.c
+++ b/wild/tests/sources/z-defs.c
@@ -1,5 +1,5 @@
 //#LinkArgs:-Bshareable -z defs
-//#Static:false
+//#Mode:dynamic
 //#ExpectError:foo
 
 int foo(void);