Inject linker boundary symbols (`__text_start`, `__bss_end`, etc.) into the symbol table so kernel startup code can zero BSS, set the stack pointer, and initialise the heap without hard-coding addresses. Symbols are stored as section-relative offsets (`load_base` is added by the ELF writer). If `layout.stack_top > 0` the value stored is `layout.stack_top - layout.load_base` so that after load-ba
(&mut self, layout: &LinkLayout)
| 923 | push_u64_le(&mut buf, shstrtab_off); |
| 924 | push_u64_le(&mut buf, shstrtab.len() as u64); |
| 925 | push_u32_le(&mut buf, 0); |
| 926 | push_u32_le(&mut buf, 0); |
| 927 | push_u64_le(&mut buf, 1); |
| 928 | push_u64_le(&mut buf, 0); |
| 929 | |
| 930 | push_u32_le(&mut buf, strtab_name); |
| 931 | push_u32_le(&mut buf, SHT_STRTAB); |
| 932 | push_u64_le(&mut buf, 0); |
| 933 | push_u64_le(&mut buf, 0); |
| 934 | push_u64_le(&mut buf, strtab_off); |
| 935 | push_u64_le(&mut buf, strtab.len() as u64); |
| 936 | push_u32_le(&mut buf, 0); |
| 937 | push_u32_le(&mut buf, 0); |
| 938 | push_u64_le(&mut buf, 1); |
| 939 | push_u64_le(&mut buf, 0); |
| 940 | |
| 941 | let strtab_shndx = 1 + prog_secs.len() + rela_secs.len() + 1; |
| 942 | push_u32_le(&mut buf, symtab_name); |
| 943 | push_u32_le(&mut buf, SHT_SYMTAB); |
| 944 | push_u64_le(&mut buf, 0); |
| 945 | push_u64_le(&mut buf, 0); |
| 946 | push_u64_le(&mut buf, symtab_off); |
| 947 | push_u64_le(&mut buf, symtab.len() as u64); |
| 948 | push_u32_le(&mut buf, strtab_shndx as u32); |
| 949 | push_u32_le(&mut buf, first_global); |
| 950 | push_u64_le(&mut buf, 8); |
| 951 | push_u64_le(&mut buf, ELF64_SYM_SIZE as u64); |
| 952 | |
| 953 | buf |
| 954 | } |
| 955 | |
| 956 | // --- Flat binary --- |
| 957 | |
| 958 | /// Raw image with no ELF headers: non-BSS sections in load order, then BSS as zeros. |
| 959 | /// For bootloaders that copy the image straight into memory. |
| 960 | pub fn to_flat_binary(&self) -> Vec<u8> { |
| 961 | let mut buf = Vec::new(); |
| 962 | for pass_bss in [false, true] { |
| 963 | for sec in &self.sections { |
| 964 | if let Some(kind) = &sec.kind { |
| 965 | if matches!(kind, SectionKind::Bss) != pass_bss { |
| 966 | continue; |
| 967 | } |
| 968 | buf.extend_from_slice(&sec.bytes); |
| 969 | } |
| 970 | } |
| 971 | } |
| 972 | buf |
| 973 | } |
| 974 | |
| 975 | // --- Layout symbol injection --- |
| 976 | |
| 977 | /// Inject boundary symbols as section-relative offsets; the ELF writer adds `load_base`. |
| 978 | /// Symbol contract: `_RISCV_SPECIFICATIONS.md` section 9.4. |
| 979 | pub fn inject_layout_symbols(&mut self, layout: &LinkLayout) { |
| 980 | if !layout.emit_layout_symbols { |
| 981 | return; |
| 982 | } |