Skip to main content

pe_assembler/types/coff/
mod.rs

1use gaia_binary::{LittleEndian, ReadBytesExt};
2use gaia_types::{helpers::Architecture, GaiaError};
3use serde::{Deserialize, Serialize};
4use std::io::Read;
5
6/// COFF file header structure
7///
8/// Contains basic information for the COFF (Common Object File Format) format,
9/// defining key information such as target machine type, number of sections, and timestamp.
10#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
11pub struct CoffHeader {
12    /// Target machine type, such as x86, x64, ARM, etc.
13    pub machine: u16,
14    /// Number of sections in the file
15    pub number_of_sections: u16,
16    /// Timestamp indicating when the file was created or linked
17    pub time_date_stamp: u32,
18    /// File offset of the symbol table, or 0 if none exists
19    pub pointer_to_symbol_table: u32,
20    /// Number of symbols in the symbol table
21    pub number_of_symbols: u32,
22    /// Size of the optional header in bytes
23    pub size_of_optional_header: u16,
24    /// File characteristics flags describing various attributes of the file
25    pub characteristics: u16,
26}
27
28impl CoffHeader {
29    /// Create a new COFF header with core fields
30    pub fn new(machine: u16, number_of_sections: u16) -> Self {
31        CoffHeader {
32            machine,
33            number_of_sections,
34            time_date_stamp: 0,
35            pointer_to_symbol_table: 0,
36            number_of_symbols: 0,
37            size_of_optional_header: 0,
38            characteristics: 0,
39        }
40    }
41
42    /// Set timestamp
43    pub fn with_timestamp(mut self, time_date_stamp: u32) -> Self {
44        self.time_date_stamp = time_date_stamp;
45        self
46    }
47
48    /// Set symbol table information
49    pub fn with_symbol_table(mut self, pointer_to_symbol_table: u32, number_of_symbols: u32) -> Self {
50        self.pointer_to_symbol_table = pointer_to_symbol_table;
51        self.number_of_symbols = number_of_symbols;
52        self
53    }
54
55    /// Set optional header size
56    pub fn with_optional_header_size(mut self, size_of_optional_header: u16) -> Self {
57        self.size_of_optional_header = size_of_optional_header;
58        self
59    }
60
61    /// Set file characteristics
62    pub fn with_characteristics(mut self, characteristics: u16) -> Self {
63        self.characteristics = characteristics;
64        self
65    }
66
67    pub fn read<R: Read>(mut reader: R) -> Result<Self, GaiaError> {
68        Ok(CoffHeader {
69            machine: reader.read_u16::<LittleEndian>()?,
70            number_of_sections: reader.read_u16::<LittleEndian>()?,
71            time_date_stamp: reader.read_u32::<LittleEndian>()?,
72            pointer_to_symbol_table: reader.read_u32::<LittleEndian>()?,
73            number_of_symbols: reader.read_u32::<LittleEndian>()?,
74            size_of_optional_header: reader.read_u16::<LittleEndian>()?,
75            characteristics: reader.read_u16::<LittleEndian>()?,
76        })
77    }
78
79    pub fn get_architecture(&self) -> Architecture {
80        match self.machine {
81            0x014C => Architecture::X86,
82            0x8664 => Architecture::X86_64,
83            0x0200 => Architecture::ARM32,
84            0xAA64 => Architecture::ARM64,
85            _ => Architecture::Unknown,
86        }
87    }
88}
89
90/// Section header structure
91///
92/// Contains metadata for a section in a COFF file, such as name, size,
93/// position, and attributes. This structure doesn't contain the actual data of the section.
94#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
95pub struct SectionHeader {
96    /// Section name, 8-byte ASCII string like ".text", ".data", etc.
97    pub name: [u8; 8],
98    /// Virtual size of the section in memory
99    pub virtual_size: u32,
100    /// Virtual address of the section (RVA) in memory
101    pub virtual_address: u32,
102    /// Size of raw data in the file
103    pub size_of_raw_data: u32,
104    /// File offset of the section
105    pub pointer_to_raw_data: u32,
106    /// File offset of the relocation table
107    pub pointer_to_relocations: u32,
108    /// File offset of the line numbers table
109    pub pointer_to_line_numbers: u32,
110    /// Number of relocation entries
111    pub number_of_relocations: u16,
112    /// Number of line number entries
113    pub number_of_line_numbers: u16,
114    /// Section characteristics flags describing attributes (read, write, execute, etc.)
115    pub characteristics: u32,
116}
117
118impl SectionHeader {
119    pub fn get_name(&self) -> &str {
120        unsafe {
121            let name = std::str::from_utf8_unchecked(&self.name);
122            name.trim_end_matches('\0')
123        }
124    }
125}
126
127/// COFF symbol table entry
128///
129/// Represents a symbol in a COFF object file, containing symbol name, value, section number, etc.
130/// Symbols can be functions, variables, labels, or other identifiers in the program.
131#[derive(Clone, Debug, Serialize, Deserialize)]
132pub struct CoffSymbol {
133    /// Symbol name, stored in the string table if length exceeds 8 bytes
134    pub name: String,
135    /// Symbol value, usually an address or offset
136    pub value: u32,
137    /// Section number where the symbol resides: 0 for undefined, -1 for absolute, -2 for debug
138    pub section_number: i16,
139    /// Symbol type, describing the basic type of the symbol
140    pub symbol_type: u16,
141    /// Storage class, describing the scope and lifetime of the symbol
142    pub storage_class: u8,
143    /// Number of auxiliary symbols
144    pub number_of_aux_symbols: u8,
145}
146
147/// COFF relocation item
148///
149/// Represents an item that requires address relocation at link time.
150/// Relocation is the process of converting relative addresses to absolute addresses.
151#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
152pub struct CoffRelocation {
153    /// Virtual address that needs relocation
154    pub virtual_address: u32,
155    /// Symbol table index pointing to the related symbol
156    pub symbol_table_index: u32,
157    /// Relocation type, defining how to perform the relocation
158    pub relocation_type: u16,
159}
160
161/// COFF section structure
162///
163/// Represents a section in a COFF object file, containing the section header and data.
164/// Similar to a PE section but used for object files instead of executables.
165#[derive(Clone, Debug, Serialize, Deserialize)]
166pub struct CoffSection {
167    /// Section header info
168    pub header: SectionHeader,
169    /// Raw data of the section
170    #[serde(skip_serializing_if = "Vec::is_empty")]
171    pub data: Vec<u8>,
172    /// Relocation table containing all relocation entries for this section
173    pub relocations: Vec<CoffRelocation>,
174}
175
176/// COFF object file structure
177///
178/// Represents a complete COFF object file, containing header, sections, symbol table, etc.
179/// COFF object files are intermediate files generated by compilers, containing unlinked code and data.
180#[derive(Clone, Debug, Serialize, Deserialize)]
181pub struct CoffObject {
182    /// COFF header info
183    pub header: CoffHeader,
184    /// Collection of all sections
185    pub sections: Vec<CoffSection>,
186    /// Symbol table containing all symbol info
187    pub symbols: Vec<CoffSymbol>,
188    /// String table for storing long symbol names
189    pub string_table: Vec<u8>,
190}
191
192/// Archive member header
193///
194/// Represents the header information for a member file in a static library.
195/// Static libraries are collections of object files, each member having its own header.
196#[derive(Clone, Debug, Serialize, Deserialize)]
197pub struct ArchiveMemberHeader {
198    /// Member file name
199    pub name: String,
200    /// File modification timestamp
201    pub timestamp: u32,
202    /// User ID
203    pub user_id: u16,
204    /// Group ID
205    pub group_id: u16,
206    /// File permission mode
207    pub mode: u32,
208    /// File size
209    pub size: u32,
210}
211
212/// Archive member
213///
214/// Represents a member in a static library, containing a header and data.
215/// Each member is typically a COFF object file.
216#[derive(Clone, Debug, Serialize, Deserialize)]
217pub struct ArchiveMember {
218    /// Member header info
219    pub header: ArchiveMemberHeader,
220    /// Member data, usually the content of a COFF object file
221    pub data: Vec<u8>,
222    /// Parsed COFF object (if successfully parsed)
223    pub coff_object: Option<CoffObject>,
224}
225
226/// Static library file structure
227///
228/// Represents a complete static library file (.lib), containing multiple object files.
229/// Static libraries pack multiple object files into one for easier distribution and linking.
230#[derive(Clone, Debug, Serialize, Deserialize)]
231pub struct StaticLibrary {
232    /// Library signature, usually "!<arch>\n"
233    pub signature: String,
234    /// Collection of all member files
235    pub members: Vec<ArchiveMember>,
236    /// Symbol index table for fast symbol lookup
237    pub symbol_index: Vec<(String, usize)>, // (symbol_name, member_index)
238}
239
240/// COFF file type enum
241///
242/// Distinguishes between different types of COFF-related file formats.
243#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
244pub enum CoffFileType {
245    /// COFF object file (.obj)
246    Object,
247    /// Static library file (.lib)
248    StaticLibrary,
249    /// PE executable file (.exe)
250    Executable,
251    /// PE dynamic library file (.dll)
252    DynamicLibrary,
253}
254
255/// COFF file info
256///
257/// Provides summary information for COFF-related files.
258#[derive(Clone, Debug, Serialize, Deserialize)]
259pub struct CoffInfo {
260    /// File type
261    pub file_type: CoffFileType,
262    /// Target architecture
263    pub target_arch: Architecture,
264    /// Number of sections
265    pub section_count: u16,
266    /// Number of symbols
267    pub symbol_count: u32,
268    /// File size
269    pub file_size: u64,
270    /// Timestamp
271    pub timestamp: u32,
272}