| 1 | use alloc::vec::Vec; |
| 2 | |
| 3 | use crate::write::elf::writer::*; |
| 4 | use crate::write::string::StringId; |
| 5 | use crate::write::*; |
| 6 | use crate::{elf, pod}; |
| 7 | |
| 8 | #[derive (Clone, Copy)] |
| 9 | struct ComdatOffsets { |
| 10 | offset: usize, |
| 11 | str_id: StringId, |
| 12 | } |
| 13 | |
| 14 | #[derive (Clone, Copy)] |
| 15 | struct SectionOffsets { |
| 16 | index: SectionIndex, |
| 17 | offset: usize, |
| 18 | str_id: StringId, |
| 19 | reloc_offset: usize, |
| 20 | reloc_str_id: Option<StringId>, |
| 21 | } |
| 22 | |
| 23 | #[derive (Default, Clone, Copy)] |
| 24 | struct SymbolOffsets { |
| 25 | index: SymbolIndex, |
| 26 | str_id: Option<StringId>, |
| 27 | } |
| 28 | |
| 29 | // Public methods. |
| 30 | impl<'a> Object<'a> { |
| 31 | /// Add a property with a u32 value to the ELF ".note.gnu.property" section. |
| 32 | /// |
| 33 | /// Requires `feature = "elf"`. |
| 34 | pub fn add_elf_gnu_property_u32(&mut self, property: u32, value: u32) { |
| 35 | if self.format != BinaryFormat::Elf { |
| 36 | return; |
| 37 | } |
| 38 | |
| 39 | let align = if self.elf_is_64() { 8 } else { 4 }; |
| 40 | let mut data = Vec::with_capacity(32); |
| 41 | let n_name = b"GNU \0" ; |
| 42 | data.extend_from_slice(pod::bytes_of(&elf::NoteHeader32 { |
| 43 | n_namesz: U32::new(self.endian, n_name.len() as u32), |
| 44 | n_descsz: U32::new(self.endian, util::align(3 * 4, align) as u32), |
| 45 | n_type: U32::new(self.endian, elf::NT_GNU_PROPERTY_TYPE_0), |
| 46 | })); |
| 47 | data.extend_from_slice(n_name); |
| 48 | // This happens to already be aligned correctly. |
| 49 | debug_assert_eq!(util::align(data.len(), align), data.len()); |
| 50 | data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, property))); |
| 51 | // Value size |
| 52 | data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, 4))); |
| 53 | data.extend_from_slice(pod::bytes_of(&U32::new(self.endian, value))); |
| 54 | util::write_align(&mut data, align); |
| 55 | |
| 56 | let section = self.section_id(StandardSection::GnuProperty); |
| 57 | self.append_section_data(section, &data, align as u64); |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | // Private methods. |
| 62 | impl<'a> Object<'a> { |
| 63 | pub(crate) fn elf_section_info( |
| 64 | &self, |
| 65 | section: StandardSection, |
| 66 | ) -> (&'static [u8], &'static [u8], SectionKind, SectionFlags) { |
| 67 | match section { |
| 68 | StandardSection::Text => (&[], &b".text" [..], SectionKind::Text, SectionFlags::None), |
| 69 | StandardSection::Data => (&[], &b".data" [..], SectionKind::Data, SectionFlags::None), |
| 70 | StandardSection::ReadOnlyData | StandardSection::ReadOnlyString => ( |
| 71 | &[], |
| 72 | &b".rodata" [..], |
| 73 | SectionKind::ReadOnlyData, |
| 74 | SectionFlags::None, |
| 75 | ), |
| 76 | StandardSection::ReadOnlyDataWithRel => ( |
| 77 | &[], |
| 78 | b".data.rel.ro" , |
| 79 | SectionKind::ReadOnlyDataWithRel, |
| 80 | SectionFlags::None, |
| 81 | ), |
| 82 | StandardSection::UninitializedData => ( |
| 83 | &[], |
| 84 | &b".bss" [..], |
| 85 | SectionKind::UninitializedData, |
| 86 | SectionFlags::None, |
| 87 | ), |
| 88 | StandardSection::Tls => (&[], &b".tdata" [..], SectionKind::Tls, SectionFlags::None), |
| 89 | StandardSection::UninitializedTls => ( |
| 90 | &[], |
| 91 | &b".tbss" [..], |
| 92 | SectionKind::UninitializedTls, |
| 93 | SectionFlags::None, |
| 94 | ), |
| 95 | StandardSection::TlsVariables => { |
| 96 | // Unsupported section. |
| 97 | (&[], &[], SectionKind::TlsVariables, SectionFlags::None) |
| 98 | } |
| 99 | StandardSection::Common => { |
| 100 | // Unsupported section. |
| 101 | (&[], &[], SectionKind::Common, SectionFlags::None) |
| 102 | } |
| 103 | StandardSection::GnuProperty => ( |
| 104 | &[], |
| 105 | &b".note.gnu.property" [..], |
| 106 | SectionKind::Note, |
| 107 | SectionFlags::Elf { |
| 108 | sh_flags: u64::from(elf::SHF_ALLOC), |
| 109 | }, |
| 110 | ), |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | pub(crate) fn elf_subsection_name(&self, section: &[u8], value: &[u8]) -> Vec<u8> { |
| 115 | let mut name = section.to_vec(); |
| 116 | if !value.is_empty() { |
| 117 | name.push(b'.' ); |
| 118 | name.extend_from_slice(value); |
| 119 | } |
| 120 | name |
| 121 | } |
| 122 | |
| 123 | fn elf_has_relocation_addend(&self) -> Result<bool> { |
| 124 | Ok(match self.architecture { |
| 125 | Architecture::Aarch64 => true, |
| 126 | Architecture::Aarch64_Ilp32 => true, |
| 127 | Architecture::Arm => false, |
| 128 | Architecture::Avr => true, |
| 129 | Architecture::Bpf => false, |
| 130 | Architecture::Csky => true, |
| 131 | Architecture::E2K32 => true, |
| 132 | Architecture::E2K64 => true, |
| 133 | Architecture::I386 => false, |
| 134 | Architecture::X86_64 => true, |
| 135 | Architecture::X86_64_X32 => true, |
| 136 | Architecture::Hexagon => true, |
| 137 | Architecture::LoongArch64 => true, |
| 138 | Architecture::M68k => true, |
| 139 | Architecture::Mips => false, |
| 140 | Architecture::Mips64 => true, |
| 141 | Architecture::Mips64_N32 => true, |
| 142 | Architecture::Msp430 => true, |
| 143 | Architecture::PowerPc => true, |
| 144 | Architecture::PowerPc64 => true, |
| 145 | Architecture::Riscv64 => true, |
| 146 | Architecture::Riscv32 => true, |
| 147 | Architecture::S390x => true, |
| 148 | Architecture::Sbf => false, |
| 149 | Architecture::Sharc => true, |
| 150 | Architecture::Sparc => true, |
| 151 | Architecture::Sparc32Plus => true, |
| 152 | Architecture::Sparc64 => true, |
| 153 | Architecture::Xtensa => true, |
| 154 | _ => { |
| 155 | return Err(Error(format!( |
| 156 | "unimplemented architecture {:?}" , |
| 157 | self.architecture |
| 158 | ))); |
| 159 | } |
| 160 | }) |
| 161 | } |
| 162 | |
| 163 | pub(crate) fn elf_translate_relocation(&mut self, reloc: &mut Relocation) -> Result<()> { |
| 164 | use RelocationEncoding as E; |
| 165 | use RelocationKind as K; |
| 166 | |
| 167 | let (kind, encoding, size) = if let RelocationFlags::Generic { |
| 168 | kind, |
| 169 | encoding, |
| 170 | size, |
| 171 | } = reloc.flags |
| 172 | { |
| 173 | (kind, encoding, size) |
| 174 | } else { |
| 175 | return Ok(()); |
| 176 | }; |
| 177 | |
| 178 | let unsupported_reloc = || Err(Error(format!("unimplemented ELF relocation {:?}" , reloc))); |
| 179 | let r_type = match self.architecture { |
| 180 | Architecture::Aarch64 => match (kind, encoding, size) { |
| 181 | (K::Absolute, E::Generic, 64) => elf::R_AARCH64_ABS64, |
| 182 | (K::Absolute, E::Generic, 32) => elf::R_AARCH64_ABS32, |
| 183 | (K::Absolute, E::Generic, 16) => elf::R_AARCH64_ABS16, |
| 184 | (K::Relative, E::Generic, 64) => elf::R_AARCH64_PREL64, |
| 185 | (K::Relative, E::Generic, 32) => elf::R_AARCH64_PREL32, |
| 186 | (K::Relative, E::Generic, 16) => elf::R_AARCH64_PREL16, |
| 187 | (K::Relative, E::AArch64Call, 26) => elf::R_AARCH64_CALL26, |
| 188 | (K::PltRelative, E::AArch64Call, 26) => elf::R_AARCH64_CALL26, |
| 189 | _ => return unsupported_reloc(), |
| 190 | }, |
| 191 | Architecture::Aarch64_Ilp32 => match (kind, encoding, size) { |
| 192 | (K::Absolute, E::Generic, 32) => elf::R_AARCH64_P32_ABS32, |
| 193 | _ => return unsupported_reloc(), |
| 194 | }, |
| 195 | Architecture::Arm => match (kind, encoding, size) { |
| 196 | (K::Absolute, _, 32) => elf::R_ARM_ABS32, |
| 197 | _ => return unsupported_reloc(), |
| 198 | }, |
| 199 | Architecture::Avr => match (kind, encoding, size) { |
| 200 | (K::Absolute, _, 32) => elf::R_AVR_32, |
| 201 | (K::Absolute, _, 16) => elf::R_AVR_16, |
| 202 | _ => return unsupported_reloc(), |
| 203 | }, |
| 204 | Architecture::Bpf => match (kind, encoding, size) { |
| 205 | (K::Absolute, _, 64) => elf::R_BPF_64_64, |
| 206 | (K::Absolute, _, 32) => elf::R_BPF_64_32, |
| 207 | _ => return unsupported_reloc(), |
| 208 | }, |
| 209 | Architecture::Csky => match (kind, encoding, size) { |
| 210 | (K::Absolute, _, 32) => elf::R_CKCORE_ADDR32, |
| 211 | (K::Relative, E::Generic, 32) => elf::R_CKCORE_PCREL32, |
| 212 | _ => return unsupported_reloc(), |
| 213 | }, |
| 214 | Architecture::I386 => match (kind, size) { |
| 215 | (K::Absolute, 32) => elf::R_386_32, |
| 216 | (K::Relative, 32) => elf::R_386_PC32, |
| 217 | (K::Got, 32) => elf::R_386_GOT32, |
| 218 | (K::PltRelative, 32) => elf::R_386_PLT32, |
| 219 | (K::GotBaseOffset, 32) => elf::R_386_GOTOFF, |
| 220 | (K::GotBaseRelative, 32) => elf::R_386_GOTPC, |
| 221 | (K::Absolute, 16) => elf::R_386_16, |
| 222 | (K::Relative, 16) => elf::R_386_PC16, |
| 223 | (K::Absolute, 8) => elf::R_386_8, |
| 224 | (K::Relative, 8) => elf::R_386_PC8, |
| 225 | _ => return unsupported_reloc(), |
| 226 | }, |
| 227 | Architecture::E2K32 | Architecture::E2K64 => match (kind, encoding, size) { |
| 228 | (K::Absolute, E::Generic, 32) => elf::R_E2K_32_ABS, |
| 229 | (K::Absolute, E::E2KLit, 64) => elf::R_E2K_64_ABS_LIT, |
| 230 | (K::Absolute, E::Generic, 64) => elf::R_E2K_64_ABS, |
| 231 | (K::Relative, E::E2KDisp, 28) => elf::R_E2K_DISP, |
| 232 | (K::Got, _, 32) => elf::R_E2K_GOT, |
| 233 | _ => return unsupported_reloc(), |
| 234 | }, |
| 235 | Architecture::X86_64 | Architecture::X86_64_X32 => match (kind, encoding, size) { |
| 236 | (K::Absolute, E::Generic, 64) => elf::R_X86_64_64, |
| 237 | (K::Relative, E::X86Branch, 32) => elf::R_X86_64_PLT32, |
| 238 | (K::Relative, _, 32) => elf::R_X86_64_PC32, |
| 239 | (K::Got, _, 32) => elf::R_X86_64_GOT32, |
| 240 | (K::PltRelative, _, 32) => elf::R_X86_64_PLT32, |
| 241 | (K::GotRelative, _, 32) => elf::R_X86_64_GOTPCREL, |
| 242 | (K::Absolute, E::Generic, 32) => elf::R_X86_64_32, |
| 243 | (K::Absolute, E::X86Signed, 32) => elf::R_X86_64_32S, |
| 244 | (K::Absolute, _, 16) => elf::R_X86_64_16, |
| 245 | (K::Relative, _, 16) => elf::R_X86_64_PC16, |
| 246 | (K::Absolute, _, 8) => elf::R_X86_64_8, |
| 247 | (K::Relative, _, 8) => elf::R_X86_64_PC8, |
| 248 | _ => return unsupported_reloc(), |
| 249 | }, |
| 250 | Architecture::Hexagon => match (kind, encoding, size) { |
| 251 | (K::Absolute, _, 32) => elf::R_HEX_32, |
| 252 | _ => return unsupported_reloc(), |
| 253 | }, |
| 254 | Architecture::LoongArch64 => match (kind, encoding, size) { |
| 255 | (K::Absolute, _, 32) => elf::R_LARCH_32, |
| 256 | (K::Absolute, _, 64) => elf::R_LARCH_64, |
| 257 | (K::Relative, _, 32) => elf::R_LARCH_32_PCREL, |
| 258 | (K::Relative, _, 64) => elf::R_LARCH_64_PCREL, |
| 259 | (K::Relative, E::LoongArchBranch, 16) => elf::R_LARCH_B16, |
| 260 | (K::PltRelative, E::LoongArchBranch, 16) => elf::R_LARCH_B16, |
| 261 | (K::Relative, E::LoongArchBranch, 21) => elf::R_LARCH_B21, |
| 262 | (K::PltRelative, E::LoongArchBranch, 21) => elf::R_LARCH_B21, |
| 263 | (K::Relative, E::LoongArchBranch, 26) => elf::R_LARCH_B26, |
| 264 | (K::PltRelative, E::LoongArchBranch, 26) => elf::R_LARCH_B26, |
| 265 | _ => return unsupported_reloc(), |
| 266 | }, |
| 267 | Architecture::M68k => match (kind, encoding, size) { |
| 268 | (K::Absolute, _, 8) => elf::R_68K_8, |
| 269 | (K::Absolute, _, 16) => elf::R_68K_16, |
| 270 | (K::Absolute, _, 32) => elf::R_68K_32, |
| 271 | (K::Relative, _, 8) => elf::R_68K_PC8, |
| 272 | (K::Relative, _, 16) => elf::R_68K_PC16, |
| 273 | (K::Relative, _, 32) => elf::R_68K_PC32, |
| 274 | (K::GotRelative, _, 8) => elf::R_68K_GOT8, |
| 275 | (K::GotRelative, _, 16) => elf::R_68K_GOT16, |
| 276 | (K::GotRelative, _, 32) => elf::R_68K_GOT32, |
| 277 | (K::Got, _, 8) => elf::R_68K_GOT8O, |
| 278 | (K::Got, _, 16) => elf::R_68K_GOT16O, |
| 279 | (K::Got, _, 32) => elf::R_68K_GOT32O, |
| 280 | (K::PltRelative, _, 8) => elf::R_68K_PLT8, |
| 281 | (K::PltRelative, _, 16) => elf::R_68K_PLT16, |
| 282 | (K::PltRelative, _, 32) => elf::R_68K_PLT32, |
| 283 | _ => return unsupported_reloc(), |
| 284 | }, |
| 285 | Architecture::Mips | Architecture::Mips64 | Architecture::Mips64_N32 => { |
| 286 | match (kind, encoding, size) { |
| 287 | (K::Absolute, _, 16) => elf::R_MIPS_16, |
| 288 | (K::Absolute, _, 32) => elf::R_MIPS_32, |
| 289 | (K::Absolute, _, 64) => elf::R_MIPS_64, |
| 290 | _ => return unsupported_reloc(), |
| 291 | } |
| 292 | } |
| 293 | Architecture::Msp430 => match (kind, encoding, size) { |
| 294 | (K::Absolute, _, 32) => elf::R_MSP430_32, |
| 295 | (K::Absolute, _, 16) => elf::R_MSP430_16_BYTE, |
| 296 | _ => return unsupported_reloc(), |
| 297 | }, |
| 298 | Architecture::PowerPc => match (kind, encoding, size) { |
| 299 | (K::Absolute, _, 32) => elf::R_PPC_ADDR32, |
| 300 | _ => return unsupported_reloc(), |
| 301 | }, |
| 302 | Architecture::PowerPc64 => match (kind, encoding, size) { |
| 303 | (K::Absolute, _, 32) => elf::R_PPC64_ADDR32, |
| 304 | (K::Absolute, _, 64) => elf::R_PPC64_ADDR64, |
| 305 | _ => return unsupported_reloc(), |
| 306 | }, |
| 307 | Architecture::Riscv32 | Architecture::Riscv64 => match (kind, encoding, size) { |
| 308 | (K::Absolute, _, 32) => elf::R_RISCV_32, |
| 309 | (K::Absolute, _, 64) => elf::R_RISCV_64, |
| 310 | (K::Relative, E::Generic, 32) => elf::R_RISCV_32_PCREL, |
| 311 | _ => return unsupported_reloc(), |
| 312 | }, |
| 313 | Architecture::S390x => match (kind, encoding, size) { |
| 314 | (K::Absolute, E::Generic, 8) => elf::R_390_8, |
| 315 | (K::Absolute, E::Generic, 16) => elf::R_390_16, |
| 316 | (K::Absolute, E::Generic, 32) => elf::R_390_32, |
| 317 | (K::Absolute, E::Generic, 64) => elf::R_390_64, |
| 318 | (K::Relative, E::Generic, 16) => elf::R_390_PC16, |
| 319 | (K::Relative, E::Generic, 32) => elf::R_390_PC32, |
| 320 | (K::Relative, E::Generic, 64) => elf::R_390_PC64, |
| 321 | (K::Relative, E::S390xDbl, 16) => elf::R_390_PC16DBL, |
| 322 | (K::Relative, E::S390xDbl, 32) => elf::R_390_PC32DBL, |
| 323 | (K::PltRelative, E::S390xDbl, 16) => elf::R_390_PLT16DBL, |
| 324 | (K::PltRelative, E::S390xDbl, 32) => elf::R_390_PLT32DBL, |
| 325 | (K::Got, E::Generic, 16) => elf::R_390_GOT16, |
| 326 | (K::Got, E::Generic, 32) => elf::R_390_GOT32, |
| 327 | (K::Got, E::Generic, 64) => elf::R_390_GOT64, |
| 328 | (K::GotRelative, E::S390xDbl, 32) => elf::R_390_GOTENT, |
| 329 | (K::GotBaseOffset, E::Generic, 16) => elf::R_390_GOTOFF16, |
| 330 | (K::GotBaseOffset, E::Generic, 32) => elf::R_390_GOTOFF32, |
| 331 | (K::GotBaseOffset, E::Generic, 64) => elf::R_390_GOTOFF64, |
| 332 | (K::GotBaseRelative, E::Generic, 64) => elf::R_390_GOTPC, |
| 333 | (K::GotBaseRelative, E::S390xDbl, 32) => elf::R_390_GOTPCDBL, |
| 334 | _ => return unsupported_reloc(), |
| 335 | }, |
| 336 | Architecture::Sbf => match (kind, encoding, size) { |
| 337 | (K::Absolute, _, 64) => elf::R_SBF_64_64, |
| 338 | (K::Absolute, _, 32) => elf::R_SBF_64_32, |
| 339 | _ => return unsupported_reloc(), |
| 340 | }, |
| 341 | Architecture::Sharc => match (kind, encoding, size) { |
| 342 | (K::Absolute, E::SharcTypeA, 32) => elf::R_SHARC_ADDR32_V3, |
| 343 | (K::Absolute, E::Generic, 32) => elf::R_SHARC_ADDR_VAR_V3, |
| 344 | (K::Relative, E::SharcTypeA, 24) => elf::R_SHARC_PCRLONG_V3, |
| 345 | (K::Relative, E::SharcTypeA, 6) => elf::R_SHARC_PCRSHORT_V3, |
| 346 | (K::Relative, E::SharcTypeB, 6) => elf::R_SHARC_PCRSHORT_V3, |
| 347 | (K::Absolute, E::Generic, 16) => elf::R_SHARC_ADDR_VAR16_V3, |
| 348 | (K::Absolute, E::SharcTypeA, 16) => elf::R_SHARC_DATA16_V3, |
| 349 | (K::Absolute, E::SharcTypeB, 16) => elf::R_SHARC_DATA16_VISA_V3, |
| 350 | (K::Absolute, E::SharcTypeA, 24) => elf::R_SHARC_ADDR24_V3, |
| 351 | (K::Absolute, E::SharcTypeA, 6) => elf::R_SHARC_DATA6_V3, |
| 352 | (K::Absolute, E::SharcTypeB, 6) => elf::R_SHARC_DATA6_VISA_V3, |
| 353 | (K::Absolute, E::SharcTypeB, 7) => elf::R_SHARC_DATA7_VISA_V3, |
| 354 | _ => return unsupported_reloc(), |
| 355 | }, |
| 356 | Architecture::Sparc | Architecture::Sparc32Plus => match (kind, encoding, size) { |
| 357 | // TODO: use R_SPARC_32 if aligned. |
| 358 | (K::Absolute, _, 32) => elf::R_SPARC_UA32, |
| 359 | _ => return unsupported_reloc(), |
| 360 | }, |
| 361 | Architecture::Sparc64 => match (kind, encoding, size) { |
| 362 | // TODO: use R_SPARC_32/R_SPARC_64 if aligned. |
| 363 | (K::Absolute, _, 32) => elf::R_SPARC_UA32, |
| 364 | (K::Absolute, _, 64) => elf::R_SPARC_UA64, |
| 365 | _ => return unsupported_reloc(), |
| 366 | }, |
| 367 | Architecture::Xtensa => match (kind, encoding, size) { |
| 368 | (K::Absolute, _, 32) => elf::R_XTENSA_32, |
| 369 | (K::Relative, E::Generic, 32) => elf::R_XTENSA_32_PCREL, |
| 370 | _ => return unsupported_reloc(), |
| 371 | }, |
| 372 | _ => { |
| 373 | return Err(Error(format!( |
| 374 | "unimplemented architecture {:?}" , |
| 375 | self.architecture |
| 376 | ))); |
| 377 | } |
| 378 | }; |
| 379 | reloc.flags = RelocationFlags::Elf { r_type }; |
| 380 | Ok(()) |
| 381 | } |
| 382 | |
| 383 | pub(crate) fn elf_adjust_addend(&mut self, _relocation: &mut Relocation) -> Result<bool> { |
| 384 | // Determine whether the addend is stored in the relocation or the data. |
| 385 | let implicit = !self.elf_has_relocation_addend()?; |
| 386 | Ok(implicit) |
| 387 | } |
| 388 | |
| 389 | pub(crate) fn elf_relocation_size(&self, reloc: &Relocation) -> Result<u8> { |
| 390 | let r_type = if let RelocationFlags::Elf { r_type } = reloc.flags { |
| 391 | r_type |
| 392 | } else { |
| 393 | return Err(Error("invalid relocation flags" .into())); |
| 394 | }; |
| 395 | // This only needs to support architectures that use implicit addends. |
| 396 | let size = match self.architecture { |
| 397 | Architecture::Arm => match r_type { |
| 398 | elf::R_ARM_ABS16 => Some(16), |
| 399 | elf::R_ARM_ABS32 | elf::R_ARM_REL32 => Some(32), |
| 400 | _ => None, |
| 401 | }, |
| 402 | Architecture::Bpf => match r_type { |
| 403 | elf::R_BPF_64_32 => Some(32), |
| 404 | elf::R_BPF_64_64 => Some(64), |
| 405 | _ => None, |
| 406 | }, |
| 407 | Architecture::I386 => match r_type { |
| 408 | elf::R_386_8 | elf::R_386_PC8 => Some(8), |
| 409 | elf::R_386_16 | elf::R_386_PC16 => Some(16), |
| 410 | elf::R_386_32 |
| 411 | | elf::R_386_PC32 |
| 412 | | elf::R_386_GOT32 |
| 413 | | elf::R_386_PLT32 |
| 414 | | elf::R_386_GOTOFF |
| 415 | | elf::R_386_GOTPC => Some(32), |
| 416 | _ => None, |
| 417 | }, |
| 418 | Architecture::Mips => match r_type { |
| 419 | elf::R_MIPS_16 => Some(16), |
| 420 | elf::R_MIPS_32 => Some(32), |
| 421 | elf::R_MIPS_64 => Some(64), |
| 422 | _ => None, |
| 423 | }, |
| 424 | Architecture::Sbf => match r_type { |
| 425 | elf::R_SBF_64_32 => Some(32), |
| 426 | elf::R_SBF_64_64 => Some(64), |
| 427 | _ => None, |
| 428 | }, |
| 429 | _ => { |
| 430 | return Err(Error(format!( |
| 431 | "unimplemented architecture {:?}" , |
| 432 | self.architecture |
| 433 | ))); |
| 434 | } |
| 435 | }; |
| 436 | size.ok_or_else(|| Error(format!("unsupported relocation for size {:?}" , reloc))) |
| 437 | } |
| 438 | |
| 439 | pub(crate) fn elf_is_64(&self) -> bool { |
| 440 | match self.architecture.address_size().unwrap() { |
| 441 | AddressSize::U8 | AddressSize::U16 | AddressSize::U32 => false, |
| 442 | AddressSize::U64 => true, |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | pub(crate) fn elf_write(&self, buffer: &mut dyn WritableBuffer) -> Result<()> { |
| 447 | // Create reloc section header names so we can reference them. |
| 448 | let is_rela = self.elf_has_relocation_addend()?; |
| 449 | let reloc_names: Vec<_> = self |
| 450 | .sections |
| 451 | .iter() |
| 452 | .map(|section| { |
| 453 | let mut reloc_name = Vec::with_capacity( |
| 454 | if is_rela { ".rela" .len() } else { ".rel" .len() } + section.name.len(), |
| 455 | ); |
| 456 | if !section.relocations.is_empty() { |
| 457 | reloc_name.extend_from_slice(if is_rela { |
| 458 | &b".rela" [..] |
| 459 | } else { |
| 460 | &b".rel" [..] |
| 461 | }); |
| 462 | reloc_name.extend_from_slice(§ion.name); |
| 463 | } |
| 464 | reloc_name |
| 465 | }) |
| 466 | .collect(); |
| 467 | |
| 468 | // Start calculating offsets of everything. |
| 469 | let mut writer = Writer::new(self.endian, self.elf_is_64(), buffer); |
| 470 | writer.reserve_file_header(); |
| 471 | |
| 472 | // Calculate size of section data. |
| 473 | let mut comdat_offsets = Vec::with_capacity(self.comdats.len()); |
| 474 | for comdat in &self.comdats { |
| 475 | if comdat.kind != ComdatKind::Any { |
| 476 | return Err(Error(format!( |
| 477 | "unsupported COMDAT symbol ` {}` kind {:?}" , |
| 478 | self.symbols[comdat.symbol.0].name().unwrap_or("" ), |
| 479 | comdat.kind |
| 480 | ))); |
| 481 | } |
| 482 | |
| 483 | writer.reserve_section_index(); |
| 484 | let offset = writer.reserve_comdat(comdat.sections.len()); |
| 485 | let str_id = writer.add_section_name(b".group" ); |
| 486 | comdat_offsets.push(ComdatOffsets { offset, str_id }); |
| 487 | } |
| 488 | let mut section_offsets = Vec::with_capacity(self.sections.len()); |
| 489 | for (section, reloc_name) in self.sections.iter().zip(reloc_names.iter()) { |
| 490 | let index = writer.reserve_section_index(); |
| 491 | let offset = writer.reserve(section.data.len(), section.align as usize); |
| 492 | let str_id = writer.add_section_name(§ion.name); |
| 493 | let mut reloc_str_id = None; |
| 494 | if !section.relocations.is_empty() { |
| 495 | writer.reserve_section_index(); |
| 496 | reloc_str_id = Some(writer.add_section_name(reloc_name)); |
| 497 | } |
| 498 | section_offsets.push(SectionOffsets { |
| 499 | index, |
| 500 | offset, |
| 501 | str_id, |
| 502 | // Relocation data is reserved later. |
| 503 | reloc_offset: 0, |
| 504 | reloc_str_id, |
| 505 | }); |
| 506 | } |
| 507 | |
| 508 | // Calculate index of symbols and add symbol strings to strtab. |
| 509 | let mut symbol_offsets = vec![SymbolOffsets::default(); self.symbols.len()]; |
| 510 | writer.reserve_null_symbol_index(); |
| 511 | // Local symbols must come before global. |
| 512 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 513 | if symbol.is_local() { |
| 514 | let section_index = symbol.section.id().map(|s| section_offsets[s.0].index); |
| 515 | symbol_offsets[index].index = writer.reserve_symbol_index(section_index); |
| 516 | } |
| 517 | } |
| 518 | let symtab_num_local = writer.symbol_count(); |
| 519 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 520 | if !symbol.is_local() { |
| 521 | let section_index = symbol.section.id().map(|s| section_offsets[s.0].index); |
| 522 | symbol_offsets[index].index = writer.reserve_symbol_index(section_index); |
| 523 | } |
| 524 | } |
| 525 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 526 | if symbol.kind != SymbolKind::Section && !symbol.name.is_empty() { |
| 527 | symbol_offsets[index].str_id = Some(writer.add_string(&symbol.name)); |
| 528 | } |
| 529 | } |
| 530 | |
| 531 | // Calculate size of symbols. |
| 532 | writer.reserve_symtab_section_index(); |
| 533 | writer.reserve_symtab(); |
| 534 | if writer.symtab_shndx_needed() { |
| 535 | writer.reserve_symtab_shndx_section_index(); |
| 536 | } |
| 537 | writer.reserve_symtab_shndx(); |
| 538 | writer.reserve_strtab_section_index(); |
| 539 | writer.reserve_strtab(); |
| 540 | |
| 541 | // Calculate size of relocations. |
| 542 | for (index, section) in self.sections.iter().enumerate() { |
| 543 | let count = section.relocations.len(); |
| 544 | if count != 0 { |
| 545 | section_offsets[index].reloc_offset = writer.reserve_relocations(count, is_rela); |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | // Calculate size of section headers. |
| 550 | writer.reserve_shstrtab_section_index(); |
| 551 | writer.reserve_shstrtab(); |
| 552 | writer.reserve_section_headers(); |
| 553 | |
| 554 | // Start writing. |
| 555 | let e_type = elf::ET_REL; |
| 556 | let e_machine = match (self.architecture, self.sub_architecture) { |
| 557 | (Architecture::Aarch64, None) => elf::EM_AARCH64, |
| 558 | (Architecture::Aarch64_Ilp32, None) => elf::EM_AARCH64, |
| 559 | (Architecture::Arm, None) => elf::EM_ARM, |
| 560 | (Architecture::Avr, None) => elf::EM_AVR, |
| 561 | (Architecture::Bpf, None) => elf::EM_BPF, |
| 562 | (Architecture::Csky, None) => elf::EM_CSKY, |
| 563 | (Architecture::E2K32, None) => elf::EM_MCST_ELBRUS, |
| 564 | (Architecture::E2K64, None) => elf::EM_MCST_ELBRUS, |
| 565 | (Architecture::I386, None) => elf::EM_386, |
| 566 | (Architecture::X86_64, None) => elf::EM_X86_64, |
| 567 | (Architecture::X86_64_X32, None) => elf::EM_X86_64, |
| 568 | (Architecture::Hexagon, None) => elf::EM_HEXAGON, |
| 569 | (Architecture::LoongArch64, None) => elf::EM_LOONGARCH, |
| 570 | (Architecture::M68k, None) => elf::EM_68K, |
| 571 | (Architecture::Mips, None) => elf::EM_MIPS, |
| 572 | (Architecture::Mips64, None) => elf::EM_MIPS, |
| 573 | (Architecture::Mips64_N32, None) => elf::EM_MIPS, |
| 574 | (Architecture::Msp430, None) => elf::EM_MSP430, |
| 575 | (Architecture::PowerPc, None) => elf::EM_PPC, |
| 576 | (Architecture::PowerPc64, None) => elf::EM_PPC64, |
| 577 | (Architecture::Riscv32, None) => elf::EM_RISCV, |
| 578 | (Architecture::Riscv64, None) => elf::EM_RISCV, |
| 579 | (Architecture::S390x, None) => elf::EM_S390, |
| 580 | (Architecture::Sbf, None) => elf::EM_SBF, |
| 581 | (Architecture::Sharc, None) => elf::EM_SHARC, |
| 582 | (Architecture::Sparc, None) => elf::EM_SPARC, |
| 583 | (Architecture::Sparc32Plus, None) => elf::EM_SPARC32PLUS, |
| 584 | (Architecture::Sparc64, None) => elf::EM_SPARCV9, |
| 585 | (Architecture::Xtensa, None) => elf::EM_XTENSA, |
| 586 | _ => { |
| 587 | return Err(Error(format!( |
| 588 | "unimplemented architecture {:?} with sub-architecture {:?}" , |
| 589 | self.architecture, self.sub_architecture |
| 590 | ))); |
| 591 | } |
| 592 | }; |
| 593 | let (os_abi, abi_version, mut e_flags) = if let FileFlags::Elf { |
| 594 | os_abi, |
| 595 | abi_version, |
| 596 | e_flags, |
| 597 | } = self.flags |
| 598 | { |
| 599 | (os_abi, abi_version, e_flags) |
| 600 | } else { |
| 601 | (elf::ELFOSABI_NONE, 0, 0) |
| 602 | }; |
| 603 | |
| 604 | if self.architecture == Architecture::Mips64_N32 { |
| 605 | e_flags |= elf::EF_MIPS_ABI2; |
| 606 | } |
| 607 | |
| 608 | writer.write_file_header(&FileHeader { |
| 609 | os_abi, |
| 610 | abi_version, |
| 611 | e_type, |
| 612 | e_machine, |
| 613 | e_entry: 0, |
| 614 | e_flags, |
| 615 | })?; |
| 616 | |
| 617 | // Write section data. |
| 618 | for comdat in &self.comdats { |
| 619 | writer.write_comdat_header(); |
| 620 | for section in &comdat.sections { |
| 621 | writer.write_comdat_entry(section_offsets[section.0].index); |
| 622 | } |
| 623 | } |
| 624 | for (index, section) in self.sections.iter().enumerate() { |
| 625 | writer.write_align(section.align as usize); |
| 626 | debug_assert_eq!(section_offsets[index].offset, writer.len()); |
| 627 | writer.write(§ion.data); |
| 628 | } |
| 629 | |
| 630 | // Write symbols. |
| 631 | writer.write_null_symbol(); |
| 632 | let mut write_symbol = |index: usize, symbol: &Symbol| -> Result<()> { |
| 633 | let st_info = if let SymbolFlags::Elf { st_info, .. } = symbol.flags { |
| 634 | st_info |
| 635 | } else { |
| 636 | let st_type = match symbol.kind { |
| 637 | SymbolKind::Text => { |
| 638 | if symbol.is_undefined() { |
| 639 | elf::STT_NOTYPE |
| 640 | } else { |
| 641 | elf::STT_FUNC |
| 642 | } |
| 643 | } |
| 644 | SymbolKind::Data => { |
| 645 | if symbol.is_undefined() { |
| 646 | elf::STT_NOTYPE |
| 647 | } else if symbol.is_common() { |
| 648 | elf::STT_COMMON |
| 649 | } else { |
| 650 | elf::STT_OBJECT |
| 651 | } |
| 652 | } |
| 653 | SymbolKind::Section => elf::STT_SECTION, |
| 654 | SymbolKind::File => elf::STT_FILE, |
| 655 | SymbolKind::Tls => elf::STT_TLS, |
| 656 | SymbolKind::Label => elf::STT_NOTYPE, |
| 657 | SymbolKind::Unknown => { |
| 658 | if symbol.is_undefined() { |
| 659 | elf::STT_NOTYPE |
| 660 | } else { |
| 661 | return Err(Error(format!( |
| 662 | "unimplemented symbol ` {}` kind {:?}" , |
| 663 | symbol.name().unwrap_or("" ), |
| 664 | symbol.kind |
| 665 | ))); |
| 666 | } |
| 667 | } |
| 668 | }; |
| 669 | let st_bind = if symbol.weak { |
| 670 | elf::STB_WEAK |
| 671 | } else if symbol.is_undefined() { |
| 672 | elf::STB_GLOBAL |
| 673 | } else if symbol.is_local() { |
| 674 | elf::STB_LOCAL |
| 675 | } else { |
| 676 | elf::STB_GLOBAL |
| 677 | }; |
| 678 | (st_bind << 4) + st_type |
| 679 | }; |
| 680 | let st_other = if let SymbolFlags::Elf { st_other, .. } = symbol.flags { |
| 681 | st_other |
| 682 | } else if symbol.scope == SymbolScope::Linkage { |
| 683 | elf::STV_HIDDEN |
| 684 | } else { |
| 685 | elf::STV_DEFAULT |
| 686 | }; |
| 687 | let (st_shndx, section) = match symbol.section { |
| 688 | SymbolSection::None => { |
| 689 | debug_assert_eq!(symbol.kind, SymbolKind::File); |
| 690 | (elf::SHN_ABS, None) |
| 691 | } |
| 692 | SymbolSection::Undefined => (elf::SHN_UNDEF, None), |
| 693 | SymbolSection::Absolute => (elf::SHN_ABS, None), |
| 694 | SymbolSection::Common => (elf::SHN_COMMON, None), |
| 695 | SymbolSection::Section(id) => (0, Some(section_offsets[id.0].index)), |
| 696 | }; |
| 697 | writer.write_symbol(&Sym { |
| 698 | name: symbol_offsets[index].str_id, |
| 699 | section, |
| 700 | st_info, |
| 701 | st_other, |
| 702 | st_shndx, |
| 703 | st_value: symbol.value, |
| 704 | st_size: symbol.size, |
| 705 | }); |
| 706 | Ok(()) |
| 707 | }; |
| 708 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 709 | if symbol.is_local() { |
| 710 | write_symbol(index, symbol)?; |
| 711 | } |
| 712 | } |
| 713 | for (index, symbol) in self.symbols.iter().enumerate() { |
| 714 | if !symbol.is_local() { |
| 715 | write_symbol(index, symbol)?; |
| 716 | } |
| 717 | } |
| 718 | writer.write_symtab_shndx(); |
| 719 | writer.write_strtab(); |
| 720 | |
| 721 | // Write relocations. |
| 722 | for (index, section) in self.sections.iter().enumerate() { |
| 723 | if !section.relocations.is_empty() { |
| 724 | writer.write_align_relocation(); |
| 725 | debug_assert_eq!(section_offsets[index].reloc_offset, writer.len()); |
| 726 | for reloc in §ion.relocations { |
| 727 | let r_type = if let RelocationFlags::Elf { r_type } = reloc.flags { |
| 728 | r_type |
| 729 | } else { |
| 730 | return Err(Error("invalid relocation flags" .into())); |
| 731 | }; |
| 732 | let r_sym = symbol_offsets[reloc.symbol.0].index.0; |
| 733 | writer.write_relocation( |
| 734 | is_rela, |
| 735 | &Rel { |
| 736 | r_offset: reloc.offset, |
| 737 | r_sym, |
| 738 | r_type, |
| 739 | r_addend: reloc.addend, |
| 740 | }, |
| 741 | ); |
| 742 | } |
| 743 | } |
| 744 | } |
| 745 | |
| 746 | writer.write_shstrtab(); |
| 747 | |
| 748 | // Write section headers. |
| 749 | writer.write_null_section_header(); |
| 750 | |
| 751 | let symtab_index = writer.symtab_index(); |
| 752 | for (comdat, comdat_offset) in self.comdats.iter().zip(comdat_offsets.iter()) { |
| 753 | writer.write_comdat_section_header( |
| 754 | comdat_offset.str_id, |
| 755 | symtab_index, |
| 756 | symbol_offsets[comdat.symbol.0].index, |
| 757 | comdat_offset.offset, |
| 758 | comdat.sections.len(), |
| 759 | ); |
| 760 | } |
| 761 | for (index, section) in self.sections.iter().enumerate() { |
| 762 | let sh_type = match section.kind { |
| 763 | SectionKind::UninitializedData | SectionKind::UninitializedTls => elf::SHT_NOBITS, |
| 764 | SectionKind::Note => elf::SHT_NOTE, |
| 765 | SectionKind::Elf(sh_type) => sh_type, |
| 766 | _ => elf::SHT_PROGBITS, |
| 767 | }; |
| 768 | let sh_flags = if let SectionFlags::Elf { sh_flags } = section.flags { |
| 769 | sh_flags |
| 770 | } else { |
| 771 | match section.kind { |
| 772 | SectionKind::Text => elf::SHF_ALLOC | elf::SHF_EXECINSTR, |
| 773 | SectionKind::Data | SectionKind::ReadOnlyDataWithRel => { |
| 774 | elf::SHF_ALLOC | elf::SHF_WRITE |
| 775 | } |
| 776 | SectionKind::Tls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, |
| 777 | SectionKind::UninitializedData => elf::SHF_ALLOC | elf::SHF_WRITE, |
| 778 | SectionKind::UninitializedTls => elf::SHF_ALLOC | elf::SHF_WRITE | elf::SHF_TLS, |
| 779 | SectionKind::ReadOnlyData => elf::SHF_ALLOC, |
| 780 | SectionKind::ReadOnlyString => { |
| 781 | elf::SHF_ALLOC | elf::SHF_STRINGS | elf::SHF_MERGE |
| 782 | } |
| 783 | SectionKind::OtherString | SectionKind::DebugString => { |
| 784 | elf::SHF_STRINGS | elf::SHF_MERGE |
| 785 | } |
| 786 | SectionKind::Other |
| 787 | | SectionKind::Debug |
| 788 | | SectionKind::Metadata |
| 789 | | SectionKind::Linker |
| 790 | | SectionKind::Note |
| 791 | | SectionKind::Elf(_) => 0, |
| 792 | SectionKind::Unknown | SectionKind::Common | SectionKind::TlsVariables => { |
| 793 | return Err(Error(format!( |
| 794 | "unimplemented section ` {}` kind {:?}" , |
| 795 | section.name().unwrap_or("" ), |
| 796 | section.kind |
| 797 | ))); |
| 798 | } |
| 799 | } |
| 800 | .into() |
| 801 | }; |
| 802 | // TODO: not sure if this is correct, maybe user should determine this |
| 803 | let sh_entsize = match section.kind { |
| 804 | SectionKind::ReadOnlyString | SectionKind::OtherString => 1, |
| 805 | _ => 0, |
| 806 | }; |
| 807 | writer.write_section_header(&SectionHeader { |
| 808 | name: Some(section_offsets[index].str_id), |
| 809 | sh_type, |
| 810 | sh_flags, |
| 811 | sh_addr: 0, |
| 812 | sh_offset: section_offsets[index].offset as u64, |
| 813 | sh_size: section.size, |
| 814 | sh_link: 0, |
| 815 | sh_info: 0, |
| 816 | sh_addralign: section.align, |
| 817 | sh_entsize, |
| 818 | }); |
| 819 | |
| 820 | if !section.relocations.is_empty() { |
| 821 | writer.write_relocation_section_header( |
| 822 | section_offsets[index].reloc_str_id.unwrap(), |
| 823 | section_offsets[index].index, |
| 824 | symtab_index, |
| 825 | section_offsets[index].reloc_offset, |
| 826 | section.relocations.len(), |
| 827 | is_rela, |
| 828 | ); |
| 829 | } |
| 830 | } |
| 831 | |
| 832 | writer.write_symtab_section_header(symtab_num_local); |
| 833 | writer.write_symtab_shndx_section_header(); |
| 834 | writer.write_strtab_section_header(); |
| 835 | writer.write_shstrtab_section_header(); |
| 836 | |
| 837 | debug_assert_eq!(writer.reserved_len(), writer.len()); |
| 838 | |
| 839 | Ok(()) |
| 840 | } |
| 841 | } |
| 842 | |