1
2use header::Header;
3use types;
4use error::Error;
5use section::*;
6use segment::*;
7use symbol;
8use section;
9use segment;
10
11use indexmap::{IndexMap};
12use std::collections::hash_map::{HashMap};
13use std::io::{Read, Seek, SeekFrom, Write};
14use std;
15use std::iter::FromIterator;
16
17#[derive(Default)]
18pub struct Elf {
19    pub header: Header,
20    pub segments: Vec<SegmentHeader>,
21    pub sections: Vec<Section>,
22}
23
24impl Elf {
25    pub fn from_header(header: Header) -> Self {
26        Self {
27            header:     header,
28            segments:   Vec::new(),
29            sections:   Vec::new(),
30        }
31    }
32
33    pub fn from_reader<R>(io: &mut R) -> Result<Elf, Error>
34    where
35        R: Read + Seek,
36    {
37        let header = Header::from_reader(io)?;
38
39        let mut segments = Vec::with_capacity(header.phnum as usize);
41        io.seek(SeekFrom::Start(header.phoff))?;
42        let mut buf = vec![0; header.phentsize as usize * header.phnum as usize];
43        {
44            io.read_exact(&mut buf)?;
45            let mut bio = buf.as_slice();
46            for _ in 0..header.phnum {
47                let segment = SegmentHeader::from_reader(&mut bio, &header)?;
48                segments.push(segment);
49            }
50        }
51
52        let mut sections = Vec::with_capacity(header.shnum as usize);
54        io.seek(SeekFrom::Start(header.shoff))?;
55        buf.resize(header.shnum as usize * header.shentsize as usize,0);
56        {
57            io.read_exact(&mut buf)?;
58            let mut bio = buf.as_slice();
59            for _ in 0..header.shnum {
60                let sh = SectionHeader::from_reader(&mut bio, &header)?;
61
62                sections.push(Section{
63                    name:       Vec::with_capacity(0),
64                    content:    SectionContent::Unloaded,
65                    header:     sh,
66                    addrlock:   true,
67                });
68            }
69        }
70
71        let shstrtab = match sections.get(header.shstrndx as usize) {
73            None => return Err(Error::MissingShstrtabSection),
74            Some(sec) => {
75                io.seek(SeekFrom::Start(sec.header.offset))?;
76                let mut shstrtab = vec![0;sec.header.size as usize];
77                io.read_exact(&mut shstrtab)?;
78                shstrtab
79            },
80        };
81
82        for ref mut sec in &mut sections {
83            sec.name = shstrtab[sec.header.name as usize..]
84                .split(|e| *e == 0)
85                .next()
86                .unwrap_or(&[0; 0])
87                .to_vec();
88        }
89
90        Ok(Elf{
91            header:     header,
92            segments:   segments,
93            sections:   sections,
94        })
95    }
96
97    pub fn load<R> (&mut self, i: usize, io: &mut R) -> Result<(), Error>
98        where
99        R: Read + Seek,
100    {
101        let mut sec = std::mem::replace(&mut self.sections[i], Section::default());
102        {
103            let link = sec.header.link.clone();
104            let linked = {
105                if link < 1 || link as usize >= self.sections.len() {
106                    None
107                } else {
108                    self.load(link as usize, io)?;
109                    Some(&self.sections[link as usize])
110                }
111            };
112            sec.from_reader(io, linked, &self.header)?;
113        }
114        self.sections[i] = sec;
115
116        Ok(())
117    }
118
119    pub fn load_all<R> (&mut self, io: &mut R) -> Result<(), Error>
120        where
121        R: Read + Seek,
122    {
123        for i in 0..self.sections.len() {
124            self.load(i, io)?;
125        }
126        Ok(())
127    }
128
129    pub fn sync_all(&mut self) -> Result<(), Error> {
132        match self.sections.iter().position(|s| s.name == b".shstrtab") {
133            Some(i) => {
134                self.header.shstrndx = i as u16;
135                let mut shstrtab = std::mem::replace(
136                    &mut self.sections[self.header.shstrndx as usize].content,
137                    SectionContent::default(),
138                );
139
140                for sec in &mut self.sections {
141                    sec.header.name = shstrtab
142                        .as_strtab_mut()
143                        .unwrap()
144                        .insert(&sec.name)
145                        as u32;
146                }
147                self.sections[self.header.shstrndx as usize].content = shstrtab;
148            }
149            None => {}
150        };
151
152
153        let mut dirty: Vec<usize> = (0..self.sections.len()).collect();
154        while dirty.len() > 0 {
155            for i in std::mem::replace(&mut dirty, Vec::new()).iter() {
156                let mut sec = std::mem::replace(&mut self.sections[*i], Section::default());
158                {
159                    let linked = {
160                        if sec.header.link < 1 || sec.header.link as usize >= self.sections.len() {
161                            None
162                        } else {
163                            dirty.push(sec.header.link as usize);
164                            Some(&mut self.sections[sec.header.link as usize].content)
165                        }
166                    };
167                    sec.sync(&self.header, linked)?;
168                }
169
170                self.sections[*i] = sec;
172            }
173        }
174
175        Ok(())
176    }
177
178    pub fn to_writer<R>(&mut self, mut io: R) -> Result<(), Error>
179    where
180        R: Write + Seek,
181    {
182        io.seek(SeekFrom::Start(0))?;
183        let off = self.header.size();
184        io.write(&vec![0; off])?;
185
186        if self.segments.len() > 0 {
190            self.header.phoff = off as u64;
191            for seg in &self.segments {
192                seg.to_writer(&self.header, &mut io)?;
193            }
194            let at = io.seek(SeekFrom::Current(0))? as usize;
195            self.header.phnum = self.segments.len() as u16;
196            self.header.phentsize = ((at - off) / self.segments.len()) as u16;
197        }
198
199        let headers: Vec<SectionHeader> = self.sections.iter().map(|s| s.header.clone()).collect();
200        let mut sections = std::mem::replace(&mut self.sections, Vec::new());
201
202        sections.sort_unstable_by(|a, b| a.header.offset.cmp(&b.header.offset));
204        for sec in sections {
205            assert_eq!(
206                io.seek(SeekFrom::Start(sec.header.offset))?,
207                sec.header.offset
208            );
209
210            sec.to_writer(&mut io, &self.header)?;
211        }
212
213
214        if self.header.shstrndx > 0 {
216            self.header.shoff = io.seek(SeekFrom::End(0))?;
217            let alignment = if self.header.ident_class == types::Class::Class64 { 8 } else { 4 };
218            let oa = self.header.shoff % alignment;
219            if oa != 0 {
220                self.header.shoff += alignment - oa;
221                io.seek(SeekFrom::Start(self.header.shoff))?;
222            }
223            for sec in &headers {
224                sec.to_writer(&self.header, &mut io)?;
225            }
226            self.header.shnum = headers.len() as u16;
227            self.header.shentsize = SectionHeader::entsize(&self.header) as u16;
228        }
229
230        self.header.ehsize = self.header.size() as u16;
232
233        io.seek(SeekFrom::Start(0))?;
234        self.header.to_writer(&mut io)?;
235
236        Ok(())
237    }
238
239    pub fn make_symtab_gnuld_compat(&mut self) -> Result<(), Error> {
245        for i in 0..self.sections.len() {
246            if self.sections[i].header.shtype == types::SectionType::SYMTAB {
247                self._make_symtab_gnuld_compat(i);
248            }
249        }
250        self.sync_all()
251    }
252
253    fn _make_symtab_gnuld_compat(&mut self, shndx: usize) {
254
255        let mut original_size = self.sections[shndx].content.as_symbols().unwrap().len();
256
257        let mut symtab_sec = HashMap::new();
258        let mut symtab_remap = Vec::new();
262        for (i, link)  in self.sections[shndx].content.as_symbols_mut().unwrap().drain(..).enumerate() {
263            if link.stype == types::SymbolType::SECTION {
264                symtab_sec.insert(i, link);
265            } else {
266                symtab_remap.push((i, link));
267            }
268        }
269
270        let mut symtab_gs = Vec::new();
271        let mut symtab_ls = Vec::new();
272        for (oi,sym) in symtab_remap {
273            if sym.bind == types::SymbolBind::GLOBAL {
274                symtab_gs.push((oi, sym));
275            } else {
276                symtab_ls.push((oi, sym));
277            }
278        }
279        symtab_gs.sort_unstable_by(|a,b|{
280            a.1.value.cmp(&b.1.value)
281        });
282
283
284        symtab_ls.insert(0, (original_size, symbol::Symbol::default()));
285        original_size += 1;
286
287        let mut nu_sec_syms = vec![0];
288        for i in 1..self.sections.len() {
289            symtab_ls.insert(i, (original_size, symbol::Symbol{
290                shndx:  symbol::SymbolSectionIndex::Section(i as u16),
291                value:  0,
292                size:   0,
293                name:   Vec::new(),
294                stype:  types::SymbolType::SECTION,
295                bind:   types::SymbolBind::LOCAL,
296                vis:    types::SymbolVis::DEFAULT,
297                _name:  0,
298            }));
299            nu_sec_syms.push(original_size);
300            original_size += 1;
301        }
302
303        symtab_ls.push((original_size, symbol::Symbol{
304            shndx:  symbol::SymbolSectionIndex::Absolute,
305            value:  0,
306            size:   0,
307            name:   Vec::new(),
308            stype:  types::SymbolType::FILE,
309            bind:   types::SymbolBind::LOCAL,
310            vis:    types::SymbolVis::DEFAULT,
311            _name:  0,
312        }));
313        let symtab_remap : IndexMap<usize, symbol::Symbol>
317            = IndexMap::from_iter(symtab_ls.into_iter().chain(symtab_gs.into_iter()));
318
319        for sec in &mut self.sections {
320            match sec.header.shtype {
321                types::SectionType::RELA => {
322                    if sec.header.link != shndx as u32{
323                        continue;
324                    }
325                    for reloc in sec.content.as_relocations_mut().unwrap().iter_mut() {
326                        if let Some(secsym) = symtab_sec.get(&(reloc.sym as usize)) {
327                            if let symbol::SymbolSectionIndex::Section(so) = secsym.shndx {
328                                reloc.addend += secsym.value as i64;
329                                reloc.sym     = nu_sec_syms[so as usize] as u32;
330                            } else {
331                                unreachable!();
332                            }
333                        }
334
335                        reloc.sym = symtab_remap.get_full(&(reloc.sym as usize))
336                            .expect("bug in elfkit: dangling reloc").0 as u32;
337                    }
338                },
339                _ => {},
340            }
341        }
342
343        self.sections[shndx].content = section::SectionContent::Symbols(
344            symtab_remap.into_iter().map(|(_,v)|v).collect());
345    }
346
347
348    pub fn reorder(self: &mut Elf) -> Result<HashMap<usize,usize>, Error> {
351
352        let mut reorder = Vec::new();
353        loop {
354            let shndx = self.sections.len() - 1;
355            if shndx < 1 || self.sections[shndx].addrlock {
356                break;
357            }
358            reorder.push((shndx, self.sections.pop().unwrap()));
359        }
360
361
362        reorder.sort_by(|&(_,ref s1),&(_,ref s2)|{
363            if s1.header.shtype != s2.header.shtype {
364                if s1.header.shtype == types::SectionType::NOBITS {
365                    return std::cmp::Ordering::Greater;
366                }
367            }
368
369            let s1_a = s1.header.flags.contains(types::SectionFlags::ALLOC);
370            let s1_w = s1.header.flags.contains(types::SectionFlags::WRITE);
371            let s2_a = s2.header.flags.contains(types::SectionFlags::ALLOC);
372            let s2_w = s2.header.flags.contains(types::SectionFlags::WRITE);
373
374            if s1_a != s2_a {
375                if s1_a {
376                    return std::cmp::Ordering::Less;
377                } else {
378                    return std::cmp::Ordering::Greater;
379                }
380            }
381            if s1_w != s2_w {
382                if s1_w {
383                    return std::cmp::Ordering::Greater;
384                } else {
385                    return std::cmp::Ordering::Less;
386                }
387            }
388
389            if s1.header.shtype != s2.header.shtype  {
390                return s1.header.shtype.to_u32().cmp(&s2.header.shtype.to_u32());
391            }
392
393            s1.name.cmp(&s2.name)
396        });
397
398        let mut remap = HashMap::new();
399        for (i,sec) in reorder {
400            remap.insert(i, self.sections.len());
401            self.sections.push(sec);
402        }
403
404        for sec in &mut self.sections {
405            if let Some(v) = remap.get(&(sec.header.link as usize)) {
406                sec.header.link = *v as u32;
407            }
408            if sec.header.flags.contains(types::SectionFlags::INFO_LINK) {
409                if let Some(v) = remap.get(&(sec.header.info as usize)) {
410                    sec.header.info = *v as u32;
411                }
412            }
413        }
414
415        Ok(remap)
416    }
417
418    pub fn layout(self: &mut Elf) -> Result<(), Error> {
419        self.sync_all()?;
420
421        let dbg_old_segments_count = self.segments.len();
422
423        self.segments.clear();
424
425        trace!("start of Elf::layout segmentation");
426
427        let mut current_load_segment_flags = types::SegmentFlags::READABLE;
428        let mut current_load_segment_poff = 0;
429        let mut current_load_segment_voff = 0;
430        let mut current_load_segment_pstart = 0;
431        let mut current_load_segment_vstart = 0;
432
433        let mut poff = 0;
434        let mut voff = poff;
435
436        let mut dbg_old_addresses = vec![self.sections[0].header.addr];
437
438        trace!("    name     \tsize\tpoff\tvoff\tpstart\tvstart\tflags");
439        for (shndx, sec)  in self.sections.iter_mut().enumerate().skip(1) {
440            dbg_old_addresses.push(sec.header.addr);
441
442            trace!(" > {:<10.10}\t{}\t{}\t{}\t{}\t{}\t{:?}",
443                     String::from_utf8_lossy(&sec.name), sec.header.size, poff, voff,
444                     current_load_segment_pstart,
445                     current_load_segment_vstart,
446                     current_load_segment_flags);
447
448            if sec.header.addralign > 0 {
449                let oa = poff % sec.header.addralign;
450                if oa != 0 {
451                    poff += sec.header.addralign - oa;
452                    voff += sec.header.addralign - oa;
453                }
454                trace!("   ^ realigned for {} to voff 0x{:x}", sec.header.addralign, voff);
455            }
456
457            if sec.header.shtype != types::SectionType::NOBITS {
458                if poff > voff {
459                    panic!("elfkit: relayout: poff>voff 0x{:x}>0x{:x} in {}.", poff, voff,
460                           String::from_utf8_lossy(&sec.name));
461                }
462                if (voff - poff) % 0x200000 != 0 {
463                    trace!("   ^ causes segmentation by load alignment");
464                    if sec.header.flags.contains(types::SectionFlags::EXECINSTR) {
465                        current_load_segment_flags.insert(types::SegmentFlags::EXECUTABLE);
466                    }
467                    if sec.header.flags.contains(types::SectionFlags::WRITE) {
468                        current_load_segment_flags.insert(types::SegmentFlags::WRITABLE);
469                    }
470                    self.segments.push(segment::SegmentHeader {
471                        phtype: types::SegmentType::LOAD,
472                        flags:  current_load_segment_flags,
473                        offset: current_load_segment_pstart,
474                        filesz: current_load_segment_poff - current_load_segment_pstart,
475                        vaddr:  current_load_segment_vstart,
476                        paddr:  current_load_segment_vstart,
477                        memsz:  current_load_segment_voff - current_load_segment_vstart,
478                        align:  0x200000,
479                    });
480
481                    voff += 0x200000 - ((voff - poff) % 0x200000);
482
483                    current_load_segment_pstart = poff;
484                    current_load_segment_vstart = voff;
485                    current_load_segment_flags = types::SegmentFlags::READABLE;
486                }
487            }
488
489
490            if sec.header.flags.contains(types::SectionFlags::ALLOC) {
491                if sec.header.flags.contains(types::SectionFlags::EXECINSTR) {
493                    current_load_segment_flags.insert(types::SegmentFlags::EXECUTABLE);
494                } else {}
495
496                if sec.header.flags.contains(types::SectionFlags::WRITE) !=
498                current_load_segment_flags.contains(types::SegmentFlags::WRITABLE) {
499                    if current_load_segment_voff >  current_load_segment_vstart || shndx == 1 {
500                        self.segments.push(segment::SegmentHeader {
502                            phtype: types::SegmentType::LOAD,
503                            flags:  current_load_segment_flags,
504                            offset: current_load_segment_pstart,
505                            filesz: current_load_segment_poff - current_load_segment_pstart,
506                            vaddr:  current_load_segment_vstart,
507                            paddr:  current_load_segment_vstart,
508                            memsz:  current_load_segment_voff - current_load_segment_vstart,
509                            align:  0x200000,
510                        });
511                        voff += 0x200000 - ((voff - poff) % 0x200000);
512                        current_load_segment_pstart = poff;
513                        current_load_segment_vstart = voff;
514                        current_load_segment_flags = types::SegmentFlags::READABLE;
515                    } else {
516                        trace!("   ^ segmentation protection change supressed because it would be empty \
517                                 voff {} <= vstart {}",
518                                 current_load_segment_voff, current_load_segment_vstart);
519                    }
520
521                    if sec.header.flags.contains(types::SectionFlags::WRITE) {
522                        current_load_segment_flags.insert(types::SegmentFlags::WRITABLE);
523                    } else {
524                        current_load_segment_flags.remove(types::SegmentFlags::WRITABLE);
525                    }
526                }
527            }
528
529
530            sec.header.offset = poff;
531            poff += sec.size(&self.header) as u64;
532
533            sec.header.addr = voff;
534            voff += sec.header.size;
535            trace!("   = final addr 0x{:x}", sec.header.addr);
536
537            if sec.header.flags.contains(types::SectionFlags::ALLOC) {
538                current_load_segment_poff = poff;
539                current_load_segment_voff = voff;
540
541                if sec.header.flags.contains(types::SectionFlags::TLS) {
542                    self.segments.push(segment::SegmentHeader {
543                        phtype: types::SegmentType::TLS,
544                        flags:  current_load_segment_flags,
545                        offset: sec.header.offset,
546                        filesz: sec.header.size,
547                        vaddr:  sec.header.addr,
548                        paddr:  sec.header.addr,
549                        memsz:  sec.header.size,
550                        align:  sec.header.addralign,
551                    });
552                }
553
554                match sec.name.as_slice() {
555                    b".dynamic" => {
556                        self.segments.push(segment::SegmentHeader {
557                            phtype: types::SegmentType::DYNAMIC,
558                            flags: types::SegmentFlags::READABLE | types::SegmentFlags::WRITABLE,
559                            offset: sec.header.offset,
560                            filesz: sec.header.size,
561                            vaddr: sec.header.addr,
562                            paddr: sec.header.addr,
563                            memsz: sec.header.size,
564                            align: 0x8,
565                        });
566                    }
567                    b".interp" => {
568                        self.segments.push(segment::SegmentHeader {
569                            phtype: types::SegmentType::INTERP,
570                            flags: types::SegmentFlags::READABLE,
571                            offset: sec.header.offset,
572                            filesz: sec.header.size,
573                            vaddr: sec.header.addr,
574                            paddr: sec.header.addr,
575                            memsz: sec.header.size,
576                            align: 0x1,
577                        });
578                    }
579                    _ => {}
580                }
581
582            }
583        }
584        if current_load_segment_voff >  current_load_segment_vstart {
585            trace!("   > segmentation caused by end of sections");
586            self.segments.push(segment::SegmentHeader {
587                phtype: types::SegmentType::LOAD,
588                flags:  current_load_segment_flags,
589                offset: current_load_segment_pstart,
590                filesz: current_load_segment_poff - current_load_segment_pstart,
591                vaddr:  current_load_segment_vstart,
592                paddr:  current_load_segment_vstart,
593                memsz:  current_load_segment_voff - current_load_segment_vstart,
594                align:  0x200000,
595            });
596        }
597
598
599        self.header.phnum     = self.segments.len() as u16 + 1;
600        self.header.phentsize = segment::SegmentHeader::entsize(&self.header) as u16;
601        self.header.phoff     = self.header.size() as u64;
602
603        self.header.ehsize    = self.header.size() as u16;
604        let mut hoff = (self.header.phnum as u64 * self.header.phentsize as u64) + self.header.ehsize as u64;
605
606        for sec in &mut self.sections[1..] {
609            if sec.header.addralign > 0 {
610                let oa = hoff % sec.header.addralign;
611                if oa != 0 {
612                    hoff += sec.header.addralign - oa;
613                }
614            }
615        }
616        for sec in &mut self.sections[1..] {
617            sec.header.offset += hoff;
618            sec.header.addr   += hoff;
619        }
620
621
622        let mut seen_first_load = false;
623        for seg in self.segments.iter_mut() {
624            if seg.phtype == types::SegmentType::LOAD && !seen_first_load {
625                seen_first_load = true;
626                seg.memsz  += hoff;
627                seg.filesz += hoff;
628            } else {
629                seg.offset += hoff;
630                seg.vaddr  += hoff;
631                seg.paddr  += hoff;
632            }
633        }
634
635        self.segments.insert(0, segment::SegmentHeader {
636            phtype: types::SegmentType::PHDR,
637            flags: types::SegmentFlags::READABLE | types::SegmentFlags::EXECUTABLE,
638            offset: self.header.phoff,
639            filesz: self.header.phnum as u64 * self.header.phentsize as u64,
640            vaddr:  self.header.phoff,
641            paddr:  self.header.phoff,
642            memsz:  self.header.phnum as u64 * self.header.phentsize as u64,
643            align:  0x8,
644        });
645
646        trace!("done {} segments", self.segments.len());
647
648        for i in 0..self.sections.len() {
649            if self.sections[i].addrlock && self.sections[i].header.addr != dbg_old_addresses[i] {
650
651                let mut cause = String::from("preceeding section or header has changed in size");
652                if dbg_old_segments_count != self.segments.len() {
653                    cause = format!("number of segments changed from {} to {}",
654                                    dbg_old_segments_count, self.segments.len());
655                }
656
657                return Err(Error::MovingLockedSection{
658                    sec: String::from_utf8_lossy(&self.sections[i].name).into_owned(),
659                    old_addr: dbg_old_addresses[i],
660                    new_addr: self.sections[i].header.addr,
661                    cause:    cause,
662                });
663            }
664        }
665
666
667        Ok(())
668    }
669
670
671
672
673
674
675
676
677
678
679
680    pub fn remove_section(&mut self, at: usize) -> Result<(Section), Error> {
683        let r = self.sections.remove(at);
684
685        for sec in &mut self.sections {
686            if sec.header.link == at as u32 {
687                sec.header.link = 0;
688                } else if sec.header.link > at as u32 {
690                sec.header.link -= 1;
691            }
692
693            if sec.header.flags.contains(types::SectionFlags::INFO_LINK) {
694                if sec.header.info == at as u32 {
695                    sec.header.info = 0;
696                    } else if sec.header.info > at as u32 {
699                    sec.header.info -= 1;
700                }
701            }
702        }
703
704        Ok(r)
705    }
706    pub fn insert_section(&mut self, at: usize, sec: Section) -> Result<(), Error> {
707        self.sections.insert(at, sec);
708
709        for sec in &mut self.sections {
710            if sec.header.link >= at as u32 {
711                sec.header.link += 1;
712            }
713
714            if sec.header.flags.contains(types::SectionFlags::INFO_LINK) {
715                if sec.header.info > at as u32 {
716                    sec.header.info += 1;
717                }
718            }
719        }
720
721        Ok(())
722    }
723
724    pub fn move_section(&mut self, from: usize, mut to: usize) -> Result<(), Error> {
725        if to == from {
726            return Ok(());
727        }
728        if to > from {
729            to -= 1;
730        }
731
732
733        for sec in &mut self.sections {
734            if sec.header.link == from as u32 {
735                sec.header.link = 999999;
736            }
737            if sec.header.flags.contains(types::SectionFlags::INFO_LINK) {
738                if sec.header.info == from as u32 {
739                    sec.header.info = 999999;
740                }
741            }
742        }
743        let sec = self.remove_section(from)?;
744        self.insert_section(to, sec)?;
745        for sec in &mut self.sections {
746            if sec.header.link == 999999 {
747                sec.header.link = to as u32;
748            }
749            if sec.header.flags.contains(types::SectionFlags::INFO_LINK) {
750                if sec.header.info == 999999 {
751                    sec.header.info = to as u32;
752                }
753            }
754        }
755
756        Ok(())
757    }
758}