]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_cranelift/src/global_asm.rs
Auto merge of #107197 - aliemjay:patch-2, r=jackh726
[rust.git] / compiler / rustc_codegen_cranelift / src / global_asm.rs
1 //! The AOT driver uses [`cranelift_object`] to write object files suitable for linking into a
2 //! standalone executable.
3
4 use std::io::Write;
5 use std::path::PathBuf;
6 use std::process::{Command, Stdio};
7 use std::sync::Arc;
8
9 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
10 use rustc_hir::ItemId;
11 use rustc_session::config::{OutputFilenames, OutputType};
12
13 use crate::prelude::*;
14
15 pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String, item_id: ItemId) {
16     let item = tcx.hir().item(item_id);
17     if let rustc_hir::ItemKind::GlobalAsm(asm) = item.kind {
18         if !asm.options.contains(InlineAsmOptions::ATT_SYNTAX) {
19             global_asm.push_str("\n.intel_syntax noprefix\n");
20         } else {
21             global_asm.push_str("\n.att_syntax\n");
22         }
23         for piece in asm.template {
24             match *piece {
25                 InlineAsmTemplatePiece::String(ref s) => global_asm.push_str(s),
26                 InlineAsmTemplatePiece::Placeholder { .. } => todo!(),
27             }
28         }
29         global_asm.push_str("\n.att_syntax\n\n");
30     } else {
31         bug!("Expected GlobalAsm found {:?}", item);
32     }
33 }
34
35 #[derive(Debug)]
36 pub(crate) struct GlobalAsmConfig {
37     asm_enabled: bool,
38     assembler: PathBuf,
39     pub(crate) output_filenames: Arc<OutputFilenames>,
40 }
41
42 impl GlobalAsmConfig {
43     pub(crate) fn new(tcx: TyCtxt<'_>) -> Self {
44         let asm_enabled = cfg!(feature = "inline_asm") && !tcx.sess.target.is_like_windows;
45
46         GlobalAsmConfig {
47             asm_enabled,
48             assembler: crate::toolchain::get_toolchain_binary(tcx.sess, "as"),
49             output_filenames: tcx.output_filenames(()).clone(),
50         }
51     }
52 }
53
54 pub(crate) fn compile_global_asm(
55     config: &GlobalAsmConfig,
56     cgu_name: &str,
57     global_asm: &str,
58 ) -> Result<Option<PathBuf>, String> {
59     if global_asm.is_empty() {
60         return Ok(None);
61     }
62
63     if !config.asm_enabled {
64         if global_asm.contains("__rust_probestack") {
65             return Ok(None);
66         }
67
68         // FIXME fix linker error on macOS
69         if cfg!(not(feature = "inline_asm")) {
70             return Err(
71                 "asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift"
72                     .to_owned(),
73             );
74         } else {
75             return Err("asm! and global_asm! are not yet supported on Windows".to_owned());
76         }
77     }
78
79     // Remove all LLVM style comments
80     let global_asm = global_asm
81         .lines()
82         .map(|line| if let Some(index) = line.find("//") { &line[0..index] } else { line })
83         .collect::<Vec<_>>()
84         .join("\n");
85
86     let output_object_file = config.output_filenames.temp_path(OutputType::Object, Some(cgu_name));
87
88     // Assemble `global_asm`
89     let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm");
90     let mut child = Command::new(&config.assembler)
91         .arg("-o")
92         .arg(&global_asm_object_file)
93         .stdin(Stdio::piped())
94         .spawn()
95         .expect("Failed to spawn `as`.");
96     child.stdin.take().unwrap().write_all(global_asm.as_bytes()).unwrap();
97     let status = child.wait().expect("Failed to wait for `as`.");
98     if !status.success() {
99         return Err(format!("Failed to assemble `{}`", global_asm));
100     }
101
102     Ok(Some(global_asm_object_file))
103 }
104
105 pub(crate) fn add_file_stem_postfix(mut path: PathBuf, postfix: &str) -> PathBuf {
106     let mut new_filename = path.file_stem().unwrap().to_owned();
107     new_filename.push(postfix);
108     if let Some(extension) = path.extension() {
109         new_filename.push(".");
110         new_filename.push(extension);
111     }
112     path.set_file_name(new_filename);
113     path
114 }