Encode all tokens into an `AssembledOutput` using the layout symbol table.
(tokens: &[AsmToken], layout: &Layout)
| 11 | use crate::traits::Instruction as _; |
| 12 | |
| 13 | // Record a pc-to-source entry for the instruction about to be emitted at `addr`. |
| 14 | fn record_line(out: &mut AssembledOutput, addr: u64, loc: Option<(u32, u32)>) { |
| 15 | if let Some((file_id, line)) = loc { |
| 16 | out.line_table.push(LineEntry { |
| 17 | addr, |
| 18 | file_id, |
| 19 | line, |
| 20 | }); |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | /// Encode all tokens into an `AssembledOutput` using the layout symbol table. |
| 25 | pub fn encode(tokens: &[AsmToken], layout: &Layout) -> Result<AssembledOutput, AssemblerError> { |
| 26 | let mut out = AssembledOutput::new(); |
| 27 | let mut sections: std::collections::HashMap<SectionKind, SectionData> = layout |
| 28 | .section_order |
| 29 | .iter() |
| 30 | .map(|k| (k.clone(), SectionData::new(k.clone()))) |
| 31 | .collect(); |
| 32 | |
| 33 | // Non-BSS sections first, BSS last to keep ELF virtual addresses contiguous. |
| 34 | let mut section_bases: std::collections::HashMap<SectionKind, u64> = |
| 35 | std::collections::HashMap::new(); |
| 36 | let mut running_base: u64 = 0; |
| 37 | for kind in layout |
| 38 | .section_order |
| 39 | .iter() |
| 40 | .filter(|k| !matches!(k, SectionKind::Bss)) |
| 41 | { |
| 42 | section_bases.insert(kind.clone(), running_base); |
| 43 | running_base += layout.section_sizes.get(kind).copied().unwrap_or(0); |
| 44 | } |
| 45 | for kind in layout |
| 46 | .section_order |
| 47 | .iter() |
| 48 | .filter(|k| matches!(k, SectionKind::Bss)) |
| 49 | { |
| 50 | section_bases.insert(kind.clone(), running_base); |
| 51 | running_base += layout.section_sizes.get(kind).copied().unwrap_or(0); |
| 52 | } |
| 53 | |
| 54 | let mut current_kind = SectionKind::Text; |
| 55 | let mut current_addr: u64 = section_bases.get(¤t_kind).copied().unwrap_or(0); |
| 56 | // Source location attributed to the instructions that follow, until reset. |
| 57 | let mut current_loc: Option<(u32, u32)> = None; |
| 58 | |
| 59 | for token in tokens { |
| 60 | match token { |
| 61 | AsmToken::Loc { file, line } => { |
| 62 | let file_id = out.intern_file(file); |
| 63 | current_loc = Some((file_id, *line)); |
| 64 | } |
| 65 | AsmToken::Section(kind) => { |
| 66 | current_kind = kind.clone(); |
| 67 | let base = section_bases.get(kind).copied().unwrap_or(0); |
| 68 | let sec = sections |
| 69 | .entry(current_kind.clone()) |
| 70 | .or_insert_with(|| SectionData::new(current_kind.clone())); |