sbpf_assembler/
header.rs

1#[derive(Debug)]
2pub struct ElfHeader {
3    pub e_ident: [u8; 16],      // ELF identification bytes = [127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
4    pub e_type: u16,            // Object file type = 3 (ET_DYN)
5    pub e_machine: u16,         // Machine architecture = 247 (BPF)
6    pub e_version: u32,         // Object file version = 1
7    pub e_entry: u64,           // Entry point address
8    pub e_phoff: u64,           // Program header offset
9    pub e_shoff: u64,           // Section header offset
10    pub e_flags: u32,           // Processor-specific flags
11    pub e_ehsize: u16,          // ELF header size = 64
12    pub e_phentsize: u16,       // Size of program header entry = 56
13    pub e_phnum: u16,           // Number of program header entries
14    pub e_shentsize: u16,       // Size of section header entry = 64
15    pub e_shnum: u16,           // Number of section header entries
16    pub e_shstrndx: u16,        // Section name string table index
17}
18
19#[derive(Debug)]
20pub struct ProgramHeader {
21    pub p_type: u32,      // Type of segment
22    pub p_flags: u32,     // Segment attributes
23    pub p_offset: u64,    // Offset in file
24    pub p_vaddr: u64,     // Virtual address in memory
25    pub p_paddr: u64,     // Physical address (reserved)
26    pub p_filesz: u64,    // Size of segment in file
27    pub p_memsz: u64,     // Size of segment in memory
28    pub p_align: u64,     // Alignment of segment
29}
30
31impl ElfHeader {
32    const SOLANA_IDENT: [u8; 16] = [
33        0x7f, 0x45, 0x4c, 0x46,  // EI_MAG0..EI_MAG3 ("\x7FELF")
34        0x02,                     // EI_CLASS (64-bit)
35        0x01,                     // EI_DATA (little endian)
36        0x01,                     // EI_VERSION
37        0x00,                     // EI_OSABI
38        0x00,                     // EI_ABIVERSION
39        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // EI_PAD
40    ];
41    const SOLANA_TYPE: u16 = 3;      // ET_DYN
42    const SOLANA_MACHINE: u16 = 247;  // BPF
43    const SOLANA_VERSION: u32 = 1;    // EV_CURRENT
44    const ELF64_HEADER_SIZE: u16 = 64;
45    const PROGRAM_HEADER_SIZE: u16 = 56;
46    const SECTION_HEADER_SIZE: u16 = 64;
47
48    pub fn new() -> Self {
49        Self {
50            e_ident: Self::SOLANA_IDENT,
51            e_type: Self::SOLANA_TYPE,
52            e_machine: Self::SOLANA_MACHINE,
53            e_version: Self::SOLANA_VERSION,
54            e_entry: 0,
55            e_phoff: Self::ELF64_HEADER_SIZE as u64,
56            e_shoff: 0,
57            e_flags: 0,
58            e_ehsize: Self::ELF64_HEADER_SIZE,
59            e_phentsize: Self::PROGRAM_HEADER_SIZE,
60            e_phnum: 0,
61            e_shentsize: Self::SECTION_HEADER_SIZE,
62            e_shnum: 0,
63            e_shstrndx: 0,
64        }
65    }
66
67    pub fn bytecode(&self) -> Vec<u8> {
68        let mut bytecode = Vec::with_capacity(Self::ELF64_HEADER_SIZE as usize);
69        
70        // e_ident (16 bytes)
71        bytecode.extend_from_slice(&self.e_ident);
72        
73        // Emit remaining fields in little-endian order
74        bytecode.extend_from_slice(&self.e_type.to_le_bytes());
75        bytecode.extend_from_slice(&self.e_machine.to_le_bytes());
76        bytecode.extend_from_slice(&self.e_version.to_le_bytes());
77        bytecode.extend_from_slice(&self.e_entry.to_le_bytes());
78        bytecode.extend_from_slice(&self.e_phoff.to_le_bytes());
79        bytecode.extend_from_slice(&self.e_shoff.to_le_bytes());
80        bytecode.extend_from_slice(&self.e_flags.to_le_bytes());
81        bytecode.extend_from_slice(&self.e_ehsize.to_le_bytes());
82        bytecode.extend_from_slice(&self.e_phentsize.to_le_bytes());
83        bytecode.extend_from_slice(&self.e_phnum.to_le_bytes());
84        bytecode.extend_from_slice(&self.e_shentsize.to_le_bytes());
85        bytecode.extend_from_slice(&self.e_shnum.to_le_bytes());
86        bytecode.extend_from_slice(&self.e_shstrndx.to_le_bytes());
87
88        bytecode
89    }
90}
91
92impl ProgramHeader {
93
94    const PT_LOAD: u32 = 1;      // Loadable segment
95    const PT_DYNAMIC: u32 = 2;   // Dynamic linking information
96    
97    const PF_X: u32 = 1;         // Executable
98    const PF_W: u32 = 2;         // Writable
99    const PF_R: u32 = 4;         // Readable
100    
101    const PAGE_SIZE: u64 = 4096;          // Standard page size
102
103    pub fn new_load(offset: u64, size: u64, executable: bool) -> Self {
104        let flags = if executable {
105            Self::PF_R | Self::PF_X  // Read + Execute
106        } else {
107            Self::PF_R        // Read only
108        };
109
110        ProgramHeader {
111            p_type: Self::PT_LOAD,
112            p_flags: flags,
113            p_offset: offset,
114            p_vaddr: offset,
115            p_paddr: offset,
116            p_filesz: size,
117            p_memsz: size,
118            p_align: Self::PAGE_SIZE
119        }
120    }
121
122    pub fn new_dynamic(offset: u64, size: u64) -> Self {
123        ProgramHeader {
124            p_type: Self::PT_DYNAMIC,
125            p_flags: Self::PF_R | Self::PF_W,
126            p_offset: offset,
127            p_vaddr: offset,
128            p_paddr: offset,
129            p_filesz: size,
130            p_memsz: size,
131            p_align: 8
132        }
133    }
134
135    pub fn bytecode(&self) -> Vec<u8> {
136        let mut bytecode = Vec::with_capacity(56); // Size of program header is 56 bytes
137        
138        bytecode.extend_from_slice(&self.p_type.to_le_bytes());
139        bytecode.extend_from_slice(&self.p_flags.to_le_bytes());
140        bytecode.extend_from_slice(&self.p_offset.to_le_bytes());
141        bytecode.extend_from_slice(&self.p_vaddr.to_le_bytes());
142        bytecode.extend_from_slice(&self.p_paddr.to_le_bytes());
143        bytecode.extend_from_slice(&self.p_filesz.to_le_bytes());
144        bytecode.extend_from_slice(&self.p_memsz.to_le_bytes());
145        bytecode.extend_from_slice(&self.p_align.to_le_bytes());
146
147        bytecode
148    }
149}
150#[derive(Debug)]
151pub struct SectionHeader {
152    sh_name: u32,      // Section name (string table index)
153    sh_type: u32,      // Section type
154    sh_flags: u64,     // Section flags
155    sh_addr: u64,      // Section virtual addr at execution
156    sh_offset: u64,    // Section file offset
157    sh_size: u64,      // Section size in bytes
158    sh_link: u32,      // Link to another section
159    sh_info: u32,      // Additional section info
160    sh_addralign: u64, // Section alignment
161    sh_entsize: u64,   // Entry size if section holds table
162}
163
164impl SectionHeader {
165    // Section types
166    pub const SHT_NULL: u32 = 0;          // Section header table entry unused
167    pub const SHT_PROGBITS: u32 = 1;      // Program data
168    pub const SHT_STRTAB: u32 = 3;        // String table
169    pub const SHT_NOBITS: u32 = 8;        // Program space with no data (bss)
170    pub const SHT_DYNAMIC: u32 = 6;      // Dynamic section
171    pub const SHT_DYNSYM: u32 = 11;      // Dynamic symbol table
172    pub const SHT_REL: u32 = 9;          // Relocation table
173    
174    // Section flags
175    pub const SHF_WRITE: u64 = 0x1;       // Writable
176    pub const SHF_ALLOC: u64 = 0x2;       // Occupies memory during execution
177    pub const SHF_EXECINSTR: u64 = 0x4;   // Executable
178    
179    pub fn new(name_offset: u32, sh_type: u32, flags: u64, addr: u64, offset: u64, size: u64, link: u32, info: u32, addralign: u64, entsize: u64) -> Self {
180        Self {
181            sh_name: name_offset,
182            sh_type,
183            sh_flags: flags,
184            sh_addr: addr,
185            sh_offset: offset,
186            sh_size: size,
187            sh_link: link,
188            sh_info: info,
189            sh_addralign: addralign,
190            sh_entsize: entsize,
191        }
192    }
193
194    pub fn bytecode(&self) -> Vec<u8> {
195        let mut bytecode = Vec::with_capacity(64); // Size of section header is 64 bytes
196        
197        bytecode.extend_from_slice(&self.sh_name.to_le_bytes());
198        bytecode.extend_from_slice(&self.sh_type.to_le_bytes());
199        bytecode.extend_from_slice(&self.sh_flags.to_le_bytes());
200        bytecode.extend_from_slice(&self.sh_addr.to_le_bytes());
201        bytecode.extend_from_slice(&self.sh_offset.to_le_bytes());
202        bytecode.extend_from_slice(&self.sh_size.to_le_bytes());
203        bytecode.extend_from_slice(&self.sh_link.to_le_bytes());
204        bytecode.extend_from_slice(&self.sh_info.to_le_bytes());
205        bytecode.extend_from_slice(&self.sh_addralign.to_le_bytes());
206        bytecode.extend_from_slice(&self.sh_entsize.to_le_bytes());
207
208        bytecode
209    }
210}