1
Fork 0

codegen_llvm: Simplify logic for relaxing PIC into PIE

This commit is contained in:
Vadim Petrochenkov 2020-04-23 21:10:01 +03:00
parent 0452725583
commit 76d85de223
6 changed files with 22 additions and 36 deletions

View file

@ -7,7 +7,7 @@ use crate::back::profiling::{
use crate::base; use crate::base;
use crate::common; use crate::common;
use crate::consts; use crate::consts;
use crate::context::is_pie_binary; use crate::context::all_outputs_are_pic_executables;
use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic}; use crate::llvm::{self, DiagnosticInfo, PassManager, SMDiagnostic};
use crate::llvm_util; use crate::llvm_util;
use crate::type_::Type; use crate::type_::Type;
@ -75,19 +75,13 @@ pub fn write_output_file(
} }
} }
pub fn create_informational_target_machine( pub fn create_informational_target_machine(sess: &Session) -> &'static mut llvm::TargetMachine {
sess: &Session, target_machine_factory(sess, config::OptLevel::No)()
find_features: bool,
) -> &'static mut llvm::TargetMachine {
target_machine_factory(sess, config::OptLevel::No, find_features)()
.unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise()) .unwrap_or_else(|err| llvm_err(sess.diagnostic(), &err).raise())
} }
pub fn create_target_machine( pub fn create_target_machine(tcx: TyCtxt<'_>) -> &'static mut llvm::TargetMachine {
tcx: TyCtxt<'_>, target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE))()
find_features: bool,
) -> &'static mut llvm::TargetMachine {
target_machine_factory(&tcx.sess, tcx.backend_optimization_level(LOCAL_CRATE), find_features)()
.unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise()) .unwrap_or_else(|err| llvm_err(tcx.sess.diagnostic(), &err).raise())
} }
@ -128,13 +122,9 @@ fn to_llvm_relocation_model(relocation_model: RelocModel) -> llvm::RelocModel {
} }
} }
// 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.
pub fn target_machine_factory( pub fn target_machine_factory(
sess: &Session, sess: &Session,
optlvl: config::OptLevel, optlvl: config::OptLevel,
find_features: bool,
) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { ) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> {
let reloc_model = to_llvm_relocation_model(sess.relocation_model()); let reloc_model = to_llvm_relocation_model(sess.relocation_model());
@ -177,7 +167,7 @@ pub fn target_machine_factory(
let features = features.join(","); let features = features.join(",");
let features = CString::new(features).unwrap(); let features = CString::new(features).unwrap();
let abi = SmallCStr::new(&sess.target.target.options.llvm_abiname); 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 trap_unreachable = sess.target.target.options.trap_unreachable;
let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes; let emit_stack_size_section = sess.opts.debugging_opts.emit_stack_sizes;
@ -194,7 +184,7 @@ pub fn target_machine_factory(
reloc_model, reloc_model,
opt_level, opt_level,
use_softfp, use_softfp,
is_pie_binary, pic_is_pie,
ffunction_sections, ffunction_sections,
fdata_sections, fdata_sections,
trap_unreachable, trap_unreachable,

View file

@ -103,9 +103,14 @@ fn get_tls_model(sess: &Session) -> llvm::ThreadLocalMode {
} }
} }
pub fn is_pie_binary(sess: &Session) -> bool { /// 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.relocation_model() == RelocModel::Pic
&& !sess.crate_types.borrow().iter().any(|ty| *ty != config::CrateType::Executable) && 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 { fn strip_function_ptr_alignment(data_layout: String) -> String {
@ -138,7 +143,7 @@ pub unsafe fn create_module(
// Ensure the data-layout values hardcoded remain the defaults. // Ensure the data-layout values hardcoded remain the defaults.
if sess.target.target.options.is_builtin { 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::LLVMRustSetDataLayoutFromTargetMachine(llmod, tm);
llvm::LLVMRustDisposeTargetMachine(tm); llvm::LLVMRustDisposeTargetMachine(tm);
@ -185,7 +190,7 @@ pub unsafe fn create_module(
llvm::LLVMRustSetModulePICLevel(llmod); llvm::LLVMRustSetModulePICLevel(llmod);
} }
if is_pie_binary(sess) { if all_outputs_are_pic_executables(sess) {
llvm::LLVMRustSetModulePIELevel(llmod); llvm::LLVMRustSetModulePIELevel(llmod);
} }

View file

@ -110,9 +110,8 @@ impl ExtraBackendMethods for LlvmCodegenBackend {
&self, &self,
sess: &Session, sess: &Session,
optlvl: OptLevel, optlvl: OptLevel,
find_features: bool,
) -> Arc<dyn Fn() -> Result<&'static mut llvm::TargetMachine, String> + Send + Sync> { ) -> 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 { fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str {
llvm_util::target_cpu(sess) llvm_util::target_cpu(sess)
@ -353,7 +352,7 @@ impl ModuleLlvm {
unsafe { unsafe {
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; 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) }
} }
} }
@ -361,11 +360,7 @@ impl ModuleLlvm {
unsafe { unsafe {
let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names()); let llcx = llvm::LLVMRustContextCreate(tcx.sess.fewer_names());
let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _; let llmod_raw = context::create_module(tcx, llcx, mod_name) as *const _;
ModuleLlvm { ModuleLlvm { llmod_raw, llcx, tm: create_informational_target_machine(tcx.sess) }
llmod_raw,
llcx,
tm: create_informational_target_machine(&tcx.sess, false),
}
} }
} }

View file

@ -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> { 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) target_feature_whitelist(sess)
.iter() .iter()
.filter_map(|&(feature, gate)| { .filter_map(|&(feature, gate)| {
@ -322,7 +322,7 @@ pub fn print_passes() {
pub(crate) fn print(req: PrintRequest, sess: &Session) { pub(crate) fn print(req: PrintRequest, sess: &Session) {
require_inited(); require_inited();
let tm = create_informational_target_machine(sess, true); let tm = create_informational_target_machine(sess);
unsafe { unsafe {
match req { match req {
PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm), PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),

View file

@ -1037,7 +1037,7 @@ fn start_executing_work<B: ExtraBackendMethods>(
regular_module_config: regular_config, regular_module_config: regular_config,
metadata_module_config: metadata_config, metadata_module_config: metadata_config,
allocator_module_config: allocator_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, total_cgus,
msvc_imps_needed: msvc_imps_needed(tcx), msvc_imps_needed: msvc_imps_needed(tcx),
target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(), target_pointer_width: tcx.sess.target.target.target_pointer_width.clone(),

View file

@ -110,14 +110,10 @@ pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Se
tcx: TyCtxt<'_>, tcx: TyCtxt<'_>,
cgu_name: Symbol, cgu_name: Symbol,
) -> (ModuleCodegen<Self::Module>, u64); ) -> (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( fn target_machine_factory(
&self, &self,
sess: &Session, sess: &Session,
opt_level: config::OptLevel, opt_level: config::OptLevel,
find_features: bool,
) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>; ) -> Arc<dyn Fn() -> Result<Self::TargetMachine, String> + Send + Sync>;
fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str; fn target_cpu<'b>(&self, sess: &'b Session) -> &'b str;
} }