Skip to main content

clr_assembler/formats/exe/writer/
mod.rs

1use crate::program::{ClrInstruction, ClrMethod, ClrOpcode, ClrProgram};
2use gaia_types::{GaiaDiagnostics, GaiaError};
3use pe_assembler::{
4    exe_write_path,
5    helpers::PeWriter,
6    types::{
7        tables::{ExportTable, ImportTable},
8        CoffHeader, DataDirectory, DosHeader, NtHeader, OptionalHeader, PeHeader, PeProgram, PeSection, SubsystemType,
9    },
10};
11use std::{
12    io::{Cursor, Seek, Write},
13    path::Path,
14};
15
16#[derive(Debug)]
17pub struct DotNetWriter<W> {
18    writer: W,
19}
20
21impl<W> DotNetWriter<W> {
22    pub fn new(writer: W) -> Self {
23        Self { writer }
24    }
25}
26
27impl<W: Write + Seek> DotNetWriter<W> {
28    pub fn write(mut self, clr: &ClrProgram) -> GaiaDiagnostics<W> {
29        match self.build_pe_program(clr) {
30            Ok(pe_program) => match self.write_pe_program(&pe_program) {
31                Ok(_) => GaiaDiagnostics::success(self.writer),
32                Err(e) => GaiaDiagnostics::failure(e),
33            },
34            Err(e) => GaiaDiagnostics::failure(e),
35        }
36    }
37
38    /// 写入 CLR 程序到指定路径
39    pub fn write_to_path(clr: &ClrProgram, path: &Path) -> Result<gaia_types::helpers::Url, GaiaError> {
40        // 使用临时 Cursor 写入器来构建 PE 程序
41        let builder: DotNetWriter<std::io::Cursor<Vec<u8>>> = DotNetWriter::new(std::io::Cursor::new(Vec::new()));
42        let pe_program = builder.build_pe_program(clr)?;
43        exe_write_path(&pe_program, path).map_err(|e| GaiaError::custom_error(format!("写入 PE 文件失败: {}", e)))
44    }
45
46    fn build_pe_program(&self, clr: &ClrProgram) -> Result<PeProgram, GaiaError> {
47        // 构建 CLR 数据
48        let clr_data = self.build_clr_data(clr)?;
49
50        // 创建 .text 节(包含 CLR 头、元数据和代码)
51        let text_section = PeSection {
52            name: ".text".to_string(),
53            virtual_size: clr_data.len() as u32,
54            virtual_address: 0x2000,
55            size_of_raw_data: align_to(clr_data.len() as u32, 0x200),
56            pointer_to_raw_data: 0x400,
57            pointer_to_relocations: 0,
58            pointer_to_line_numbers: 0,
59            number_of_relocations: 0,
60            number_of_line_numbers: 0,
61            characteristics: 0x60000020, // IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ
62            data: clr_data,
63        };
64
65        // 创建 PE 头
66        let pe_header = self.build_pe_header(&text_section)?;
67
68        // 直接创建 PE 程序
69        let pe_program = PeProgram {
70            header: pe_header,
71            sections: vec![text_section],
72            imports: ImportTable::new(),
73            exports: ExportTable::new(),
74        };
75
76        Ok(pe_program)
77    }
78
79    fn write_pe_program(&mut self, pe_program: &PeProgram) -> Result<(), GaiaError> {
80        use pe_assembler::formats::exe::writer::ExeWriter;
81        let mut pe_writer = ExeWriter::new(&mut self.writer);
82        pe_writer.write_program(pe_program)?;
83        Ok(())
84    }
85    fn build_pe_header(&self, text_section: &PeSection) -> Result<PeHeader, GaiaError> {
86        let dos_header = DosHeader::new(0x80); // PE 头偏移
87
88        let nt_header = NtHeader {
89            signature: 0x00004550, // "PE\0\0"
90        };
91
92        let coff_header = CoffHeader::new(0x014C, 1) // IMAGE_FILE_MACHINE_I386
93            .with_timestamp(0)
94            .with_symbol_table(0, 0)
95            .with_optional_header_size(224) // PE32 可选头大小
96            .with_characteristics(0x0102); // IMAGE_FILE_EXECUTABLE_IMAGE | IMAGE_FILE_32BIT_MACHINE
97
98        let optional_header = OptionalHeader::new(
99            0x2000,                        // entry_point
100            0x400000,                      // image_base
101            text_section.size_of_raw_data, // size_of_code
102            0x400,                         // size_of_headers
103            0x4000,                        // size_of_image
104            SubsystemType::Console,        // subsystem
105        );
106
107        Ok(PeHeader { dos_header, nt_header, coff_header, optional_header })
108    }
109
110    fn build_clr_data(&self, clr: &ClrProgram) -> Result<Vec<u8>, GaiaError> {
111        let mut data = Vec::new();
112
113        // 预留 CLR 头的空间 (72 字节)
114        let clr_header_size = 72;
115        data.resize(clr_header_size, 0);
116
117        // 计算各部分的偏移量
118        let metadata_offset = clr_header_size;
119        let metadata_start = data.len();
120
121        // 写入元数据
122        self.write_metadata_to_buffer(&mut data, clr)?;
123        let metadata_size = data.len() - metadata_start;
124
125        // 对齐到 4 字节边界
126        while data.len() % 4 != 0 {
127            data.push(0);
128        }
129
130        let code_offset = data.len();
131
132        // 写入代码
133        self.write_code_to_buffer(&mut data, clr)?;
134
135        // 现在回填 CLR 头,使用正确的 RVA 和大小
136        let base_rva = 0x2000; // .text 节的虚拟地址
137        let metadata_rva = base_rva + metadata_offset as u32;
138        let code_rva = base_rva + code_offset as u32;
139
140        self.write_clr_header_with_offsets(&mut data, clr, metadata_rva, metadata_size as u32)?;
141
142        Ok(data)
143    }
144
145    fn write_clr_header_with_offsets(
146        &self,
147        buffer: &mut Vec<u8>,
148        clr: &ClrProgram,
149        metadata_rva: u32,
150        metadata_size: u32,
151    ) -> Result<(), GaiaError> {
152        let clr_header = ClrHeader::new(
153            clr.version.major as u16,
154            clr.version.minor as u16,
155            metadata_rva,
156            metadata_size,
157            0, // 入口点方法的 token
158        );
159
160        // 将 CLR 头写入到缓冲区的开始位置
161        let mut cursor = std::io::Cursor::new(&mut buffer[0..72]);
162
163        // 写入 CLR 头的字节
164        cursor.write_all(&clr_header.cb.to_le_bytes())?;
165        cursor.write_all(&clr_header.major_runtime_version.to_le_bytes())?;
166        cursor.write_all(&clr_header.minor_runtime_version.to_le_bytes())?;
167        cursor.write_all(&clr_header.metadata_rva.to_le_bytes())?;
168        cursor.write_all(&clr_header.metadata_size.to_le_bytes())?;
169        cursor.write_all(&clr_header.flags.to_le_bytes())?;
170        cursor.write_all(&clr_header.entry_point_token.to_le_bytes())?;
171        cursor.write_all(&clr_header.resources_rva.to_le_bytes())?;
172        cursor.write_all(&clr_header.resources_size.to_le_bytes())?;
173        cursor.write_all(&clr_header.strong_name_signature_rva.to_le_bytes())?;
174        cursor.write_all(&clr_header.strong_name_signature_size.to_le_bytes())?;
175        cursor.write_all(&clr_header.code_manager_table_rva.to_le_bytes())?;
176        cursor.write_all(&clr_header.code_manager_table_size.to_le_bytes())?;
177        cursor.write_all(&clr_header.vtable_fixups_rva.to_le_bytes())?;
178        cursor.write_all(&clr_header.vtable_fixups_size.to_le_bytes())?;
179        cursor.write_all(&clr_header.export_address_table_jumps_rva.to_le_bytes())?;
180        cursor.write_all(&clr_header.export_address_table_jumps_size.to_le_bytes())?;
181        cursor.write_all(&clr_header.managed_native_header_rva.to_le_bytes())?;
182        cursor.write_all(&clr_header.managed_native_header_size.to_le_bytes())?;
183
184        Ok(())
185    }
186
187    fn write_metadata_to_buffer(&self, buffer: &mut Vec<u8>, clr: &ClrProgram) -> Result<(), GaiaError> {
188        // .NET 元数据根结构
189        // 元数据头签名
190        buffer.extend_from_slice(b"BSJB");
191
192        // 版本信息
193        buffer.extend_from_slice(&1u16.to_le_bytes()); // major version
194        buffer.extend_from_slice(&1u16.to_le_bytes()); // minor version
195        buffer.extend_from_slice(&0u32.to_le_bytes()); // reserved
196
197        // 版本字符串长度和内容
198        let version_str = "v4.0.30319";
199        let version_len = ((version_str.len() + 3) / 4) * 4; // 对齐到 4 字节
200        buffer.extend_from_slice(&(version_len as u32).to_le_bytes());
201        buffer.extend_from_slice(version_str.as_bytes());
202
203        // 填充到 4 字节对齐
204        while buffer.len() % 4 != 0 {
205            buffer.push(0);
206        }
207
208        // 标志和流数量
209        buffer.extend_from_slice(&0u16.to_le_bytes()); // flags
210        buffer.extend_from_slice(&5u16.to_le_bytes()); // 5 个流
211
212        // 写入流头信息
213        self.write_stream_headers(buffer)?;
214
215        // 写入各个流的数据
216        self.write_metadata_streams(buffer, clr)?;
217
218        Ok(())
219    }
220
221    fn write_stream_headers(&self, buffer: &mut Vec<u8>) -> Result<(), GaiaError> {
222        // #~ 流 (压缩元数据表)
223        buffer.extend_from_slice(&0u32.to_le_bytes()); // offset (稍后填充)
224        buffer.extend_from_slice(&0u32.to_le_bytes()); // size (稍后填充)
225        buffer.extend_from_slice(b"#~\0\0"); // name
226
227        // #Strings 流
228        buffer.extend_from_slice(&0u32.to_le_bytes()); // offset
229        buffer.extend_from_slice(&0u32.to_le_bytes()); // size
230        buffer.extend_from_slice(b"#Strings\0\0\0\0"); // name (对齐到 4 字节)
231
232        // #US 流 (用户字符串)
233        buffer.extend_from_slice(&0u32.to_le_bytes()); // offset
234        buffer.extend_from_slice(&0u32.to_le_bytes()); // size
235        buffer.extend_from_slice(b"#US\0"); // name
236
237        // #GUID 流
238        buffer.extend_from_slice(&0u32.to_le_bytes()); // offset
239        buffer.extend_from_slice(&0u32.to_le_bytes()); // size
240        buffer.extend_from_slice(b"#GUID\0\0\0"); // name
241
242        // #Blob 流
243        buffer.extend_from_slice(&0u32.to_le_bytes()); // offset
244        buffer.extend_from_slice(&0u32.to_le_bytes()); // size
245        buffer.extend_from_slice(b"#Blob\0\0\0"); // name
246
247        Ok(())
248    }
249
250    fn write_metadata_streams(&self, buffer: &mut Vec<u8>, clr: &ClrProgram) -> Result<(), GaiaError> {
251        // 简化实现:写入最小的元数据流
252
253        // #~ 流 (元数据表)
254        self.write_metadata_tables_stream(buffer, clr)?;
255
256        // #Strings 流
257        self.write_strings_stream(buffer, clr)?;
258
259        // #US 流 (用户字符串)
260        self.write_user_strings_stream(buffer)?;
261
262        // #GUID 流
263        self.write_guid_stream(buffer)?;
264
265        // #Blob 流
266        self.write_blob_stream(buffer)?;
267
268        Ok(())
269    }
270
271    fn write_metadata_tables_stream(&self, buffer: &mut Vec<u8>, clr: &ClrProgram) -> Result<(), GaiaError> {
272        // 元数据表流头
273        buffer.extend_from_slice(&0u32.to_le_bytes()); // reserved
274        buffer.extend_from_slice(&2u8.to_le_bytes()); // major version
275        buffer.extend_from_slice(&0u8.to_le_bytes()); // minor version
276        buffer.extend_from_slice(&0u8.to_le_bytes()); // heap sizes
277        buffer.extend_from_slice(&1u8.to_le_bytes()); // reserved
278
279        // 有效表的位掩码 (简化:只包含 Module 表)
280        buffer.extend_from_slice(&0x01u64.to_le_bytes()); // valid tables
281        buffer.extend_from_slice(&0x01u64.to_le_bytes()); // sorted tables
282
283        // 表行数
284        buffer.extend_from_slice(&1u32.to_le_bytes()); // Module 表有 1 行
285
286        // Module 表数据 (简化)
287        buffer.extend_from_slice(&0u16.to_le_bytes()); // Generation
288        buffer.extend_from_slice(&1u16.to_le_bytes()); // Name (字符串索引)
289        buffer.extend_from_slice(&1u16.to_le_bytes()); // Mvid (GUID 索引)
290        buffer.extend_from_slice(&0u16.to_le_bytes()); // EncId
291        buffer.extend_from_slice(&0u16.to_le_bytes()); // EncBaseId
292
293        Ok(())
294    }
295
296    fn write_strings_stream(&self, buffer: &mut Vec<u8>, clr: &ClrProgram) -> Result<(), GaiaError> {
297        // 字符串流以空字节开始
298        buffer.push(0);
299
300        // 添加模块名称
301        let module_name = clr.name.as_bytes();
302        buffer.extend_from_slice(module_name);
303        buffer.push(0); // null terminator
304
305        // 对齐到 4 字节边界
306        while buffer.len() % 4 != 0 {
307            buffer.push(0);
308        }
309
310        Ok(())
311    }
312
313    fn write_user_strings_stream(&self, buffer: &mut Vec<u8>) -> Result<(), GaiaError> {
314        // 用户字符串流以空字节开始
315        buffer.push(0);
316
317        // 对齐到 4 字节边界
318        while buffer.len() % 4 != 0 {
319            buffer.push(0);
320        }
321
322        Ok(())
323    }
324
325    fn write_guid_stream(&self, buffer: &mut Vec<u8>) -> Result<(), GaiaError> {
326        // GUID 流包含一个模块 GUID (16 字节)
327        let module_guid = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0];
328        buffer.extend_from_slice(&module_guid);
329
330        Ok(())
331    }
332
333    fn write_blob_stream(&self, buffer: &mut Vec<u8>) -> Result<(), GaiaError> {
334        // Blob 流以空字节开始
335        buffer.push(0);
336
337        // 对齐到 4 字节边界
338        while buffer.len() % 4 != 0 {
339            buffer.push(0);
340        }
341
342        Ok(())
343    }
344
345    fn write_code_to_buffer(&self, buffer: &mut Vec<u8>, clr: &ClrProgram) -> Result<(), GaiaError> {
346        // 写入方法代码
347        for clr_type in &clr.types {
348            for method in &clr_type.methods {
349                self.write_method_code_to_buffer(buffer, method)?;
350            }
351        }
352
353        // 写入全局方法
354        for method in &clr.global_methods {
355            self.write_method_code_to_buffer(buffer, method)?;
356        }
357        Ok(())
358    }
359
360    fn write_method_code_to_buffer(&self, buffer: &mut Vec<u8>, method: &ClrMethod) -> Result<(), GaiaError> {
361        // 计算代码大小
362        let mut code_size = 0u32;
363        for instruction in &method.instructions {
364            code_size += self.calculate_instruction_size(instruction)?;
365        }
366
367        // 选择方法头格式
368        if code_size < 64 && method.max_stack <= 8 && method.locals.is_empty() {
369            // 使用 Tiny 格式
370            let header = (code_size << 2) | 0x02; // CorILMethod_TinyFormat
371            buffer.push(header as u8);
372        }
373        else {
374            // 使用 Fat 格式
375            let flags: u16 = 0x03; // CorILMethod_FatFormat | CorILMethod_InitLocals
376            buffer.extend_from_slice(&flags.to_le_bytes());
377            buffer.push(0x30); // 头大小 (12 字节)
378            buffer.extend_from_slice(&method.max_stack.to_le_bytes());
379            buffer.extend_from_slice(&code_size.to_le_bytes());
380            buffer.extend_from_slice(&0u32.to_le_bytes()); // 局部变量签名 token
381        }
382
383        // 写入指令
384        for instruction in &method.instructions {
385            self.write_instruction_to_buffer(buffer, instruction)?;
386        }
387
388        // 对齐到 4 字节边界
389        while buffer.len() % 4 != 0 {
390            buffer.push(0);
391        }
392
393        Ok(())
394    }
395
396    fn calculate_instruction_size(&self, instruction: &ClrInstruction) -> Result<u32, GaiaError> {
397        match instruction {
398            ClrInstruction::Simple { opcode } => {
399                match opcode {
400                    ClrOpcode::Nop | ClrOpcode::Ret => Ok(1),
401                    ClrOpcode::Ldstr | ClrOpcode::Call => Ok(5), // opcode + 4 字节 token
402                    _ => Ok(1),                                  // 默认单字节指令
403                }
404            }
405            ClrInstruction::WithImmediate { opcode, .. } => {
406                match opcode {
407                    ClrOpcode::LdcI4 => Ok(5), // opcode + 4 字节立即数
408                    _ => Ok(5),
409                }
410            }
411            ClrInstruction::WithImmediate64 { .. } => Ok(9), // opcode + 8 字节立即数
412            ClrInstruction::WithFloat32 { .. } => Ok(5),     // opcode + 4 字节浮点数
413            ClrInstruction::WithFloat64 { .. } => Ok(9),     // opcode + 8 字节浮点数
414            ClrInstruction::WithString { .. } => Ok(5),      // opcode + 4 字节 token
415            ClrInstruction::WithMethod { .. } => Ok(5),      // opcode + 4 字节 token
416            _ => Ok(1),
417        }
418    }
419
420    fn write_instruction_to_buffer(&self, buffer: &mut Vec<u8>, instruction: &ClrInstruction) -> Result<(), GaiaError> {
421        match instruction {
422            ClrInstruction::Simple { opcode } => match opcode {
423                ClrOpcode::Nop => buffer.push(0x00),
424                ClrOpcode::Ldstr => buffer.push(0x72),
425                ClrOpcode::Call => buffer.push(0x28),
426                ClrOpcode::Ret => buffer.push(0x2A),
427                _ => return Err(GaiaError::not_implemented("Unsupported opcode")),
428            },
429            ClrInstruction::WithImmediate { opcode, value } => match opcode {
430                ClrOpcode::LdcI4 => {
431                    buffer.push(0x20);
432                    buffer.extend_from_slice(&value.to_le_bytes());
433                }
434                _ => return Err(GaiaError::not_implemented("Unsupported opcode with immediate")),
435            },
436            ClrInstruction::WithImmediate64 { opcode, value } => match opcode {
437                ClrOpcode::LdcI8 => {
438                    buffer.push(0x21);
439                    buffer.extend_from_slice(&value.to_le_bytes());
440                }
441                _ => return Err(GaiaError::not_implemented("Unsupported opcode with immediate64")),
442            },
443            ClrInstruction::WithFloat32 { opcode, value } => match opcode {
444                ClrOpcode::LdcR4 => {
445                    buffer.push(0x22);
446                    buffer.extend_from_slice(&value.to_le_bytes());
447                }
448                _ => return Err(GaiaError::not_implemented("Unsupported opcode with float32")),
449            },
450            ClrInstruction::WithFloat64 { opcode, value } => match opcode {
451                ClrOpcode::LdcR8 => {
452                    buffer.push(0x23);
453                    buffer.extend_from_slice(&value.to_le_bytes());
454                }
455                _ => return Err(GaiaError::not_implemented("Unsupported opcode with float64")),
456            },
457            ClrInstruction::WithString { opcode, value } => {
458                match opcode {
459                    ClrOpcode::Ldstr => {
460                        buffer.push(0x72);
461                        // 这里应该写入字符串表的索引,暂时写入占位符
462                        buffer.extend_from_slice(&[0x01, 0x00, 0x00, 0x70]);
463                    }
464                    _ => return Err(GaiaError::not_implemented("Unsupported opcode with string")),
465                }
466            }
467            ClrInstruction::WithMethod { opcode, method_ref } => {
468                match opcode {
469                    ClrOpcode::Call => {
470                        buffer.push(0x28);
471                        // 这里应该写入方法表的索引,暂时写入占位符
472                        buffer.extend_from_slice(&[0x01, 0x00, 0x00, 0x0A]);
473                    }
474                    _ => return Err(GaiaError::not_implemented("Unsupported opcode with method")),
475                }
476            }
477            _ => return Err(GaiaError::not_implemented("Unsupported instruction type")),
478        }
479        Ok(())
480    }
481}
482
483// 对齐到指定边界的辅助函数
484fn align_to(value: u32, alignment: u32) -> u32 {
485    (value + alignment - 1) & !(alignment - 1)
486}
487
488// CLR 头结构
489#[derive(Debug, Copy, Clone)]
490pub struct ClrHeader {
491    cb: u32,
492    major_runtime_version: u16,
493    minor_runtime_version: u16,
494    metadata_rva: u32,
495    metadata_size: u32,
496    flags: u32,
497    entry_point_token: u32,
498    resources_rva: u32,
499    resources_size: u32,
500    strong_name_signature_rva: u32,
501    strong_name_signature_size: u32,
502    code_manager_table_rva: u32,
503    code_manager_table_size: u32,
504    vtable_fixups_rva: u32,
505    vtable_fixups_size: u32,
506    export_address_table_jumps_rva: u32,
507    export_address_table_jumps_size: u32,
508    managed_native_header_rva: u32,
509    managed_native_header_size: u32,
510}
511
512impl ClrHeader {
513    /// 创建一个标准的 CLR 头
514    pub fn new(
515        major_runtime_version: u16,
516        minor_runtime_version: u16,
517        metadata_rva: u32,
518        metadata_size: u32,
519        entry_point_token: u32,
520    ) -> Self {
521        Self {
522            cb: 72, // CLR 头大小
523            major_runtime_version,
524            minor_runtime_version,
525            metadata_rva,
526            metadata_size,
527            flags: 0x01, // COMIMAGE_FLAGS_ILONLY
528            entry_point_token,
529            resources_rva: 0,
530            resources_size: 0,
531            strong_name_signature_rva: 0,
532            strong_name_signature_size: 0,
533            code_manager_table_rva: 0,
534            code_manager_table_size: 0,
535            vtable_fixups_rva: 0,
536            vtable_fixups_size: 0,
537            export_address_table_jumps_rva: 0,
538            export_address_table_jumps_size: 0,
539            managed_native_header_rva: 0,
540            managed_native_header_size: 0,
541        }
542    }
543}