Skip to main content

gaia_assembler/backends/windows/
x86_64.rs

1//! Native x86_64 backend compiler for Windows
2//! This backend generates native x86_64 machine code wrapped in a PE container
3
4#[cfg(feature = "x86_64-assembler")]
5use crate::{
6    backends::{
7        windows::emitter::{RelocationKind, X64Emitter},
8        Backend, GeneratedFiles,
9    },
10    config::GaiaConfig,
11    instruction::{CoreInstruction, GaiaInstruction, ManagedInstruction},
12    program::{GaiaConstant, GaiaFunction, GaiaModule},
13    types::GaiaType,
14};
15use gaia_types::{
16    helpers::{AbiCompatible, ApiCompatible, Architecture, ArtifactType, CompilationTarget},
17    GaiaError, Result,
18};
19
20#[cfg(feature = "pe-assembler")]
21use pe_assembler::formats::exe::writer::ExeWriter;
22use std::collections::HashMap;
23
24#[cfg(feature = "x86_64-assembler")]
25use x86_64_assembler::{
26    encoder::InstructionEncoder,
27    instruction::{Instruction, Operand, Register},
28};
29
30/// Native x86_64 Backend implementation for Windows
31#[cfg(feature = "x86_64-assembler")]
32pub struct X64Backend {
33    encoder: InstructionEncoder,
34}
35
36#[cfg(feature = "x86_64-assembler")]
37impl X64Backend {
38    /// Create a new X64Backend instance
39    pub fn new() -> Self {
40        Self {
41            encoder: InstructionEncoder::new(Architecture::X86_64),
42        }
43    }
44}
45
46#[cfg(feature = "x86_64-assembler")]
47impl Default for X64Backend {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53#[cfg(feature = "x86_64-assembler")]
54impl Backend for X64Backend {
55    fn name(&self) -> &'static str {
56        "Windows (Native x86_64)"
57    }
58
59    fn primary_target(&self) -> CompilationTarget {
60        CompilationTarget { build: Architecture::X86_64, host: AbiCompatible::PE, target: ApiCompatible::MicrosoftVisualC }
61    }
62
63    fn artifact_type(&self) -> ArtifactType {
64        ArtifactType::Executable
65    }
66
67    fn match_score(&self, target: &CompilationTarget) -> f32 {
68        if target.build == Architecture::X86_64 && target.host == AbiCompatible::PE {
69            if target.target == ApiCompatible::MicrosoftVisualC {
70                return 100.0;
71            }
72            return 80.0;
73        }
74        0.0
75    }
76
77    fn generate(&self, program: &GaiaModule, config: &GaiaConfig) -> Result<GeneratedFiles> {
78        let mut emitter = X64Emitter::new(program);
79        emitter.emit()?;
80        let (instructions, relocations, _rdata) = emitter.take_result();
81
82        let mut code = Vec::new();
83        let mut labels = HashMap::new();
84        let mut inst_offsets = Vec::new();
85
86        // Pass 1: Encode and find labels
87        for inst in &instructions {
88            inst_offsets.push(code.len());
89            match inst {
90                Instruction::Label(name) => {
91                    labels.insert(name.clone(), code.len());
92                }
93                _ => {
94                    let bytes = self.encode_inst(inst)?;
95                    code.extend_from_slice(&bytes);
96                }
97            }
98        }
99
100        // Pass 2: Apply relocations (Simplified for now)
101        let mut exit_pos = 0;
102        let mut external_calls: HashMap<String, Vec<usize>> = HashMap::new();
103        let string_patches: Vec<(usize, usize)> = Vec::new();
104
105        for reloc in &relocations {
106            let inst_pos = inst_offsets[reloc.instruction_index];
107            match reloc.kind {
108                RelocationKind::Relative32 => {
109                    if let Some(&target_offset) = labels.get(&reloc.target) {
110                        let rel = (target_offset as i32) - (inst_pos as i32 + 5);
111                        code[inst_pos + 1..inst_pos + 5].copy_from_slice(&rel.to_le_bytes());
112                    }
113                }
114                RelocationKind::RipRelative => {
115                    if reloc.target == "ExitProcess" {
116                        exit_pos = inst_pos;
117                    }
118                    external_calls.entry(reloc.target.clone()).or_default().push(inst_pos);
119                }
120                _ => {}
121            }
122        }
123
124        let mut files = HashMap::new();
125        files.insert("main.exe".to_string(), code.clone());
126
127        #[cfg(feature = "pe-assembler")]
128        {
129            let rdata = &[];
130            let pe_bytes = self.create_pe_exe(&code, program, exit_pos, &external_calls, rdata, &string_patches)?;
131            files.insert("main.exe".to_string(), pe_bytes);
132        }
133
134        Ok(GeneratedFiles { artifact_type: self.artifact_type(), files, custom: None, diagnostics: vec![] })
135    }
136}
137
138#[cfg(feature = "x86_64-assembler")]
139impl X64Backend {
140    fn encode_inst(&self, inst: &Instruction) -> Result<Vec<u8>> {
141        self.encoder.encode(inst)
142    }
143
144    #[cfg(feature = "pe-assembler")]
145    fn create_pe_exe(
146        &self,
147        code: &[u8],
148        program: &GaiaModule,
149        exit_pos: usize,
150        external_calls: &HashMap<String, Vec<usize>>,
151        rdata: &[u8],
152        string_patches: &[(usize, usize)],
153    ) -> Result<Vec<u8>> {
154        use pe_assembler::formats::exe::writer::ExeWriter;
155        use pe_assembler::helpers::PeWriter;
156        use pe_assembler::types::{ImportEntry, ImportTable, PeProgram};
157        use std::io::Cursor;
158        
159        // 创建 PE 程序
160        let mut pe_program = PeProgram::create_executable(code.to_vec());
161        
162        // 添加导入表(如果有外部调用)
163        if !external_calls.is_empty() {
164            let mut imports = ImportTable::default();
165            
166            // 处理 kernel32.dll 导入
167            if external_calls.contains_key("ExitProcess") {
168                let kernel32_entry = ImportEntry {
169                    dll_name: "kernel32.dll".to_string(),
170                    functions: vec!["ExitProcess".to_string()],
171                };
172                imports.entries.push(kernel32_entry);
173            }
174            
175            // 处理其他 DLL 导入
176            if external_calls.contains_key("printf") {
177                let msvcrt_entry = ImportEntry {
178                    dll_name: "msvcrt.dll".to_string(),
179                    functions: vec!["printf".to_string()],
180                };
181                imports.entries.push(msvcrt_entry);
182            }
183            
184            if !imports.entries.is_empty() {
185                pe_program = pe_program.with_imports(imports);
186            }
187        }
188        
189        // 写入 PE 文件
190        let mut buffer = Vec::new();
191        let mut cursor = Cursor::new(&mut buffer);
192        let mut writer = ExeWriter::new(cursor);
193        writer.write_program(&pe_program)?;
194        Ok(buffer)
195    }
196}