From 84b058ac47e2ea5f29887a4ed5ae286e37b22194 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 2 Sep 2021 15:41:10 -0700 Subject: [PATCH] add support for #[start] --- benches/helpers/miri_helper.rs | 5 +- src/bin/miri.rs | 6 +-- src/eval.rs | 90 +++++++++++++++++++++++----------- src/lib.rs | 2 +- tests/run-pass/start.rs | 8 +++ tests/run-pass/start.stdout | 1 + 6 files changed, 78 insertions(+), 34 deletions(-) create mode 100644 tests/run-pass/start.rs create mode 100644 tests/run-pass/start.stdout diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2d27616a361..be542c2bc0a 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -20,11 +20,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, _) = tcx.entry_fn(()).expect("no main or start function found"); + let (entry_def_id, entry_type) = + tcx.entry_fn(()).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id, config); + miri::eval_entry(tcx, entry_def_id, entry_type, config); }); }); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 18c393815ca..fbc87148ec7 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -58,8 +58,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); - let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(()) { - (entry_def, x) + let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) { + entry_def } else { let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( ColorConfig::Auto, @@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { env::set_current_dir(cwd).unwrap(); } - if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { + if let Some(return_code) = miri::eval_entry(tcx, entry_def_id, entry_type, config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), ); diff --git a/src/eval.rs b/src/eval.rs index 2b8fc0f5ade..f90a77fafd5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -10,6 +10,8 @@ use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; +use rustc_session::config::EntryFnType; + use crate::*; #[derive(Copy, Clone, Debug, PartialEq)] @@ -117,12 +119,13 @@ impl Default for MiriConfig { } /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing -/// the location where the return value of the `start` lang item will be +/// the location where the return value of the `start` function will be /// written to. /// Public because this is also used by `priroda`. pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, - main_id: DefId, + entry_id: DefId, + entry_type: EntryFnType, config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { let param_env = ty::ParamEnv::reveal_all(); @@ -145,26 +148,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Setup first stack-frame - let main_instance = ty::Instance::mono(tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def, None)?; + let entry_instance = ty::Instance::mono(tcx, entry_id); + /*let entry_mir = ecx.load_mir(entry_instance.def, None)?; if main_mir.arg_count != 0 { bug!("main function must not take any arguments"); - } + }*/ - let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - start_id, - tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), - ) - .unwrap() - .unwrap(); + // First argument is constructed later, because its skipped if the entry function uses #[start] - // First argument: pointer to `main()`. - let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx); // Third argument (`argv`): created from `config.args`. @@ -237,28 +228,71 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argv }; + /*let args: &[_] = match entry_type { + EntryFnType::Main => { + // First argument: pointer to `main()`. + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); + + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv] + } + EntryFnType::Start => &[argc.into(), argv], + };*/ + // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; // Call start function. - ecx.call_function( - start_instance, - Abi::Rust, - &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], - Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, - )?; + + match entry_type { + EntryFnType::Main => { + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(entry_id).output(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); + let start_instance = ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + start_id, + tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), + ) + .unwrap() + .unwrap(); + + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance)); + + ecx.call_function( + start_instance, + Abi::Rust, + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], + Some(&ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + } + EntryFnType::Start => { + ecx.call_function( + entry_instance, + Abi::Rust, + &[argc.into(), argv], + Some(&ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + } + } Ok((ecx, ret_place)) } -/// Evaluates the main function specified by `main_id`. +/// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. -pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option<i64> { +pub fn eval_entry<'tcx>( + tcx: TyCtxt<'tcx>, + entry_id: DefId, + entry_type: EntryFnType, + config: MiriConfig, +) -> Option<i64> { // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { + let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) { Ok(v) => v, Err(err) => { err.print_backtrace(); diff --git a/src/lib.rs b/src/lib.rs index f8d8aacce3c..7ed915b6d1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub use crate::diagnostics::{ NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{ - create_ecx, eval_main, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, + create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ diff --git a/tests/run-pass/start.rs b/tests/run-pass/start.rs new file mode 100644 index 00000000000..f25d62fa8c3 --- /dev/null +++ b/tests/run-pass/start.rs @@ -0,0 +1,8 @@ +#![feature(start)] + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + println!("Hello from start!"); + + 0 +} diff --git a/tests/run-pass/start.stdout b/tests/run-pass/start.stdout new file mode 100644 index 00000000000..d7f627d237c --- /dev/null +++ b/tests/run-pass/start.stdout @@ -0,0 +1 @@ +Hello from start!