object_rewrite/
elf.rs

1use std::collections::{HashMap, HashSet};
2
3#[cfg(feature = "logging")]
4use log::info;
5use object::{build, elf};
6
7use super::{Error, Result, Rewriter};
8
9/// Options for modifying an ELF file.
10///
11/// This struct contains options for modifying an ELF file. It is
12/// contained in the [`Options`](super::Options) struct.
13///
14/// Options are listed in the order they are processed.
15#[derive(Debug, Default)]
16#[non_exhaustive]
17pub struct ElfOptions {
18    /// Add a `DT_DEBUG` entry to the dynamic section.
19    ///
20    /// See [`Rewriter::elf_add_dynamic_debug`].
21    pub add_dynamic_debug: bool,
22    /// Delete any `DT_RUNPATH` and `DT_RPATH` entries in the dynamic section.
23    ///
24    /// See [`Rewriter::elf_delete_runpath`].
25    pub delete_runpath: bool,
26    /// Set the path for any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section.
27    ///
28    /// See [`Rewriter::elf_set_runpath`].
29    pub set_runpath: Option<Vec<u8>>,
30    /// Add additional paths to any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section.
31    ///
32    /// See [`Rewriter::elf_add_runpath`].
33    pub add_runpath: Vec<Vec<u8>>,
34    /// Change any `DT_RPATH` entry in the dynamic section to `DT_RUNPATH`.
35    ///
36    /// See [`Rewriter::elf_use_runpath`].
37    pub use_runpath: bool,
38    /// Change any `DT_RUNPATH` entry in the dynamic section to `DT_RPATH`.
39    ///
40    /// See [`Rewriter::elf_use_rpath`].
41    pub use_rpath: bool,
42    /// Delete `DT_NEEDED` entries from the dynamic section.
43    ///
44    /// See [`Rewriter::elf_delete_needed`].
45    pub delete_needed: HashSet<Vec<u8>>,
46    /// Replace `DT_NEEDED` entries in the dynamic section.
47    ///
48    /// See [`Rewriter::elf_replace_needed`].
49    pub replace_needed: HashMap<Vec<u8>, Vec<u8>>,
50    /// Add `DT_NEEDED` entries to the start of the dynamic section.
51    ///
52    /// See [`Rewriter::elf_add_needed`].
53    pub add_needed: Vec<Vec<u8>>,
54    /// Set the `DT_SONAME` entry in the dynamic section.
55    ///
56    /// See [`Rewriter::elf_set_soname`].
57    pub set_soname: Option<Vec<u8>>,
58    /// Set the interpreter path in the `PT_INTERP` segment.
59    ///
60    /// See [`Rewriter::elf_set_interpreter`].
61    pub set_interpreter: Option<Vec<u8>>,
62}
63
64impl<'data> Rewriter<'data> {
65    /// Delete symbols from the symbol table.
66    pub fn elf_delete_symbols(&mut self, names: &HashSet<Vec<u8>>) {
67        for symbol in &mut self.builder.dynamic_symbols {
68            if names.contains(&*symbol.name) {
69                #[cfg(feature = "logging")]
70                info!("Deleting symbol {}", symbol.name);
71                symbol.delete = true;
72                self.modified = true;
73            }
74        }
75    }
76
77    /// Delete symbols from the dynamic symbol table.
78    pub fn elf_delete_dynamic_symbols(&mut self, names: &HashSet<Vec<u8>>) {
79        for symbol in &mut self.builder.symbols {
80            if names.contains(&*symbol.name) {
81                #[cfg(feature = "logging")]
82                info!("Deleting dynamic symbol {}", symbol.name);
83                symbol.delete = true;
84                self.modified = true;
85            }
86        }
87    }
88
89    /// Rename symbols in the symbol table.
90    ///
91    /// The `names` map is from old names to new names.
92    pub fn elf_rename_symbols(&mut self, names: &HashMap<Vec<u8>, Vec<u8>>) {
93        for symbol in &mut self.builder.dynamic_symbols {
94            if let Some(name) = names.get(&*symbol.name) {
95                let name = name.clone().into();
96                #[cfg(feature = "logging")]
97                info!("Renaming symbol {} to {}", symbol.name, name);
98                symbol.name = name;
99                self.modified = true;
100            }
101        }
102    }
103
104    /// Rename symbols in the dynamic symbol table.
105    ///
106    /// The `names` map is from old names to new names.
107    pub fn elf_rename_dynamic_symbols(&mut self, names: &HashMap<Vec<u8>, Vec<u8>>) {
108        for symbol in &mut self.builder.dynamic_symbols {
109            if let Some(name) = names.get(&*symbol.name) {
110                let name = name.clone().into();
111                #[cfg(feature = "logging")]
112                info!("Renaming dynamic symbol {} to {}", symbol.name, name);
113                symbol.name = name;
114                self.modified = true;
115            }
116        }
117    }
118
119    pub(crate) fn elf_delete_sections(&mut self, names: &HashSet<Vec<u8>>) {
120        for section in &mut self.builder.sections {
121            if names.contains(&*section.name) {
122                #[cfg(feature = "logging")]
123                info!("Deleting section {}", section.name);
124                // Associated program header will be deleted by delete_orphan_segments.
125                section.delete = true;
126                self.modified = true;
127            }
128        }
129    }
130
131    pub(crate) fn elf_rename_sections(&mut self, names: &HashMap<Vec<u8>, Vec<u8>>) {
132        for section in &mut self.builder.sections {
133            if let Some(name) = names.get(&*section.name) {
134                let name = name.clone().into();
135                #[cfg(feature = "logging")]
136                info!("Renaming section {} to {}", section.name, name);
137                section.name = name;
138                self.modified = true;
139            }
140        }
141    }
142
143    pub(crate) fn elf_modify(&mut self, options: ElfOptions) -> Result<()> {
144        if options.add_dynamic_debug {
145            self.elf_add_dynamic_debug()?;
146        }
147        if options.delete_runpath {
148            self.elf_delete_runpath()?;
149        }
150        if let Some(path) = options.set_runpath {
151            self.elf_set_runpath(path)?;
152        }
153        if !options.add_runpath.is_empty() {
154            self.elf_add_runpath(&options.add_runpath)?;
155        }
156        if options.use_runpath {
157            self.elf_use_runpath()?;
158        }
159        if options.use_rpath {
160            self.elf_use_rpath()?;
161        }
162        if !options.delete_needed.is_empty() {
163            self.elf_delete_needed(&options.delete_needed)?;
164        }
165        if !options.replace_needed.is_empty() {
166            self.elf_replace_needed(&options.replace_needed)?;
167        }
168        if !options.add_needed.is_empty() {
169            self.elf_add_needed(&options.add_needed)?;
170        }
171        if let Some(name) = options.set_soname {
172            self.elf_set_soname(name)?;
173        }
174        if let Some(interpreter) = options.set_interpreter {
175            self.elf_set_interpreter(interpreter)?;
176        }
177        Ok(())
178    }
179
180    /// Add a `DT_DEBUG` entry to the dynamic section.
181    pub fn elf_add_dynamic_debug(&mut self) -> Result<()> {
182        let dynamic = self
183            .builder
184            .dynamic_data_mut()
185            .ok_or_else(|| Error::modify("No dynamic section found; can't add debug entry"))?;
186        if dynamic.iter().any(|entry| entry.tag() == elf::DT_DEBUG) {
187            return Ok(());
188        }
189
190        #[cfg(feature = "logging")]
191        info!("Adding DT_DEBUG entry");
192        dynamic.push(build::elf::Dynamic::Integer {
193            tag: elf::DT_DEBUG,
194            val: 0,
195        });
196        self.modified = true;
197        Ok(())
198    }
199
200    /// Find the first `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section.
201    pub fn elf_runpath(&self) -> Option<&[u8]> {
202        let dynamic = self.builder.dynamic_data()?;
203        for entry in dynamic.iter() {
204            let build::elf::Dynamic::String { tag, val } = entry else {
205                continue;
206            };
207            if *tag != elf::DT_RPATH && *tag != elf::DT_RUNPATH {
208                continue;
209            }
210            return Some(val);
211        }
212        None
213    }
214
215    /// Delete any `DT_RUNPATH` or `DT_RPATH` entries in the dynamic section.
216    pub fn elf_delete_runpath(&mut self) -> Result<()> {
217        let dynamic = self
218            .builder
219            .dynamic_data_mut()
220            .ok_or_else(|| Error::modify("No dynamic section found; can't delete runpath"))?;
221        let mut modified = false;
222        dynamic.retain(|entry| {
223            let tag = entry.tag();
224            if tag != elf::DT_RPATH && tag != elf::DT_RUNPATH {
225                return true;
226            }
227
228            #[cfg(feature = "logging")]
229            info!(
230                "Deleting {} entry",
231                if tag == elf::DT_RPATH {
232                    "DT_RPATH"
233                } else {
234                    "DT_RUNPATH"
235                }
236            );
237            modified = true;
238            false
239        });
240        if modified {
241            self.modified = true;
242        }
243        Ok(())
244    }
245
246    /// Set the path for any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section.
247    pub fn elf_set_runpath(&mut self, runpath: Vec<u8>) -> Result<()> {
248        let dynamic = self
249            .builder
250            .dynamic_data_mut()
251            .ok_or_else(|| Error::modify("No dynamic section found; can't set runpath"))?;
252        let mut found = false;
253        for entry in dynamic.iter_mut() {
254            let build::elf::Dynamic::String { tag, val } = entry else {
255                continue;
256            };
257            if *tag != elf::DT_RPATH && *tag != elf::DT_RUNPATH {
258                continue;
259            }
260
261            *val = build::ByteString::from(runpath.clone());
262            #[cfg(feature = "logging")]
263            info!(
264                "Setting {} entry to {}",
265                if *tag == elf::DT_RPATH {
266                    "DT_RPATH"
267                } else {
268                    "DT_RUNPATH"
269                },
270                *val
271            );
272            found = true;
273        }
274        if !found {
275            let val = build::ByteString::from(runpath);
276            #[cfg(feature = "logging")]
277            info!("Adding DT_RUNPATH entry {}", val);
278            dynamic.push(build::elf::Dynamic::String {
279                tag: elf::DT_RUNPATH,
280                val,
281            });
282        }
283        self.modified = true;
284        Ok(())
285    }
286
287    /// Add additional paths to any `DT_RUNPATH` or `DT_RPATH` entry in the dynamic section.
288    pub fn elf_add_runpath(&mut self, runpaths: &[Vec<u8>]) -> Result<()> {
289        let dynamic = self
290            .builder
291            .dynamic_data_mut()
292            .ok_or_else(|| Error::modify("No dynamic section found; can't add runpath"))?;
293        let mut found = false;
294        for entry in dynamic.iter_mut() {
295            let build::elf::Dynamic::String { tag, val } = entry else {
296                continue;
297            };
298            if *tag != elf::DT_RPATH && *tag != elf::DT_RUNPATH {
299                continue;
300            }
301
302            for path in runpaths {
303                if !val.is_empty() {
304                    val.to_mut().push(b':');
305                }
306                val.to_mut().extend_from_slice(path);
307            }
308            #[cfg(feature = "logging")]
309            info!(
310                "Changing {} entry to {}",
311                if *tag == elf::DT_RPATH {
312                    "DT_RPATH"
313                } else {
314                    "DT_RUNPATH"
315                },
316                val
317            );
318            found = true;
319        }
320        if !found {
321            let val = runpaths.join(&[b':'][..]).into();
322            #[cfg(feature = "logging")]
323            info!("Adding DT_RUNPATH entry {}", val);
324            dynamic.push(build::elf::Dynamic::String {
325                tag: elf::DT_RUNPATH,
326                val,
327            });
328        }
329        self.modified = true;
330        Ok(())
331    }
332
333    /// Change any `DT_RPATH` entry in the dynamic section to `DT_RUNPATH`.
334    pub fn elf_use_runpath(&mut self) -> Result<()> {
335        let dynamic = self
336            .builder
337            .dynamic_data_mut()
338            .ok_or_else(|| Error::modify("No dynamic section found; can't change runpath"))?;
339        for entry in dynamic.iter_mut() {
340            let build::elf::Dynamic::String { tag, .. } = entry else {
341                continue;
342            };
343            if *tag != elf::DT_RPATH {
344                continue;
345            }
346
347            #[cfg(feature = "logging")]
348            info!("Changing DT_RPATH to DT_RUNPATH");
349            *tag = elf::DT_RUNPATH;
350            self.modified = true;
351        }
352        Ok(())
353    }
354
355    /// Change any `DT_RUNPATH` entry in the dynamic section to `DT_RPATH`.
356    pub fn elf_use_rpath(&mut self) -> Result<()> {
357        let dynamic = self
358            .builder
359            .dynamic_data_mut()
360            .ok_or_else(|| Error::modify("No dynamic section found; can't change rpath"))?;
361        for entry in dynamic.iter_mut() {
362            let build::elf::Dynamic::String { tag, .. } = entry else {
363                continue;
364            };
365            if *tag != elf::DT_RUNPATH {
366                continue;
367            }
368
369            #[cfg(feature = "logging")]
370            info!("Changing DT_RUNPATH to DT_RPATH");
371            *tag = elf::DT_RPATH;
372            self.modified = true;
373        }
374        Ok(())
375    }
376
377    /// Find the `DT_NEEDED` entries in the dynamic section.
378    pub fn elf_needed(&self) -> impl Iterator<Item = &[u8]> {
379        let dynamic = self.builder.dynamic_data().unwrap_or(&[]);
380        dynamic.iter().filter_map(|entry| {
381            if let build::elf::Dynamic::String { tag, val } = entry {
382                if *tag == elf::DT_NEEDED {
383                    return Some(val.as_slice());
384                }
385            }
386            None
387        })
388    }
389
390    /// Delete `DT_NEEDED` entries from the dynamic section.
391    pub fn elf_delete_needed(&mut self, names: &HashSet<Vec<u8>>) -> Result<()> {
392        let dynamic = self.builder.dynamic_data_mut().ok_or_else(|| {
393            Error::modify("No dynamic section found; can't delete needed library")
394        })?;
395        let mut modified = false;
396        dynamic.retain(|entry| {
397            let build::elf::Dynamic::String { tag, val } = entry else {
398                return true;
399            };
400            if *tag != elf::DT_NEEDED || !names.contains(val.as_slice()) {
401                return true;
402            }
403
404            #[cfg(feature = "logging")]
405            info!("Deleting DT_NEEDED entry {}", val);
406            modified = true;
407            false
408        });
409        if modified {
410            self.modified = true;
411        }
412        Ok(())
413    }
414
415    /// Replace `DT_NEEDED` entries in the dynamic section.
416    pub fn elf_replace_needed(&mut self, names: &HashMap<Vec<u8>, Vec<u8>>) -> Result<()> {
417        let dynamic = self.builder.dynamic_data_mut().ok_or_else(|| {
418            Error::modify("No dynamic section found; can't replace needed library")
419        })?;
420        for entry in dynamic.iter_mut() {
421            let build::elf::Dynamic::String { tag, val } = entry else {
422                continue;
423            };
424            if *tag != elf::DT_NEEDED {
425                continue;
426            }
427            let Some(name) = names.get(val.as_slice()) else {
428                continue;
429            };
430
431            let name = name.clone().into();
432            #[cfg(feature = "logging")]
433            info!("Replacing DT_NEEDED entry {} with {}", val, name);
434            *val = name;
435            self.modified = true;
436        }
437        Ok(())
438    }
439
440    /// Add `DT_NEEDED` entries to the start of the dynamic section.
441    ///
442    /// This does not add a `DT_NEEDED` entry if the library is already listed.
443    pub fn elf_add_needed(&mut self, names: &[Vec<u8>]) -> Result<()> {
444        let dynamic = self
445            .builder
446            .dynamic_data_mut()
447            .ok_or_else(|| Error::modify("No dynamic section found; can't add needed library"))?;
448        let mut found = HashSet::new();
449        for entry in dynamic.iter() {
450            let build::elf::Dynamic::String { tag, val } = entry else {
451                continue;
452            };
453            if *tag != elf::DT_NEEDED {
454                continue;
455            }
456            found.insert(val.clone());
457        }
458        for name in names
459            .iter()
460            .rev()
461            .filter(|name| !found.contains(name.as_slice()))
462        {
463            let val = name.clone().into();
464            #[cfg(feature = "logging")]
465            info!("Adding DT_NEEDED entry {}", val);
466            dynamic.insert(
467                0,
468                build::elf::Dynamic::String {
469                    tag: elf::DT_NEEDED,
470                    val,
471                },
472            );
473            self.modified = true;
474        }
475        Ok(())
476    }
477
478    /// Find the `DT_SONAME` entry in the dynamic section.
479    pub fn elf_soname(&self) -> Option<&[u8]> {
480        let id = self.builder.dynamic_section()?;
481        let section = self.builder.sections.get(id);
482        let build::elf::SectionData::Dynamic(dynamic) = &section.data else {
483            return None;
484        };
485        for entry in dynamic.iter() {
486            let build::elf::Dynamic::String { tag, val } = entry else {
487                continue;
488            };
489            if *tag != elf::DT_SONAME {
490                continue;
491            }
492
493            return Some(val);
494        }
495        None
496    }
497
498    /// Set the `DT_SONAME` entry in the dynamic section.
499    pub fn elf_set_soname(&mut self, soname: Vec<u8>) -> Result<()> {
500        let dynamic = self
501            .builder
502            .dynamic_data_mut()
503            .ok_or_else(|| Error::modify("No dynamic section found; can't set soname"))?;
504        let mut found = false;
505        for entry in dynamic.iter_mut() {
506            let build::elf::Dynamic::String { tag, val } = entry else {
507                continue;
508            };
509            if *tag != elf::DT_SONAME {
510                continue;
511            }
512
513            *val = soname.clone().into();
514            #[cfg(feature = "logging")]
515            info!("Setting DT_SONAME entry to {}", val);
516            found = true;
517        }
518        if !found {
519            let val = soname.into();
520            #[cfg(feature = "logging")]
521            info!("Adding DT_SONAME entry {}", val);
522            dynamic.push(build::elf::Dynamic::String {
523                tag: elf::DT_SONAME,
524                val,
525            });
526        }
527        self.modified = true;
528        Ok(())
529    }
530
531    /// Find the interpreter path in the `PT_INTERP` segment.
532    pub fn elf_interpreter(&self) -> Option<&[u8]> {
533        self.builder.interp_data()
534    }
535
536    /// Set the interpreter path in the `PT_INTERP` segment.
537    ///
538    /// The null terminator is automatically added if needed.
539    pub fn elf_set_interpreter(&mut self, mut interpreter: Vec<u8>) -> Result<()> {
540        let data = self
541            .builder
542            .interp_data_mut()
543            .ok_or_else(|| Error::modify("No interp section found; can't set interpreter"))?;
544        #[cfg(feature = "logging")]
545        info!(
546            "Setting interpreter to {}",
547            build::ByteString::from(interpreter.as_slice())
548        );
549        if !interpreter.is_empty() && interpreter.last() != Some(&0) {
550            interpreter.push(0);
551        }
552        *data = interpreter.into();
553        self.modified = true;
554        Ok(())
555    }
556
557    pub(crate) fn elf_finalize(&mut self) -> Result<()> {
558        if self.modified {
559            move_sections(&mut self.builder)?;
560        }
561        Ok(())
562    }
563}
564
565enum BlockKind {
566    FileHeader,
567    ProgramHeaders,
568    Segment,
569    Section(build::elf::SectionId),
570}
571
572struct Block<'a> {
573    #[allow(dead_code)]
574    name: build::ByteString<'a>,
575    kind: BlockKind,
576    address: u64,
577    size: u64,
578    // Higher means better to move. 0 means never move.
579    move_priority: u8,
580}
581
582/// Move sections between segments if needed, and assign file offsets to segments and sections.
583///
584/// Does not change the size of existing `PT_LOAD` segments, but may add new segments.
585// TODO: allow changing size of existing `PT_LOAD` segments
586fn move_sections(builder: &mut build::elf::Builder) -> Result<()> {
587    builder.delete_orphans();
588    builder.delete_unused_versions();
589    builder.set_section_sizes();
590
591    let mut added_p_flags = Vec::new();
592    let mut added_segments = 0;
593
594    // Loop until we reach a fixed point for the number of additional segments needed.
595    loop {
596        let mut move_sections = find_move_sections(builder, added_segments)?;
597        if move_sections.is_empty() {
598            return Ok(());
599        }
600
601        // Calculate the number of additional PT_LOAD segments needed.
602        added_p_flags.clear();
603        for id in &move_sections {
604            let section = builder.sections.get_mut(*id);
605            // Flag the section as needing to move.
606            section.sh_offset = 0;
607            // We need one PT_LOAD segment for each unique combination of p_flags.
608            let p_flags = section.p_flags();
609            if !added_p_flags.contains(&p_flags) {
610                added_p_flags.push(p_flags);
611            }
612        }
613
614        // If moving a section that is part of a non-PT_LOAD segment, then we may need to
615        // split the segment, which will require an additional segment.
616        let mut split_segments = 0;
617        for segment in &mut builder.segments {
618            if segment.p_type == elf::PT_LOAD {
619                continue;
620            }
621            let mut any = false;
622            let mut all = true;
623            for id in &segment.sections {
624                if move_sections.contains(id) {
625                    any = true;
626                } else {
627                    all = false;
628                }
629            }
630            if !any || all {
631                continue;
632            }
633            split_segments += 1;
634        }
635
636        // Check if we have reached a fixed point for the number of additional segments needed.
637        if added_segments < split_segments + added_p_flags.len() {
638            added_segments = split_segments + added_p_flags.len();
639            continue;
640        }
641
642        #[cfg(feature = "logging")]
643        info!(
644            "Moving {} sections, adding {} PT_LOAD segments, splitting {} segments",
645            move_sections.len(),
646            added_p_flags.len(),
647            split_segments,
648        );
649
650        // Add the PT_LOAD segments and append sections to them.
651        // Try to keep the same order of sections in the new segments.
652        move_sections.sort_by_key(|id| {
653            let section = builder.sections.get(*id);
654            (section.sh_addr, section.sh_size)
655        });
656        for p_flags in added_p_flags {
657            // TODO: reuse segments that only contain movable sections
658            let segment = builder
659                .segments
660                .add_load_segment(p_flags, builder.load_align);
661            for id in &move_sections {
662                let section = builder.sections.get_mut(*id);
663                if p_flags == section.p_flags() {
664                    segment.append_section(section);
665                    #[cfg(feature = "logging")]
666                    info!(
667                        "Moved {} to offset {:x}, addr {:x}",
668                        section.name, section.sh_offset, section.sh_addr
669                    );
670                }
671            }
672            #[cfg(feature = "logging")]
673            info!(
674                "Added PT_LOAD segment with p_flags {:x}, offset {:x}, addr {:x}, size {:x}",
675                p_flags, segment.p_offset, segment.p_vaddr, segment.p_memsz,
676            );
677        }
678
679        // Split or move non-PT_LOAD segments that contain sections that have been moved.
680        let sections = &builder.sections;
681        let mut split_segments = Vec::new();
682        for segment in &mut builder.segments {
683            if segment.p_type == elf::PT_LOAD {
684                continue;
685            }
686
687            let mut any = false;
688            let mut all = true;
689            for id in &segment.sections {
690                if move_sections.contains(id) {
691                    any = true;
692                } else {
693                    all = false;
694                }
695            }
696            if !any {
697                continue;
698            }
699            if !all {
700                // Segment needs splitting.
701                // Remove all the sections that have been moved, and store them so
702                // that we can add the new segment later.
703                let mut split_sections = Vec::new();
704                segment.sections.retain(|id| {
705                    if move_sections.contains(id) {
706                        split_sections.push(*id);
707                        false
708                    } else {
709                        true
710                    }
711                });
712                split_segments.push((segment.id(), split_sections));
713            }
714
715            // The remaining sections have already been assigned an address.
716            // Recalcuate the file and address ranges for the segment.
717            // TODO: verify that the sections are contiguous. If not, try to slide the sections
718            // down in memory.
719            segment.recalculate_ranges(sections);
720        }
721
722        // Add new segments due to splitting.
723        for (segment_id, split_sections) in split_segments {
724            let segment = builder.segments.copy(segment_id);
725            for id in split_sections {
726                let section = builder.sections.get_mut(id);
727                segment.append_section(section);
728            }
729            #[cfg(feature = "logging")]
730            info!(
731                "Split segment with type {:x}, offset {:x}, addr {:x}, size {:x}",
732                segment.p_type, segment.p_offset, segment.p_vaddr, segment.p_memsz,
733            );
734        }
735
736        // Update the PT_PHDR segment to include the new program headers.
737        let size = builder.program_headers_size() as u64;
738        for segment in &mut builder.segments {
739            if segment.p_type != elf::PT_PHDR {
740                continue;
741            }
742            segment.p_filesz = size;
743            segment.p_memsz = size;
744        }
745        return Ok(());
746    }
747}
748
749fn find_move_sections(
750    builder: &build::elf::Builder,
751    added_segments: usize,
752) -> Result<Vec<build::elf::SectionId>> {
753    use build::elf::SectionData;
754
755    let mut move_sections = Vec::new();
756    let mut blocks = Vec::new();
757    let file_header_size = builder.file_header_size() as u64;
758    let program_headers_size = (builder.program_headers_size()
759        + added_segments * builder.class().program_header_size())
760        as u64;
761    let interp = builder.interp_section();
762
763    if let Some(segment) = builder.segments.find_load_segment_from_offset(0) {
764        let address = segment.address_from_offset(0);
765        blocks.push(Block {
766            name: "file header".into(),
767            kind: BlockKind::FileHeader,
768            address,
769            size: file_header_size,
770            move_priority: 0,
771        });
772    }
773    if let Some(segment) = builder
774        .segments
775        .find_load_segment_from_offset(builder.header.e_phoff)
776    {
777        let address = segment.address_from_offset(builder.header.e_phoff);
778        blocks.push(Block {
779            name: "program headers".into(),
780            kind: BlockKind::ProgramHeaders,
781            address,
782            size: program_headers_size,
783            move_priority: 0,
784        });
785    }
786    for segment in &builder.segments {
787        if segment.p_type != elf::PT_LOAD {
788            continue;
789        }
790        // Add zero-sized blocks at the start and end of the segment
791        // to prevent changing the segment address or size.
792        blocks.push(Block {
793            name: "segment start".into(),
794            kind: BlockKind::Segment,
795            address: segment.p_vaddr,
796            size: 0,
797            move_priority: 0,
798        });
799        blocks.push(Block {
800            name: "segment end".into(),
801            kind: BlockKind::Segment,
802            address: segment.p_vaddr + segment.p_memsz,
803            size: 0,
804            move_priority: 0,
805        });
806    }
807    for section in &builder.sections {
808        if !section.is_alloc() {
809            continue;
810        }
811        if section.sh_offset == 0 {
812            // Newly added section that needs to be assigned to a segment,
813            // or a section that has already been flagged for moving.
814            move_sections.push(section.id());
815            continue;
816        }
817        if section.sh_type == elf::SHT_NOBITS && section.sh_flags & u64::from(elf::SHF_TLS) != 0 {
818            // Uninitialized TLS sections are not part of the address space.
819            continue;
820        }
821        let move_priority = match &section.data {
822            // Can't move sections whose address may referenced from
823            // a section that we can't rewrite.
824            SectionData::Data(_) => {
825                if Some(section.id()) == interp {
826                    1
827                } else {
828                    0
829                }
830            }
831            SectionData::UninitializedData(_) | SectionData::Dynamic(_) => 0,
832            // TODO: Can be referenced by dynamic entries, but we don't support that yet.
833            SectionData::DynamicRelocation(_) => 0,
834            // None of these can be referenced by address that I am aware of.
835            SectionData::Relocation(_)
836            | SectionData::Note(_)
837            | SectionData::Attributes(_)
838            | SectionData::SectionString
839            | SectionData::Symbol
840            | SectionData::SymbolSectionIndex
841            | SectionData::String
842            | SectionData::DynamicSymbol
843            | SectionData::DynamicString
844            | SectionData::Hash
845            | SectionData::GnuHash
846            | SectionData::GnuVersym
847            | SectionData::GnuVerdef
848            | SectionData::GnuVerneed => 2,
849        };
850        blocks.push(Block {
851            name: (*section.name).into(),
852            kind: BlockKind::Section(section.id()),
853            address: section.sh_addr,
854            size: section.sh_size,
855            move_priority,
856        });
857    }
858    blocks.sort_by_key(|block| (block.address, block.size));
859
860    // For each pair of overlapping blocks, decide which one to move.
861    let mut i = 0;
862    while i + 1 < blocks.len() {
863        let end_address = blocks[i].address + blocks[i].size;
864        if end_address <= blocks[i + 1].address {
865            i += 1;
866            continue;
867        }
868        // Prefer moving the earlier block, since it is the reason for the overlap.
869        if blocks[i].move_priority >= blocks[i + 1].move_priority {
870            if blocks[i].move_priority == 0 {
871                #[cfg(feature = "logging")]
872                info!(
873                    "Immovable {} (end address {:x}) overlaps immovable {} (start address {:x})",
874                    blocks[i].name,
875                    end_address,
876                    blocks[i + 1].name,
877                    blocks[i + 1].address,
878                );
879                return Err(Error::modify("Overlapping immovable sections"));
880            }
881            #[cfg(feature = "logging")]
882            info!(
883                "Need to move {} (end address {:x}) because of {} (start address {:x})",
884                blocks[i].name,
885                end_address,
886                blocks[i + 1].name,
887                blocks[i + 1].address,
888            );
889            if let BlockKind::Section(section) = blocks[i].kind {
890                move_sections.push(section);
891                blocks.remove(i);
892            } else {
893                // Only sections can be moved.
894                unreachable!();
895            }
896        } else {
897            #[cfg(feature = "logging")]
898            info!(
899                "Need to move {} (start address {:x}) because of {} (end address {:x})",
900                blocks[i + 1].name,
901                blocks[i + 1].address,
902                blocks[i].name,
903                end_address,
904            );
905            if let BlockKind::Section(section) = blocks[i + 1].kind {
906                move_sections.push(section);
907                blocks.remove(i + 1);
908            } else {
909                // Only sections can be moved.
910                unreachable!();
911            }
912        }
913    }
914    Ok(move_sections)
915}