Skip to main content

macho_assembler/formats/object/
reader.rs

1use crate::{
2    helpers::MachoReader,
3    types::{MachoProgram, MachoReadConfig},
4};
5use gaia_binary::{BinaryReader, Fixed, LittleEndian};
6use gaia_types::GaiaError;
7use std::{
8    cell::RefCell,
9    io::{Read, Seek},
10    sync::OnceLock,
11};
12
13/// Mach-O 目标文件信息
14#[derive(Debug, Clone, Copy)]
15pub struct ObjectInfo {
16    /// CPU类型
17    pub cpu_type: u32,
18    /// 文件类型
19    pub file_type: u32,
20    /// 加载命令数量
21    pub ncmds: u32,
22    /// 加载命令总大小
23    pub sizeofcmds: u32,
24    /// 标志位
25    pub flags: u32,
26    /// 符号表中符号数量(可选)
27    pub symbol_count: Option<u32>,
28}
29
30/// Mach-O 目标文件延迟读取器
31#[derive(Debug)]
32pub struct ObjectReader<R: Read + Seek> {
33    reader: RefCell<BinaryReader<R, Fixed<LittleEndian>>>,
34    config: MachoReadConfig,
35    program: OnceLock<Result<MachoProgram, GaiaError>>,
36    info: OnceLock<Result<ObjectInfo, GaiaError>>,
37}
38
39impl<R: Read + Seek> ObjectReader<R> {
40    /// 创建一个新的目标文件读取器
41    pub fn new(reader: BinaryReader<R, Fixed<LittleEndian>>, config: MachoReadConfig) -> Self {
42        Self { reader: RefCell::new(reader), config, program: OnceLock::new(), info: OnceLock::new() }
43    }
44
45    /// 获取程序信息(延迟加载)
46    pub fn get_program(&self) -> Result<&MachoProgram, &GaiaError> {
47        self.program.get_or_init(|| self.read_program_internal()).as_ref()
48    }
49
50    /// 获取文件信息(延迟加载)
51    pub fn get_info(&self) -> Result<&ObjectInfo, &GaiaError> {
52        self.info.get_or_init(|| self.read_info()).as_ref()
53    }
54
55    /// 读取完整程序(内部方法)
56    fn read_program_internal(&self) -> Result<MachoProgram, GaiaError> {
57        let mut reader = self.reader.borrow_mut();
58
59        // 读取 Mach-O 文件头
60        let magic = reader.read_u32()?;
61        let cpu_type = reader.read_u32()?;
62        let cpu_subtype = reader.read_u32()?;
63        let file_type = reader.read_u32()?;
64        let ncmds = reader.read_u32()?;
65        let sizeofcmds = reader.read_u32()?;
66        let flags = reader.read_u32()?;
67
68        let reserved = if magic == 0xfeedfacf { Some(reader.read_u32()?) } else { None };
69
70        let header = crate::types::MachoHeader { magic, cpu_type, cpu_subtype, file_type, ncmds, sizeofcmds, flags, reserved };
71
72        // 读取加载命令
73        let mut load_commands = Vec::new();
74        for _ in 0..ncmds {
75            let cmd = reader.read_u32()?;
76            let cmdsize = reader.read_u32()?;
77
78            let data_size = cmdsize.saturating_sub(8) as usize;
79            let mut data = vec![0u8; data_size];
80            reader.read_exact(&mut data)?;
81
82            load_commands.push(crate::types::LoadCommand { cmd, cmdsize, data });
83        }
84
85        Ok(MachoProgram { header, load_commands, segments: Vec::new(), sections: Vec::new() })
86    }
87
88    /// 读取文件基本信息
89    fn read_info(&self) -> Result<ObjectInfo, GaiaError> {
90        let mut reader = self.reader.borrow_mut();
91
92        let _magic = reader.read_u32()?;
93        let cpu_type = reader.read_u32()?;
94        let _cpu_subtype = reader.read_u32()?;
95        let file_type = reader.read_u32()?;
96        let ncmds = reader.read_u32()?;
97        let sizeofcmds = reader.read_u32()?;
98        let flags = reader.read_u32()?;
99
100        Ok(ObjectInfo {
101            cpu_type,
102            file_type,
103            ncmds,
104            sizeofcmds,
105            flags,
106            symbol_count: None, // TODO: 从 LC_SYMTAB 中提取
107        })
108    }
109}
110
111impl<R: Read + Seek> MachoReader<R> for ObjectReader<R> {
112    fn read_program(&mut self) -> Result<MachoProgram, GaiaError> {
113        self.read_program_internal()
114    }
115
116    fn reader(&mut self) -> &mut BinaryReader<R, Fixed<LittleEndian>> {
117        self.reader.get_mut()
118    }
119
120    fn config(&self) -> &MachoReadConfig {
121        &self.config
122    }
123}