1 use cranelift_frontend
::{FunctionBuilder, FunctionBuilderContext}
;
2 use rustc_hir
::LangItem
;
3 use rustc_middle
::ty
::AssocKind
;
4 use rustc_middle
::ty
::GenericArg
;
5 use rustc_session
::config
::{sigpipe, EntryFnType}
;
6 use rustc_span
::symbol
::Ident
;
10 /// Create the `main` function which will initialize the rust runtime and call
11 /// users main function.
12 pub(crate) fn maybe_create_entry_wrapper(
14 module
: &mut impl Module
,
15 unwind_context
: &mut UnwindContext
,
19 let (main_def_id
, (is_main_fn
, sigpipe
)) = match tcx
.entry_fn(()) {
20 Some((def_id
, entry_ty
)) => (
23 EntryFnType
::Main { sigpipe }
=> (true, sigpipe
),
24 EntryFnType
::Start
=> (false, sigpipe
::DEFAULT
),
30 if main_def_id
.is_local() {
31 let instance
= Instance
::mono(tcx
, main_def_id
).polymorphize(tcx
);
32 if module
.get_name(tcx
.symbol_name(instance
).name
).is_none() {
35 } else if !is_primary_cgu
{
39 create_entry_fn(tcx
, module
, unwind_context
, main_def_id
, is_jit
, is_main_fn
, sigpipe
);
44 unwind_context
: &mut UnwindContext
,
45 rust_main_def_id
: DefId
,
46 ignore_lang_start_wrapper
: bool
,
50 let main_ret_ty
= tcx
.fn_sig(rust_main_def_id
).no_bound_vars().unwrap().output();
51 // Given that `main()` has no arguments,
52 // then its return type cannot have
53 // late-bound regions, since late-bound
54 // regions must appear in the argument
56 let main_ret_ty
= tcx
.normalize_erasing_regions(
57 ty
::ParamEnv
::reveal_all(),
58 main_ret_ty
.no_bound_vars().unwrap(),
61 let cmain_sig
= Signature
{
63 AbiParam
::new(m
.target_config().pointer_type()),
64 AbiParam
::new(m
.target_config().pointer_type()),
66 returns
: vec
![AbiParam
::new(m
.target_config().pointer_type() /*isize*/)],
67 call_conv
: crate::conv_to_call_conv(
69 tcx
.sess
.target
.options
.entry_abi
,
70 m
.target_config().default_call_conv
,
74 let entry_name
= tcx
.sess
.target
.options
.entry_name
.as_ref();
75 let cmain_func_id
= match m
.declare_function(entry_name
, Linkage
::Export
, &cmain_sig
) {
76 Ok(func_id
) => func_id
,
79 .fatal(format
!("entry symbol `{entry_name}` declared multiple times: {err}"));
83 let instance
= Instance
::mono(tcx
, rust_main_def_id
).polymorphize(tcx
);
85 let main_name
= tcx
.symbol_name(instance
).name
;
86 let main_sig
= get_function_sig(tcx
, m
.target_config().default_call_conv
, instance
);
87 let main_func_id
= m
.declare_function(main_name
, Linkage
::Import
, &main_sig
).unwrap();
89 let mut ctx
= Context
::new();
90 ctx
.func
.signature
= cmain_sig
;
92 let mut func_ctx
= FunctionBuilderContext
::new();
93 let mut bcx
= FunctionBuilder
::new(&mut ctx
.func
, &mut func_ctx
);
95 let block
= bcx
.create_block();
96 bcx
.switch_to_block(block
);
97 let arg_argc
= bcx
.append_block_param(block
, m
.target_config().pointer_type());
98 let arg_argv
= bcx
.append_block_param(block
, m
.target_config().pointer_type());
99 let arg_sigpipe
= bcx
.ins().iconst(types
::I8
, sigpipe
as i64);
101 let main_func_ref
= m
.declare_func_in_func(main_func_id
, &mut bcx
.func
);
103 let result
= if is_main_fn
&& ignore_lang_start_wrapper
{
104 // regular main fn, but ignoring #[lang = "start"] as we are running in the jit
105 // FIXME set program arguments somehow
106 let call_inst
= bcx
.ins().call(main_func_ref
, &[]);
107 let call_results
= bcx
.func
.dfg
.inst_results(call_inst
).to_owned();
109 let termination_trait
= tcx
.require_lang_item(LangItem
::Termination
, None
);
111 .associated_items(termination_trait
)
112 .find_by_name_and_kind(
114 Ident
::from_str("report"),
119 let report
= Instance
::expect_resolve(
121 ParamEnv
::reveal_all(),
123 tcx
.mk_args(&[GenericArg
::from(main_ret_ty
)]),
127 let report_name
= tcx
.symbol_name(report
).name
;
128 let report_sig
= get_function_sig(tcx
, m
.target_config().default_call_conv
, report
);
130 m
.declare_function(report_name
, Linkage
::Import
, &report_sig
).unwrap();
131 let report_func_ref
= m
.declare_func_in_func(report_func_id
, &mut bcx
.func
);
133 // FIXME do proper abi handling instead of expecting the pass mode to be identical
134 // for returns and arguments.
135 let report_call_inst
= bcx
.ins().call(report_func_ref
, &call_results
);
136 let res
= bcx
.func
.dfg
.inst_results(report_call_inst
)[0];
137 match m
.target_config().pointer_type() {
139 types
::I64
=> bcx
.ins().sextend(types
::I64
, res
),
140 _
=> unimplemented
!("16bit systems are not yet supported"),
142 } else if is_main_fn
{
143 let start_def_id
= tcx
.require_lang_item(LangItem
::Start
, None
);
144 let start_instance
= Instance
::expect_resolve(
146 ParamEnv
::reveal_all(),
148 tcx
.mk_args(&[main_ret_ty
.into()]),
151 let start_func_id
= import_function(tcx
, m
, start_instance
);
153 let main_val
= bcx
.ins().func_addr(m
.target_config().pointer_type(), main_func_ref
);
155 let func_ref
= m
.declare_func_in_func(start_func_id
, &mut bcx
.func
);
157 bcx
.ins().call(func_ref
, &[main_val
, arg_argc
, arg_argv
, arg_sigpipe
]);
158 bcx
.inst_results(call_inst
)[0]
160 // using user-defined start fn
161 let call_inst
= bcx
.ins().call(main_func_ref
, &[arg_argc
, arg_argv
]);
162 bcx
.inst_results(call_inst
)[0]
165 bcx
.ins().return_(&[result
]);
166 bcx
.seal_all_blocks();
170 if let Err(err
) = m
.define_function(cmain_func_id
, &mut ctx
) {
171 tcx
.dcx().fatal(format
!("entry symbol `{entry_name}` defined multiple times: {err}"));
174 unwind_context
.add_function(cmain_func_id
, &ctx
, m
.isa());