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 | |