Skip to content

Commit 5b638c1

Browse files
committed
Auto merge of rust-lang#85086 - petrochenkov:linkord2, r=nagisa
linker: Reorder linker arguments - Split arguments into order-independent and order-dependent, to define more precisely what (pre-,post-,late-,)link-args mean. - Add some comments.
2 parents 86b0baf + 3eab280 commit 5b638c1

File tree

2 files changed

+164
-165
lines changed

2 files changed

+164
-165
lines changed

compiler/rustc_codegen_ssa/src/back/link.rs

+160-136
Original file line numberDiff line numberDiff line change
@@ -1058,7 +1058,7 @@ fn link_natively<'a, B: ArchiveBuilder<'a>>(
10581058
}
10591059
}
10601060

1061-
fn link_sanitizers(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
1061+
fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
10621062
// On macOS the runtimes are distributed as dylibs which should be linked to
10631063
// both executables and dynamic shared objects. Everywhere else the runtimes
10641064
// are currently distributed as static liraries which should be linked to
@@ -1680,55 +1680,6 @@ fn add_local_crate_metadata_objects(
16801680
}
16811681
}
16821682

1683-
/// Link native libraries corresponding to the current crate and all libraries corresponding to
1684-
/// all its dependency crates.
1685-
/// FIXME: Consider combining this with the functions above adding object files for the local crate.
1686-
fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<'a>>(
1687-
cmd: &mut dyn Linker,
1688-
sess: &'a Session,
1689-
crate_type: CrateType,
1690-
codegen_results: &CodegenResults,
1691-
tmpdir: &Path,
1692-
) {
1693-
// Take careful note of the ordering of the arguments we pass to the linker
1694-
// here. Linkers will assume that things on the left depend on things to the
1695-
// right. Things on the right cannot depend on things on the left. This is
1696-
// all formally implemented in terms of resolving symbols (libs on the right
1697-
// resolve unknown symbols of libs on the left, but not vice versa).
1698-
//
1699-
// For this reason, we have organized the arguments we pass to the linker as
1700-
// such:
1701-
//
1702-
// 1. The local object that LLVM just generated
1703-
// 2. Local native libraries
1704-
// 3. Upstream rust libraries
1705-
// 4. Upstream native libraries
1706-
//
1707-
// The rationale behind this ordering is that those items lower down in the
1708-
// list can't depend on items higher up in the list. For example nothing can
1709-
// depend on what we just generated (e.g., that'd be a circular dependency).
1710-
// Upstream rust libraries are not allowed to depend on our local native
1711-
// libraries as that would violate the structure of the DAG, in that
1712-
// scenario they are required to link to them as well in a shared fashion.
1713-
//
1714-
// Note that upstream rust libraries may contain native dependencies as
1715-
// well, but they also can't depend on what we just started to add to the
1716-
// link line. And finally upstream native libraries can't depend on anything
1717-
// in this DAG so far because they're only dylibs and dylibs can only depend
1718-
// on other dylibs (e.g., other native deps).
1719-
//
1720-
// If -Zlink-native-libraries=false is set, then the assumption is that an
1721-
// external build system already has the native dependencies defined, and it
1722-
// will provide them to the linker itself.
1723-
if sess.opts.debugging_opts.link_native_libraries {
1724-
add_local_native_libraries(cmd, sess, codegen_results);
1725-
}
1726-
add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
1727-
if sess.opts.debugging_opts.link_native_libraries {
1728-
add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
1729-
}
1730-
}
1731-
17321683
/// Add sysroot and other globally set directories to the directory search list.
17331684
fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) {
17341685
// The default library location, we need this to find the runtime.
@@ -1787,12 +1738,13 @@ fn add_rpath_args(
17871738
}
17881739

17891740
/// Produce the linker command line containing linker path and arguments.
1790-
/// `NO-OPT-OUT` marks the arguments that cannot be removed from the command line
1791-
/// by the user without creating a custom target specification.
1792-
/// `OBJECT-FILES` specify whether the arguments can add object files.
1793-
/// `CUSTOMIZATION-POINT` means that arbitrary arguments defined by the user
1794-
/// or by the target spec can be inserted here.
1795-
/// `AUDIT-ORDER` - need to figure out whether the option is order-dependent or not.
1741+
///
1742+
/// When comments in the function say "order-(in)dependent" they mean order-dependence between
1743+
/// options and libraries/object files. For example `--whole-archive` (order-dependent) applies
1744+
/// to specific libraries passed after it, and `-o` (output file, order-independent) applies
1745+
/// to the linking process as a whole.
1746+
/// Order-independent options may still override each other in order-dependent fashion,
1747+
/// e.g `--foo=yes --foo=no` may be equivalent to `--foo=no`.
17961748
fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
17971749
path: &Path,
17981750
flavor: LinkerFlavor,
@@ -1810,16 +1762,151 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
18101762
let cmd = &mut *codegen_results.linker_info.to_linker(base_cmd, &sess, flavor);
18111763
let link_output_kind = link_output_kind(sess, crate_type);
18121764

1813-
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
1765+
// ------------ Early order-dependent options ------------
1766+
1767+
// If we're building something like a dynamic library then some platforms
1768+
// need to make sure that all symbols are exported correctly from the
1769+
// dynamic library.
1770+
// Must be passed before any libraries to prevent the symbols to export from being thrown away,
1771+
// at least on some platforms (e.g. windows-gnu).
1772+
cmd.export_symbols(tmpdir, crate_type);
1773+
1774+
// Can be used for adding custom CRT objects or overriding order-dependent options above.
1775+
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
1776+
// introduce a target spec option for order-independent linker options and migrate built-in
1777+
// specs to it.
18141778
add_pre_link_args(cmd, sess, flavor);
18151779

1816-
// NO-OPT-OUT, OBJECT-FILES-NO
1780+
// ------------ Object code and libraries, order-dependent ------------
1781+
1782+
// Pre-link CRT objects.
1783+
add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
1784+
1785+
// Sanitizer libraries.
1786+
add_sanitizer_libraries(sess, crate_type, cmd);
1787+
1788+
// Object code from the current crate.
1789+
// Take careful note of the ordering of the arguments we pass to the linker
1790+
// here. Linkers will assume that things on the left depend on things to the
1791+
// right. Things on the right cannot depend on things on the left. This is
1792+
// all formally implemented in terms of resolving symbols (libs on the right
1793+
// resolve unknown symbols of libs on the left, but not vice versa).
1794+
//
1795+
// For this reason, we have organized the arguments we pass to the linker as
1796+
// such:
1797+
//
1798+
// 1. The local object that LLVM just generated
1799+
// 2. Local native libraries
1800+
// 3. Upstream rust libraries
1801+
// 4. Upstream native libraries
1802+
//
1803+
// The rationale behind this ordering is that those items lower down in the
1804+
// list can't depend on items higher up in the list. For example nothing can
1805+
// depend on what we just generated (e.g., that'd be a circular dependency).
1806+
// Upstream rust libraries are not supposed to depend on our local native
1807+
// libraries as that would violate the structure of the DAG, in that
1808+
// scenario they are required to link to them as well in a shared fashion.
1809+
// (The current implementation still doesn't prevent it though, see the FIXME below.)
1810+
//
1811+
// Note that upstream rust libraries may contain native dependencies as
1812+
// well, but they also can't depend on what we just started to add to the
1813+
// link line. And finally upstream native libraries can't depend on anything
1814+
// in this DAG so far because they can only depend on other native libraries
1815+
// and such dependencies are also required to be specified.
1816+
add_local_crate_regular_objects(cmd, codegen_results);
1817+
add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
1818+
add_local_crate_allocator_objects(cmd, codegen_results);
1819+
1820+
// Avoid linking to dynamic libraries unless they satisfy some undefined symbols
1821+
// at the point at which they are specified on the command line.
1822+
// Must be passed before any (dynamic) libraries to have effect on them.
1823+
// On Solaris-like systems, `-z ignore` acts as both `--as-needed` and `--gc-sections`
1824+
// so it will ignore unreferenced ELF sections from relocatable objects.
1825+
// For that reason, we put this flag after metadata objects as they would otherwise be removed.
1826+
// FIXME: Support more fine-grained dead code removal on Solaris/illumos
1827+
// and move this option back to the top.
1828+
cmd.add_as_needed();
1829+
1830+
// FIXME: Move this below to other native libraries
1831+
// (or alternatively link all native libraries after their respective crates).
1832+
// This change is somewhat breaking in practice due to local static libraries being linked
1833+
// as whole-archive (#85144), so removing whole-archive may be a pre-requisite.
1834+
if sess.opts.debugging_opts.link_native_libraries {
1835+
add_local_native_libraries(cmd, sess, codegen_results);
1836+
}
1837+
1838+
// Rust libraries.
1839+
add_upstream_rust_crates::<B>(cmd, sess, codegen_results, crate_type, tmpdir);
1840+
1841+
// Native libraries linked with `#[link]` attributes at and `-l` command line options.
1842+
// If -Zlink-native-libraries=false is set, then the assumption is that an
1843+
// external build system already has the native dependencies defined, and it
1844+
// will provide them to the linker itself.
1845+
if sess.opts.debugging_opts.link_native_libraries {
1846+
add_upstream_native_libraries(cmd, sess, codegen_results, crate_type);
1847+
}
1848+
1849+
// Library linking above uses some global state for things like `-Bstatic`/`-Bdynamic` to make
1850+
// command line shorter, reset it to default here before adding more libraries.
1851+
cmd.reset_per_library_state();
1852+
1853+
// FIXME: Built-in target specs occasionally use this for linking system libraries,
1854+
// eliminate all such uses by migrating them to `#[link]` attributes in `lib(std,c,unwind)`
1855+
// and remove the option.
1856+
add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
1857+
1858+
// ------------ Arbitrary order-independent options ------------
1859+
1860+
// Add order-independent options determined by rustc from its compiler options,
1861+
// target properties and source code.
1862+
add_order_independent_options(
1863+
cmd,
1864+
sess,
1865+
link_output_kind,
1866+
crt_objects_fallback,
1867+
flavor,
1868+
crate_type,
1869+
codegen_results,
1870+
out_filename,
1871+
tmpdir,
1872+
);
1873+
1874+
// Can be used for arbitrary order-independent options.
1875+
// In practice may also be occasionally used for linking native libraries.
1876+
// Passed after compiler-generated options to support manual overriding when necessary.
1877+
add_user_defined_link_args(cmd, sess);
1878+
1879+
// ------------ Object code and libraries, order-dependent ------------
1880+
1881+
// Post-link CRT objects.
1882+
add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
1883+
1884+
// ------------ Late order-dependent options ------------
1885+
1886+
// Doesn't really make sense.
1887+
// FIXME: In practice built-in target specs use this for arbitrary order-independent options,
1888+
// introduce a target spec option for order-independent linker options, migrate built-in specs
1889+
// to it and remove the option.
1890+
add_post_link_args(cmd, sess, flavor);
1891+
1892+
cmd.take_cmd()
1893+
}
1894+
1895+
fn add_order_independent_options(
1896+
cmd: &mut dyn Linker,
1897+
sess: &Session,
1898+
link_output_kind: LinkOutputKind,
1899+
crt_objects_fallback: bool,
1900+
flavor: LinkerFlavor,
1901+
crate_type: CrateType,
1902+
codegen_results: &CodegenResults,
1903+
out_filename: &Path,
1904+
tmpdir: &Path,
1905+
) {
18171906
add_apple_sdk(cmd, sess, flavor);
18181907

1819-
// NO-OPT-OUT
18201908
add_link_script(cmd, sess, tmpdir, crate_type);
18211909

1822-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
18231910
if sess.target.is_like_fuchsia && crate_type == CrateType::Executable {
18241911
let prefix = if sess.opts.debugging_opts.sanitizer.contains(SanitizerSet::ADDRESS) {
18251912
"asan/"
@@ -1829,36 +1916,17 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
18291916
cmd.arg(format!("--dynamic-linker={}ld.so.1", prefix));
18301917
}
18311918

1832-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
18331919
if sess.target.eh_frame_header {
18341920
cmd.add_eh_frame_header();
18351921
}
18361922

1837-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
18381923
// Make the binary compatible with data execution prevention schemes.
18391924
cmd.add_no_exec();
18401925

1841-
// OBJECT-FILES-YES
1842-
add_local_crate_metadata_objects(cmd, crate_type, codegen_results);
1843-
1844-
// NO-OPT-OUT, OBJECT-FILES-NO
1845-
// Avoid linking to dynamic libraries unless they satisfy some undefined symbols
1846-
// at the point at which they are specified on the command line.
1847-
// Must be passed before any dynamic libraries.
1848-
// On solaris-like systems, this also will ignore unreferenced ELF sections
1849-
// from relocatable objects. For that reason, we move the metadata objects
1850-
// to before this flag as they would otherwise be removed.
1851-
cmd.add_as_needed();
1852-
1853-
// NO-OPT-OUT, OBJECT-FILES-NO
18541926
if crt_objects_fallback {
18551927
cmd.no_crt_objects();
18561928
}
18571929

1858-
// NO-OPT-OUT, OBJECT-FILES-YES
1859-
add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
1860-
1861-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
18621930
if sess.target.is_like_emscripten {
18631931
cmd.arg("-s");
18641932
cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort {
@@ -1868,108 +1936,64 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
18681936
});
18691937
}
18701938

1871-
// OBJECT-FILES-YES, AUDIT-ORDER
1872-
link_sanitizers(sess, crate_type, cmd);
1939+
if flavor == LinkerFlavor::PtxLinker {
1940+
// Provide the linker with fallback to internal `target-cpu`.
1941+
cmd.arg("--fallback-arch");
1942+
cmd.arg(&codegen_results.linker_info.target_cpu);
1943+
} else if flavor == LinkerFlavor::BpfLinker {
1944+
cmd.arg("--cpu");
1945+
cmd.arg(&codegen_results.linker_info.target_cpu);
1946+
cmd.arg("--cpu-features");
1947+
cmd.arg(match &sess.opts.cg.target_feature {
1948+
feat if !feat.is_empty() => feat,
1949+
_ => &sess.target.options.features,
1950+
});
1951+
}
18731952

1874-
// OBJECT-FILES-NO, AUDIT-ORDER
1875-
// Linker plugins should be specified early in the list of arguments
1876-
// FIXME: How "early" exactly?
18771953
cmd.linker_plugin_lto();
18781954

1879-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
1880-
// FIXME: Order-dependent, at least relatively to other args adding searh directories.
18811955
add_library_search_dirs(cmd, sess, crt_objects_fallback);
18821956

1883-
// OBJECT-FILES-YES
1884-
add_local_crate_regular_objects(cmd, codegen_results);
1885-
1886-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
18871957
cmd.output_filename(out_filename);
18881958

1889-
// OBJECT-FILES-NO, AUDIT-ORDER
18901959
if crate_type == CrateType::Executable && sess.target.is_like_windows {
18911960
if let Some(ref s) = codegen_results.windows_subsystem {
18921961
cmd.subsystem(s);
18931962
}
18941963
}
18951964

1896-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
1897-
// If we're building something like a dynamic library then some platforms
1898-
// need to make sure that all symbols are exported correctly from the
1899-
// dynamic library.
1900-
cmd.export_symbols(tmpdir, crate_type);
1901-
1902-
// OBJECT-FILES-YES
1903-
add_local_crate_allocator_objects(cmd, codegen_results);
1904-
1905-
// OBJECT-FILES-NO, AUDIT-ORDER
1906-
// FIXME: Order dependent, applies to the following objects. Where should it be placed?
19071965
// Try to strip as much out of the generated object by removing unused
19081966
// sections if possible. See more comments in linker.rs
19091967
if !sess.link_dead_code() {
19101968
let keep_metadata = crate_type == CrateType::Dylib;
19111969
cmd.gc_sections(keep_metadata);
19121970
}
19131971

1914-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
19151972
cmd.set_output_kind(link_output_kind, out_filename);
19161973

1917-
// OBJECT-FILES-NO, AUDIT-ORDER
19181974
add_relro_args(cmd, sess);
19191975

1920-
// OBJECT-FILES-NO, AUDIT-ORDER
19211976
// Pass optimization flags down to the linker.
19221977
cmd.optimize();
19231978

1924-
// OBJECT-FILES-NO, AUDIT-ORDER
19251979
// Pass debuginfo and strip flags down to the linker.
19261980
cmd.debuginfo(sess.opts.debugging_opts.strip);
19271981

1928-
// OBJECT-FILES-NO, AUDIT-ORDER
19291982
// We want to prevent the compiler from accidentally leaking in any system libraries,
19301983
// so by default we tell linkers not to link to any default libraries.
19311984
if !sess.opts.cg.default_linker_libraries && sess.target.no_default_libraries {
19321985
cmd.no_default_libraries();
19331986
}
19341987

1935-
// OBJECT-FILES-YES
1936-
link_local_crate_native_libs_and_dependent_crate_libs::<B>(
1937-
cmd,
1938-
sess,
1939-
crate_type,
1940-
codegen_results,
1941-
tmpdir,
1942-
);
1943-
1944-
// OBJECT-FILES-NO, AUDIT-ORDER
19451988
if sess.opts.cg.profile_generate.enabled() || sess.instrument_coverage() {
19461989
cmd.pgo_gen();
19471990
}
19481991

1949-
// OBJECT-FILES-NO, AUDIT-ORDER
19501992
if sess.opts.cg.control_flow_guard != CFGuard::Disabled {
19511993
cmd.control_flow_guard();
19521994
}
19531995

1954-
// OBJECT-FILES-NO, AUDIT-ORDER
19551996
add_rpath_args(cmd, sess, codegen_results, out_filename);
1956-
1957-
// OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
1958-
add_user_defined_link_args(cmd, sess);
1959-
1960-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
1961-
cmd.finalize();
1962-
1963-
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
1964-
add_late_link_args(cmd, sess, flavor, crate_type, codegen_results);
1965-
1966-
// NO-OPT-OUT, OBJECT-FILES-YES
1967-
add_post_link_objects(cmd, sess, link_output_kind, crt_objects_fallback);
1968-
1969-
// NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT
1970-
add_post_link_args(cmd, sess, flavor);
1971-
1972-
cmd.take_cmd()
19731997
}
19741998

19751999
/// # Native library linking

0 commit comments

Comments
 (0)