Collect all distinct section kinds present across all modules, in canonical ELF load order: Text, `RoData`, Data, Custom(k), Bss.
(modules: &[(&str, &AssembledOutput)])
| 296 | let text_len = module.section_bytes(&SectionKind::Text).len() as u64; |
| 297 | if text_len > 0 { |
| 298 | let file_id = sentinel_file_id(&mut merged_file_table); |
| 299 | merged_line_table.push(LineEntry { |
| 300 | addr: abs_base + text_len, |
| 301 | file_id, |
| 302 | line: 0, |
| 303 | }); |
| 304 | } |
| 305 | } |
| 306 | } |
| 307 | // Real entries win over sentinels that land on the same address. |
| 308 | merged_line_table.sort_by_key(|e| (e.addr, e.line == 0)); |
| 309 | merged_line_table.dedup_by_key(|e| e.addr); |
| 310 | |
| 311 | // Assemble the final output |
| 312 | let sections: Vec<SectionData> = merged_secs |
| 313 | .into_iter() |
| 314 | .map(|ms| SectionData { |
| 315 | kind: Some(ms.kind), |
| 316 | bytes: ms.bytes, |
| 317 | symbols: Vec::new(), |
| 318 | globals: Vec::new(), |
| 319 | }) |
| 320 | .collect(); |
| 321 | |
| 322 | Ok(AssembledOutput { |
| 323 | sections, |
| 324 | symbol_table: output_symbols, |
| 325 | global_symbols: global_names, |
| 326 | relocations: Vec::new(), |
| 327 | line_table: merged_line_table, |
| 328 | file_table: merged_file_table, |
| 329 | }) |
| 330 | } |
| 331 | } |
| 332 | |
| 333 | // --- Helpers --- |
| 334 | |
| 335 | // Id of the empty "no source" file name used by module-end line sentinels. |
| 336 | fn sentinel_file_id(file_table: &mut Vec<String>) -> u32 { |
| 337 | if let Some(pos) = file_table.iter().position(|f| f.is_empty()) { |
| 338 | return pos as u32; |
| 339 | } |
| 340 | file_table.push(String::new()); |