1 | //! Helper for writing ELF files. |
2 | use alloc::string::String; |
3 | use alloc::vec::Vec; |
4 | use core::mem; |
5 | |
6 | use crate::elf; |
7 | use crate::endian::*; |
8 | use crate::pod; |
9 | use crate::write::string::{StringId, StringTable}; |
10 | use crate::write::util; |
11 | use crate::write::{Error, Result, WritableBuffer}; |
12 | |
13 | /// The index of an ELF section. |
14 | #[derive (Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
15 | pub struct SectionIndex(pub u32); |
16 | |
17 | /// The index of an ELF symbol. |
18 | #[derive (Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] |
19 | pub struct SymbolIndex(pub u32); |
20 | |
21 | /// A helper for writing ELF files. |
22 | /// |
23 | /// Writing uses a two phase approach. The first phase builds up all of the information |
24 | /// that may need to be known ahead of time: |
25 | /// - build string tables |
26 | /// - reserve section indices |
27 | /// - reserve symbol indices |
28 | /// - reserve file ranges for headers and sections |
29 | /// |
30 | /// Some of the information has ordering requirements. For example, strings must be added |
31 | /// to string tables before reserving the file range for the string table. Symbol indices |
32 | /// must be reserved after reserving the section indices they reference. There are debug |
33 | /// asserts to check some of these requirements. |
34 | /// |
35 | /// The second phase writes everything out in order. Thus the caller must ensure writing |
36 | /// is in the same order that file ranges were reserved. There are debug asserts to assist |
37 | /// with checking this. |
38 | #[allow (missing_debug_implementations)] |
39 | pub struct Writer<'a> { |
40 | endian: Endianness, |
41 | is_64: bool, |
42 | is_mips64el: bool, |
43 | elf_align: usize, |
44 | |
45 | buffer: &'a mut dyn WritableBuffer, |
46 | len: usize, |
47 | |
48 | segment_offset: usize, |
49 | segment_num: u32, |
50 | |
51 | section_offset: usize, |
52 | section_num: u32, |
53 | |
54 | shstrtab: StringTable<'a>, |
55 | shstrtab_str_id: Option<StringId>, |
56 | shstrtab_index: SectionIndex, |
57 | shstrtab_offset: usize, |
58 | shstrtab_data: Vec<u8>, |
59 | |
60 | need_strtab: bool, |
61 | strtab: StringTable<'a>, |
62 | strtab_str_id: Option<StringId>, |
63 | strtab_index: SectionIndex, |
64 | strtab_offset: usize, |
65 | strtab_data: Vec<u8>, |
66 | |
67 | symtab_str_id: Option<StringId>, |
68 | symtab_index: SectionIndex, |
69 | symtab_offset: usize, |
70 | symtab_num: u32, |
71 | |
72 | need_symtab_shndx: bool, |
73 | symtab_shndx_str_id: Option<StringId>, |
74 | symtab_shndx_offset: usize, |
75 | symtab_shndx_data: Vec<u8>, |
76 | |
77 | need_dynstr: bool, |
78 | dynstr: StringTable<'a>, |
79 | dynstr_str_id: Option<StringId>, |
80 | dynstr_index: SectionIndex, |
81 | dynstr_offset: usize, |
82 | dynstr_data: Vec<u8>, |
83 | |
84 | dynsym_str_id: Option<StringId>, |
85 | dynsym_index: SectionIndex, |
86 | dynsym_offset: usize, |
87 | dynsym_num: u32, |
88 | |
89 | dynamic_str_id: Option<StringId>, |
90 | dynamic_offset: usize, |
91 | dynamic_num: usize, |
92 | |
93 | hash_str_id: Option<StringId>, |
94 | hash_offset: usize, |
95 | hash_size: usize, |
96 | |
97 | gnu_hash_str_id: Option<StringId>, |
98 | gnu_hash_offset: usize, |
99 | gnu_hash_size: usize, |
100 | |
101 | gnu_versym_str_id: Option<StringId>, |
102 | gnu_versym_offset: usize, |
103 | |
104 | gnu_verdef_str_id: Option<StringId>, |
105 | gnu_verdef_offset: usize, |
106 | gnu_verdef_size: usize, |
107 | gnu_verdef_count: u16, |
108 | gnu_verdef_remaining: u16, |
109 | gnu_verdaux_remaining: u16, |
110 | |
111 | gnu_verneed_str_id: Option<StringId>, |
112 | gnu_verneed_offset: usize, |
113 | gnu_verneed_size: usize, |
114 | gnu_verneed_count: u16, |
115 | gnu_verneed_remaining: u16, |
116 | gnu_vernaux_remaining: u16, |
117 | |
118 | gnu_attributes_str_id: Option<StringId>, |
119 | gnu_attributes_offset: usize, |
120 | gnu_attributes_size: usize, |
121 | } |
122 | |
123 | impl<'a> Writer<'a> { |
124 | /// Create a new `Writer` for the given endianness and ELF class. |
125 | pub fn new(endian: Endianness, is_64: bool, buffer: &'a mut dyn WritableBuffer) -> Self { |
126 | let elf_align = if is_64 { 8 } else { 4 }; |
127 | Writer { |
128 | endian, |
129 | is_64, |
130 | // Determined later. |
131 | is_mips64el: false, |
132 | elf_align, |
133 | |
134 | buffer, |
135 | len: 0, |
136 | |
137 | segment_offset: 0, |
138 | segment_num: 0, |
139 | |
140 | section_offset: 0, |
141 | section_num: 0, |
142 | |
143 | shstrtab: StringTable::default(), |
144 | shstrtab_str_id: None, |
145 | shstrtab_index: SectionIndex(0), |
146 | shstrtab_offset: 0, |
147 | shstrtab_data: Vec::new(), |
148 | |
149 | need_strtab: false, |
150 | strtab: StringTable::default(), |
151 | strtab_str_id: None, |
152 | strtab_index: SectionIndex(0), |
153 | strtab_offset: 0, |
154 | strtab_data: Vec::new(), |
155 | |
156 | symtab_str_id: None, |
157 | symtab_index: SectionIndex(0), |
158 | symtab_offset: 0, |
159 | symtab_num: 0, |
160 | |
161 | need_symtab_shndx: false, |
162 | symtab_shndx_str_id: None, |
163 | symtab_shndx_offset: 0, |
164 | symtab_shndx_data: Vec::new(), |
165 | |
166 | need_dynstr: false, |
167 | dynstr: StringTable::default(), |
168 | dynstr_str_id: None, |
169 | dynstr_index: SectionIndex(0), |
170 | dynstr_offset: 0, |
171 | dynstr_data: Vec::new(), |
172 | |
173 | dynsym_str_id: None, |
174 | dynsym_index: SectionIndex(0), |
175 | dynsym_offset: 0, |
176 | dynsym_num: 0, |
177 | |
178 | dynamic_str_id: None, |
179 | dynamic_offset: 0, |
180 | dynamic_num: 0, |
181 | |
182 | hash_str_id: None, |
183 | hash_offset: 0, |
184 | hash_size: 0, |
185 | |
186 | gnu_hash_str_id: None, |
187 | gnu_hash_offset: 0, |
188 | gnu_hash_size: 0, |
189 | |
190 | gnu_versym_str_id: None, |
191 | gnu_versym_offset: 0, |
192 | |
193 | gnu_verdef_str_id: None, |
194 | gnu_verdef_offset: 0, |
195 | gnu_verdef_size: 0, |
196 | gnu_verdef_count: 0, |
197 | gnu_verdef_remaining: 0, |
198 | gnu_verdaux_remaining: 0, |
199 | |
200 | gnu_verneed_str_id: None, |
201 | gnu_verneed_offset: 0, |
202 | gnu_verneed_size: 0, |
203 | gnu_verneed_count: 0, |
204 | gnu_verneed_remaining: 0, |
205 | gnu_vernaux_remaining: 0, |
206 | |
207 | gnu_attributes_str_id: None, |
208 | gnu_attributes_offset: 0, |
209 | gnu_attributes_size: 0, |
210 | } |
211 | } |
212 | |
213 | /// Return the current file length that has been reserved. |
214 | pub fn reserved_len(&self) -> usize { |
215 | self.len |
216 | } |
217 | |
218 | /// Return the current file length that has been written. |
219 | #[allow (clippy::len_without_is_empty)] |
220 | pub fn len(&self) -> usize { |
221 | self.buffer.len() |
222 | } |
223 | |
224 | /// Reserve a file range with the given size and starting alignment. |
225 | /// |
226 | /// Returns the aligned offset of the start of the range. |
227 | pub fn reserve(&mut self, len: usize, align_start: usize) -> usize { |
228 | if align_start > 1 { |
229 | self.len = util::align(self.len, align_start); |
230 | } |
231 | let offset = self.len; |
232 | self.len += len; |
233 | offset |
234 | } |
235 | |
236 | /// Write alignment padding bytes. |
237 | pub fn write_align(&mut self, align_start: usize) { |
238 | if align_start > 1 { |
239 | util::write_align(self.buffer, align_start); |
240 | } |
241 | } |
242 | |
243 | /// Write data. |
244 | /// |
245 | /// This is typically used to write section data. |
246 | pub fn write(&mut self, data: &[u8]) { |
247 | self.buffer.write_bytes(data); |
248 | } |
249 | |
250 | /// Reserve the file range up to the given file offset. |
251 | pub fn reserve_until(&mut self, offset: usize) { |
252 | debug_assert!(self.len <= offset); |
253 | self.len = offset; |
254 | } |
255 | |
256 | /// Write padding up to the given file offset. |
257 | pub fn pad_until(&mut self, offset: usize) { |
258 | debug_assert!(self.buffer.len() <= offset); |
259 | self.buffer.resize(offset); |
260 | } |
261 | |
262 | fn file_header_size(&self) -> usize { |
263 | if self.is_64 { |
264 | mem::size_of::<elf::FileHeader64<Endianness>>() |
265 | } else { |
266 | mem::size_of::<elf::FileHeader32<Endianness>>() |
267 | } |
268 | } |
269 | |
270 | /// Reserve the range for the file header. |
271 | /// |
272 | /// This must be at the start of the file. |
273 | pub fn reserve_file_header(&mut self) { |
274 | debug_assert_eq!(self.len, 0); |
275 | self.reserve(self.file_header_size(), 1); |
276 | } |
277 | |
278 | /// Write the file header. |
279 | /// |
280 | /// This must be at the start of the file. |
281 | /// |
282 | /// Fields that can be derived from known information are automatically set by this function. |
283 | pub fn write_file_header(&mut self, header: &FileHeader) -> Result<()> { |
284 | debug_assert_eq!(self.buffer.len(), 0); |
285 | |
286 | self.is_mips64el = |
287 | self.is_64 && self.endian.is_little_endian() && header.e_machine == elf::EM_MIPS; |
288 | |
289 | // Start writing. |
290 | self.buffer |
291 | .reserve(self.len) |
292 | .map_err(|_| Error(String::from("Cannot allocate buffer" )))?; |
293 | |
294 | // Write file header. |
295 | let e_ident = elf::Ident { |
296 | magic: elf::ELFMAG, |
297 | class: if self.is_64 { |
298 | elf::ELFCLASS64 |
299 | } else { |
300 | elf::ELFCLASS32 |
301 | }, |
302 | data: if self.endian.is_little_endian() { |
303 | elf::ELFDATA2LSB |
304 | } else { |
305 | elf::ELFDATA2MSB |
306 | }, |
307 | version: elf::EV_CURRENT, |
308 | os_abi: header.os_abi, |
309 | abi_version: header.abi_version, |
310 | padding: [0; 7], |
311 | }; |
312 | |
313 | let e_ehsize = self.file_header_size() as u16; |
314 | |
315 | let e_phoff = self.segment_offset as u64; |
316 | let e_phentsize = if self.segment_num == 0 { |
317 | 0 |
318 | } else { |
319 | self.program_header_size() as u16 |
320 | }; |
321 | // TODO: overflow |
322 | let e_phnum = self.segment_num as u16; |
323 | |
324 | let e_shoff = self.section_offset as u64; |
325 | let e_shentsize = if self.section_num == 0 { |
326 | 0 |
327 | } else { |
328 | self.section_header_size() as u16 |
329 | }; |
330 | let e_shnum = if self.section_num >= elf::SHN_LORESERVE.into() { |
331 | 0 |
332 | } else { |
333 | self.section_num as u16 |
334 | }; |
335 | let e_shstrndx = if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() { |
336 | elf::SHN_XINDEX |
337 | } else { |
338 | self.shstrtab_index.0 as u16 |
339 | }; |
340 | |
341 | let endian = self.endian; |
342 | if self.is_64 { |
343 | let file = elf::FileHeader64 { |
344 | e_ident, |
345 | e_type: U16::new(endian, header.e_type), |
346 | e_machine: U16::new(endian, header.e_machine), |
347 | e_version: U32::new(endian, elf::EV_CURRENT.into()), |
348 | e_entry: U64::new(endian, header.e_entry), |
349 | e_phoff: U64::new(endian, e_phoff), |
350 | e_shoff: U64::new(endian, e_shoff), |
351 | e_flags: U32::new(endian, header.e_flags), |
352 | e_ehsize: U16::new(endian, e_ehsize), |
353 | e_phentsize: U16::new(endian, e_phentsize), |
354 | e_phnum: U16::new(endian, e_phnum), |
355 | e_shentsize: U16::new(endian, e_shentsize), |
356 | e_shnum: U16::new(endian, e_shnum), |
357 | e_shstrndx: U16::new(endian, e_shstrndx), |
358 | }; |
359 | self.buffer.write(&file) |
360 | } else { |
361 | let file = elf::FileHeader32 { |
362 | e_ident, |
363 | e_type: U16::new(endian, header.e_type), |
364 | e_machine: U16::new(endian, header.e_machine), |
365 | e_version: U32::new(endian, elf::EV_CURRENT.into()), |
366 | e_entry: U32::new(endian, header.e_entry as u32), |
367 | e_phoff: U32::new(endian, e_phoff as u32), |
368 | e_shoff: U32::new(endian, e_shoff as u32), |
369 | e_flags: U32::new(endian, header.e_flags), |
370 | e_ehsize: U16::new(endian, e_ehsize), |
371 | e_phentsize: U16::new(endian, e_phentsize), |
372 | e_phnum: U16::new(endian, e_phnum), |
373 | e_shentsize: U16::new(endian, e_shentsize), |
374 | e_shnum: U16::new(endian, e_shnum), |
375 | e_shstrndx: U16::new(endian, e_shstrndx), |
376 | }; |
377 | self.buffer.write(&file); |
378 | } |
379 | |
380 | Ok(()) |
381 | } |
382 | |
383 | fn program_header_size(&self) -> usize { |
384 | if self.is_64 { |
385 | mem::size_of::<elf::ProgramHeader64<Endianness>>() |
386 | } else { |
387 | mem::size_of::<elf::ProgramHeader32<Endianness>>() |
388 | } |
389 | } |
390 | |
391 | /// Reserve the range for the program headers. |
392 | pub fn reserve_program_headers(&mut self, num: u32) { |
393 | debug_assert_eq!(self.segment_offset, 0); |
394 | if num == 0 { |
395 | return; |
396 | } |
397 | self.segment_num = num; |
398 | self.segment_offset = |
399 | self.reserve(num as usize * self.program_header_size(), self.elf_align); |
400 | } |
401 | |
402 | /// Write alignment padding bytes prior to the program headers. |
403 | pub fn write_align_program_headers(&mut self) { |
404 | if self.segment_offset == 0 { |
405 | return; |
406 | } |
407 | util::write_align(self.buffer, self.elf_align); |
408 | debug_assert_eq!(self.segment_offset, self.buffer.len()); |
409 | } |
410 | |
411 | /// Write a program header. |
412 | pub fn write_program_header(&mut self, header: &ProgramHeader) { |
413 | let endian = self.endian; |
414 | if self.is_64 { |
415 | let header = elf::ProgramHeader64 { |
416 | p_type: U32::new(endian, header.p_type), |
417 | p_flags: U32::new(endian, header.p_flags), |
418 | p_offset: U64::new(endian, header.p_offset), |
419 | p_vaddr: U64::new(endian, header.p_vaddr), |
420 | p_paddr: U64::new(endian, header.p_paddr), |
421 | p_filesz: U64::new(endian, header.p_filesz), |
422 | p_memsz: U64::new(endian, header.p_memsz), |
423 | p_align: U64::new(endian, header.p_align), |
424 | }; |
425 | self.buffer.write(&header); |
426 | } else { |
427 | let header = elf::ProgramHeader32 { |
428 | p_type: U32::new(endian, header.p_type), |
429 | p_offset: U32::new(endian, header.p_offset as u32), |
430 | p_vaddr: U32::new(endian, header.p_vaddr as u32), |
431 | p_paddr: U32::new(endian, header.p_paddr as u32), |
432 | p_filesz: U32::new(endian, header.p_filesz as u32), |
433 | p_memsz: U32::new(endian, header.p_memsz as u32), |
434 | p_flags: U32::new(endian, header.p_flags), |
435 | p_align: U32::new(endian, header.p_align as u32), |
436 | }; |
437 | self.buffer.write(&header); |
438 | } |
439 | } |
440 | |
441 | /// Reserve the section index for the null section header. |
442 | /// |
443 | /// The null section header is usually automatically reserved, |
444 | /// but this can be used to force an empty section table. |
445 | /// |
446 | /// This must be called before [`Self::reserve_section_headers`]. |
447 | pub fn reserve_null_section_index(&mut self) -> SectionIndex { |
448 | debug_assert_eq!(self.section_num, 0); |
449 | if self.section_num == 0 { |
450 | self.section_num = 1; |
451 | } |
452 | SectionIndex(0) |
453 | } |
454 | |
455 | /// Reserve a section table index. |
456 | /// |
457 | /// Automatically also reserves the null section header if required. |
458 | /// |
459 | /// This must be called before [`Self::reserve_section_headers`]. |
460 | pub fn reserve_section_index(&mut self) -> SectionIndex { |
461 | debug_assert_eq!(self.section_offset, 0); |
462 | if self.section_num == 0 { |
463 | self.section_num = 1; |
464 | } |
465 | let index = self.section_num; |
466 | self.section_num += 1; |
467 | SectionIndex(index) |
468 | } |
469 | |
470 | fn section_header_size(&self) -> usize { |
471 | if self.is_64 { |
472 | mem::size_of::<elf::SectionHeader64<Endianness>>() |
473 | } else { |
474 | mem::size_of::<elf::SectionHeader32<Endianness>>() |
475 | } |
476 | } |
477 | |
478 | /// Reserve the range for the section headers. |
479 | /// |
480 | /// This function does nothing if no sections were reserved. |
481 | /// This must be called after [`Self::reserve_section_index`] |
482 | /// and other functions that reserve section indices. |
483 | pub fn reserve_section_headers(&mut self) { |
484 | debug_assert_eq!(self.section_offset, 0); |
485 | if self.section_num == 0 { |
486 | return; |
487 | } |
488 | self.section_offset = self.reserve( |
489 | self.section_num as usize * self.section_header_size(), |
490 | self.elf_align, |
491 | ); |
492 | } |
493 | |
494 | /// Write the null section header. |
495 | /// |
496 | /// This must be the first section header that is written. |
497 | /// This function does nothing if no sections were reserved. |
498 | pub fn write_null_section_header(&mut self) { |
499 | if self.section_num == 0 { |
500 | return; |
501 | } |
502 | util::write_align(self.buffer, self.elf_align); |
503 | debug_assert_eq!(self.section_offset, self.buffer.len()); |
504 | self.write_section_header(&SectionHeader { |
505 | name: None, |
506 | sh_type: 0, |
507 | sh_flags: 0, |
508 | sh_addr: 0, |
509 | sh_offset: 0, |
510 | sh_size: if self.section_num >= elf::SHN_LORESERVE.into() { |
511 | self.section_num.into() |
512 | } else { |
513 | 0 |
514 | }, |
515 | sh_link: if self.shstrtab_index.0 >= elf::SHN_LORESERVE.into() { |
516 | self.shstrtab_index.0 |
517 | } else { |
518 | 0 |
519 | }, |
520 | // TODO: e_phnum overflow |
521 | sh_info: 0, |
522 | sh_addralign: 0, |
523 | sh_entsize: 0, |
524 | }); |
525 | } |
526 | |
527 | /// Write a section header. |
528 | pub fn write_section_header(&mut self, section: &SectionHeader) { |
529 | let sh_name = if let Some(name) = section.name { |
530 | self.shstrtab.get_offset(name) as u32 |
531 | } else { |
532 | 0 |
533 | }; |
534 | let endian = self.endian; |
535 | if self.is_64 { |
536 | let section = elf::SectionHeader64 { |
537 | sh_name: U32::new(endian, sh_name), |
538 | sh_type: U32::new(endian, section.sh_type), |
539 | sh_flags: U64::new(endian, section.sh_flags), |
540 | sh_addr: U64::new(endian, section.sh_addr), |
541 | sh_offset: U64::new(endian, section.sh_offset), |
542 | sh_size: U64::new(endian, section.sh_size), |
543 | sh_link: U32::new(endian, section.sh_link), |
544 | sh_info: U32::new(endian, section.sh_info), |
545 | sh_addralign: U64::new(endian, section.sh_addralign), |
546 | sh_entsize: U64::new(endian, section.sh_entsize), |
547 | }; |
548 | self.buffer.write(§ion); |
549 | } else { |
550 | let section = elf::SectionHeader32 { |
551 | sh_name: U32::new(endian, sh_name), |
552 | sh_type: U32::new(endian, section.sh_type), |
553 | sh_flags: U32::new(endian, section.sh_flags as u32), |
554 | sh_addr: U32::new(endian, section.sh_addr as u32), |
555 | sh_offset: U32::new(endian, section.sh_offset as u32), |
556 | sh_size: U32::new(endian, section.sh_size as u32), |
557 | sh_link: U32::new(endian, section.sh_link), |
558 | sh_info: U32::new(endian, section.sh_info), |
559 | sh_addralign: U32::new(endian, section.sh_addralign as u32), |
560 | sh_entsize: U32::new(endian, section.sh_entsize as u32), |
561 | }; |
562 | self.buffer.write(§ion); |
563 | } |
564 | } |
565 | |
566 | /// Add a section name to the section header string table. |
567 | /// |
568 | /// This will be stored in the `.shstrtab` section. |
569 | /// |
570 | /// This must be called before [`Self::reserve_shstrtab`]. |
571 | pub fn add_section_name(&mut self, name: &'a [u8]) -> StringId { |
572 | debug_assert_eq!(self.shstrtab_offset, 0); |
573 | self.shstrtab.add(name) |
574 | } |
575 | |
576 | /// Reserve the range for the section header string table. |
577 | /// |
578 | /// This range is used for a section named `.shstrtab`. |
579 | /// |
580 | /// This function does nothing if no sections were reserved. |
581 | /// This must be called after [`Self::add_section_name`]. |
582 | /// and other functions that reserve section names and indices. |
583 | pub fn reserve_shstrtab(&mut self) { |
584 | debug_assert_eq!(self.shstrtab_offset, 0); |
585 | if self.section_num == 0 { |
586 | return; |
587 | } |
588 | // Start with null section name. |
589 | self.shstrtab_data = vec![0]; |
590 | self.shstrtab.write(1, &mut self.shstrtab_data); |
591 | self.shstrtab_offset = self.reserve(self.shstrtab_data.len(), 1); |
592 | } |
593 | |
594 | /// Write the section header string table. |
595 | /// |
596 | /// This function does nothing if the section was not reserved. |
597 | pub fn write_shstrtab(&mut self) { |
598 | if self.shstrtab_offset == 0 { |
599 | return; |
600 | } |
601 | debug_assert_eq!(self.shstrtab_offset, self.buffer.len()); |
602 | self.buffer.write_bytes(&self.shstrtab_data); |
603 | } |
604 | |
605 | /// Reserve the section index for the section header string table. |
606 | /// |
607 | /// This must be called before [`Self::reserve_shstrtab`] |
608 | /// and [`Self::reserve_section_headers`]. |
609 | pub fn reserve_shstrtab_section_index(&mut self) -> SectionIndex { |
610 | debug_assert_eq!(self.shstrtab_index, SectionIndex(0)); |
611 | self.shstrtab_str_id = Some(self.add_section_name(&b".shstrtab" [..])); |
612 | self.shstrtab_index = self.reserve_section_index(); |
613 | self.shstrtab_index |
614 | } |
615 | |
616 | /// Write the section header for the section header string table. |
617 | /// |
618 | /// This function does nothing if the section index was not reserved. |
619 | pub fn write_shstrtab_section_header(&mut self) { |
620 | if self.shstrtab_index == SectionIndex(0) { |
621 | return; |
622 | } |
623 | self.write_section_header(&SectionHeader { |
624 | name: self.shstrtab_str_id, |
625 | sh_type: elf::SHT_STRTAB, |
626 | sh_flags: 0, |
627 | sh_addr: 0, |
628 | sh_offset: self.shstrtab_offset as u64, |
629 | sh_size: self.shstrtab_data.len() as u64, |
630 | sh_link: 0, |
631 | sh_info: 0, |
632 | sh_addralign: 1, |
633 | sh_entsize: 0, |
634 | }); |
635 | } |
636 | |
637 | /// Add a string to the string table. |
638 | /// |
639 | /// This will be stored in the `.strtab` section. |
640 | /// |
641 | /// This must be called before [`Self::reserve_strtab`]. |
642 | pub fn add_string(&mut self, name: &'a [u8]) -> StringId { |
643 | debug_assert_eq!(self.strtab_offset, 0); |
644 | self.need_strtab = true; |
645 | self.strtab.add(name) |
646 | } |
647 | |
648 | /// Return true if `.strtab` is needed. |
649 | pub fn strtab_needed(&self) -> bool { |
650 | self.need_strtab |
651 | } |
652 | |
653 | /// Reserve the range for the string table. |
654 | /// |
655 | /// This range is used for a section named `.strtab`. |
656 | /// |
657 | /// This function does nothing if no strings or symbols were defined. |
658 | /// This must be called after [`Self::add_string`]. |
659 | pub fn reserve_strtab(&mut self) { |
660 | debug_assert_eq!(self.strtab_offset, 0); |
661 | if !self.need_strtab { |
662 | return; |
663 | } |
664 | // Start with null string. |
665 | self.strtab_data = vec![0]; |
666 | self.strtab.write(1, &mut self.strtab_data); |
667 | self.strtab_offset = self.reserve(self.strtab_data.len(), 1); |
668 | } |
669 | |
670 | /// Write the string table. |
671 | /// |
672 | /// This function does nothing if the section was not reserved. |
673 | pub fn write_strtab(&mut self) { |
674 | if self.strtab_offset == 0 { |
675 | return; |
676 | } |
677 | debug_assert_eq!(self.strtab_offset, self.buffer.len()); |
678 | self.buffer.write_bytes(&self.strtab_data); |
679 | } |
680 | |
681 | /// Reserve the section index for the string table. |
682 | /// |
683 | /// This must be called before [`Self::reserve_section_headers`]. |
684 | pub fn reserve_strtab_section_index(&mut self) -> SectionIndex { |
685 | debug_assert_eq!(self.strtab_index, SectionIndex(0)); |
686 | self.strtab_str_id = Some(self.add_section_name(&b".strtab" [..])); |
687 | self.strtab_index = self.reserve_section_index(); |
688 | self.strtab_index |
689 | } |
690 | |
691 | /// Write the section header for the string table. |
692 | /// |
693 | /// This function does nothing if the section index was not reserved. |
694 | pub fn write_strtab_section_header(&mut self) { |
695 | if self.strtab_index == SectionIndex(0) { |
696 | return; |
697 | } |
698 | self.write_section_header(&SectionHeader { |
699 | name: self.strtab_str_id, |
700 | sh_type: elf::SHT_STRTAB, |
701 | sh_flags: 0, |
702 | sh_addr: 0, |
703 | sh_offset: self.strtab_offset as u64, |
704 | sh_size: self.strtab_data.len() as u64, |
705 | sh_link: 0, |
706 | sh_info: 0, |
707 | sh_addralign: 1, |
708 | sh_entsize: 0, |
709 | }); |
710 | } |
711 | |
712 | /// Reserve the null symbol table entry. |
713 | /// |
714 | /// This will be stored in the `.symtab` section. |
715 | /// |
716 | /// The null symbol table entry is usually automatically reserved, |
717 | /// but this can be used to force an empty symbol table. |
718 | /// |
719 | /// This must be called before [`Self::reserve_symtab`]. |
720 | pub fn reserve_null_symbol_index(&mut self) -> SymbolIndex { |
721 | debug_assert_eq!(self.symtab_offset, 0); |
722 | debug_assert_eq!(self.symtab_num, 0); |
723 | self.symtab_num = 1; |
724 | // The symtab must link to a strtab. |
725 | self.need_strtab = true; |
726 | SymbolIndex(0) |
727 | } |
728 | |
729 | /// Reserve a symbol table entry. |
730 | /// |
731 | /// This will be stored in the `.symtab` section. |
732 | /// |
733 | /// `section_index` is used to determine whether `.symtab_shndx` is required. |
734 | /// |
735 | /// Automatically also reserves the null symbol if required. |
736 | /// Callers may assume that the returned indices will be sequential |
737 | /// starting at 1. |
738 | /// |
739 | /// This must be called before [`Self::reserve_symtab`] and |
740 | /// [`Self::reserve_symtab_shndx`]. |
741 | pub fn reserve_symbol_index(&mut self, section_index: Option<SectionIndex>) -> SymbolIndex { |
742 | debug_assert_eq!(self.symtab_offset, 0); |
743 | debug_assert_eq!(self.symtab_shndx_offset, 0); |
744 | if self.symtab_num == 0 { |
745 | self.symtab_num = 1; |
746 | // The symtab must link to a strtab. |
747 | self.need_strtab = true; |
748 | } |
749 | let index = self.symtab_num; |
750 | self.symtab_num += 1; |
751 | if let Some(section_index) = section_index { |
752 | if section_index.0 >= elf::SHN_LORESERVE.into() { |
753 | self.need_symtab_shndx = true; |
754 | } |
755 | } |
756 | SymbolIndex(index) |
757 | } |
758 | |
759 | /// Return the number of reserved symbol table entries. |
760 | /// |
761 | /// Includes the null symbol. |
762 | pub fn symbol_count(&self) -> u32 { |
763 | self.symtab_num |
764 | } |
765 | |
766 | fn symbol_size(&self) -> usize { |
767 | if self.is_64 { |
768 | mem::size_of::<elf::Sym64<Endianness>>() |
769 | } else { |
770 | mem::size_of::<elf::Sym32<Endianness>>() |
771 | } |
772 | } |
773 | |
774 | /// Reserve the range for the symbol table. |
775 | /// |
776 | /// This range is used for a section named `.symtab`. |
777 | /// This function does nothing if no symbols were reserved. |
778 | /// This must be called after [`Self::reserve_symbol_index`]. |
779 | pub fn reserve_symtab(&mut self) { |
780 | debug_assert_eq!(self.symtab_offset, 0); |
781 | if self.symtab_num == 0 { |
782 | return; |
783 | } |
784 | self.symtab_offset = self.reserve( |
785 | self.symtab_num as usize * self.symbol_size(), |
786 | self.elf_align, |
787 | ); |
788 | } |
789 | |
790 | /// Write the null symbol. |
791 | /// |
792 | /// This must be the first symbol that is written. |
793 | /// This function does nothing if no symbols were reserved. |
794 | pub fn write_null_symbol(&mut self) { |
795 | if self.symtab_num == 0 { |
796 | return; |
797 | } |
798 | util::write_align(self.buffer, self.elf_align); |
799 | debug_assert_eq!(self.symtab_offset, self.buffer.len()); |
800 | if self.is_64 { |
801 | self.buffer.write(&elf::Sym64::<Endianness>::default()); |
802 | } else { |
803 | self.buffer.write(&elf::Sym32::<Endianness>::default()); |
804 | } |
805 | |
806 | if self.need_symtab_shndx { |
807 | self.symtab_shndx_data.write_pod(&U32::new(self.endian, 0)); |
808 | } |
809 | } |
810 | |
811 | /// Write a symbol. |
812 | pub fn write_symbol(&mut self, sym: &Sym) { |
813 | let st_name = if let Some(name) = sym.name { |
814 | self.strtab.get_offset(name) as u32 |
815 | } else { |
816 | 0 |
817 | }; |
818 | let st_shndx = if let Some(section) = sym.section { |
819 | if section.0 >= elf::SHN_LORESERVE as u32 { |
820 | elf::SHN_XINDEX |
821 | } else { |
822 | section.0 as u16 |
823 | } |
824 | } else { |
825 | sym.st_shndx |
826 | }; |
827 | |
828 | let endian = self.endian; |
829 | if self.is_64 { |
830 | let sym = elf::Sym64 { |
831 | st_name: U32::new(endian, st_name), |
832 | st_info: sym.st_info, |
833 | st_other: sym.st_other, |
834 | st_shndx: U16::new(endian, st_shndx), |
835 | st_value: U64::new(endian, sym.st_value), |
836 | st_size: U64::new(endian, sym.st_size), |
837 | }; |
838 | self.buffer.write(&sym); |
839 | } else { |
840 | let sym = elf::Sym32 { |
841 | st_name: U32::new(endian, st_name), |
842 | st_info: sym.st_info, |
843 | st_other: sym.st_other, |
844 | st_shndx: U16::new(endian, st_shndx), |
845 | st_value: U32::new(endian, sym.st_value as u32), |
846 | st_size: U32::new(endian, sym.st_size as u32), |
847 | }; |
848 | self.buffer.write(&sym); |
849 | } |
850 | |
851 | if self.need_symtab_shndx { |
852 | let section_index = sym.section.unwrap_or(SectionIndex(0)); |
853 | self.symtab_shndx_data |
854 | .write_pod(&U32::new(self.endian, section_index.0)); |
855 | } |
856 | } |
857 | |
858 | /// Reserve the section index for the symbol table. |
859 | /// |
860 | /// This must be called before [`Self::reserve_section_headers`]. |
861 | pub fn reserve_symtab_section_index(&mut self) -> SectionIndex { |
862 | debug_assert_eq!(self.symtab_index, SectionIndex(0)); |
863 | self.symtab_str_id = Some(self.add_section_name(&b".symtab" [..])); |
864 | self.symtab_index = self.reserve_section_index(); |
865 | self.symtab_index |
866 | } |
867 | |
868 | /// Return the section index of the symbol table. |
869 | pub fn symtab_index(&mut self) -> SectionIndex { |
870 | self.symtab_index |
871 | } |
872 | |
873 | /// Write the section header for the symbol table. |
874 | /// |
875 | /// This function does nothing if the section index was not reserved. |
876 | pub fn write_symtab_section_header(&mut self, num_local: u32) { |
877 | if self.symtab_index == SectionIndex(0) { |
878 | return; |
879 | } |
880 | self.write_section_header(&SectionHeader { |
881 | name: self.symtab_str_id, |
882 | sh_type: elf::SHT_SYMTAB, |
883 | sh_flags: 0, |
884 | sh_addr: 0, |
885 | sh_offset: self.symtab_offset as u64, |
886 | sh_size: self.symtab_num as u64 * self.symbol_size() as u64, |
887 | sh_link: self.strtab_index.0, |
888 | sh_info: num_local, |
889 | sh_addralign: self.elf_align as u64, |
890 | sh_entsize: self.symbol_size() as u64, |
891 | }); |
892 | } |
893 | |
894 | /// Return true if `.symtab_shndx` is needed. |
895 | pub fn symtab_shndx_needed(&self) -> bool { |
896 | self.need_symtab_shndx |
897 | } |
898 | |
899 | /// Reserve the range for the extended section indices for the symbol table. |
900 | /// |
901 | /// This range is used for a section named `.symtab_shndx`. |
902 | /// This also reserves a section index. |
903 | /// |
904 | /// This function does nothing if extended section indices are not needed. |
905 | /// This must be called after [`Self::reserve_symbol_index`]. |
906 | pub fn reserve_symtab_shndx(&mut self) { |
907 | debug_assert_eq!(self.symtab_shndx_offset, 0); |
908 | if !self.need_symtab_shndx { |
909 | return; |
910 | } |
911 | self.symtab_shndx_offset = self.reserve(self.symtab_num as usize * 4, 4); |
912 | self.symtab_shndx_data.reserve(self.symtab_num as usize * 4); |
913 | } |
914 | |
915 | /// Write the extended section indices for the symbol table. |
916 | /// |
917 | /// This function does nothing if the section was not reserved. |
918 | pub fn write_symtab_shndx(&mut self) { |
919 | if self.symtab_shndx_offset == 0 { |
920 | return; |
921 | } |
922 | debug_assert_eq!(self.symtab_shndx_offset, self.buffer.len()); |
923 | debug_assert_eq!(self.symtab_num as usize * 4, self.symtab_shndx_data.len()); |
924 | self.buffer.write_bytes(&self.symtab_shndx_data); |
925 | } |
926 | |
927 | /// Reserve the section index for the extended section indices symbol table. |
928 | /// |
929 | /// You should check [`Self::symtab_shndx_needed`] before calling this |
930 | /// unless you have other means of knowing if this section is needed. |
931 | /// |
932 | /// This must be called before [`Self::reserve_section_headers`]. |
933 | pub fn reserve_symtab_shndx_section_index(&mut self) -> SectionIndex { |
934 | debug_assert!(self.symtab_shndx_str_id.is_none()); |
935 | self.symtab_shndx_str_id = Some(self.add_section_name(&b".symtab_shndx" [..])); |
936 | self.reserve_section_index() |
937 | } |
938 | |
939 | /// Write the section header for the extended section indices for the symbol table. |
940 | /// |
941 | /// This function does nothing if the section index was not reserved. |
942 | pub fn write_symtab_shndx_section_header(&mut self) { |
943 | if self.symtab_shndx_str_id.is_none() { |
944 | return; |
945 | } |
946 | let sh_size = if self.symtab_shndx_offset == 0 { |
947 | 0 |
948 | } else { |
949 | (self.symtab_num * 4) as u64 |
950 | }; |
951 | self.write_section_header(&SectionHeader { |
952 | name: self.symtab_shndx_str_id, |
953 | sh_type: elf::SHT_SYMTAB_SHNDX, |
954 | sh_flags: 0, |
955 | sh_addr: 0, |
956 | sh_offset: self.symtab_shndx_offset as u64, |
957 | sh_size, |
958 | sh_link: self.symtab_index.0, |
959 | sh_info: 0, |
960 | sh_addralign: 4, |
961 | sh_entsize: 4, |
962 | }); |
963 | } |
964 | |
965 | /// Add a string to the dynamic string table. |
966 | /// |
967 | /// This will be stored in the `.dynstr` section. |
968 | /// |
969 | /// This must be called before [`Self::reserve_dynstr`]. |
970 | pub fn add_dynamic_string(&mut self, name: &'a [u8]) -> StringId { |
971 | debug_assert_eq!(self.dynstr_offset, 0); |
972 | self.need_dynstr = true; |
973 | self.dynstr.add(name) |
974 | } |
975 | |
976 | /// Get a string that was previously added to the dynamic string table. |
977 | /// |
978 | /// Panics if the string was not added. |
979 | pub fn get_dynamic_string(&self, name: &'a [u8]) -> StringId { |
980 | self.dynstr.get_id(name) |
981 | } |
982 | |
983 | /// Return true if `.dynstr` is needed. |
984 | pub fn dynstr_needed(&self) -> bool { |
985 | self.need_dynstr |
986 | } |
987 | |
988 | /// Reserve the range for the dynamic string table. |
989 | /// |
990 | /// This range is used for a section named `.dynstr`. |
991 | /// |
992 | /// This function does nothing if no dynamic strings or symbols were defined. |
993 | /// This must be called after [`Self::add_dynamic_string`]. |
994 | pub fn reserve_dynstr(&mut self) { |
995 | debug_assert_eq!(self.dynstr_offset, 0); |
996 | if !self.need_dynstr { |
997 | return; |
998 | } |
999 | // Start with null string. |
1000 | self.dynstr_data = vec![0]; |
1001 | self.dynstr.write(1, &mut self.dynstr_data); |
1002 | self.dynstr_offset = self.reserve(self.dynstr_data.len(), 1); |
1003 | } |
1004 | |
1005 | /// Write the dynamic string table. |
1006 | /// |
1007 | /// This function does nothing if the section was not reserved. |
1008 | pub fn write_dynstr(&mut self) { |
1009 | if self.dynstr_offset == 0 { |
1010 | return; |
1011 | } |
1012 | debug_assert_eq!(self.dynstr_offset, self.buffer.len()); |
1013 | self.buffer.write_bytes(&self.dynstr_data); |
1014 | } |
1015 | |
1016 | /// Reserve the section index for the dynamic string table. |
1017 | /// |
1018 | /// This must be called before [`Self::reserve_section_headers`]. |
1019 | pub fn reserve_dynstr_section_index(&mut self) -> SectionIndex { |
1020 | debug_assert_eq!(self.dynstr_index, SectionIndex(0)); |
1021 | self.dynstr_str_id = Some(self.add_section_name(&b".dynstr" [..])); |
1022 | self.dynstr_index = self.reserve_section_index(); |
1023 | self.dynstr_index |
1024 | } |
1025 | |
1026 | /// Return the section index of the dynamic string table. |
1027 | pub fn dynstr_index(&mut self) -> SectionIndex { |
1028 | self.dynstr_index |
1029 | } |
1030 | |
1031 | /// Write the section header for the dynamic string table. |
1032 | /// |
1033 | /// This function does nothing if the section index was not reserved. |
1034 | pub fn write_dynstr_section_header(&mut self, sh_addr: u64) { |
1035 | if self.dynstr_index == SectionIndex(0) { |
1036 | return; |
1037 | } |
1038 | self.write_section_header(&SectionHeader { |
1039 | name: self.dynstr_str_id, |
1040 | sh_type: elf::SHT_STRTAB, |
1041 | sh_flags: elf::SHF_ALLOC.into(), |
1042 | sh_addr, |
1043 | sh_offset: self.dynstr_offset as u64, |
1044 | sh_size: self.dynstr_data.len() as u64, |
1045 | sh_link: 0, |
1046 | sh_info: 0, |
1047 | sh_addralign: 1, |
1048 | sh_entsize: 0, |
1049 | }); |
1050 | } |
1051 | |
1052 | /// Reserve the null dynamic symbol table entry. |
1053 | /// |
1054 | /// This will be stored in the `.dynsym` section. |
1055 | /// |
1056 | /// The null dynamic symbol table entry is usually automatically reserved, |
1057 | /// but this can be used to force an empty dynamic symbol table. |
1058 | /// |
1059 | /// This must be called before [`Self::reserve_dynsym`]. |
1060 | pub fn reserve_null_dynamic_symbol_index(&mut self) -> SymbolIndex { |
1061 | debug_assert_eq!(self.dynsym_offset, 0); |
1062 | debug_assert_eq!(self.dynsym_num, 0); |
1063 | self.dynsym_num = 1; |
1064 | // The symtab must link to a strtab. |
1065 | self.need_dynstr = true; |
1066 | SymbolIndex(0) |
1067 | } |
1068 | |
1069 | /// Reserve a dynamic symbol table entry. |
1070 | /// |
1071 | /// This will be stored in the `.dynsym` section. |
1072 | /// |
1073 | /// Automatically also reserves the null symbol if required. |
1074 | /// Callers may assume that the returned indices will be sequential |
1075 | /// starting at 1. |
1076 | /// |
1077 | /// This must be called before [`Self::reserve_dynsym`]. |
1078 | pub fn reserve_dynamic_symbol_index(&mut self) -> SymbolIndex { |
1079 | debug_assert_eq!(self.dynsym_offset, 0); |
1080 | if self.dynsym_num == 0 { |
1081 | self.dynsym_num = 1; |
1082 | // The symtab must link to a strtab. |
1083 | self.need_dynstr = true; |
1084 | } |
1085 | let index = self.dynsym_num; |
1086 | self.dynsym_num += 1; |
1087 | SymbolIndex(index) |
1088 | } |
1089 | |
1090 | /// Return the number of reserved dynamic symbols. |
1091 | /// |
1092 | /// Includes the null symbol. |
1093 | pub fn dynamic_symbol_count(&mut self) -> u32 { |
1094 | self.dynsym_num |
1095 | } |
1096 | |
1097 | /// Reserve the range for the dynamic symbol table. |
1098 | /// |
1099 | /// This range is used for a section named `.dynsym`. |
1100 | /// |
1101 | /// This function does nothing if no dynamic symbols were reserved. |
1102 | /// This must be called after [`Self::reserve_dynamic_symbol_index`]. |
1103 | pub fn reserve_dynsym(&mut self) { |
1104 | debug_assert_eq!(self.dynsym_offset, 0); |
1105 | if self.dynsym_num == 0 { |
1106 | return; |
1107 | } |
1108 | self.dynsym_offset = self.reserve( |
1109 | self.dynsym_num as usize * self.symbol_size(), |
1110 | self.elf_align, |
1111 | ); |
1112 | } |
1113 | |
1114 | /// Write the null dynamic symbol. |
1115 | /// |
1116 | /// This must be the first dynamic symbol that is written. |
1117 | /// This function does nothing if no dynamic symbols were reserved. |
1118 | pub fn write_null_dynamic_symbol(&mut self) { |
1119 | if self.dynsym_num == 0 { |
1120 | return; |
1121 | } |
1122 | util::write_align(self.buffer, self.elf_align); |
1123 | debug_assert_eq!(self.dynsym_offset, self.buffer.len()); |
1124 | if self.is_64 { |
1125 | self.buffer.write(&elf::Sym64::<Endianness>::default()); |
1126 | } else { |
1127 | self.buffer.write(&elf::Sym32::<Endianness>::default()); |
1128 | } |
1129 | } |
1130 | |
1131 | /// Write a dynamic symbol. |
1132 | pub fn write_dynamic_symbol(&mut self, sym: &Sym) { |
1133 | let st_name = if let Some(name) = sym.name { |
1134 | self.dynstr.get_offset(name) as u32 |
1135 | } else { |
1136 | 0 |
1137 | }; |
1138 | |
1139 | let st_shndx = if let Some(section) = sym.section { |
1140 | if section.0 >= elf::SHN_LORESERVE as u32 { |
1141 | // TODO: we don't actually write out .dynsym_shndx yet. |
1142 | // This is unlikely to be needed though. |
1143 | elf::SHN_XINDEX |
1144 | } else { |
1145 | section.0 as u16 |
1146 | } |
1147 | } else { |
1148 | sym.st_shndx |
1149 | }; |
1150 | |
1151 | let endian = self.endian; |
1152 | if self.is_64 { |
1153 | let sym = elf::Sym64 { |
1154 | st_name: U32::new(endian, st_name), |
1155 | st_info: sym.st_info, |
1156 | st_other: sym.st_other, |
1157 | st_shndx: U16::new(endian, st_shndx), |
1158 | st_value: U64::new(endian, sym.st_value), |
1159 | st_size: U64::new(endian, sym.st_size), |
1160 | }; |
1161 | self.buffer.write(&sym); |
1162 | } else { |
1163 | let sym = elf::Sym32 { |
1164 | st_name: U32::new(endian, st_name), |
1165 | st_info: sym.st_info, |
1166 | st_other: sym.st_other, |
1167 | st_shndx: U16::new(endian, st_shndx), |
1168 | st_value: U32::new(endian, sym.st_value as u32), |
1169 | st_size: U32::new(endian, sym.st_size as u32), |
1170 | }; |
1171 | self.buffer.write(&sym); |
1172 | } |
1173 | } |
1174 | |
1175 | /// Reserve the section index for the dynamic symbol table. |
1176 | /// |
1177 | /// This must be called before [`Self::reserve_section_headers`]. |
1178 | pub fn reserve_dynsym_section_index(&mut self) -> SectionIndex { |
1179 | debug_assert_eq!(self.dynsym_index, SectionIndex(0)); |
1180 | self.dynsym_str_id = Some(self.add_section_name(&b".dynsym" [..])); |
1181 | self.dynsym_index = self.reserve_section_index(); |
1182 | self.dynsym_index |
1183 | } |
1184 | |
1185 | /// Return the section index of the dynamic symbol table. |
1186 | pub fn dynsym_index(&mut self) -> SectionIndex { |
1187 | self.dynsym_index |
1188 | } |
1189 | |
1190 | /// Write the section header for the dynamic symbol table. |
1191 | /// |
1192 | /// This function does nothing if the section index was not reserved. |
1193 | pub fn write_dynsym_section_header(&mut self, sh_addr: u64, num_local: u32) { |
1194 | if self.dynsym_index == SectionIndex(0) { |
1195 | return; |
1196 | } |
1197 | self.write_section_header(&SectionHeader { |
1198 | name: self.dynsym_str_id, |
1199 | sh_type: elf::SHT_DYNSYM, |
1200 | sh_flags: elf::SHF_ALLOC.into(), |
1201 | sh_addr, |
1202 | sh_offset: self.dynsym_offset as u64, |
1203 | sh_size: self.dynsym_num as u64 * self.symbol_size() as u64, |
1204 | sh_link: self.dynstr_index.0, |
1205 | sh_info: num_local, |
1206 | sh_addralign: self.elf_align as u64, |
1207 | sh_entsize: self.symbol_size() as u64, |
1208 | }); |
1209 | } |
1210 | |
1211 | fn dyn_size(&self) -> usize { |
1212 | if self.is_64 { |
1213 | mem::size_of::<elf::Dyn64<Endianness>>() |
1214 | } else { |
1215 | mem::size_of::<elf::Dyn32<Endianness>>() |
1216 | } |
1217 | } |
1218 | |
1219 | /// Reserve the range for the `.dynamic` section. |
1220 | /// |
1221 | /// This function does nothing if `dynamic_num` is zero. |
1222 | pub fn reserve_dynamic(&mut self, dynamic_num: usize) { |
1223 | debug_assert_eq!(self.dynamic_offset, 0); |
1224 | if dynamic_num == 0 { |
1225 | return; |
1226 | } |
1227 | self.dynamic_num = dynamic_num; |
1228 | self.dynamic_offset = self.reserve(dynamic_num * self.dyn_size(), self.elf_align); |
1229 | } |
1230 | |
1231 | /// Write alignment padding bytes prior to the `.dynamic` section. |
1232 | /// |
1233 | /// This function does nothing if the section was not reserved. |
1234 | pub fn write_align_dynamic(&mut self) { |
1235 | if self.dynamic_offset == 0 { |
1236 | return; |
1237 | } |
1238 | util::write_align(self.buffer, self.elf_align); |
1239 | debug_assert_eq!(self.dynamic_offset, self.buffer.len()); |
1240 | } |
1241 | |
1242 | /// Write a dynamic string entry. |
1243 | pub fn write_dynamic_string(&mut self, tag: u32, id: StringId) { |
1244 | self.write_dynamic(tag, self.dynstr.get_offset(id) as u64); |
1245 | } |
1246 | |
1247 | /// Write a dynamic value entry. |
1248 | pub fn write_dynamic(&mut self, d_tag: u32, d_val: u64) { |
1249 | debug_assert!(self.dynamic_offset <= self.buffer.len()); |
1250 | let endian = self.endian; |
1251 | if self.is_64 { |
1252 | let d = elf::Dyn64 { |
1253 | d_tag: U64::new(endian, d_tag.into()), |
1254 | d_val: U64::new(endian, d_val), |
1255 | }; |
1256 | self.buffer.write(&d); |
1257 | } else { |
1258 | let d = elf::Dyn32 { |
1259 | d_tag: U32::new(endian, d_tag), |
1260 | d_val: U32::new(endian, d_val as u32), |
1261 | }; |
1262 | self.buffer.write(&d); |
1263 | } |
1264 | debug_assert!( |
1265 | self.dynamic_offset + self.dynamic_num * self.dyn_size() >= self.buffer.len() |
1266 | ); |
1267 | } |
1268 | |
1269 | /// Reserve the section index for the dynamic table. |
1270 | pub fn reserve_dynamic_section_index(&mut self) -> SectionIndex { |
1271 | debug_assert!(self.dynamic_str_id.is_none()); |
1272 | self.dynamic_str_id = Some(self.add_section_name(&b".dynamic" [..])); |
1273 | self.reserve_section_index() |
1274 | } |
1275 | |
1276 | /// Write the section header for the dynamic table. |
1277 | /// |
1278 | /// This function does nothing if the section index was not reserved. |
1279 | pub fn write_dynamic_section_header(&mut self, sh_addr: u64) { |
1280 | if self.dynamic_str_id.is_none() { |
1281 | return; |
1282 | } |
1283 | self.write_section_header(&SectionHeader { |
1284 | name: self.dynamic_str_id, |
1285 | sh_type: elf::SHT_DYNAMIC, |
1286 | sh_flags: (elf::SHF_WRITE | elf::SHF_ALLOC).into(), |
1287 | sh_addr, |
1288 | sh_offset: self.dynamic_offset as u64, |
1289 | sh_size: (self.dynamic_num * self.dyn_size()) as u64, |
1290 | sh_link: self.dynstr_index.0, |
1291 | sh_info: 0, |
1292 | sh_addralign: self.elf_align as u64, |
1293 | sh_entsize: self.dyn_size() as u64, |
1294 | }); |
1295 | } |
1296 | |
1297 | fn rel_size(&self, is_rela: bool) -> usize { |
1298 | if self.is_64 { |
1299 | if is_rela { |
1300 | mem::size_of::<elf::Rela64<Endianness>>() |
1301 | } else { |
1302 | mem::size_of::<elf::Rel64<Endianness>>() |
1303 | } |
1304 | } else { |
1305 | if is_rela { |
1306 | mem::size_of::<elf::Rela32<Endianness>>() |
1307 | } else { |
1308 | mem::size_of::<elf::Rel32<Endianness>>() |
1309 | } |
1310 | } |
1311 | } |
1312 | |
1313 | /// Reserve a file range for a SysV hash section. |
1314 | /// |
1315 | /// `symbol_count` is the number of symbols in the hash, |
1316 | /// not the total number of symbols. |
1317 | pub fn reserve_hash(&mut self, bucket_count: u32, chain_count: u32) { |
1318 | self.hash_size = mem::size_of::<elf::HashHeader<Endianness>>() |
1319 | + bucket_count as usize * 4 |
1320 | + chain_count as usize * 4; |
1321 | self.hash_offset = self.reserve(self.hash_size, self.elf_align); |
1322 | } |
1323 | |
1324 | /// Write a SysV hash section. |
1325 | /// |
1326 | /// `chain_count` is the number of symbols in the hash. |
1327 | /// The argument to `hash` will be in the range `0..chain_count`. |
1328 | pub fn write_hash<F>(&mut self, bucket_count: u32, chain_count: u32, hash: F) |
1329 | where |
1330 | F: Fn(u32) -> Option<u32>, |
1331 | { |
1332 | let mut buckets = vec![U32::new(self.endian, 0); bucket_count as usize]; |
1333 | let mut chains = vec![U32::new(self.endian, 0); chain_count as usize]; |
1334 | for i in 0..chain_count { |
1335 | if let Some(hash) = hash(i) { |
1336 | let bucket = hash % bucket_count; |
1337 | chains[i as usize] = buckets[bucket as usize]; |
1338 | buckets[bucket as usize] = U32::new(self.endian, i); |
1339 | } |
1340 | } |
1341 | |
1342 | util::write_align(self.buffer, self.elf_align); |
1343 | debug_assert_eq!(self.hash_offset, self.buffer.len()); |
1344 | self.buffer.write(&elf::HashHeader { |
1345 | bucket_count: U32::new(self.endian, bucket_count), |
1346 | chain_count: U32::new(self.endian, chain_count), |
1347 | }); |
1348 | self.buffer.write_slice(&buckets); |
1349 | self.buffer.write_slice(&chains); |
1350 | } |
1351 | |
1352 | /// Reserve the section index for the SysV hash table. |
1353 | pub fn reserve_hash_section_index(&mut self) -> SectionIndex { |
1354 | debug_assert!(self.hash_str_id.is_none()); |
1355 | self.hash_str_id = Some(self.add_section_name(&b".hash" [..])); |
1356 | self.reserve_section_index() |
1357 | } |
1358 | |
1359 | /// Write the section header for the SysV hash table. |
1360 | /// |
1361 | /// This function does nothing if the section index was not reserved. |
1362 | pub fn write_hash_section_header(&mut self, sh_addr: u64) { |
1363 | if self.hash_str_id.is_none() { |
1364 | return; |
1365 | } |
1366 | self.write_section_header(&SectionHeader { |
1367 | name: self.hash_str_id, |
1368 | sh_type: elf::SHT_HASH, |
1369 | sh_flags: elf::SHF_ALLOC.into(), |
1370 | sh_addr, |
1371 | sh_offset: self.hash_offset as u64, |
1372 | sh_size: self.hash_size as u64, |
1373 | sh_link: self.dynsym_index.0, |
1374 | sh_info: 0, |
1375 | sh_addralign: self.elf_align as u64, |
1376 | sh_entsize: 4, |
1377 | }); |
1378 | } |
1379 | |
1380 | /// Reserve a file range for a GNU hash section. |
1381 | /// |
1382 | /// `symbol_count` is the number of symbols in the hash, |
1383 | /// not the total number of symbols. |
1384 | pub fn reserve_gnu_hash(&mut self, bloom_count: u32, bucket_count: u32, symbol_count: u32) { |
1385 | self.gnu_hash_size = mem::size_of::<elf::GnuHashHeader<Endianness>>() |
1386 | + bloom_count as usize * self.elf_align |
1387 | + bucket_count as usize * 4 |
1388 | + symbol_count as usize * 4; |
1389 | self.gnu_hash_offset = self.reserve(self.gnu_hash_size, self.elf_align); |
1390 | } |
1391 | |
1392 | /// Write a GNU hash section. |
1393 | /// |
1394 | /// `symbol_count` is the number of symbols in the hash. |
1395 | /// The argument to `hash` will be in the range `0..symbol_count`. |
1396 | /// |
1397 | /// This requires that symbols are already sorted by bucket. |
1398 | pub fn write_gnu_hash<F>( |
1399 | &mut self, |
1400 | symbol_base: u32, |
1401 | bloom_shift: u32, |
1402 | bloom_count: u32, |
1403 | bucket_count: u32, |
1404 | symbol_count: u32, |
1405 | hash: F, |
1406 | ) where |
1407 | F: Fn(u32) -> u32, |
1408 | { |
1409 | util::write_align(self.buffer, self.elf_align); |
1410 | debug_assert_eq!(self.gnu_hash_offset, self.buffer.len()); |
1411 | self.buffer.write(&elf::GnuHashHeader { |
1412 | bucket_count: U32::new(self.endian, bucket_count), |
1413 | symbol_base: U32::new(self.endian, symbol_base), |
1414 | bloom_count: U32::new(self.endian, bloom_count), |
1415 | bloom_shift: U32::new(self.endian, bloom_shift), |
1416 | }); |
1417 | |
1418 | // Calculate and write bloom filter. |
1419 | if self.is_64 { |
1420 | let mut bloom_filters = vec![0; bloom_count as usize]; |
1421 | for i in 0..symbol_count { |
1422 | let h = hash(i); |
1423 | bloom_filters[((h / 64) & (bloom_count - 1)) as usize] |= |
1424 | 1 << (h % 64) | 1 << ((h >> bloom_shift) % 64); |
1425 | } |
1426 | for bloom_filter in bloom_filters { |
1427 | self.buffer.write(&U64::new(self.endian, bloom_filter)); |
1428 | } |
1429 | } else { |
1430 | let mut bloom_filters = vec![0; bloom_count as usize]; |
1431 | for i in 0..symbol_count { |
1432 | let h = hash(i); |
1433 | bloom_filters[((h / 32) & (bloom_count - 1)) as usize] |= |
1434 | 1 << (h % 32) | 1 << ((h >> bloom_shift) % 32); |
1435 | } |
1436 | for bloom_filter in bloom_filters { |
1437 | self.buffer.write(&U32::new(self.endian, bloom_filter)); |
1438 | } |
1439 | } |
1440 | |
1441 | // Write buckets. |
1442 | // |
1443 | // This requires that symbols are already sorted by bucket. |
1444 | let mut bucket = 0; |
1445 | for i in 0..symbol_count { |
1446 | let symbol_bucket = hash(i) % bucket_count; |
1447 | while bucket < symbol_bucket { |
1448 | self.buffer.write(&U32::new(self.endian, 0)); |
1449 | bucket += 1; |
1450 | } |
1451 | if bucket == symbol_bucket { |
1452 | self.buffer.write(&U32::new(self.endian, symbol_base + i)); |
1453 | bucket += 1; |
1454 | } |
1455 | } |
1456 | while bucket < bucket_count { |
1457 | self.buffer.write(&U32::new(self.endian, 0)); |
1458 | bucket += 1; |
1459 | } |
1460 | |
1461 | // Write hash values. |
1462 | for i in 0..symbol_count { |
1463 | let mut h = hash(i); |
1464 | if i == symbol_count - 1 || h % bucket_count != hash(i + 1) % bucket_count { |
1465 | h |= 1; |
1466 | } else { |
1467 | h &= !1; |
1468 | } |
1469 | self.buffer.write(&U32::new(self.endian, h)); |
1470 | } |
1471 | } |
1472 | |
1473 | /// Reserve the section index for the GNU hash table. |
1474 | pub fn reserve_gnu_hash_section_index(&mut self) -> SectionIndex { |
1475 | debug_assert!(self.gnu_hash_str_id.is_none()); |
1476 | self.gnu_hash_str_id = Some(self.add_section_name(&b".gnu.hash" [..])); |
1477 | self.reserve_section_index() |
1478 | } |
1479 | |
1480 | /// Write the section header for the GNU hash table. |
1481 | /// |
1482 | /// This function does nothing if the section index was not reserved. |
1483 | pub fn write_gnu_hash_section_header(&mut self, sh_addr: u64) { |
1484 | if self.gnu_hash_str_id.is_none() { |
1485 | return; |
1486 | } |
1487 | self.write_section_header(&SectionHeader { |
1488 | name: self.gnu_hash_str_id, |
1489 | sh_type: elf::SHT_GNU_HASH, |
1490 | sh_flags: elf::SHF_ALLOC.into(), |
1491 | sh_addr, |
1492 | sh_offset: self.gnu_hash_offset as u64, |
1493 | sh_size: self.gnu_hash_size as u64, |
1494 | sh_link: self.dynsym_index.0, |
1495 | sh_info: 0, |
1496 | sh_addralign: self.elf_align as u64, |
1497 | sh_entsize: 0, |
1498 | }); |
1499 | } |
1500 | |
1501 | /// Reserve the range for the `.gnu.version` section. |
1502 | /// |
1503 | /// This function does nothing if no dynamic symbols were reserved. |
1504 | pub fn reserve_gnu_versym(&mut self) { |
1505 | debug_assert_eq!(self.gnu_versym_offset, 0); |
1506 | if self.dynsym_num == 0 { |
1507 | return; |
1508 | } |
1509 | self.gnu_versym_offset = self.reserve(self.dynsym_num as usize * 2, 2); |
1510 | } |
1511 | |
1512 | /// Write the null symbol version entry. |
1513 | /// |
1514 | /// This must be the first symbol version that is written. |
1515 | /// This function does nothing if no dynamic symbols were reserved. |
1516 | pub fn write_null_gnu_versym(&mut self) { |
1517 | if self.dynsym_num == 0 { |
1518 | return; |
1519 | } |
1520 | util::write_align(self.buffer, 2); |
1521 | debug_assert_eq!(self.gnu_versym_offset, self.buffer.len()); |
1522 | self.write_gnu_versym(0); |
1523 | } |
1524 | |
1525 | /// Write a symbol version entry. |
1526 | pub fn write_gnu_versym(&mut self, versym: u16) { |
1527 | self.buffer.write(&U16::new(self.endian, versym)); |
1528 | } |
1529 | |
1530 | /// Reserve the section index for the `.gnu.version` section. |
1531 | pub fn reserve_gnu_versym_section_index(&mut self) -> SectionIndex { |
1532 | debug_assert!(self.gnu_versym_str_id.is_none()); |
1533 | self.gnu_versym_str_id = Some(self.add_section_name(&b".gnu.version" [..])); |
1534 | self.reserve_section_index() |
1535 | } |
1536 | |
1537 | /// Write the section header for the `.gnu.version` section. |
1538 | /// |
1539 | /// This function does nothing if the section index was not reserved. |
1540 | pub fn write_gnu_versym_section_header(&mut self, sh_addr: u64) { |
1541 | if self.gnu_versym_str_id.is_none() { |
1542 | return; |
1543 | } |
1544 | self.write_section_header(&SectionHeader { |
1545 | name: self.gnu_versym_str_id, |
1546 | sh_type: elf::SHT_GNU_VERSYM, |
1547 | sh_flags: elf::SHF_ALLOC.into(), |
1548 | sh_addr, |
1549 | sh_offset: self.gnu_versym_offset as u64, |
1550 | sh_size: self.dynsym_num as u64 * 2, |
1551 | sh_link: self.dynsym_index.0, |
1552 | sh_info: 0, |
1553 | sh_addralign: 2, |
1554 | sh_entsize: 2, |
1555 | }); |
1556 | } |
1557 | |
1558 | /// Reserve the range for the `.gnu.version_d` section. |
1559 | pub fn reserve_gnu_verdef(&mut self, verdef_count: usize, verdaux_count: usize) { |
1560 | debug_assert_eq!(self.gnu_verdef_offset, 0); |
1561 | if verdef_count == 0 { |
1562 | return; |
1563 | } |
1564 | self.gnu_verdef_size = verdef_count * mem::size_of::<elf::Verdef<Endianness>>() |
1565 | + verdaux_count * mem::size_of::<elf::Verdaux<Endianness>>(); |
1566 | self.gnu_verdef_offset = self.reserve(self.gnu_verdef_size, self.elf_align); |
1567 | self.gnu_verdef_count = verdef_count as u16; |
1568 | self.gnu_verdef_remaining = self.gnu_verdef_count; |
1569 | } |
1570 | |
1571 | /// Write alignment padding bytes prior to a `.gnu.version_d` section. |
1572 | pub fn write_align_gnu_verdef(&mut self) { |
1573 | if self.gnu_verdef_offset == 0 { |
1574 | return; |
1575 | } |
1576 | util::write_align(self.buffer, self.elf_align); |
1577 | debug_assert_eq!(self.gnu_verdef_offset, self.buffer.len()); |
1578 | } |
1579 | |
1580 | /// Write a version definition entry. |
1581 | pub fn write_gnu_verdef(&mut self, verdef: &Verdef) { |
1582 | debug_assert_ne!(self.gnu_verdef_remaining, 0); |
1583 | self.gnu_verdef_remaining -= 1; |
1584 | let vd_next = if self.gnu_verdef_remaining == 0 { |
1585 | 0 |
1586 | } else { |
1587 | mem::size_of::<elf::Verdef<Endianness>>() as u32 |
1588 | + verdef.aux_count as u32 * mem::size_of::<elf::Verdaux<Endianness>>() as u32 |
1589 | }; |
1590 | |
1591 | self.gnu_verdaux_remaining = verdef.aux_count; |
1592 | let vd_aux = if verdef.aux_count == 0 { |
1593 | 0 |
1594 | } else { |
1595 | mem::size_of::<elf::Verdef<Endianness>>() as u32 |
1596 | }; |
1597 | |
1598 | self.buffer.write(&elf::Verdef { |
1599 | vd_version: U16::new(self.endian, verdef.version), |
1600 | vd_flags: U16::new(self.endian, verdef.flags), |
1601 | vd_ndx: U16::new(self.endian, verdef.index), |
1602 | vd_cnt: U16::new(self.endian, verdef.aux_count), |
1603 | vd_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(verdef.name))), |
1604 | vd_aux: U32::new(self.endian, vd_aux), |
1605 | vd_next: U32::new(self.endian, vd_next), |
1606 | }); |
1607 | self.write_gnu_verdaux(verdef.name); |
1608 | } |
1609 | |
1610 | /// Write a version definition auxiliary entry. |
1611 | pub fn write_gnu_verdaux(&mut self, name: StringId) { |
1612 | debug_assert_ne!(self.gnu_verdaux_remaining, 0); |
1613 | self.gnu_verdaux_remaining -= 1; |
1614 | let vda_next = if self.gnu_verdaux_remaining == 0 { |
1615 | 0 |
1616 | } else { |
1617 | mem::size_of::<elf::Verdaux<Endianness>>() as u32 |
1618 | }; |
1619 | self.buffer.write(&elf::Verdaux { |
1620 | vda_name: U32::new(self.endian, self.dynstr.get_offset(name) as u32), |
1621 | vda_next: U32::new(self.endian, vda_next), |
1622 | }); |
1623 | } |
1624 | |
1625 | /// Reserve the section index for the `.gnu.version_d` section. |
1626 | pub fn reserve_gnu_verdef_section_index(&mut self) -> SectionIndex { |
1627 | debug_assert!(self.gnu_verdef_str_id.is_none()); |
1628 | self.gnu_verdef_str_id = Some(self.add_section_name(&b".gnu.version_d" [..])); |
1629 | self.reserve_section_index() |
1630 | } |
1631 | |
1632 | /// Write the section header for the `.gnu.version_d` section. |
1633 | /// |
1634 | /// This function does nothing if the section index was not reserved. |
1635 | pub fn write_gnu_verdef_section_header(&mut self, sh_addr: u64) { |
1636 | if self.gnu_verdef_str_id.is_none() { |
1637 | return; |
1638 | } |
1639 | self.write_section_header(&SectionHeader { |
1640 | name: self.gnu_verdef_str_id, |
1641 | sh_type: elf::SHT_GNU_VERDEF, |
1642 | sh_flags: elf::SHF_ALLOC.into(), |
1643 | sh_addr, |
1644 | sh_offset: self.gnu_verdef_offset as u64, |
1645 | sh_size: self.gnu_verdef_size as u64, |
1646 | sh_link: self.dynstr_index.0, |
1647 | sh_info: self.gnu_verdef_count.into(), |
1648 | sh_addralign: self.elf_align as u64, |
1649 | sh_entsize: 0, |
1650 | }); |
1651 | } |
1652 | |
1653 | /// Reserve the range for the `.gnu.version_r` section. |
1654 | pub fn reserve_gnu_verneed(&mut self, verneed_count: usize, vernaux_count: usize) { |
1655 | debug_assert_eq!(self.gnu_verneed_offset, 0); |
1656 | if verneed_count == 0 { |
1657 | return; |
1658 | } |
1659 | self.gnu_verneed_size = verneed_count * mem::size_of::<elf::Verneed<Endianness>>() |
1660 | + vernaux_count * mem::size_of::<elf::Vernaux<Endianness>>(); |
1661 | self.gnu_verneed_offset = self.reserve(self.gnu_verneed_size, self.elf_align); |
1662 | self.gnu_verneed_count = verneed_count as u16; |
1663 | self.gnu_verneed_remaining = self.gnu_verneed_count; |
1664 | } |
1665 | |
1666 | /// Write alignment padding bytes prior to a `.gnu.version_r` section. |
1667 | pub fn write_align_gnu_verneed(&mut self) { |
1668 | if self.gnu_verneed_offset == 0 { |
1669 | return; |
1670 | } |
1671 | util::write_align(self.buffer, self.elf_align); |
1672 | debug_assert_eq!(self.gnu_verneed_offset, self.buffer.len()); |
1673 | } |
1674 | |
1675 | /// Write a version need entry. |
1676 | pub fn write_gnu_verneed(&mut self, verneed: &Verneed) { |
1677 | debug_assert_ne!(self.gnu_verneed_remaining, 0); |
1678 | self.gnu_verneed_remaining -= 1; |
1679 | let vn_next = if self.gnu_verneed_remaining == 0 { |
1680 | 0 |
1681 | } else { |
1682 | mem::size_of::<elf::Verneed<Endianness>>() as u32 |
1683 | + verneed.aux_count as u32 * mem::size_of::<elf::Vernaux<Endianness>>() as u32 |
1684 | }; |
1685 | |
1686 | self.gnu_vernaux_remaining = verneed.aux_count; |
1687 | let vn_aux = if verneed.aux_count == 0 { |
1688 | 0 |
1689 | } else { |
1690 | mem::size_of::<elf::Verneed<Endianness>>() as u32 |
1691 | }; |
1692 | |
1693 | self.buffer.write(&elf::Verneed { |
1694 | vn_version: U16::new(self.endian, verneed.version), |
1695 | vn_cnt: U16::new(self.endian, verneed.aux_count), |
1696 | vn_file: U32::new(self.endian, self.dynstr.get_offset(verneed.file) as u32), |
1697 | vn_aux: U32::new(self.endian, vn_aux), |
1698 | vn_next: U32::new(self.endian, vn_next), |
1699 | }); |
1700 | } |
1701 | |
1702 | /// Write a version need auxiliary entry. |
1703 | pub fn write_gnu_vernaux(&mut self, vernaux: &Vernaux) { |
1704 | debug_assert_ne!(self.gnu_vernaux_remaining, 0); |
1705 | self.gnu_vernaux_remaining -= 1; |
1706 | let vna_next = if self.gnu_vernaux_remaining == 0 { |
1707 | 0 |
1708 | } else { |
1709 | mem::size_of::<elf::Vernaux<Endianness>>() as u32 |
1710 | }; |
1711 | self.buffer.write(&elf::Vernaux { |
1712 | vna_hash: U32::new(self.endian, elf::hash(self.dynstr.get_string(vernaux.name))), |
1713 | vna_flags: U16::new(self.endian, vernaux.flags), |
1714 | vna_other: U16::new(self.endian, vernaux.index), |
1715 | vna_name: U32::new(self.endian, self.dynstr.get_offset(vernaux.name) as u32), |
1716 | vna_next: U32::new(self.endian, vna_next), |
1717 | }); |
1718 | } |
1719 | |
1720 | /// Reserve the section index for the `.gnu.version_r` section. |
1721 | pub fn reserve_gnu_verneed_section_index(&mut self) -> SectionIndex { |
1722 | debug_assert!(self.gnu_verneed_str_id.is_none()); |
1723 | self.gnu_verneed_str_id = Some(self.add_section_name(&b".gnu.version_r" [..])); |
1724 | self.reserve_section_index() |
1725 | } |
1726 | |
1727 | /// Write the section header for the `.gnu.version_r` section. |
1728 | /// |
1729 | /// This function does nothing if the section index was not reserved. |
1730 | pub fn write_gnu_verneed_section_header(&mut self, sh_addr: u64) { |
1731 | if self.gnu_verneed_str_id.is_none() { |
1732 | return; |
1733 | } |
1734 | self.write_section_header(&SectionHeader { |
1735 | name: self.gnu_verneed_str_id, |
1736 | sh_type: elf::SHT_GNU_VERNEED, |
1737 | sh_flags: elf::SHF_ALLOC.into(), |
1738 | sh_addr, |
1739 | sh_offset: self.gnu_verneed_offset as u64, |
1740 | sh_size: self.gnu_verneed_size as u64, |
1741 | sh_link: self.dynstr_index.0, |
1742 | sh_info: self.gnu_verneed_count.into(), |
1743 | sh_addralign: self.elf_align as u64, |
1744 | sh_entsize: 0, |
1745 | }); |
1746 | } |
1747 | |
1748 | /// Reserve the section index for the `.gnu.attributes` section. |
1749 | pub fn reserve_gnu_attributes_section_index(&mut self) -> SectionIndex { |
1750 | debug_assert!(self.gnu_attributes_str_id.is_none()); |
1751 | self.gnu_attributes_str_id = Some(self.add_section_name(&b".gnu.attributes" [..])); |
1752 | self.reserve_section_index() |
1753 | } |
1754 | |
1755 | /// Reserve the range for the `.gnu.attributes` section. |
1756 | pub fn reserve_gnu_attributes(&mut self, gnu_attributes_size: usize) { |
1757 | debug_assert_eq!(self.gnu_attributes_offset, 0); |
1758 | if gnu_attributes_size == 0 { |
1759 | return; |
1760 | } |
1761 | self.gnu_attributes_size = gnu_attributes_size; |
1762 | self.gnu_attributes_offset = self.reserve(self.gnu_attributes_size, self.elf_align); |
1763 | } |
1764 | |
1765 | /// Write the section header for the `.gnu.attributes` section. |
1766 | /// |
1767 | /// This function does nothing if the section index was not reserved. |
1768 | pub fn write_gnu_attributes_section_header(&mut self) { |
1769 | if self.gnu_attributes_str_id.is_none() { |
1770 | return; |
1771 | } |
1772 | self.write_section_header(&SectionHeader { |
1773 | name: self.gnu_attributes_str_id, |
1774 | sh_type: elf::SHT_GNU_ATTRIBUTES, |
1775 | sh_flags: 0, |
1776 | sh_addr: 0, |
1777 | sh_offset: self.gnu_attributes_offset as u64, |
1778 | sh_size: self.gnu_attributes_size as u64, |
1779 | sh_link: self.dynstr_index.0, |
1780 | sh_info: 0, // TODO |
1781 | sh_addralign: self.elf_align as u64, |
1782 | sh_entsize: 0, |
1783 | }); |
1784 | } |
1785 | |
1786 | /// Write the data for the `.gnu.attributes` section. |
1787 | pub fn write_gnu_attributes(&mut self, data: &[u8]) { |
1788 | if self.gnu_attributes_offset == 0 { |
1789 | return; |
1790 | } |
1791 | util::write_align(self.buffer, self.elf_align); |
1792 | debug_assert_eq!(self.gnu_attributes_offset, self.buffer.len()); |
1793 | self.buffer.write_bytes(data); |
1794 | } |
1795 | |
1796 | /// Reserve a file range for the given number of relocations. |
1797 | /// |
1798 | /// Returns the offset of the range. |
1799 | pub fn reserve_relocations(&mut self, count: usize, is_rela: bool) -> usize { |
1800 | self.reserve(count * self.rel_size(is_rela), self.elf_align) |
1801 | } |
1802 | |
1803 | /// Write alignment padding bytes prior to a relocation section. |
1804 | pub fn write_align_relocation(&mut self) { |
1805 | util::write_align(self.buffer, self.elf_align); |
1806 | } |
1807 | |
1808 | /// Write a relocation. |
1809 | pub fn write_relocation(&mut self, is_rela: bool, rel: &Rel) { |
1810 | let endian = self.endian; |
1811 | if self.is_64 { |
1812 | if is_rela { |
1813 | let rel = elf::Rela64 { |
1814 | r_offset: U64::new(endian, rel.r_offset), |
1815 | r_info: elf::Rela64::r_info(endian, self.is_mips64el, rel.r_sym, rel.r_type), |
1816 | r_addend: I64::new(endian, rel.r_addend), |
1817 | }; |
1818 | self.buffer.write(&rel); |
1819 | } else { |
1820 | let rel = elf::Rel64 { |
1821 | r_offset: U64::new(endian, rel.r_offset), |
1822 | r_info: elf::Rel64::r_info(endian, rel.r_sym, rel.r_type), |
1823 | }; |
1824 | self.buffer.write(&rel); |
1825 | } |
1826 | } else { |
1827 | if is_rela { |
1828 | let rel = elf::Rela32 { |
1829 | r_offset: U32::new(endian, rel.r_offset as u32), |
1830 | r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), |
1831 | r_addend: I32::new(endian, rel.r_addend as i32), |
1832 | }; |
1833 | self.buffer.write(&rel); |
1834 | } else { |
1835 | let rel = elf::Rel32 { |
1836 | r_offset: U32::new(endian, rel.r_offset as u32), |
1837 | r_info: elf::Rel32::r_info(endian, rel.r_sym, rel.r_type as u8), |
1838 | }; |
1839 | self.buffer.write(&rel); |
1840 | } |
1841 | } |
1842 | } |
1843 | |
1844 | /// Write the section header for a relocation section. |
1845 | /// |
1846 | /// `section` is the index of the section the relocations apply to, |
1847 | /// or 0 if none. |
1848 | /// |
1849 | /// `symtab` is the index of the symbol table the relocations refer to, |
1850 | /// or 0 if none. |
1851 | /// |
1852 | /// `offset` is the file offset of the relocations. |
1853 | pub fn write_relocation_section_header( |
1854 | &mut self, |
1855 | name: StringId, |
1856 | section: SectionIndex, |
1857 | symtab: SectionIndex, |
1858 | offset: usize, |
1859 | count: usize, |
1860 | is_rela: bool, |
1861 | ) { |
1862 | self.write_section_header(&SectionHeader { |
1863 | name: Some(name), |
1864 | sh_type: if is_rela { elf::SHT_RELA } else { elf::SHT_REL }, |
1865 | sh_flags: elf::SHF_INFO_LINK.into(), |
1866 | sh_addr: 0, |
1867 | sh_offset: offset as u64, |
1868 | sh_size: (count * self.rel_size(is_rela)) as u64, |
1869 | sh_link: symtab.0, |
1870 | sh_info: section.0, |
1871 | sh_addralign: self.elf_align as u64, |
1872 | sh_entsize: self.rel_size(is_rela) as u64, |
1873 | }); |
1874 | } |
1875 | |
1876 | /// Reserve a file range for a COMDAT section. |
1877 | /// |
1878 | /// `count` is the number of sections in the COMDAT group. |
1879 | /// |
1880 | /// Returns the offset of the range. |
1881 | pub fn reserve_comdat(&mut self, count: usize) -> usize { |
1882 | self.reserve((count + 1) * 4, 4) |
1883 | } |
1884 | |
1885 | /// Write `GRP_COMDAT` at the start of the COMDAT section. |
1886 | pub fn write_comdat_header(&mut self) { |
1887 | util::write_align(self.buffer, 4); |
1888 | self.buffer.write(&U32::new(self.endian, elf::GRP_COMDAT)); |
1889 | } |
1890 | |
1891 | /// Write an entry in a COMDAT section. |
1892 | pub fn write_comdat_entry(&mut self, entry: SectionIndex) { |
1893 | self.buffer.write(&U32::new(self.endian, entry.0)); |
1894 | } |
1895 | |
1896 | /// Write the section header for a COMDAT section. |
1897 | pub fn write_comdat_section_header( |
1898 | &mut self, |
1899 | name: StringId, |
1900 | symtab: SectionIndex, |
1901 | symbol: SymbolIndex, |
1902 | offset: usize, |
1903 | count: usize, |
1904 | ) { |
1905 | self.write_section_header(&SectionHeader { |
1906 | name: Some(name), |
1907 | sh_type: elf::SHT_GROUP, |
1908 | sh_flags: 0, |
1909 | sh_addr: 0, |
1910 | sh_offset: offset as u64, |
1911 | sh_size: ((count + 1) * 4) as u64, |
1912 | sh_link: symtab.0, |
1913 | sh_info: symbol.0, |
1914 | sh_addralign: 4, |
1915 | sh_entsize: 4, |
1916 | }); |
1917 | } |
1918 | |
1919 | /// Return a helper for writing an attributes section. |
1920 | pub fn attributes_writer(&self) -> AttributesWriter { |
1921 | AttributesWriter::new(self.endian) |
1922 | } |
1923 | } |
1924 | |
1925 | /// A helper for writing an attributes section. |
1926 | /// |
1927 | /// Attributes have a variable length encoding, so it is awkward to write them in a |
1928 | /// single pass. Instead, we build the entire attributes section data in memory, using |
1929 | /// placeholders for unknown lengths that are filled in later. |
1930 | #[allow (missing_debug_implementations)] |
1931 | pub struct AttributesWriter { |
1932 | endian: Endianness, |
1933 | data: Vec<u8>, |
1934 | subsection_offset: usize, |
1935 | subsubsection_offset: usize, |
1936 | } |
1937 | |
1938 | impl AttributesWriter { |
1939 | /// Create a new `AttributesWriter` for the given endianness. |
1940 | pub fn new(endian: Endianness) -> Self { |
1941 | AttributesWriter { |
1942 | endian, |
1943 | data: vec![0x41], |
1944 | subsection_offset: 0, |
1945 | subsubsection_offset: 0, |
1946 | } |
1947 | } |
1948 | |
1949 | /// Start a new subsection with the given vendor name. |
1950 | pub fn start_subsection(&mut self, vendor: &[u8]) { |
1951 | debug_assert_eq!(self.subsection_offset, 0); |
1952 | debug_assert_eq!(self.subsubsection_offset, 0); |
1953 | self.subsection_offset = self.data.len(); |
1954 | self.data.extend_from_slice(&[0; 4]); |
1955 | self.data.extend_from_slice(vendor); |
1956 | self.data.push(0); |
1957 | } |
1958 | |
1959 | /// End the subsection. |
1960 | /// |
1961 | /// The subsection length is automatically calculated and written. |
1962 | pub fn end_subsection(&mut self) { |
1963 | debug_assert_ne!(self.subsection_offset, 0); |
1964 | debug_assert_eq!(self.subsubsection_offset, 0); |
1965 | let length = self.data.len() - self.subsection_offset; |
1966 | self.data[self.subsection_offset..][..4] |
1967 | .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32))); |
1968 | self.subsection_offset = 0; |
1969 | } |
1970 | |
1971 | /// Start a new sub-subsection with the given tag. |
1972 | pub fn start_subsubsection(&mut self, tag: u8) { |
1973 | debug_assert_ne!(self.subsection_offset, 0); |
1974 | debug_assert_eq!(self.subsubsection_offset, 0); |
1975 | self.subsubsection_offset = self.data.len(); |
1976 | self.data.push(tag); |
1977 | self.data.extend_from_slice(&[0; 4]); |
1978 | } |
1979 | |
1980 | /// Write a section or symbol index to the sub-subsection. |
1981 | /// |
1982 | /// The user must also call this function to write the terminating 0 index. |
1983 | pub fn write_subsubsection_index(&mut self, index: u32) { |
1984 | debug_assert_ne!(self.subsection_offset, 0); |
1985 | debug_assert_ne!(self.subsubsection_offset, 0); |
1986 | util::write_uleb128(&mut self.data, u64::from(index)); |
1987 | } |
1988 | |
1989 | /// Write raw index data to the sub-subsection. |
1990 | /// |
1991 | /// The terminating 0 index is automatically written. |
1992 | pub fn write_subsubsection_indices(&mut self, indices: &[u8]) { |
1993 | debug_assert_ne!(self.subsection_offset, 0); |
1994 | debug_assert_ne!(self.subsubsection_offset, 0); |
1995 | self.data.extend_from_slice(indices); |
1996 | self.data.push(0); |
1997 | } |
1998 | |
1999 | /// Write an attribute tag to the sub-subsection. |
2000 | pub fn write_attribute_tag(&mut self, tag: u64) { |
2001 | debug_assert_ne!(self.subsection_offset, 0); |
2002 | debug_assert_ne!(self.subsubsection_offset, 0); |
2003 | util::write_uleb128(&mut self.data, tag); |
2004 | } |
2005 | |
2006 | /// Write an attribute integer value to the sub-subsection. |
2007 | pub fn write_attribute_integer(&mut self, value: u64) { |
2008 | debug_assert_ne!(self.subsection_offset, 0); |
2009 | debug_assert_ne!(self.subsubsection_offset, 0); |
2010 | util::write_uleb128(&mut self.data, value); |
2011 | } |
2012 | |
2013 | /// Write an attribute string value to the sub-subsection. |
2014 | /// |
2015 | /// The value must not include the null terminator. |
2016 | pub fn write_attribute_string(&mut self, value: &[u8]) { |
2017 | debug_assert_ne!(self.subsection_offset, 0); |
2018 | debug_assert_ne!(self.subsubsection_offset, 0); |
2019 | self.data.extend_from_slice(value); |
2020 | self.data.push(0); |
2021 | } |
2022 | |
2023 | /// Write raw attribute data to the sub-subsection. |
2024 | pub fn write_subsubsection_attributes(&mut self, attributes: &[u8]) { |
2025 | debug_assert_ne!(self.subsection_offset, 0); |
2026 | debug_assert_ne!(self.subsubsection_offset, 0); |
2027 | self.data.extend_from_slice(attributes); |
2028 | } |
2029 | |
2030 | /// End the sub-subsection. |
2031 | /// |
2032 | /// The sub-subsection length is automatically calculated and written. |
2033 | pub fn end_subsubsection(&mut self) { |
2034 | debug_assert_ne!(self.subsection_offset, 0); |
2035 | debug_assert_ne!(self.subsubsection_offset, 0); |
2036 | let length = self.data.len() - self.subsubsection_offset; |
2037 | self.data[self.subsubsection_offset + 1..][..4] |
2038 | .copy_from_slice(pod::bytes_of(&U32::new(self.endian, length as u32))); |
2039 | self.subsubsection_offset = 0; |
2040 | } |
2041 | |
2042 | /// Return the completed section data. |
2043 | pub fn data(self) -> Vec<u8> { |
2044 | debug_assert_eq!(self.subsection_offset, 0); |
2045 | debug_assert_eq!(self.subsubsection_offset, 0); |
2046 | self.data |
2047 | } |
2048 | } |
2049 | |
2050 | /// Native endian version of [`elf::FileHeader64`]. |
2051 | #[allow (missing_docs)] |
2052 | #[derive (Debug, Clone)] |
2053 | pub struct FileHeader { |
2054 | pub os_abi: u8, |
2055 | pub abi_version: u8, |
2056 | pub e_type: u16, |
2057 | pub e_machine: u16, |
2058 | pub e_entry: u64, |
2059 | pub e_flags: u32, |
2060 | } |
2061 | |
2062 | /// Native endian version of [`elf::ProgramHeader64`]. |
2063 | #[allow (missing_docs)] |
2064 | #[derive (Debug, Clone)] |
2065 | pub struct ProgramHeader { |
2066 | pub p_type: u32, |
2067 | pub p_flags: u32, |
2068 | pub p_offset: u64, |
2069 | pub p_vaddr: u64, |
2070 | pub p_paddr: u64, |
2071 | pub p_filesz: u64, |
2072 | pub p_memsz: u64, |
2073 | pub p_align: u64, |
2074 | } |
2075 | |
2076 | /// Native endian version of [`elf::SectionHeader64`]. |
2077 | #[allow (missing_docs)] |
2078 | #[derive (Debug, Clone)] |
2079 | pub struct SectionHeader { |
2080 | pub name: Option<StringId>, |
2081 | pub sh_type: u32, |
2082 | pub sh_flags: u64, |
2083 | pub sh_addr: u64, |
2084 | pub sh_offset: u64, |
2085 | pub sh_size: u64, |
2086 | pub sh_link: u32, |
2087 | pub sh_info: u32, |
2088 | pub sh_addralign: u64, |
2089 | pub sh_entsize: u64, |
2090 | } |
2091 | |
2092 | /// Native endian version of [`elf::Sym64`]. |
2093 | #[allow (missing_docs)] |
2094 | #[derive (Debug, Clone)] |
2095 | pub struct Sym { |
2096 | pub name: Option<StringId>, |
2097 | pub section: Option<SectionIndex>, |
2098 | pub st_info: u8, |
2099 | pub st_other: u8, |
2100 | pub st_shndx: u16, |
2101 | pub st_value: u64, |
2102 | pub st_size: u64, |
2103 | } |
2104 | |
2105 | /// Unified native endian version of [`elf::Rel64`] and [`elf::Rela64`]. |
2106 | #[allow (missing_docs)] |
2107 | #[derive (Debug, Clone)] |
2108 | pub struct Rel { |
2109 | pub r_offset: u64, |
2110 | pub r_sym: u32, |
2111 | pub r_type: u32, |
2112 | pub r_addend: i64, |
2113 | } |
2114 | |
2115 | /// Information required for writing [`elf::Verdef`]. |
2116 | #[allow (missing_docs)] |
2117 | #[derive (Debug, Clone)] |
2118 | pub struct Verdef { |
2119 | pub version: u16, |
2120 | pub flags: u16, |
2121 | pub index: u16, |
2122 | pub aux_count: u16, |
2123 | /// The name for the first [`elf::Verdaux`] entry. |
2124 | pub name: StringId, |
2125 | } |
2126 | |
2127 | /// Information required for writing [`elf::Verneed`]. |
2128 | #[allow (missing_docs)] |
2129 | #[derive (Debug, Clone)] |
2130 | pub struct Verneed { |
2131 | pub version: u16, |
2132 | pub aux_count: u16, |
2133 | pub file: StringId, |
2134 | } |
2135 | |
2136 | /// Information required for writing [`elf::Vernaux`]. |
2137 | #[allow (missing_docs)] |
2138 | #[derive (Debug, Clone)] |
2139 | pub struct Vernaux { |
2140 | pub flags: u16, |
2141 | pub index: u16, |
2142 | pub name: StringId, |
2143 | } |
2144 | |