Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7aef3a0

Browse files
authoredMay 29, 2020
Rollup merge of #71804 - petrochenkov:static-pie, r=cuviper
linker: Support `-static-pie` and `-static -shared` This PR adds support for passing linker arguments for creating statically linked position-independent executables and "statically linked" shared libraries. Therefore it incorporates the majority of #70740 except for the linker rerun hack and actually flipping the "`static-pie` is supported" switch for musl targets.
2 parents 1cfe0e9 + 96a466c commit 7aef3a0

File tree

3 files changed

+127
-134
lines changed

3 files changed

+127
-134
lines changed
 

‎src/librustc_codegen_ssa/back/link.rs

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1194,9 +1194,10 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind {
11941194
};
11951195

11961196
// Adjust the output kind to target capabilities.
1197-
let pic_exe_supported = sess.target.target.options.position_independent_executables;
1198-
let static_pic_exe_supported = false; // FIXME: Add this option to target specs.
1199-
let static_dylib_supported = sess.target.target.options.crt_static_allows_dylibs;
1197+
let opts = &sess.target.target.options;
1198+
let pic_exe_supported = opts.position_independent_executables;
1199+
let static_pic_exe_supported = opts.static_position_independent_executables;
1200+
let static_dylib_supported = opts.crt_static_allows_dylibs;
12001201
match kind {
12011202
LinkOutputKind::DynamicPicExe if !pic_exe_supported => LinkOutputKind::DynamicNoPicExe,
12021203
LinkOutputKind::StaticPicExe if !static_pic_exe_supported => LinkOutputKind::StaticNoPicExe,
@@ -1580,16 +1581,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
15801581
}
15811582

15821583
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
1583-
// FIXME: Support `StaticPicExe` correctly.
1584-
match link_output_kind {
1585-
LinkOutputKind::DynamicPicExe | LinkOutputKind::StaticPicExe => {
1586-
cmd.position_independent_executable()
1587-
}
1588-
LinkOutputKind::DynamicNoPicExe | LinkOutputKind::StaticNoPicExe => {
1589-
cmd.no_position_independent_executable()
1590-
}
1591-
_ => {}
1592-
}
1584+
cmd.set_output_kind(link_output_kind, out_filename);
15931585

15941586
// OBJECT-FILES-NO, AUDIT-ORDER
15951587
add_relro_args(cmd, sess);
@@ -1618,17 +1610,6 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>(
16181610
tmpdir,
16191611
);
16201612

