Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup and document -C relocation-model #71490

Merged
merged 5 commits into from
Apr 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 39 additions & 4 deletions src/doc/rustc/src/codegen-options/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -319,11 +319,46 @@ to a valid `.profdata` file. See the chapter on

## relocation-model

This option lets you choose which
[relocation](https://en.wikipedia.org/wiki/Relocation_\(computing\)) model to
use.
This option controls generation of
[position-independent code (PIC)](https://en.wikipedia.org/wiki/Position-independent_code).

To find the valid options for this flag, run `rustc --print relocation-models`.
Supported values for this option are:

#### Primary relocation models

- `static` - non-relocatable code, machine instructions may use absolute addressing modes.

- `pic` - fully relocatable position independent code,
machine instructions need to use relative addressing modes.
Equivalent to the "uppercase" `-fPIC` or `-fPIE` options in other compilers,
depending on the produced crate types.
This is the default model for majority of supported targets.

#### Special relocation models

- `dynamic-no-pic` - relocatable external references, non-relocatable code.
Only makes sense on Darwin and is rarely used.
If StackOverflow tells you to use this as an opt-out of PIC or PIE, don't believe it,
use `-C relocation-model=static` instead.
- `ropi`, `rwpi` and `ropi-rwpi` - relocatable code and read-only data, relocatable read-write data,
and combination of both, respectively.
Only makes sense for certain embedded ARM targets.
- `default` - relocation model default to the current target.
Only makes sense as an override for some other explicitly specified relocation model
previously set on the command line.

Supported values can also be discovered by running `rustc --print relocation-models`.

#### Linking effects

In addition to codegen effects, `relocation-model` has effects during linking.

If the relocation model is `pic` and the current target supports position-independent executables
(PIE), the linker will be instructed (`-pie`) to produce one.
If the target doesn't support both position-independent and statically linked executables,
then `-C target-feature=+crt-static` "wins" over `-C relocation-model=pic`,
and the linker is instructed (`-static`) to produce a statically linked
but not position-independent executable.

## remark

Expand Down
48 changes: 20 additions & 28 deletions src/librustc_codegen_llvm/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::back::profiling::{
use crate::base;
use crate::common;
use crate::consts;
use crate::context::{get_reloc_model, is_pie_binary};
use crate::context::all_outputs_are_pic_executables;
use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
use crate::llvm_util;
use crate::type_::Type;
Expand All @@ -25,6 +25,7 @@ use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, Lto, OutputType, Passes, Sanitizer, SwitchWithOptPath};
use rustc_session::Session;
use rustc_target::spec::RelocModel;

use libc::{c_char, c_int, c_uint, c_void, size_t};
use std::ffi::CString;
Expand All @@ -35,16 +36,6 @@ use std::slice;
use std::str;
use std::sync::Arc;

pub const RELOC_MODEL_ARGS: [(&str, llvm::RelocMode); 7] = [
("pic", llvm::RelocMode::PIC),
("static", llvm::RelocMode::Static),
("default", llvm::RelocMode::Default),
("dynamic-no-pic", llvm::RelocMode::DynamicNoPic),
("ropi", llvm::RelocMode::ROPI),
("rwpi", llvm::RelocMode::RWPI),
("ropi-rwpi", llvm::RelocMode::ROPI_RWPI),
];

pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[
("small", llvm::CodeModel::Small),
("kernel", llvm::CodeModel::Kernel),
Expand Down Expand Up @@ -84,19 +75,13 @@ pub fn write_output_file(
}
}

pub fn create_informational_target_machine(
sess: &Session,
find_features: bool,
) -> &'static mut llvm::TargetMachine {
target_machine_factory(sess, config::OptLevel::No, find_features)()
pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine {
target_machine_factory(sess, config::OptLevel::No)()
.unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise())
}

pub fn create_target_machine(
tcx: TyCtxt<'_>,
find_features: bool,
) -> &'static mut llvm::TargetMachine {
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE), find_features)()
pub fn create_target_machine(tcx: TyCtxt<'_>) -> &'static mut llvm::TargetMachine {
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))()
.unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
}

Expand Down Expand Up @@ -126,15 +111,22 @@ fn to_pass_builder_opt_level(cfg: config::OptLevel) -> llvm::PassBuilderOptLevel
}
}

// If find_features is true this won't access `sess.crate_types` by assuming
// that `is_pie_binary` is false. When we discover LLVM target features
// `sess.crate_types` is uninitialized so we cannot access it.
fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel {
match relocation_model {
RelocModel::Static => llvm::RelocModel::Static,
RelocModel::Pic => llvm::RelocModel::PIC,
RelocModel::DynamicNoPic => llvm::RelocModel::DynamicNoPic,
RelocModel::Ropi => llvm::RelocModel::ROPI,
RelocModel::Rwpi => llvm::RelocModel::RWPI,
RelocModel::RopiRwpi => llvm::RelocModel::ROPI_RWPI,
}
}

pub fn target_machine_factory(
sess: &Session,
optlvl: config::OptLevel,
find_features: bool,
) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
let reloc_model = get_reloc_model(sess);
let reloc_model = to_llvm_relocation_model(sess.relocation_model());

