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}