squid_ewe/toolchain/
gas.rs

1use std::{
2    io::Write,
3    process::{
4        exit,
5        Command,
6    },
7};
8
9use crate::{
10    asm::separate_statements,
11    getopt::{
12        GetoptParser,
13        OptVal,
14    },
15    listing::EXTENSION,
16};
17
18const OPTION_BLACKLIST: [&str; 1] = ["-mrelax"];
19
20#[derive(Debug)]
21pub struct AsWrapper {
22    args: Vec<String>,
23    inputs: Vec<String>,
24    output: String,
25}
26
27impl AsWrapper {
28    pub fn from_cmdline(args: Vec<String>) -> Option<Self> {
29        let parser = GetoptParser::new()
30            .optstring("o:JKLMRWZa::Dg::I:vwXt:")
31            .optstring("O::g::G:")
32            .long("alternate", OptVal::None, None)
33            .long("compress-debug-sections", OptVal::Optional, None)
34            .long("nocompress-debug-sections", OptVal::None, None)
35            .long("debug-prefix-map", OptVal::Required, None)
36            .long("defsym", OptVal::Required, None)
37            .long("dump-config", OptVal::None, None)
38            .long("emulation", OptVal::Required, None)
39            .long("execstack", OptVal::None, None)
40            .long("noexecstack", OptVal::None, None)
41            .long("size-check", OptVal::Required, None)
42            .long("elf-stt-common", OptVal::Required, None)
43            .long("sectname-subst", OptVal::None, None)
44            .long("generate-missing-build-notes", OptVal::Required, None)
45            .long("fatal-warnings", OptVal::None, None)
46            .long("gdwarf-cie-version", OptVal::Required, None)
47            .long("gen-debug", OptVal::None, None)
48            .long("gstabs", OptVal::None, None)
49            .long("gstabs+", OptVal::None, None)
50            .long("gdwarf-2", OptVal::None, None)
51            .long("gdwarf-3", OptVal::None, None)
52            .long("gdwarf-4", OptVal::None, None)
53            .long("gdwarf-5", OptVal::None, None)
54            .long("gdwarf-sections", OptVal::None, None)
55            .long("hash-size", OptVal::Required, None)
56            .long("help", OptVal::None, None)
57            .long("itbl", OptVal::Required, None)
58            .long("keep-locals", OptVal::None, None)
59            .long("listing-lhs-width", OptVal::Required, None)
60            .long("listing-lhs-width2", OptVal::Required, None)
61            .long("listing-rhs-width", OptVal::Required, None)
62            .long("listing-cont-lines", OptVal::Required, None)
63            .long("MD", OptVal::Required, None)
64            .long("mri", OptVal::None, None)
65            .long("nocpp", OptVal::None, None)
66            .long("no-pad-sections", OptVal::None, None)
67            .long("no-warn", OptVal::None, None)
68            .long("reduce-memory-overheads", OptVal::None, None)
69            .long("statistics", OptVal::None, None)
70            .long("strip-local-absolute", OptVal::None, None)
71            .long("version", OptVal::None, None)
72            .long("verbose", OptVal::None, None)
73            .long("target-help", OptVal::None, None)
74            .long("traditional-format", OptVal::None, None)
75            .long("warn", OptVal::None, None)
76            .long("multibyte-handling", OptVal::Required, None)
77            .long("march", OptVal::Required, None)
78            .short('f', OptVal::Required, None)
79            .long("mabi", OptVal::Required, None)
80            .long("misa-spec", OptVal::Required, None)
81            .long("mpriv-spec", OptVal::Required, None)
82            .short('m', OptVal::Required, None);
83
84        let cmdline = parser.parse_long_only(&args).unwrap();
85        let output = if let Some(output) = cmdline.arg_value('o') {
86            output.to_string()
87        } else {
88            return None;
89        };
90        let mut inputs = Vec::new();
91
92        for input in cmdline.positionals() {
93            if *input != "-" {
94                inputs.push(input.to_string());
95            }
96        }
97
98        Some(Self {
99            args,
100            inputs,
101            output,
102        })
103    }
104
105    pub fn preprocess(&self) {
106        for filename in &self.inputs {
107            let input = std::fs::read(filename).unwrap();
108            let output = separate_statements(&input, filename);
109            let mut file = std::fs::OpenOptions::new().create(true).truncate(true).write(true).open(filename).unwrap();
110            file.write_all(&output).unwrap();
111        }
112    }
113
114    pub fn compile(&self) {
115        let listing = format!("{}.{}", self.output, EXTENSION);
116        let status = Command::new(&self.args[0])
117            .arg(format!("-almd={listing}"))
118            .args(self.args[1..].iter().filter(|x| !OPTION_BLACKLIST.contains(&x.as_str())))
119            .arg("-mno-relax")
120            .envs(std::env::vars())
121            .status()
122            .unwrap();
123
124        if let Some(code) = status.code() {
125            if code != 0 {
126                exit(code);
127            }
128        } else {
129            exit(-1);
130        }
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137
138    #[test]
139    fn test_assembly_preprocessing() {
140        let output = separate_statements(
141            b".file \":;\\\"\\\\\"# single-line comment\n/* multi-line\ncomment */.L0:.directive;inst;\n",
142            "<test>",
143        );
144        println!("{}", std::str::from_utf8(&output).unwrap());
145    }
146
147    #[test]
148    fn test_as_wrapper1() {
149        let wrapper = AsWrapper::from_cmdline(vec!["as".to_string(), "--help".to_string()]);
150        assert!(wrapper.is_none());
151    }
152
153    #[test]
154    fn test_as_wrapper2() {
155        let wrapper = AsWrapper::from_cmdline(vec![
156            "as".to_string(),
157            "-fpic".to_string(),
158            "--traditional-format".to_string(),
159            "-march=rv64imafd".to_string(),
160            "-mabi=lp64d".to_string(),
161            "-misa-spec=2.2".to_string(),
162            "-o".to_string(),
163            "/tmp/cc5hz51Q.o".to_string(),
164            "/tmp/ccNyPyiT.s".to_string(),
165            "-".to_string(),
166        ])
167        .unwrap();
168        assert_eq!(wrapper.inputs, &["/tmp/ccNyPyiT.s"]);
169        assert_eq!(wrapper.output, "/tmp/cc5hz51Q.o");
170    }
171
172    #[test]
173    fn test_glibc() {
174        let wrapper = AsWrapper::from_cmdline(vec![
175            "as".to_string(),
176            "-I".to_string(),
177            "../include".to_string(),
178            "--gdwarf-5".to_string(),
179            "--traditional-format".to_string(),
180            "-fpic".to_string(),
181            "-march=rv64imafd".to_string(),
182            "-march=rv64imafd".to_string(),
183            "-mabi=lp64d".to_string(),
184            "-misa-spec=2.2".to_string(),
185            "-o".to_string(),
186            "/io/test-data/glibc/build/libio/clearerr.os".to_string(),
187            "/tmp/ccJfUCIc.s".to_string(),
188        ])
189        .unwrap();
190        println!("{:?}", wrapper);
191    }
192}