let (opt_level, _) = to_llvm_opt_settings(optlvl);
let use_softfp = sess.opts.cg.soft_float;
Expand Down Expand Up @@ -175,7 +167,7 @@ pub fn target_machine_factory(
let features = features.join(",");
let features = CString::new(features).unwrap();
let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname);
let is_pie_binary = !find_features && is_pie_binary(sess);
let pic_is_pie = all_outputs_are_pic_executables(sess);
let trap_unreachable = sess.target.target.options.trap_unreachable;
let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;

Expand All @@ -192,7 +184,7 @@ pub fn target_machine_factory(
reloc_model,
opt_level,
use_softfp,
is_pie_binary,
pic_is_pie,
ffunction_sections,
fdata_sections,
trap_unreachable,
Expand Down
38 changes: 12 additions & 26 deletions src/librustc_codegen_llvm/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustc_session::Session;
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_span::symbol::Symbol;
use rustc_target::abi::{HasDataLayout, LayoutOf, PointeeInfo, Size, TargetDataLayout, VariantIdx};
use rustc_target::spec::{HasTargetSpec, Target};
use rustc_target::spec::{HasTargetSpec, RelocModel, Target};

use std::cell::{Cell, RefCell};
use std::ffi::CStr;
Expand Down Expand Up @@ -87,22 +87,6 @@ pub struct CodegenCx<'ll, 'tcx> {
local_gen_sym_counter: Cell<usize>,
}

pub fn get_reloc_model(sess: &Session) -> llvm::RelocMode {
let reloc_model_arg = match sess.opts.cg.relocation_model {
Some(ref s) => &s[..],
None => &sess.target.target.options.relocation_model[..],
};

match crate::back::write::RELOC_MODEL_ARGS.iter().find(|&&arg| arg.0 == reloc_model_arg) {
Some(x) => x.1,
_ => {
sess.err(&format!("{:?} is not a valid relocation mode", reloc_model_arg));
sess.abort_if_errors();
bug!();
}
}
}

fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode {
let tls_model_arg = match sess.opts.debugging_opts.tls_model {
Some(ref s) => &s[..],
Expand All @@ -119,12 +103,14 @@ fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode {
}
}

fn is_any_library(sess: &Session) -> bool {
sess.crate_types.borrow().iter().any(|ty| *ty != config::CrateType::Executable)
}

pub fn is_pie_binary(sess: &Session) -> bool {
!is_any_library(sess) && get_reloc_model(sess) == llvm::RelocMode::PIC
/// PIE is potentially more effective than PIC, but can only be used in executables.
/// If all our outputs are executables, then we can relax PIC to PIE when producing object code.
/// If the list of crate types is not yet known we conservatively return `false`.
pub fn all_outputs_are_pic_executables(sess: &Session) -> bool {
sess.relocation_model() == RelocModel::Pic
&& sess.crate_types.try_get().map_or(false, |crate_types| {
crate_types.iter().all(|ty| *ty == config::CrateType::Executable)
})
}

fn strip_function_ptr_alignment(data_layout: String) -> String {
Expand Down Expand Up @@ -157,7 +143,7 @@ pub unsafe fn create_module(

// Ensure the data-layout values hardcoded remain the defaults.
if sess.target.target.options.is_builtin {
let tm = crate::back::write::create_informational_target_machine(&tcx.sess, false);
let tm = crate::back::write::create_informational_target_machine(tcx.sess);
llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
llvm::LLVMRustDisposeTargetMachine(tm);

Expand Down Expand Up @@ -200,11 +186,11 @@ pub unsafe fn create_module(
let llvm_target = SmallCStr::new(&sess.target.target.llvm_target);
llvm::LLVMRustSetNormalizedTarget(llmod, llvm_target.as_ptr());

if get_reloc_model(sess) == llvm::RelocMode::PIC {
if sess.relocation_model() == RelocModel::Pic {
llvm::LLVMRustSetModulePICLevel(llmod);
}

if is_pie_binary(sess) {
if all_outputs_are_pic_executables(sess) {
llvm::LLVMRustSetModulePIELevel(llmod);
}

Expand Down
15 changes: 6 additions & 9 deletions src/librustc_codegen_llvm/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,8 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
&self,
sess: &Session,
optlvl: OptLevel,
find_features: bool,
) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
back::write::target_machine_factory(sess, optlvl, find_features)
back::write::target_machine_factory(sess, optlvl)
}
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
llvm_util::target_cpu(sess)
Expand Down Expand Up @@ -201,7 +200,9 @@ impl CodegenBackend for LlvmCodegenBackend {
match req {
PrintRequest::RelocationModels => {
println!("Available relocation models:");
for &(name, _) in back::write::RELOC_MODEL_ARGS.iter() {
for name in
&["static", "pic", "dynamic-no-pic", "ropi", "rwpi", "ropi-rwpi", "default"]
{
println!(" {}", name);
}
println!();
Expand Down Expand Up @@ -351,19 +352,15 @@ impl ModuleLlvm {
unsafe {
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx, false) }
ModuleLlvm { llmod_raw, llcx, tm: create_target_machine(tcx) }
}
}

fn new_metadata(tcx: TyCtxt<'_>, mod_name: &str) -> Self {
unsafe {
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
ModuleLlvm {
llmod_raw,
llcx,
tm: create_informational_target_machine(&tcx.sess, false),
}
ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) }
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/librustc_codegen_llvm/llvm/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -445,8 +445,7 @@ pub struct SanitizerOptions {
/// LLVMRelocMode
#[derive(Copy, Clone, PartialEq)]
#[repr(C)]
pub enum RelocMode {
Default,
pub enum RelocModel {
Static,
PIC,
DynamicNoPic,
Expand Down Expand Up @@ -1946,7 +1945,7 @@ extern "C" {
Features: *const c_char,
Abi: *const c_char,
Model: CodeModel,
Reloc: RelocMode,
Reloc: RelocModel,
Level: CodeGenOptLevel,
UseSoftFP: bool,
PositionIndependentExecutable: bool,
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_codegen_llvm/llvm_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str {
}

pub fn target_features(sess: &Session) -> Vec<Symbol> {
let target_machine = create_informational_target_machine(sess, true);
let target_machine = create_informational_target_machine(sess);
target_feature_whitelist(sess)
.iter()
.filter_map(|&(feature, gate)| {
Expand Down Expand Up @@ -322,7 +322,7 @@ pub fn print_passes() {

pub(crate) fn print(req: PrintRequest, sess: &Session) {
require_inited();
let tm = create_informational_target_machine(sess, true);
let tm = create_informational_target_machine(sess);
unsafe {
match req {
PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
Expand Down
13 changes: 2 additions & 11 deletions src/librustc_codegen_ssa/back/link.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_session::search_paths::PathKind;
/// need out of the shared crate context before we get rid of it.
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
use rustc_target::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelroLevel};
use rustc_target::spec::{LinkerFlavor, LldFlavor, PanicStrategy, RelocModel, RelroLevel};

use super::archive::ArchiveBuilder;
use super::command::Command;
Expand Down Expand Up @@ -1352,7 +1352,7 @@ fn add_position_independent_executable_args(
if sess.target.target.options.position_independent_executables {
let attr_link_args = &*codegen_results.crate_info.link_args;
let mut user_defined_link_args = sess.opts.cg.link_args.iter().chain(attr_link_args);
if is_pic(sess)
if sess.relocation_model() == RelocModel::Pic
&& !sess.crt_static(Some(crate_type))
&& !user_defined_link_args.any(|x| x == "-static")
{
Expand Down Expand Up @@ -1992,12 +1992,3 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool {
config::Lto::No | config::Lto::ThinLocal => false,
}
}

fn is_pic(sess: &Session) -> bool {
let reloc_model_arg = match sess.opts.cg.relocation_model {
Some(ref s) => &s[..],
None => &sess.target.target.options.relocation_model[..],
};

reloc_model_arg == "pic"
}
2 changes: 1 addition & 1 deletion src/librustc_codegen_ssa/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1037,7 +1037,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
regular_module_config: regular_config,
metadata_module_config: metadata_config,
allocator_module_config: allocator_config,
tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol, false)),
tm_factory: TargetMachineFactory(backend.target_machine_factory(tcx.sess, ol)),
total_cgus,
msvc_imps_needed: msvc_imps_needed(tcx),
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),
Expand Down
4 changes: 0 additions & 4 deletions src/librustc_codegen_ssa/traits/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,10 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
tcx: TyCtxt<'_>,
cgu_name: Symbol,
) -> (ModuleCodegen<Self::Module>, u64);
// If find_features is true this won't access `sess.crate_types` by assuming
// that `is_pie_binary` is false. When we discover LLVM target features
// `sess.crate_types` is uninitialized so we cannot access it.
fn target_machine_factory(
&self,
sess: &Session,
opt_level: config::OptLevel,
find_features: bool,
) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>;
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
}
4 changes: 2 additions & 2 deletions src/librustc_interface/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use rustc_session::{build_session, Session};
use rustc_span::edition::{Edition, DEFAULT_EDITION};
use rustc_span::symbol::sym;
use rustc_span::SourceFileHashAlgorithm;
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelroLevel};
use rustc_target::spec::{LinkerFlavor, MergeFunctions, PanicStrategy, RelocModel, RelroLevel};
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
use std::path::PathBuf;
Expand Down Expand Up @@ -430,7 +430,7 @@ fn test_codegen_options_tracking_hash() {
tracked!(prefer_dynamic, true);
tracked!(profile_generate, SwitchWithOptPath::Enabled(None));
tracked!(profile_use, Some(PathBuf::from("abc")));
tracked!(relocation_model, Some(String::from("relocation model")));
tracked!(relocation_model, Some(RelocModel::Pic));
tracked!(soft_float, true);
tracked!(target_cpu, Some(String::from("abc")));
tracked!(target_feature, String::from("all the features, all of them"));
Expand Down
Loading