1621-
// NO-OPT-OUT, OBJECT-FILES-NO, AUDIT-ORDER
1622-
// FIXME: Merge with the previous `link_output_kind` match,
1623-
// and support `StaticPicExe` and `StaticDylib` correctly.
1624-
match link_output_kind {
1625-
LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {
1626-
cmd.build_static_executable()
1627-
}
1628-
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => cmd.build_dylib(out_filename),
1629-
_ => {}
1630-
}
1631-
16321613
// OBJECT-FILES-NO, AUDIT-ORDER
16331614
if sess.opts.cg.profile_generate.enabled() {
16341615
cmd.pgo_gen();

‎src/librustc_codegen_ssa/back/linker.rs

Lines changed: 117 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustc_serialize::{json, Encoder};
1717
use rustc_session::config::{self, CrateType, DebugInfo, LinkerPluginLto, Lto, OptLevel, Strip};
1818
use rustc_session::Session;
1919
use rustc_span::symbol::Symbol;
20-
use rustc_target::spec::{LinkerFlavor, LldFlavor};
20+
use rustc_target::spec::{LinkOutputKind, LinkerFlavor, LldFlavor};
2121

2222
/// Disables non-English messages from localized linkers.
2323
/// Such messages may cause issues with text encoding on Windows (#35785)
@@ -101,6 +101,7 @@ impl LinkerInfo {
101101
/// MSVC linker (e.g., `link.exe`) is being used.
102102
pub trait Linker {
103103
fn cmd(&mut self) -> &mut Command;
104+
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path);
104105
fn link_dylib(&mut self, lib: Symbol);
105106
fn link_rust_dylib(&mut self, lib: Symbol, path: &Path);
106107
fn link_framework(&mut self, framework: Symbol);
@@ -113,8 +114,6 @@ pub trait Linker {
113114
fn output_filename(&mut self, path: &Path);
114115
fn add_object(&mut self, path: &Path);
115116
fn gc_sections(&mut self, keep_metadata: bool);
116-
fn position_independent_executable(&mut self);
117-
fn no_position_independent_executable(&mut self);
118117
fn full_relro(&mut self);
119118
fn partial_relro(&mut self);
120119
fn no_relro(&mut self);
@@ -124,8 +123,6 @@ pub trait Linker {
124123
fn debuginfo(&mut self, strip: Strip);
125124
fn no_crt_objects(&mut self);
126125
fn no_default_libraries(&mut self);
127-
fn build_dylib(&mut self, out_filename: &Path);
128-
fn build_static_executable(&mut self);
129126
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType);
130127
fn subsystem(&mut self, subsystem: &str);
131128
fn group_start(&mut self);
@@ -232,12 +229,94 @@ impl<'a> GccLinker<'a> {
232229
let target_cpu = self.target_cpu;
233230
self.linker_arg(&format!("-plugin-opt=mcpu={}", target_cpu));
234231
}
232+
233+
fn build_dylib(&mut self, out_filename: &Path) {
234+
// On mac we need to tell the linker to let this library be rpathed
235+
if self.sess.target.target.options.is_like_osx {
236+
self.cmd.arg("-dynamiclib");
237+
self.linker_arg("-dylib");
238+
239+
// Note that the `osx_rpath_install_name` option here is a hack
240+
// purely to support rustbuild right now, we should get a more
241+
// principled solution at some point to force the compiler to pass
242+
// the right `-Wl,-install_name` with an `@rpath` in it.
243+
if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
244+
self.linker_arg("-install_name");
245+
let mut v = OsString::from("@rpath/");
246+
v.push(out_filename.file_name().unwrap());
247+
self.linker_arg(&v);
248+
}
249+
} else {
250+
self.cmd.arg("-shared");
251+
if self.sess.target.target.options.is_like_windows {
252+
// The output filename already contains `dll_suffix` so
253+
// the resulting import library will have a name in the
254+
// form of libfoo.dll.a
255+
let implib_name =
256+
out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
257+
format!(
258+
"{}{}{}",
259+
self.sess.target.target.options.staticlib_prefix,
260+
file,
261+
self.sess.target.target.options.staticlib_suffix
262+
)
263+
});
264+
if let Some(implib_name) = implib_name {
265+
let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
266+
if let Some(implib) = implib {
267+
self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
268+
}
269+
}
270+
}
271+
}
272+
}
235273
}
236274

