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