sbpf_assembler/
section.rs

1use {
2    crate::{
3        astnode::{ASTNode, ROData},
4        debuginfo::DebugInfo,
5        dynsym::{DynamicSymbol, RelDyn},
6        header::SectionHeader,
7        parser::Token,
8    },
9    std::collections::HashMap,
10};
11
12// Base Section trait
13pub trait Section {
14    fn name(&self) -> &str {
15        ".unknown" // Default section name
16    }
17
18    fn bytecode(&self) -> Vec<u8> {
19        Vec::new() // Default empty bytecode
20    }
21
22    // fn get_size(&self) -> u64
23    fn size(&self) -> u64 {
24        self.bytecode().len() as u64
25    }
26
27    // fn get_aligned_size(&self) -> u64
28
29    // fn section_header_bytecode(&self) -> Vec<u8>
30}
31
32// Code Section implementation
33#[derive(Debug)]
34pub struct CodeSection {
35    name: String,
36    nodes: Vec<ASTNode>,
37    size: u64,
38    offset: u64,
39    debug_map: HashMap<u64, DebugInfo>,
40}
41
42impl CodeSection {
43    pub fn new(nodes: Vec<ASTNode>, size: u64) -> Self {
44        let mut debug_map = HashMap::new();
45        for node in &nodes {
46            if let Some((_, node_debug_map)) = node.bytecode_with_debug_map() {
47                debug_map.extend(node_debug_map);
48            }
49        }
50        Self {
51            name: String::from(".text"),
52            nodes,
53            size,
54            offset: 0,
55            debug_map,
56        }
57    }
58
59    pub fn get_nodes(&self) -> &Vec<ASTNode> {
60        &self.nodes
61    }
62
63    pub fn get_size(&self) -> u64 {
64        self.size
65    }
66
67    pub fn get_debug_map(&self) -> &HashMap<u64, DebugInfo> {
68        &self.debug_map
69    }
70
71    pub fn set_offset(&mut self, offset: u64) {
72        self.offset = offset;
73    }
74
75    pub fn section_header_bytecode(&self) -> Vec<u8> {
76        let flags = SectionHeader::SHF_ALLOC | SectionHeader::SHF_EXECINSTR;
77        SectionHeader::new(
78            1,
79            SectionHeader::SHT_PROGBITS,
80            flags,
81            self.offset,
82            self.offset,
83            self.size,
84            0,
85            0,
86            4,
87            0,
88        )
89        .bytecode()
90    }
91}
92
93impl Section for CodeSection {
94    fn name(&self) -> &str {
95        &self.name
96    }
97
98    fn bytecode(&self) -> Vec<u8> {
99        let mut bytecode = Vec::new();
100        for node in &self.nodes {
101            if let Some(node_bytes) = node.bytecode() {
102                bytecode.extend(node_bytes);
103            }
104        }
105        bytecode
106    }
107
108    fn size(&self) -> u64 {
109        self.size
110    }
111}
112
113// Data Section implementation
114#[derive(Debug)]
115pub struct DataSection {
116    name: String,
117    nodes: Vec<ASTNode>,
118    size: u64,
119    offset: u64,
120}
121
122impl DataSection {
123    pub fn new(nodes: Vec<ASTNode>, size: u64) -> Self {
124        Self {
125            name: String::from(".rodata"),
126            nodes,
127            size,
128            offset: 0,
129        }
130    }
131
132    pub fn get_nodes(&self) -> &Vec<ASTNode> {
133        &self.nodes
134    }
135
136    pub fn get_size(&self) -> u64 {
137        self.size
138    }
139
140    pub fn set_offset(&mut self, offset: u64) {
141        self.offset = offset;
142    }
143
144    pub fn rodata(&self) -> Vec<(String, usize, String)> {
145        let mut ro_data_labels = Vec::new();
146        for node in &self.nodes {
147            if let ASTNode::ROData {
148                rodata: ROData { name, args, .. },
149                offset,
150            } = node
151                && let Some(Token::StringLiteral(str_literal, _)) = args.get(1)
152            {
153                ro_data_labels.push((name.clone(), *offset as usize, str_literal.clone()));
154            }
155        }
156        ro_data_labels
157    }
158
159    pub fn section_header_bytecode(&self) -> Vec<u8> {
160        let flags = SectionHeader::SHF_ALLOC; // Read-only data
161        SectionHeader::new(
162            7,
163            SectionHeader::SHT_PROGBITS,
164            flags,
165            self.offset,
166            self.offset,
167            self.size,
168            0,
169            0,
170            1,
171            0,
172        )
173        .bytecode()
174    }
175}
176
177impl Section for DataSection {
178    fn name(&self) -> &str {
179        &self.name
180    }
181
182    fn size(&self) -> u64 {
183        self.size
184    }
185
186    fn bytecode(&self) -> Vec<u8> {
187        let mut bytecode = Vec::new();
188        for node in &self.nodes {
189            if let Some(node_bytes) = node.bytecode() {
190                bytecode.extend(node_bytes);
191            }
192        }
193        // Add padding to make size multiple of 8
194        while bytecode.len() % 8 != 0 {
195            bytecode.push(0);
196        }
197
198        bytecode
199    }
200}
201
202#[derive(Debug, Default)]
203pub struct NullSection {
204    name: String,
205    offset: u64,
206}
207
208impl NullSection {
209    pub fn new() -> Self {
210        Self::default()
211    }
212
213    pub fn section_header_bytecode(&self) -> Vec<u8> {
214        SectionHeader::new(0, SectionHeader::SHT_NULL, 0, 0, 0, 0, 0, 0, 0, 0).bytecode()
215    }
216}
217
218impl Section for NullSection {
219    // We can use all default implementations from the Section trait
220}
221
222#[derive(Debug)]
223pub struct ShStrTabSection {
224    name: String,
225    name_offset: u32,
226    section_names: Vec<String>,
227    offset: u64,
228}
229
230impl ShStrTabSection {
231    pub fn new(name_offset: u32, section_names: Vec<String>) -> Self {
232        Self {
233            name: String::from(".s"),
234            name_offset,
235            section_names: {
236                let mut names = section_names;
237                names.push(".s".to_string());
238                names
239            },
240            offset: 0,
241        }
242    }
243
244    pub fn set_offset(&mut self, offset: u64) {
245        self.offset = offset;
246    }
247
248    pub fn section_header_bytecode(&self) -> Vec<u8> {
249        SectionHeader::new(
250            self.name_offset,
251            SectionHeader::SHT_STRTAB,
252            0,
253            0,
254            self.offset,
255            self.size(),
256            0,
257            0,
258            1,
259            0,
260        )
261        .bytecode()
262    }
263}
264
265impl Section for ShStrTabSection {
266    fn name(&self) -> &str {
267        &self.name
268    }
269
270    fn bytecode(&self) -> Vec<u8> {
271        let mut bytes = Vec::new();
272        // First byte is null
273        bytes.push(0);
274
275        // Add each non-empty section name with null terminator
276        for name in &self.section_names {
277            if !name.is_empty() {
278                bytes.extend(name.as_bytes());
279                bytes.push(0); // null terminator
280            }
281        }
282
283        // Add padding to make size multiple of 8
284        while bytes.len() % 8 != 0 {
285            bytes.push(0);
286        }
287
288        bytes
289    }
290
291    fn size(&self) -> u64 {
292        // Calculate section header offset
293        let mut section_name_size = 0;
294
295        for name in &self.section_names {
296            if !name.is_empty() {
297                section_name_size += 1 + name.len();
298            }
299        }
300
301        section_name_size += 1; // null section
302
303        section_name_size as u64 // Return the calculated size
304    }
305}
306
307#[derive(Debug)]
308pub struct DynamicSection {
309    name: String,
310    name_offset: u32,
311    offset: u64,
312    link: u32,
313    rel_offset: u64,
314    rel_size: u64,
315    rel_count: u64,
316    dynsym_offset: u64,
317    dynstr_offset: u64,
318    dynstr_size: u64,
319}
320
321impl DynamicSection {
322    pub fn new(name_offset: u32) -> Self {
323        Self {
324            name: String::from(".dynamic"),
325            name_offset,
326            offset: 0,
327            link: 0,
328            rel_offset: 0,
329            rel_size: 0,
330            rel_count: 0,
331            dynsym_offset: 0,
332            dynstr_offset: 0,
333            dynstr_size: 0,
334        }
335    }
336
337    pub fn set_offset(&mut self, offset: u64) {
338        self.offset = offset;
339    }
340
341    pub fn set_link(&mut self, link: u32) {
342        self.link = link;
343    }
344
345    pub fn set_rel_offset(&mut self, offset: u64) {
346        self.rel_offset = offset;
347    }
348
349    pub fn set_rel_size(&mut self, size: u64) {
350        self.rel_size = size;
351    }
352
353    pub fn set_rel_count(&mut self, count: u64) {
354        self.rel_count = count;
355    }
356
357    pub fn set_dynsym_offset(&mut self, offset: u64) {
358        self.dynsym_offset = offset;
359    }
360
361    pub fn set_dynstr_offset(&mut self, offset: u64) {
362        self.dynstr_offset = offset;
363    }
364
365    pub fn set_dynstr_size(&mut self, size: u64) {
366        self.dynstr_size = size;
367    }
368
369    pub fn section_header_bytecode(&self) -> Vec<u8> {
370        SectionHeader::new(
371            self.name_offset,
372            SectionHeader::SHT_DYNAMIC,
373            SectionHeader::SHF_ALLOC | SectionHeader::SHF_WRITE,
374            self.offset,
375            self.offset,
376            self.size(),
377            self.link,
378            0,
379            8,
380            16,
381        )
382        .bytecode()
383    }
384}
385
386impl Section for DynamicSection {
387    fn name(&self) -> &str {
388        &self.name
389    }
390
391    fn bytecode(&self) -> Vec<u8> {
392        let mut bytes = Vec::new();
393
394        // DT_FLAGS (DF_TEXTREL)
395        bytes.extend_from_slice(&0x1e_u64.to_le_bytes());
396        bytes.extend_from_slice(&0x04_u64.to_le_bytes());
397
398        // DT_REL
399        bytes.extend_from_slice(&0x11_u64.to_le_bytes());
400        bytes.extend_from_slice(&self.rel_offset.to_le_bytes());
401
402        // DT_RELSZ
403        bytes.extend_from_slice(&0x12_u64.to_le_bytes());
404        bytes.extend_from_slice(&self.rel_size.to_le_bytes());
405
406        // DT_RELENT
407        bytes.extend_from_slice(&0x13_u64.to_le_bytes());
408        bytes.extend_from_slice(&0x10_u64.to_le_bytes()); // Constant: 16 bytes per entry
409
410        // DT_RELCOUNT: number of relative relocation entries
411        if self.rel_count > 0 {
412            bytes.extend_from_slice(&0x6fff_fffa_u64.to_le_bytes());
413            bytes.extend_from_slice(&self.rel_count.to_le_bytes());
414        }
415
416        // DT_SYMTAB
417        bytes.extend_from_slice(&0x06_u64.to_le_bytes());
418        bytes.extend_from_slice(&self.dynsym_offset.to_le_bytes());
419
420        // DT_SYMENT
421        bytes.extend_from_slice(&0x0b_u64.to_le_bytes());
422        bytes.extend_from_slice(&0x18_u64.to_le_bytes()); // Constant: 24 bytes per symbol
423
424        // DT_STRTAB
425        bytes.extend_from_slice(&0x05_u64.to_le_bytes());
426        bytes.extend_from_slice(&self.dynstr_offset.to_le_bytes());
427
428        // DT_STRSZ
429        bytes.extend_from_slice(&0x0a_u64.to_le_bytes());
430        bytes.extend_from_slice(&self.dynstr_size.to_le_bytes());
431
432        // DT_TEXTREL
433        bytes.extend_from_slice(&0x16_u64.to_le_bytes());
434        bytes.extend_from_slice(&0x00_u64.to_le_bytes());
435
436        // DT_NULL
437        bytes.extend_from_slice(&0x00_u64.to_le_bytes());
438        bytes.extend_from_slice(&0x00_u64.to_le_bytes());
439
440        bytes
441    }
442
443    fn size(&self) -> u64 {
444        if self.rel_count > 0 { 11 * 16 } else { 10 * 16 }
445    }
446}
447
448#[derive(Debug)]
449pub struct DynStrSection {
450    name: String,
451    name_offset: u32,
452    symbol_names: Vec<String>,
453    offset: u64,
454}
455
456impl DynStrSection {
457    pub fn new(name_offset: u32, symbol_names: Vec<String>) -> Self {
458        Self {
459            name: String::from(".dynstr"),
460            name_offset,
461            symbol_names,
462            offset: 0,
463        }
464    }
465
466    pub fn set_offset(&mut self, offset: u64) {
467        self.offset = offset;
468    }
469
470    pub fn section_header_bytecode(&self) -> Vec<u8> {
471        SectionHeader::new(
472            self.name_offset,
473            SectionHeader::SHT_STRTAB,
474            SectionHeader::SHF_ALLOC, // Allocatable section
475            self.offset,
476            self.offset,
477            self.size(),
478            0,
479            0,
480            1,
481            0,
482        )
483        .bytecode()
484    }
485}
486
487impl Section for DynStrSection {
488    fn name(&self) -> &str {
489        &self.name
490    }
491
492    fn bytecode(&self) -> Vec<u8> {
493        let mut bytes = Vec::new();
494        // First byte is null
495        bytes.push(0);
496
497        // Add each symbol name with null terminator
498        for name in &self.symbol_names {
499            bytes.extend(name.as_bytes());
500            bytes.push(0); // null terminator
501        }
502        // add padding to make size multiple of 8
503        while bytes.len() % 8 != 0 {
504            bytes.push(0);
505        }
506        bytes
507    }
508
509    fn size(&self) -> u64 {
510        // Calculate total size: initial null byte + sum of (name lengths + null terminators)
511        let mut size = 1 + self
512            .symbol_names
513            .iter()
514            .map(|name| name.len() + 1)
515            .sum::<usize>();
516        // add padding to make size multiple of 8
517        while size % 8 != 0 {
518            size += 1;
519        }
520        size as u64
521    }
522}
523
524#[derive(Debug)]
525pub struct DynSymSection {
526    name: String,
527    name_offset: u32,
528    offset: u64,
529    link: u32,
530    symbols: Vec<DynamicSymbol>,
531}
532
533impl DynSymSection {
534    pub fn new(name_offset: u32, symbols: Vec<DynamicSymbol>) -> Self {
535        Self {
536            name: String::from(".dynsym"),
537            name_offset,
538            offset: 0,
539            link: 0,
540            symbols,
541        }
542    }
543
544    pub fn set_offset(&mut self, offset: u64) {
545        self.offset = offset;
546    }
547
548    pub fn set_link(&mut self, link: u32) {
549        self.link = link;
550    }
551
552    pub fn section_header_bytecode(&self) -> Vec<u8> {
553        let flags = SectionHeader::SHF_ALLOC;
554        SectionHeader::new(
555            self.name_offset,
556            SectionHeader::SHT_DYNSYM,
557            flags,
558            self.offset,
559            self.offset,
560            self.size(),
561            self.link,
562            1,
563            8,
564            24,
565        )
566        .bytecode()
567    }
568}
569
570impl Section for DynSymSection {
571    fn name(&self) -> &str {
572        &self.name
573    }
574
575    fn size(&self) -> u64 {
576        // Each symbol entry is 24 bytes
577        (self.symbols.len() as u64) * 24
578    }
579
580    fn bytecode(&self) -> Vec<u8> {
581        let mut bytes = Vec::new();
582        for symbol in &self.symbols {
583            bytes.extend(symbol.bytecode());
584        }
585        bytes
586    }
587}
588
589#[derive(Debug)]
590pub struct RelDynSection {
591    name: String,
592    name_offset: u32,
593    offset: u64,
594    link: u32,
595    entries: Vec<RelDyn>,
596}
597
598impl RelDynSection {
599    pub fn new(name_offset: u32, entries: Vec<RelDyn>) -> Self {
600        Self {
601            name: String::from(".rel.dyn"),
602            name_offset,
603            offset: 0,
604            link: 0,
605            entries,
606        }
607    }
608
609    pub fn set_offset(&mut self, offset: u64) {
610        self.offset = offset;
611    }
612
613    pub fn set_link(&mut self, link: u32) {
614        self.link = link;
615    }
616
617    pub fn size(&self) -> u64 {
618        (self.entries.len() * 16) as u64 // Each RelDyn entry is 16 bytes
619    }
620
621    pub fn section_header_bytecode(&self) -> Vec<u8> {
622        let flags = SectionHeader::SHF_ALLOC;
623        SectionHeader::new(
624            self.name_offset,
625            SectionHeader::SHT_REL,
626            flags,
627            self.offset,
628            self.offset,
629            self.size(),
630            self.link,
631            0,
632            8,
633            16,
634        )
635        .bytecode()
636    }
637}
638
639impl Section for RelDynSection {
640    fn name(&self) -> &str {
641        &self.name
642    }
643
644    fn size(&self) -> u64 {
645        self.size()
646    }
647
648    fn bytecode(&self) -> Vec<u8> {
649        let mut bytes = Vec::new();
650        for entry in &self.entries {
651            bytes.extend(entry.bytecode());
652        }
653        bytes
654    }
655}
656
657#[derive(Debug)]
658pub enum SectionType {
659    Code(CodeSection),
660    Data(DataSection),
661    ShStrTab(ShStrTabSection),
662    Dynamic(DynamicSection),
663    DynStr(DynStrSection),
664    DynSym(DynSymSection),
665    Default(NullSection),
666    RelDyn(RelDynSection),
667}
668
669impl SectionType {
670    pub fn name(&self) -> &str {
671        match self {
672            SectionType::Code(cs) => &cs.name,
673            SectionType::Data(ds) => &ds.name,
674            SectionType::ShStrTab(ss) => &ss.name,
675            SectionType::Dynamic(ds) => &ds.name,
676            SectionType::DynStr(ds) => &ds.name,
677            SectionType::DynSym(ds) => &ds.name,
678            SectionType::Default(ds) => &ds.name,
679            SectionType::RelDyn(ds) => &ds.name,
680        }
681    }
682
683    pub fn bytecode(&self) -> Vec<u8> {
684        match self {
685            SectionType::Code(cs) => cs.bytecode(),
686            SectionType::Data(ds) => ds.bytecode(),
687            SectionType::ShStrTab(ss) => ss.bytecode(),
688            SectionType::Dynamic(ds) => ds.bytecode(),
689            SectionType::DynStr(ds) => ds.bytecode(),
690            SectionType::DynSym(ds) => ds.bytecode(),
691            SectionType::Default(ds) => ds.bytecode(),
692            SectionType::RelDyn(ds) => ds.bytecode(),
693        }
694    }
695
696    pub fn size(&self) -> u64 {
697        match self {
698            SectionType::Code(cs) => cs.size(),
699            SectionType::Data(ds) => ds.size(),
700            SectionType::ShStrTab(ss) => ss.size(),
701            SectionType::Dynamic(ds) => ds.size(),
702            SectionType::DynStr(ds) => ds.size(),
703            SectionType::DynSym(ds) => ds.size(),
704            SectionType::Default(ds) => ds.size(),
705            SectionType::RelDyn(ds) => ds.size(),
706        }
707    }
708
709    pub fn section_header_bytecode(&self) -> Vec<u8> {
710        match self {
711            SectionType::Code(cs) => cs.section_header_bytecode(),
712            SectionType::Data(ds) => ds.section_header_bytecode(),
713            SectionType::ShStrTab(ss) => ss.section_header_bytecode(),
714            SectionType::Dynamic(ds) => ds.section_header_bytecode(),
715            SectionType::DynStr(ds) => ds.section_header_bytecode(),
716            SectionType::DynSym(ds) => ds.section_header_bytecode(),
717            SectionType::Default(ds) => ds.section_header_bytecode(),
718            SectionType::RelDyn(ds) => ds.section_header_bytecode(),
719        }
720    }
721
722    pub fn set_offset(&mut self, offset: u64) {
723        match self {
724            SectionType::Code(cs) => cs.set_offset(offset),
725            SectionType::Data(ds) => ds.set_offset(offset),
726            SectionType::ShStrTab(ss) => ss.set_offset(offset),
727            SectionType::Dynamic(ds) => ds.set_offset(offset),
728            SectionType::DynStr(ds) => ds.set_offset(offset),
729            SectionType::DynSym(ds) => ds.set_offset(offset),
730            SectionType::RelDyn(ds) => ds.set_offset(offset),
731            SectionType::Default(_) => (), // NullSection doesn't need offset
732        }
733    }
734
735    pub fn offset(&self) -> u64 {
736        match self {
737            SectionType::Code(cs) => cs.offset,
738            SectionType::Data(ds) => ds.offset,
739            SectionType::ShStrTab(ss) => ss.offset,
740            SectionType::Dynamic(ds) => ds.offset,
741            SectionType::DynStr(ds) => ds.offset,
742            SectionType::DynSym(ds) => ds.offset,
743            SectionType::Default(ns) => ns.offset,
744            SectionType::RelDyn(rs) => rs.offset,
745        }
746    }
747}
748
749#[cfg(test)]
750mod tests {
751    use {
752        super::*,
753        sbpf_common::{instruction::Instruction, opcode::Opcode},
754    };
755
756    #[test]
757    fn test_code_section_new() {
758        let inst = Instruction {
759            opcode: Opcode::Exit,
760            dst: None,
761            src: None,
762            off: None,
763            imm: None,
764            span: 0..4,
765        };
766        let nodes = vec![ASTNode::Instruction {
767            instruction: inst,
768            offset: 0,
769        }];
770
771        let section = CodeSection::new(nodes, 8);
772        assert_eq!(section.name(), ".text");
773        assert_eq!(section.get_size(), 8);
774    }
775
776    #[test]
777    fn test_code_section_bytecode() {
778        let inst = Instruction {
779            opcode: Opcode::Exit,
780            dst: None,
781            src: None,
782            off: None,
783            imm: None,
784            span: 0..4,
785        };
786        let nodes = vec![ASTNode::Instruction {
787            instruction: inst,
788            offset: 0,
789        }];
790
791        let section = CodeSection::new(nodes, 8);
792        let bytes = section.bytecode();
793        assert_eq!(bytes.len(), 8);
794    }
795
796    #[test]
797    fn test_data_section_new() {
798        let rodata = ROData {
799            name: "msg".to_string(),
800            args: vec![
801                Token::Directive("ascii".to_string(), 0..5),
802                Token::StringLiteral("Hi".to_string(), 6..10),
803            ],
804            span: 0..10,
805        };
806        let nodes = vec![ASTNode::ROData { rodata, offset: 0 }];
807
808        let section = DataSection::new(nodes, 2);
809        assert_eq!(section.name(), ".rodata");
810        assert_eq!(section.get_size(), 2);
811    }
812
813    #[test]
814    fn test_data_section_rodata() {
815        let rodata = ROData {
816            name: "my_str".to_string(),
817            args: vec![
818                Token::Directive("ascii".to_string(), 0..5),
819                Token::StringLiteral("test".to_string(), 6..12),
820            ],
821            span: 0..12,
822        };
823        let nodes = vec![ASTNode::ROData { rodata, offset: 0 }];
824
825        let section = DataSection::new(nodes, 4);
826        let rodata = section.rodata();
827        assert_eq!(rodata.len(), 1);
828        assert_eq!(rodata[0].0, "my_str");
829        assert_eq!(rodata[0].2, "test");
830    }
831
832    #[test]
833    fn test_null_section() {
834        let section = NullSection::new();
835        assert_eq!(section.name(), ".unknown");
836        assert_eq!(section.bytecode().len(), 0);
837        assert_eq!(section.size(), 0);
838    }
839
840    #[test]
841    fn test_shstrtab_section() {
842        let names = vec![".text".to_string(), ".data".to_string()];
843        let mut section = ShStrTabSection::new(10, names);
844        section.set_offset(100);
845
846        assert_eq!(section.name(), ".s");
847        assert!(section.size() > 0);
848
849        let bytes = section.bytecode();
850        assert!(bytes.len() > 0);
851        assert_eq!(bytes[0], 0); // First byte is null
852    }
853
854    #[test]
855    fn test_dynamic_section_setters() {
856        let mut section = DynamicSection::new(5);
857        section.set_offset(100);
858        section.set_link(3);
859        section.set_rel_offset(200);
860        section.set_rel_size(48);
861        section.set_rel_count(2);
862        section.set_dynsym_offset(300);
863        section.set_dynstr_offset(400);
864        section.set_dynstr_size(50);
865
866        assert_eq!(section.name(), ".dynamic");
867        assert!(section.size() > 0);
868    }
869
870    #[test]
871    fn test_dynamic_section_bytecode_with_rel_count() {
872        let mut section = DynamicSection::new(0);
873        section.set_rel_count(3);
874        assert_eq!(section.size(), 11 * 16); // With rel_count
875    }
876
877    #[test]
878    fn test_dynamic_section_bytecode_without_rel_count() {
879        let section = DynamicSection::new(0);
880        assert_eq!(section.size(), 10 * 16); // Without rel_count
881    }
882
883    #[test]
884    fn test_dynstr_section() {
885        let names = vec!["entrypoint".to_string(), "function".to_string()];
886        let mut section = DynStrSection::new(8, names);
887        section.set_offset(200);
888
889        assert_eq!(section.name(), ".dynstr");
890
891        let bytes = section.bytecode();
892        assert_eq!(bytes[0], 0);
893        assert_eq!(bytes.len() % 8, 0);
894    }
895
896    #[test]
897    fn test_dynsym_section() {
898        let symbols = vec![
899            DynamicSymbol::new(0, 0, 0, 0, 0, 0),
900            DynamicSymbol::new(1, 0x12, 0, 1, 0x120, 48),
901        ];
902        let mut section = DynSymSection::new(15, symbols);
903        section.set_offset(300);
904        section.set_link(4);
905
906        assert_eq!(section.name(), ".dynsym");
907        assert_eq!(section.size(), 2 * 24); // 2 symbols * 24 bytes each
908    }
909
910    #[test]
911    fn test_rel_dyn_section() {
912        let entries = vec![RelDyn::new(0x120, 0x08, 0), RelDyn::new(0x200, 0x0a, 1)];
913        let mut section = RelDynSection::new(18, entries);
914        section.set_offset(400);
915        section.set_link(3);
916
917        assert_eq!(section.name(), ".rel.dyn");
918        assert_eq!(section.size(), 2 * 16); // 2 entries * 16 bytes each
919    }
920
921    #[test]
922    fn test_section_type_enum_code() {
923        let inst = Instruction {
924            opcode: Opcode::Exit,
925            dst: None,
926            src: None,
927            off: None,
928            imm: None,
929            span: 0..4,
930        };
931        let code_section = CodeSection::new(
932            vec![ASTNode::Instruction {
933                instruction: inst,
934                offset: 0,
935            }],
936            8,
937        );
938
939        let section_type = SectionType::Code(code_section);
940        assert_eq!(section_type.name(), ".text");
941        assert_eq!(section_type.size(), 8);
942    }
943
944    #[test]
945    fn test_section_type_set_offset() {
946        let mut section = SectionType::Default(NullSection::new());
947        section.set_offset(100);
948
949        let mut dyn_section = SectionType::Dynamic(DynamicSection::new(0));
950        dyn_section.set_offset(200);
951        assert_eq!(dyn_section.offset(), 200);
952    }
953}