237275
impl<'a> Linker for GccLinker<'a> {
238276
fn cmd(&mut self) -> &mut Command {
239277
&mut self.cmd
240278
}
279+
280+
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
281+
match output_kind {
282+
LinkOutputKind::DynamicNoPicExe => {
283+
if !self.is_ld {
284+
self.cmd.arg("-no-pie");
285+
}
286+
}
287+
LinkOutputKind::DynamicPicExe => {
288+
// `-pie` works for both gcc wrapper and ld.
289+
self.cmd.arg("-pie");
290+
}
291+
LinkOutputKind::StaticNoPicExe => {
292+
// `-static` works for both gcc wrapper and ld.
293+
self.cmd.arg("-static");
294+
if !self.is_ld {
295+
self.cmd.arg("-no-pie");
296+
}
297+
}
298+
LinkOutputKind::StaticPicExe => {
299+
if !self.is_ld {
300+
// Note that combination `-static -pie` doesn't work as expected
301+
// for the gcc wrapper, `-static` in that case suppresses `-pie`.
302+
self.cmd.arg("-static-pie");
303+
} else {
304+
// `--no-dynamic-linker` and `-z text` are not strictly necessary for producing
305+
// a static pie, but currently passed because gcc and clang pass them.
306+
// The former suppresses the `INTERP` ELF header specifying dynamic linker,
307+
// which is otherwise implicitly injected by ld (but not lld).
308+
// The latter doesn't change anything, only ensures that everything is pic.
309+
self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]);
310+
}
311+
}
312+
LinkOutputKind::DynamicDylib => self.build_dylib(out_filename),
313+
LinkOutputKind::StaticDylib => {
314+
self.cmd.arg("-static");
315+
self.build_dylib(out_filename);
316+
}
317+
}
318+
}
319+
241320
fn link_dylib(&mut self, lib: Symbol) {
242321
self.hint_dynamic();
243322
self.cmd.arg(format!("-l{}", lib));
@@ -262,14 +341,6 @@ impl<'a> Linker for GccLinker<'a> {
262341
fn add_object(&mut self, path: &Path) {
263342
self.cmd.arg(path);
264343
}
265-
fn position_independent_executable(&mut self) {
266-
self.cmd.arg("-pie");
267-
}
268-
fn no_position_independent_executable(&mut self) {
269-
if !self.is_ld {
270-
self.cmd.arg("-no-pie");
271-
}
272-
}
273344
fn full_relro(&mut self) {
274345
self.linker_arg("-zrelro");
275346
self.linker_arg("-znow");
@@ -280,9 +351,6 @@ impl<'a> Linker for GccLinker<'a> {
280351
fn no_relro(&mut self) {
281352
self.linker_arg("-znorelro");
282353
}
283-
fn build_static_executable(&mut self) {
284-
self.cmd.arg("-static");
285-
}
286354

287355
fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
288356
self.hint_dynamic();
@@ -418,47 +486,6 @@ impl<'a> Linker for GccLinker<'a> {
418486
}
419487
}
420488

421-
fn build_dylib(&mut self, out_filename: &Path) {
422-
// On mac we need to tell the linker to let this library be rpathed
423-
if self.sess.target.target.options.is_like_osx {
424-
self.cmd.arg("-dynamiclib");
425-
self.linker_arg("-dylib");
426-
427-
// Note that the `osx_rpath_install_name` option here is a hack
428-
// purely to support rustbuild right now, we should get a more
429-
// principled solution at some point to force the compiler to pass
430-
// the right `-Wl,-install_name` with an `@rpath` in it.
431-
if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name {
432-
self.linker_arg("-install_name");
433-
let mut v = OsString::from("@rpath/");
434-
v.push(out_filename.file_name().unwrap());
435-
self.linker_arg(&v);
436-
}
437-
} else {
438-
self.cmd.arg("-shared");
439-
if self.sess.target.target.options.is_like_windows {
440-
// The output filename already contains `dll_suffix` so
441-
// the resulting import library will have a name in the
442-
// form of libfoo.dll.a
443-
let implib_name =
444-
out_filename.file_name().and_then(|file| file.to_str()).map(|file| {
445-
format!(
446-
"{}{}{}",
447-
self.sess.target.target.options.staticlib_prefix,
448-
file,
449-
self.sess.target.target.options.staticlib_suffix
450-
)
451-
});
452-
if let Some(implib_name) = implib_name {
453-
let implib = out_filename.parent().map(|dir| dir.join(&implib_name));
454-
if let Some(implib) = implib {
455-
self.linker_arg(&format!("--out-implib,{}", (*implib).to_str().unwrap()));
456-
}
457-
}
458-
}
459-
}
460-
}
461-
462489
fn export_symbols(&mut self, tmpdir: &Path, crate_type: CrateType) {
463490
// Symbol visibility in object files typically takes care of this.
464491
if crate_type == CrateType::Executable
@@ -582,24 +609,29 @@ impl<'a> Linker for MsvcLinker<'a> {
582609
fn cmd(&mut self) -> &mut Command {
583610
&mut self.cmd
584611
}
612+
613+
fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) {
614+
match output_kind {
615+
LinkOutputKind::DynamicNoPicExe
616+
| LinkOutputKind::DynamicPicExe
617+
| LinkOutputKind::StaticNoPicExe
618+
| LinkOutputKind::StaticPicExe => {}
619+
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
620+
self.cmd.arg("/DLL");
621+
let mut arg: OsString = "/IMPLIB:".into();
622+
arg.push(out_filename.with_extension("dll.lib"));
623+
self.cmd.arg(arg);
624+
}
625+
}
626+
}
627+
585628
fn link_rlib(&mut self, lib: &Path) {
586629
self.cmd.arg(lib);
587630
}
588631
fn add_object(&mut self, path: &Path) {
589632
self.cmd.arg(path);
590633
}
591634

592-
fn build_dylib(&mut self, out_filename: &Path) {
593-
self.cmd.arg("/DLL");
594-
let mut arg: OsString = "/IMPLIB:".into();
595-
arg.push(out_filename.with_extension("dll.lib"));
596-
self.cmd.arg(arg);
597-
}
598-
599-
fn build_static_executable(&mut self) {
600-
// noop
601-
}
602-
603635
fn gc_sections(&mut self, _keep_metadata: bool) {
604636
// MSVC's ICF (Identical COMDAT Folding) link optimization is
605637
// slow for Rust and thus we disable it by default when not in
@@ -632,14 +664,6 @@ impl<'a> Linker for MsvcLinker<'a> {
632664
self.cmd.arg(&format!("{}.lib", lib));
633665
}
634666

635-
fn position_independent_executable(&mut self) {
636-
// noop
637-
}
638-
639-
fn no_position_independent_executable(&mut self) {
640-
// noop
641-
}
642-
643667
fn full_relro(&mut self) {
644668
// noop
645669
}
@@ -817,6 +841,9 @@ impl<'a> Linker for EmLinker<'a> {
817841
fn cmd(&mut self) -> &mut Command {
818842
&mut self.cmd
819843
}
844+
845+
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
846+
820847
fn include_path(&mut self, path: &Path) {
821848
self.cmd.arg("-L").arg(path);
822849
}
@@ -856,14 +883,6 @@ impl<'a> Linker for EmLinker<'a> {
856883
self.add_object(lib);
857884
}
858885

859-
fn position_independent_executable(&mut self) {
860-
// noop
861-
}
862-
863-
fn no_position_independent_executable(&mut self) {
864-
// noop
865-
}
866-
867886
fn full_relro(&mut self) {
868887
// noop
869888
}
@@ -925,14 +944,6 @@ impl<'a> Linker for EmLinker<'a> {
925944
self.cmd.args(&["-s", "DEFAULT_LIBRARY_FUNCS_TO_INCLUDE=[]"]);
926945
}
927946

928-
fn build_dylib(&mut self, _out_filename: &Path) {
929-
bug!("building dynamic library is unsupported on Emscripten")
930-
}
931-
932-
fn build_static_executable(&mut self) {
933-
// noop
934-
}
935-
936947
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
937948
let symbols = &self.info.exports[&crate_type];
938949

@@ -1031,6 +1042,18 @@ impl<'a> Linker for WasmLd<'a> {
10311042
&mut self.cmd
10321043
}
10331044

1045+
fn set_output_kind(&mut self, output_kind: LinkOutputKind, _out_filename: &Path) {
1046+
match output_kind {
1047+
LinkOutputKind::DynamicNoPicExe
1048+
| LinkOutputKind::DynamicPicExe
1049+
| LinkOutputKind::StaticNoPicExe
1050+
| LinkOutputKind::StaticPicExe => {}
1051+
LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => {
1052+
self.cmd.arg("--no-entry");
1053+
}
1054+
}
1055+
}
1056+
10341057
fn link_dylib(&mut self, lib: Symbol) {
10351058
self.cmd.arg("-l").sym_arg(lib);
10361059
}
@@ -1059,16 +1082,12 @@ impl<'a> Linker for WasmLd<'a> {
10591082
self.cmd.arg(path);
10601083
}
10611084

1062-
fn position_independent_executable(&mut self) {}
1063-
10641085
fn full_relro(&mut self) {}
10651086

10661087
fn partial_relro(&mut self) {}
10671088

10681089
fn no_relro(&mut self) {}
10691090

1070-
fn build_static_executable(&mut self) {}
1071-
10721091
fn link_rust_dylib(&mut self, lib: Symbol, _path: &Path) {
10731092
self.cmd.arg("-l").sym_arg(lib);
10741093
}
@@ -1124,10 +1143,6 @@ impl<'a> Linker for WasmLd<'a> {
11241143

11251144
fn no_default_libraries(&mut self) {}
11261145

1127-
fn build_dylib(&mut self, _out_filename: &Path) {
1128-
self.cmd.arg("--no-entry");
1129-
}
1130-
11311146
fn export_symbols(&mut self, _tmpdir: &Path, crate_type: CrateType) {
11321147
for sym in self.info.exports[&crate_type].iter() {
11331148
self.cmd.arg("--export").arg(&sym);
@@ -1143,8 +1158,6 @@ impl<'a> Linker for WasmLd<'a> {
11431158

11441159
fn subsystem(&mut self, _subsystem: &str) {}
11451160

1146-
fn no_position_independent_executable(&mut self) {}
1147-
11481161
fn finalize(&mut self) {}
11491162

11501163
// Not needed for now with LLD
@@ -1207,6 +1220,8 @@ impl<'a> Linker for PtxLinker<'a> {
12071220
&mut self.cmd
12081221
}
12091222

1223+
fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {}
1224+
12101225
fn link_rlib(&mut self, path: &Path) {
12111226
self.cmd.arg("--rlib").arg(path);
12121227
}
@@ -1273,16 +1288,12 @@ impl<'a> Linker for PtxLinker<'a> {
12731288
panic!("frameworks not supported")
12741289
}
12751290

1276-
fn position_independent_executable(&mut self) {}
1277-
12781291
fn full_relro(&mut self) {}
12791292

12801293
fn partial_relro(&mut self) {}
12811294

12821295
fn no_relro(&mut self) {}
12831296

1284-
fn build_static_executable(&mut self) {}
1285-
12861297
fn gc_sections(&mut self, _keep_metadata: bool) {}
12871298

12881299
fn pgo_gen(&mut self) {}
@@ -1295,14 +1306,10 @@ impl<'a> Linker for PtxLinker<'a> {
12951306
self.sess.warn("Windows Control Flow Guard is not supported by this linker.");
12961307
}
12971308

1298-
fn build_dylib(&mut self, _out_filename: &Path) {}
1299-
13001309
fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType) {}
13011310

13021311
fn subsystem(&mut self, _subsystem: &str) {}
13031312

1304-
fn no_position_independent_executable(&mut self) {}
1305-
13061313
fn group_start(&mut self) {}
13071314

13081315
fn group_end(&mut self) {}

‎src/librustc_target/spec/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -856,6 +856,8 @@ pub struct TargetOptions {
856856
/// the functions in the executable are not randomized and can be used
857857
/// during an exploit of a vulnerability in any code.
858858
pub position_independent_executables: bool,
859+
/// Executables that are both statically linked and position-independent are supported.
860+
pub static_position_independent_executables: bool,
859861
/// Determines if the target always requires using the PLT for indirect
860862
/// library calls or not. This controls the default value of the `-Z plt` flag.
861863
pub needs_plt: bool,
@@ -1029,6 +1031,7 @@ impl Default for TargetOptions {
10291031
has_rpath: false,
10301032
no_default_libraries: true,
10311033
position_independent_executables: false,
1034+
static_position_independent_executables: false,
10321035
needs_plt: false,
10331036
relro_level: RelroLevel::None,
10341037
pre_link_objects: Default::default(),
@@ -1433,6 +1436,7 @@ impl Target {
14331436
key!(has_rpath, bool);
14341437
key!(no_default_libraries, bool);
14351438
key!(position_independent_executables, bool);
1439+
key!(static_position_independent_executables, bool);
14361440
key!(needs_plt, bool);
14371441
key!(relro_level, RelroLevel)?;
14381442
key!(archive_format);
@@ -1664,6 +1668,7 @@ impl ToJson for Target {
16641668
target_option_val!(has_rpath);
16651669
target_option_val!(no_default_libraries);
16661670
target_option_val!(position_independent_executables);
1671+
target_option_val!(static_position_independent_executables);
16671672
target_option_val!(needs_plt);
16681673
target_option_val!(relro_level);
16691674
target_option_val!(archive_format);

0 commit comments

Comments
 (0)
Please sign in to comment.