source: trunk/third/firefox/config/elf-dynstr-gc.c @ 21695

Revision 21695, 30.3 KB checked in by rbasch, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21694, which included commits to RCS files with non-trunk default branches.
Line 
1/* elf_gc_dynst
2 *
3 * This is a program that removes unreferenced strings from the .dynstr
4 * section in ELF shared objects. It also shrinks the .dynstr section and
5 * relocates all symbols after it.
6 *
7 * This program was written and copyrighted by:
8 *   Alexander Larsson <alla@lysator.liu.se>
9 *
10 *
11 *
12 * The contents of this file are subject to the Mozilla Public License
13 * Version 1.1 (the "License"); you may not use this file except in
14 * compliance with the License. You may obtain a copy of the License at
15 * http://www.mozilla.org/MPL/
16 *
17 * Software distributed under the License is distributed on an "AS IS"
18 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
19 * License for the specific language governing rights and limitations
20 * under the License.
21 */
22
23
24#include <stdio.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <sys/types.h>
28#include <sys/stat.h>
29#include <sys/mman.h>
30
31#include <elf.h>
32#include <glib.h>
33#include <string.h>
34
35
36Elf32_Ehdr *elf_header = NULL;
37#define FILE_OFFSET(offset) ((unsigned char *)(elf_header) + (offset))
38
39struct dynamic_symbol {
40  Elf32_Word old_index;
41  Elf32_Word new_index;
42  char *string;
43};
44
45GHashTable *used_dynamic_symbols = NULL;
46/* Data is dynamic_symbols, hashes on old_index */
47Elf32_Word hole_index;
48Elf32_Word hole_end;
49Elf32_Word hole_len;
50
51Elf32_Addr hole_addr_start;
52Elf32_Addr hole_addr_remap_start;
53Elf32_Addr hole_addr_remap_end;
54
55int need_byteswap;
56
57unsigned char machine_type;
58
59Elf32_Word
60read_word(Elf32_Word w)
61{
62  if (need_byteswap)
63    w = GUINT32_SWAP_LE_BE(w);
64  return w;
65}
66
67Elf32_Sword
68read_sword(Elf32_Sword w)
69{
70  if (need_byteswap)
71    w = (Elf32_Sword)GUINT32_SWAP_LE_BE((guint32)w);
72  return w;
73}
74
75void
76write_word(Elf32_Word *ptr, Elf32_Word w)
77{
78  if (need_byteswap)
79    w = GUINT32_SWAP_LE_BE(w);
80  *ptr = w;
81}
82
83Elf32_Half
84read_half(Elf32_Half h)
85{
86  if (need_byteswap)
87    h = GUINT16_SWAP_LE_BE(h);
88  return h;
89}
90
91void
92write_half(Elf32_Half *ptr, Elf32_Half h)
93{
94  if (need_byteswap)
95    h = GUINT16_SWAP_LE_BE(h);
96  *ptr = h;
97}
98
99void
100setup_byteswapping(unsigned char ei_data)
101{
102  need_byteswap = 0;
103#if G_BYTE_ORDER == G_BIG_ENDIAN
104  if (ei_data == ELFDATA2LSB)
105    need_byteswap = 1;
106#endif
107#if G_BYTE_ORDER == G_LITTLE_ENDIAN
108  if (ei_data == ELFDATA2MSB)
109    need_byteswap = 1;
110#endif
111}
112
113
114Elf32_Shdr *
115elf_find_section_num(int section_index)
116{
117  Elf32_Shdr *section;
118  Elf32_Word sectionsize;
119
120  section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
121  sectionsize = read_half(elf_header->e_shentsize);
122
123  section = (Elf32_Shdr *)((char *)section + sectionsize*section_index);
124
125  return section;
126}
127
128Elf32_Shdr *
129elf_find_section_named(char *name)
130{
131  Elf32_Shdr *section;
132  Elf32_Shdr *strtab_section;
133  Elf32_Word sectionsize;
134  int numsections;
135  char *strtab;
136  int i = 0;
137
138  section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
139
140  strtab_section = elf_find_section_num(read_half(elf_header->e_shstrndx));
141 
142  strtab = (char *)FILE_OFFSET(read_word(strtab_section->sh_offset));
143 
144  sectionsize = read_half(elf_header->e_shentsize);
145  numsections = read_half(elf_header->e_shnum);
146
147  for (i=0;i<numsections;i++) {
148    if (strcmp(&strtab[read_word(section->sh_name)], name) == 0) {
149      return section;
150    }
151    section = (Elf32_Shdr *)((char *)section + sectionsize);
152  }
153  return NULL;
154}
155
156
157Elf32_Shdr *
158elf_find_section(Elf32_Word sh_type)
159{
160  Elf32_Shdr *section;
161  Elf32_Word sectionsize;
162  int numsections;
163  int i = 0;
164
165  section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
166  sectionsize = read_half(elf_header->e_shentsize);
167  numsections = read_half(elf_header->e_shnum);
168
169  for (i=0;i<numsections;i++) {
170    if (read_word(section->sh_type) == sh_type) {
171      return section;
172    }
173    section = (Elf32_Shdr *)((char *)section + sectionsize);
174  }
175  return NULL;
176}
177
178Elf32_Shdr *
179elf_find_next_higher_section(Elf32_Word offset)
180{
181  Elf32_Shdr *section;
182  Elf32_Shdr *higher;
183  Elf32_Word sectionsize;
184  int numsections;
185  int i = 0;
186
187  section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
188  sectionsize = read_half(elf_header->e_shentsize);
189  numsections = read_half(elf_header->e_shnum);
190
191  higher = NULL;
192
193  for (i=0;i<numsections;i++) {
194    if (read_word(section->sh_offset) >= offset) {
195      if (higher == NULL) {
196        higher = section;
197      } else if (read_word(section->sh_offset) < read_word(higher->sh_offset)) {
198        higher = section;
199      }
200    }
201   
202    section = (Elf32_Shdr *)((char *)section + sectionsize);
203  }
204 
205  return higher;
206}
207
208Elf32_Word
209vma_to_offset(Elf32_Addr addr)
210{
211  Elf32_Shdr *section;
212  Elf32_Shdr *higher;
213  Elf32_Word sectionsize;
214  int numsections;
215  int i = 0;
216
217  section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
218  sectionsize = read_half(elf_header->e_shentsize);
219  numsections = read_half(elf_header->e_shnum);
220
221  higher = NULL;
222
223  for (i=0;i<numsections;i++) {
224    if ( (addr >= read_word(section->sh_addr)) &&
225         (addr < read_word(section->sh_addr) + read_word(section->sh_size)) ) {
226      return read_word(section->sh_offset) + (addr - read_word(section->sh_addr));
227    }
228   
229    section = (Elf32_Shdr *)((char *)section + sectionsize);
230  }
231
232  fprintf(stderr, "Warning, unable to convert address %d (0x%x) to file offset\n",
233         addr, addr);
234  return 0;
235}
236
237
238void
239find_segment_addr_min_max(Elf32_Word file_offset,
240                          Elf32_Addr *start, Elf32_Addr *end)
241{
242  Elf32_Phdr *segment;
243  Elf32_Word segmentsize;
244  int numsegments;
245  int i = 0;
246
247  segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
248  segmentsize = read_half(elf_header->e_phentsize);
249  numsegments = read_half(elf_header->e_phnum);
250
251  for (i=0;i<numsegments;i++) {
252    if ((file_offset >= read_word(segment->p_offset)) &&
253        (file_offset < read_word(segment->p_offset) + read_word(segment->p_filesz)))  {
254      *start = read_word(segment->p_vaddr);
255      *end = read_word(segment->p_vaddr) + read_word(segment->p_memsz);
256      return;
257    }
258
259    segment = (Elf32_Phdr *)((char *)segment + segmentsize);
260  }
261  fprintf(stderr, "Error: Couldn't find segment in find_segment_addr_min_max()\n");
262}
263
264void *
265dynamic_find_tag(Elf32_Shdr *dynamic, Elf32_Sword d_tag)
266{
267  int i;
268  Elf32_Dyn *element;
269
270  element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
271  for (i=0; read_sword(element[i].d_tag) != DT_NULL; i++) {
272    if (read_sword(element[i].d_tag) == d_tag) {
273      return FILE_OFFSET(read_word(element[i].d_un.d_ptr));
274    }
275  }
276 
277  return NULL;
278}
279
280Elf32_Word
281fixup_offset(Elf32_Word offset)
282{
283  if (offset >= hole_index) {
284    return offset - hole_len;
285  }
286  return offset;
287}
288
289Elf32_Word
290fixup_size(Elf32_Word offset, Elf32_Word size)
291{
292  /* Note: Doesn't handle the cases where the hole and the size intersect
293     partially. */
294 
295  if ( (hole_index >= offset) &&
296       (hole_index < offset + size)){
297    return size - hole_len;
298  }
299 
300  return size;
301}
302
303Elf32_Addr
304fixup_addr(Elf32_Addr addr)
305{
306  if (addr == 0)
307    return 0;
308
309  /*
310  if ( (addr < hole_addr_remap_start) ||
311       (addr >= hole_addr_remap_end))
312    return addr;
313  */
314 
315  if (addr >= hole_addr_start) {
316    return addr - hole_len;
317  }
318  return addr;
319}
320
321Elf32_Word
322fixup_addr_size(Elf32_Addr addr, Elf32_Word size)
323{
324  /* Note: Doesn't handle the cases where the hole and the size intersect
325     partially. */
326  /*
327  if ( (addr < hole_addr_remap_start) ||
328       (addr >= hole_addr_remap_end))
329    return size;
330  */
331  if ( (hole_addr_start >= addr) &&
332       (hole_addr_start < addr + size)){
333    return size - hole_len;
334  }
335 
336  return size;
337}
338
339void
340possibly_add_string(int name_idx, const char *name)
341{
342  struct dynamic_symbol *dynamic_symbol;
343  if (name_idx != 0) {
344    dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) name_idx);
345   
346    if (dynamic_symbol == NULL) {
347     
348      dynamic_symbol = g_new(struct dynamic_symbol, 1);
349     
350      dynamic_symbol->old_index = name_idx;
351      dynamic_symbol->new_index = 0;
352      dynamic_symbol->string = g_strdup(name);
353     
354      g_hash_table_insert(used_dynamic_symbols, (gpointer)name_idx, dynamic_symbol);
355      /*printf("added dynamic string: %s (%d)\n", dynamic_symbol->string, name_idx);*/
356    }
357  }
358}
359
360Elf32_Word
361fixup_string(Elf32_Word old_idx)
362{
363  struct dynamic_symbol *dynamic_symbol;
364
365  if (old_idx == 0)
366    return 0;
367 
368  dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) old_idx);
369
370  if (dynamic_symbol == NULL) {
371    fprintf(stderr, "AAAAAAAAAAAARGH!? Unknown string found in fixup (index: %d)!\n", old_idx);
372    return 0;
373  }
374 
375  return dynamic_symbol->new_index;
376}
377
378
379
380void
381add_strings_from_dynsym(Elf32_Shdr *dynsym, char *strtab)
382{
383  Elf32_Sym *symbol;
384  Elf32_Sym *symbol_end;
385  Elf32_Word entry_size;
386 
387
388  symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset));
389  symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size));
390  entry_size = read_word(dynsym->sh_entsize);
391
392  while (symbol < symbol_end) {
393    int name_idx;
394    struct dynamic_symbol *dynamic_symbol;
395
396    name_idx = read_word(symbol->st_name);
397    possibly_add_string(name_idx, &strtab[name_idx]);
398
399   
400    symbol = (Elf32_Sym *)((char *)symbol + entry_size);
401  }
402}
403
404
405void
406fixup_strings_in_dynsym(Elf32_Shdr *dynsym)
407{
408  Elf32_Sym *symbol;
409  Elf32_Sym *symbol_end;
410  Elf32_Word entry_size;
411 
412
413  symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset));
414  symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size));
415  entry_size = read_word(dynsym->sh_entsize);
416 
417  while (symbol < symbol_end) {
418    struct dynamic_symbol *dynamic_symbol;
419
420    write_word(&symbol->st_name,
421               fixup_string(read_word(symbol->st_name)));
422                         
423    symbol = (Elf32_Sym *)((char *)symbol + entry_size);
424  }
425}
426
427
428void
429add_strings_from_dynamic(Elf32_Shdr *dynamic, char *strtab)
430{
431  int i;
432  int name_idx;
433  Elf32_Dyn *element;
434  Elf32_Word entry_size;
435
436  entry_size = read_word(dynamic->sh_entsize);
437 
438
439  element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
440  while (read_sword(element->d_tag) != DT_NULL) {
441
442    switch(read_sword(element->d_tag)) {
443    case DT_NEEDED:
444    case DT_SONAME:
445    case DT_RPATH:
446      name_idx = read_word(element->d_un.d_val);
447      /*if (name_idx) printf("d_tag: %d\n", element->d_tag);*/
448      possibly_add_string(name_idx, &strtab[name_idx]);
449      break;
450    default:
451      ;
452      /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
453    }
454
455    element = (Elf32_Dyn *)((char *)element + entry_size);
456  }
457 
458}
459
460void
461fixup_strings_in_dynamic(Elf32_Shdr *dynamic)
462{
463  int i;
464  int name_idx;
465  Elf32_Dyn *element;
466  Elf32_Word entry_size;
467
468  entry_size = read_word(dynamic->sh_entsize);
469
470  element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
471  while (read_sword(element->d_tag) != DT_NULL) {
472
473    switch(read_sword(element->d_tag)) {
474    case DT_NEEDED:
475    case DT_SONAME:
476    case DT_RPATH:
477      write_word(&element->d_un.d_val,
478                 fixup_string(read_word(element->d_un.d_val)));
479      break;
480    default:
481      ;
482      /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
483    }
484
485    element = (Elf32_Dyn *)((char *)element + entry_size);
486  }
487 
488}
489
490
491void
492add_strings_from_ver_d(Elf32_Shdr *ver_d, char *strtab)
493{
494  Elf32_Verdaux *veraux;
495  Elf32_Verdef *verdef;
496  int num_aux;
497  int name_idx;
498  int i;
499  int cont;
500
501  verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
502
503  do {
504    num_aux = read_half(verdef->vd_cnt);
505    veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
506    for (i=0; i<num_aux; i++) {
507      name_idx = read_word(veraux->vda_name);
508      possibly_add_string(name_idx, &strtab[name_idx]);
509      veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
510    }
511
512    cont = read_word(verdef->vd_next) != 0;
513    verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
514  } while (cont);
515 
516}
517
518void
519fixup_strings_in_ver_d(Elf32_Shdr *ver_d)
520{
521  Elf32_Verdaux *veraux;
522  Elf32_Verdef *verdef;
523  int num_aux;
524  int name_idx;
525  int i;
526  int cont;
527
528  verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
529
530  do {
531    num_aux = read_half(verdef->vd_cnt);
532    veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
533    for (i=0; i<num_aux; i++) {
534      write_word(&veraux->vda_name,
535                 fixup_string(read_word(veraux->vda_name)));
536      veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
537    }
538
539    cont = read_word(verdef->vd_next) != 0;
540    verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
541  } while (cont);
542 
543}
544
545void
546add_strings_from_ver_r(Elf32_Shdr *ver_r, char *strtab)
547{
548  Elf32_Vernaux *veraux;
549  Elf32_Verneed *verneed;
550  int num_aux;
551  int name_idx;
552  int i;
553  int cont;
554
555  verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
556
557  do {
558    name_idx = read_word(verneed->vn_file);
559    possibly_add_string(name_idx, &strtab[name_idx]);
560    num_aux = read_half(verneed->vn_cnt);
561    veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
562    for (i=0; i<num_aux; i++) {
563      name_idx = read_word(veraux->vna_name);
564      possibly_add_string(name_idx, &strtab[name_idx]);
565      veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
566    }
567
568    cont = read_word(verneed->vn_next) != 0;
569    verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
570  } while (cont);
571}
572
573void
574fixup_strings_in_ver_r(Elf32_Shdr *ver_r)
575{
576  Elf32_Vernaux *veraux;
577  Elf32_Verneed *verneed;
578  int num_aux;
579  int name_idx;
580  int i;
581  int cont;
582
583  verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
584
585  do {
586    write_word(&verneed->vn_file,
587               fixup_string(read_word(verneed->vn_file)));
588    num_aux = read_half(verneed->vn_cnt);
589    veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
590    for (i=0; i<num_aux; i++) {
591      write_word(&veraux->vna_name,
592                 fixup_string(read_word(veraux->vna_name)));
593      veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
594    }
595
596    cont = read_word(verneed->vn_next) != 0;
597    verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
598  } while (cont);
599}
600
601gboolean sum_size(gpointer      key,
602                  struct dynamic_symbol *sym,
603                  int *size)
604{
605  *size += strlen(sym->string) + 1;
606  return 1;
607}
608
609struct index_n_dynstr {
610  int index;
611  unsigned char *dynstr;
612};
613
614gboolean output_string(gpointer key,
615                       struct dynamic_symbol *sym,
616                       struct index_n_dynstr *x)
617{
618  sym->new_index = x->index;
619  memcpy(x->dynstr + x->index, sym->string, strlen(sym->string) + 1);
620  x->index += strlen(sym->string) + 1;
621  return 1;
622}
623
624
625unsigned char *
626generate_new_dynstr(Elf32_Word *size_out)
627{
628  int size;
629  unsigned char *new_dynstr;
630  struct index_n_dynstr x;
631
632  size = 1; /* first a zero */
633  g_hash_table_foreach  (used_dynamic_symbols,
634                         (GHFunc)sum_size,
635                         &size);
636
637
638  new_dynstr = g_malloc(size);
639
640  new_dynstr[0] = 0;
641  x.index = 1;
642  x.dynstr = new_dynstr;
643  g_hash_table_foreach  (used_dynamic_symbols,
644                         (GHFunc)output_string,
645                         &x);
646 
647  *size_out = size;
648  return new_dynstr;
649}
650
651void
652remap_sections(void)
653{
654  Elf32_Shdr *section;
655  Elf32_Word sectionsize;
656  int numsections;
657  int i = 0;
658
659  section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
660  sectionsize = read_half(elf_header->e_shentsize);
661  numsections = read_half(elf_header->e_shnum);
662
663  for (i=0;i<numsections;i++) {
664    write_word(&section->sh_size,
665               fixup_size(read_word(section->sh_offset),
666                          read_word(section->sh_size)));
667    write_word(&section->sh_offset,
668               fixup_offset(read_word(section->sh_offset)));
669    write_word(&section->sh_addr,
670               fixup_addr(read_word(section->sh_addr)));
671   
672    section = (Elf32_Shdr *)((char *)section + sectionsize);
673  }
674}
675
676
677void
678remap_segments(void)
679{
680  Elf32_Phdr *segment;
681  Elf32_Word segmentsize;
682  Elf32_Word p_align;
683  int numsegments;
684  int i = 0;
685
686  segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
687  segmentsize = read_half(elf_header->e_phentsize);
688  numsegments = read_half(elf_header->e_phnum);
689
690  for (i=0;i<numsegments;i++) {
691    write_word(&segment->p_filesz,
692               fixup_size(read_word(segment->p_offset),
693                          read_word(segment->p_filesz)));
694    write_word(&segment->p_offset,
695               fixup_offset(read_word(segment->p_offset)));
696
697    write_word(&segment->p_memsz,
698               fixup_addr_size(read_word(segment->p_vaddr),
699                               read_word(segment->p_memsz)));
700    write_word(&segment->p_vaddr,
701               fixup_addr(read_word(segment->p_vaddr)));
702    write_word(&segment->p_paddr,
703               read_word(segment->p_vaddr));
704
705    /* Consistancy checking: */
706    p_align = read_word(segment->p_align);
707    if (p_align > 1) {
708      if ((read_word(segment->p_vaddr) - read_word(segment->p_offset))%p_align != 0) {
709        fprintf(stderr, "Warning, creating non-aligned segment addr: %x offset: %x allign: %x\n",
710                read_word(segment->p_vaddr), read_word(segment->p_offset), p_align);
711      }
712    }
713   
714    segment = (Elf32_Phdr *)((char *)segment + segmentsize);
715  }
716}
717
718void
719remap_elf_header(void)
720{
721  write_word(&elf_header->e_phoff,
722             fixup_offset(read_word(elf_header->e_phoff)));
723  write_word(&elf_header->e_shoff,
724             fixup_offset(read_word(elf_header->e_shoff)));
725
726  write_word(&elf_header->e_entry,
727             fixup_addr(read_word(elf_header->e_entry)));
728}
729
730void
731remap_symtab(Elf32_Shdr *symtab)
732{
733  Elf32_Sym *symbol;
734  Elf32_Sym *symbol_end;
735  Elf32_Word entry_size;
736
737  symbol = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset));
738  symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset) +
739                                        read_word(symtab->sh_size));
740  entry_size = read_word(symtab->sh_entsize);
741
742  while (symbol < symbol_end) {
743    write_word(&symbol->st_value,
744               fixup_addr(read_word(symbol->st_value)));
745    symbol = (Elf32_Sym *)((char *)symbol + entry_size);
746  }
747}
748
749
750/* Ugly global variables: */
751Elf32_Addr got_data_start = 0;
752Elf32_Addr got_data_end = 0;
753
754
755void
756remap_rel_section(Elf32_Rel *rel, Elf32_Word size, Elf32_Word entry_size)
757{
758  Elf32_Rel *rel_end;
759  Elf32_Word offset;
760  Elf32_Addr *addr;
761  Elf32_Word type;
762
763  rel_end = (Elf32_Rel *)((char *)rel + size);
764
765  while (rel < rel_end) {
766    type = ELF32_R_TYPE(read_word(rel->r_info));
767    switch (machine_type) {
768    case EM_386:
769      if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
770        /* We need to relocate the data this is pointing to too. */
771        offset = vma_to_offset(read_word(rel->r_offset));
772       
773        addr =  (Elf32_Addr *)FILE_OFFSET(offset);
774        write_word(addr,
775                   fixup_addr(read_word(*addr)));
776      }
777      write_word(&rel->r_offset,
778                 fixup_addr(read_word(rel->r_offset)));
779      break;
780    case EM_PPC:
781      /* The PPC always uses RELA relocations */
782      break;
783    }
784
785   
786    rel = (Elf32_Rel *)((char *)rel + entry_size);
787  }
788}
789
790void
791remap_rela_section(Elf32_Rela *rela, Elf32_Word size, Elf32_Word entry_size)
792{
793  Elf32_Rela *rela_end;
794  Elf32_Addr *addr;
795  Elf32_Word offset;
796  Elf32_Word type;
797  Elf32_Word bitmask;
798
799  rela_end = (Elf32_Rela *)((char *)rela + size);
800
801  while (rela < rela_end) {
802    type = ELF32_R_TYPE(read_word(rela->r_info));
803    switch (machine_type) {
804    case EM_386:
805      if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
806        /* We need to relocate the data this is pointing to too. */
807        offset = vma_to_offset(read_word(rela->r_offset));
808       
809        addr =  (Elf32_Addr *)FILE_OFFSET(offset);
810        write_word(addr,
811                   fixup_addr(read_word(*addr)));
812      }
813      write_word(&rela->r_offset,
814                 fixup_addr(read_word(rela->r_offset)));
815      break;
816    case EM_PPC:
817/* Some systems do not have PowerPC relocations defined */
818#ifdef R_PPC_NONE
819      switch (type) {
820      case R_PPC_RELATIVE:
821        write_word((Elf32_Word *)&rela->r_addend,
822                   fixup_addr(read_word(rela->r_addend)));
823        /* Fall through for 32bit offset fixup */
824      case R_PPC_ADDR32:
825      case R_PPC_GLOB_DAT:
826      case R_PPC_JMP_SLOT:
827        write_word(&rela->r_offset,
828                   fixup_addr(read_word(rela->r_offset)));
829        break;
830      case R_PPC_NONE:
831        break;
832      default:
833        fprintf(stderr, "Warning, unhandled PPC relocation type %d\n", type);
834      }
835#endif
836      break;
837    }
838   
839    rela = (Elf32_Rela *)((char *)rela + entry_size);
840  }
841}
842
843void
844remap_i386_got(void)
845{
846  Elf32_Shdr *got_section;
847  Elf32_Addr *got;
848  Elf32_Addr *got_end;
849  Elf32_Word entry_size;
850
851  got_section = elf_find_section_named(".got");
852  if (got_section == NULL) {
853    fprintf(stderr, "Warning, no .got section\n");
854    return;
855  }
856
857  got_data_start = read_word(got_section->sh_offset);
858  got_data_end = got_data_start + read_word(got_section->sh_size);
859 
860  got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
861  got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
862  entry_size = read_word(got_section->sh_entsize);
863
864  write_word(got,
865             fixup_addr(read_word(*got))); /* Pointer to .dynamic */
866}
867
868void
869remap_ppc_got(void)
870{
871  Elf32_Shdr *got_section;
872  Elf32_Addr *got;
873  Elf32_Addr *got_end;
874  Elf32_Word entry_size;
875
876  got_section = elf_find_section_named(".got");
877  if (got_section == NULL) {
878    fprintf(stderr, "Warning, no .got section\n");
879    return;
880  }
881
882  got_data_start = read_word(got_section->sh_offset);
883  got_data_end = got_data_start + read_word(got_section->sh_size);
884 
885  got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
886  got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
887  entry_size = read_word(got_section->sh_entsize);
888
889  /* Skip reserved part.
890   * Note that this should really be found by finding the
891   * _GLOBAL_OFFSET_TABLE symbol, as it could (according to
892   * the spec) point to the middle of the got.
893   */
894  got = (Elf32_Addr *)((char *)got + entry_size); /* Skip blrl instruction */
895  write_word(got,
896             fixup_addr(read_word(*got))); /* Pointer to .dynamic */
897}
898
899
900Elf32_Word
901get_dynamic_val(Elf32_Shdr *dynamic, Elf32_Sword tag)
902{
903  Elf32_Dyn *element;
904  Elf32_Word entry_size;
905
906  entry_size = read_word(dynamic->sh_entsize);
907
908  element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
909  while (read_sword(element->d_tag) != DT_NULL) {
910    if (read_sword(element->d_tag) == tag) {
911      return read_word(element->d_un.d_val);
912    }
913    element = (Elf32_Dyn *)((char *)element + entry_size);
914  }
915  return 0;
916}
917
918void
919remap_dynamic(Elf32_Shdr *dynamic, Elf32_Word new_dynstr_size)
920{
921  Elf32_Dyn *element;
922  Elf32_Word entry_size;
923  Elf32_Word rel_size;
924  Elf32_Word rel_entry_size;
925  Elf32_Rel *rel;
926  Elf32_Rela *rela;
927  int jmprel_overlaps;
928  Elf32_Word rel_start, rel_end, jmprel_start, jmprel_end;
929   
930  entry_size = read_word(dynamic->sh_entsize);
931
932  /* Find out if REL/RELA and JMPREL overlaps: */
933  if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
934    rel_start = get_dynamic_val(dynamic, DT_REL);
935    rel_end = rel_start + get_dynamic_val(dynamic, DT_RELSZ);
936  } else {
937    rel_start = get_dynamic_val(dynamic, DT_RELA);
938    rel_end = rel_start + get_dynamic_val(dynamic, DT_RELASZ);
939  }
940  jmprel_start = get_dynamic_val(dynamic, DT_JMPREL);
941 
942  jmprel_overlaps = 0;
943  if ((jmprel_start >= rel_start) && (jmprel_start < rel_end))
944    jmprel_overlaps = 1;
945   
946  element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
947  while (read_sword(element->d_tag) != DT_NULL) {
948    switch(read_sword(element->d_tag)) {
949    case DT_STRSZ:
950      write_word(&element->d_un.d_val, new_dynstr_size);
951      break;
952    case DT_PLTGOT:
953    case DT_HASH:
954    case DT_STRTAB:
955    case DT_INIT:
956    case DT_FINI:
957    case DT_VERDEF:
958    case DT_VERNEED:
959    case DT_VERSYM:
960      write_word(&element->d_un.d_ptr,
961                 fixup_addr(read_word(element->d_un.d_ptr)));
962      break;
963    case DT_JMPREL:
964      rel_size = get_dynamic_val(dynamic, DT_PLTRELSZ);
965      if (!jmprel_overlaps) {
966        if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
967          rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
968          rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
969          remap_rel_section(rel, rel_size, rel_entry_size);
970        } else {
971          rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
972          rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
973          remap_rela_section(rela, rel_size, rel_entry_size);
974        }
975      }
976      write_word(&element->d_un.d_ptr,
977                 fixup_addr(read_word(element->d_un.d_ptr)));
978      break;
979    case DT_REL:
980      rel_size = get_dynamic_val(dynamic, DT_RELSZ);
981      rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
982      rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
983      remap_rel_section(rel, rel_size, rel_entry_size);
984
985      write_word(&element->d_un.d_ptr,
986                 fixup_addr(read_word(element->d_un.d_ptr)));
987      break;
988    case DT_RELA:
989      rel_size = get_dynamic_val(dynamic, DT_RELASZ);
990      rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
991      rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
992      remap_rela_section(rela, rel_size, rel_entry_size);
993
994      write_word(&element->d_un.d_ptr,
995                 fixup_addr(read_word(element->d_un.d_ptr)));
996      break;
997    default:
998      /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/
999      break;
1000    }
1001
1002    element = (Elf32_Dyn *)((char *)element + entry_size);
1003  }
1004}
1005
1006void
1007align_hole(Elf32_Word *start, Elf32_Word *end)
1008{
1009  Elf32_Word len;
1010  Elf32_Word align;
1011  Elf32_Shdr *section;
1012  Elf32_Word sectionsize;
1013  int numsections;
1014  int i = 0;
1015  int unaligned;
1016 
1017  len = *end - *start;
1018  align = 0;
1019   
1020  sectionsize = read_half(elf_header->e_shentsize);
1021  numsections = read_half(elf_header->e_shnum);
1022  do {
1023    section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
1024    unaligned = 0;
1025   
1026    for (i=0;i<numsections;i++) {
1027      if ( (read_word(section->sh_addralign) > 1) &&
1028           ( (read_word(section->sh_offset) - len + align)%read_word(section->sh_addralign) != 0) ) {
1029        unaligned = 1;
1030      }
1031     
1032      section = (Elf32_Shdr *)((char *)section + sectionsize);
1033    }
1034
1035    if (unaligned) {
1036      align++;
1037    }
1038     
1039  } while (unaligned);
1040
1041  *start += align;
1042}
1043
1044int
1045main(int argc, char *argv[])
1046{
1047  int fd;
1048  unsigned char *mapping;
1049  Elf32_Word size;
1050  struct stat statbuf;
1051  Elf32_Shdr *dynamic;
1052  Elf32_Shdr *dynsym;
1053  Elf32_Shdr *symtab;
1054  Elf32_Shdr *dynstr;
1055  Elf32_Shdr *hash;
1056  Elf32_Shdr *higher_section;
1057  Elf32_Word dynstr_index;
1058  Elf32_Shdr *ver_r;
1059  Elf32_Shdr *ver_d;
1060  char *dynstr_data;
1061  unsigned char *new_dynstr;
1062  Elf32_Word old_dynstr_size;
1063  Elf32_Word new_dynstr_size;
1064 
1065  if (argc != 2) {
1066    fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
1067    return 1;
1068  }
1069
1070  fd = open(argv[1], O_RDWR);
1071  if (fd == -1) {
1072    fprintf(stderr, "Cannot open file %s\n", argv[1]);
1073    return 1;
1074  }
1075 
1076  if (fstat(fd, &statbuf) == -1) {
1077    fprintf(stderr, "Cannot stat file %s\n", argv[1]);
1078    return 1;
1079  }
1080 
1081  size = statbuf.st_size;
1082   
1083  mapping = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1084
1085  if (mapping == (unsigned char *)-1) {
1086    fprintf(stderr, "Cannot mmap file %s\n", argv[1]);
1087    return 1;
1088  }
1089
1090  used_dynamic_symbols = g_hash_table_new(g_direct_hash, g_direct_equal);
1091
1092  elf_header = (Elf32_Ehdr *)mapping;
1093
1094  if (strncmp((void *)elf_header, ELFMAG, SELFMAG)!=0) {
1095    fprintf(stderr, "Not an ELF file\n");
1096    return 1;
1097  }
1098
1099  if (elf_header->e_ident[EI_VERSION] != EV_CURRENT) {
1100    fprintf(stderr, "Wrong ELF file version\n");
1101    return 1;
1102  }
1103
1104  if (elf_header->e_ident[EI_CLASS] != ELFCLASS32) {
1105    fprintf(stderr, "Only 32bit ELF files supported\n");
1106    return 1;
1107  }
1108 
1109  setup_byteswapping(elf_header->e_ident[EI_DATA]);
1110
1111  machine_type = read_half(elf_header->e_machine);
1112  if ( (machine_type != EM_386) &&
1113       (machine_type != EM_PPC) ) {
1114    fprintf(stderr, "Unsupported architecture. Supported are: x86, ppc\n");
1115    return 1;
1116  }
1117
1118  if (read_half(elf_header->e_type) != ET_DYN) {
1119    fprintf(stderr, "Not an ELF shared object\n");
1120    return 1;
1121  }
1122 
1123  dynamic = elf_find_section(SHT_DYNAMIC);
1124  dynsym = elf_find_section(SHT_DYNSYM);
1125  symtab = elf_find_section(SHT_SYMTAB);
1126  dynstr_index = read_word(dynsym->sh_link);
1127  dynstr = elf_find_section_num(dynstr_index);
1128  dynstr_data = (char *)FILE_OFFSET(read_word(dynstr->sh_offset));
1129  old_dynstr_size = read_word(dynstr->sh_size);
1130  ver_d = elf_find_section(SHT_GNU_verdef);
1131  ver_r = elf_find_section(SHT_GNU_verneed);
1132  hash = elf_find_section(SHT_HASH);
1133
1134  /* Generate hash table with all used strings: */
1135 
1136  add_strings_from_dynsym(dynsym, dynstr_data);
1137  add_strings_from_dynamic(dynamic, dynstr_data);
1138  if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
1139    add_strings_from_ver_d(ver_d, dynstr_data);
1140  if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
1141    add_strings_from_ver_r(ver_r, dynstr_data);
1142
1143  /* Generate new dynstr section from the used strings hashtable: */
1144 
1145  new_dynstr = generate_new_dynstr(&new_dynstr_size);
1146  /*
1147  printf("New dynstr size: %d\n", new_dynstr_size);
1148  printf("Old dynstr size: %d\n", old_dynstr_size);
1149  */
1150 
1151  if (new_dynstr_size >= old_dynstr_size) {
1152    fprintf(stderr, "Couldn't GC any strings, exiting.\n");
1153    return 0;
1154  }
1155
1156  /* Fixup all references: */
1157  fixup_strings_in_dynsym(dynsym);
1158  fixup_strings_in_dynamic(dynamic);
1159  if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
1160    fixup_strings_in_ver_d(ver_d);
1161  if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
1162    fixup_strings_in_ver_r(ver_r);
1163 
1164  /* Copy over the new dynstr: */
1165  memcpy(dynstr_data, new_dynstr, new_dynstr_size);
1166  memset(dynstr_data + new_dynstr_size, ' ', old_dynstr_size-new_dynstr_size);
1167
1168  /* Compact the dynstr section and the file: */
1169
1170  /* 1. Set up the data for the fixup_offset() function: */
1171  hole_index = read_word(dynstr->sh_offset) + new_dynstr_size;
1172  higher_section = elf_find_next_higher_section(hole_index);
1173  hole_end = read_word(higher_section->sh_offset);
1174
1175  align_hole(&hole_index, &hole_end);
1176  hole_len = hole_end - hole_index;
1177
1178  hole_addr_start = hole_index; /* TODO: Fix this to something better */
1179
1180  find_segment_addr_min_max(read_word(dynstr->sh_offset),
1181                            &hole_addr_remap_start, &hole_addr_remap_end);
1182 
1183  /*
1184  printf("Hole remap: 0x%lx - 0x%lx\n", hole_addr_remap_start, hole_addr_remap_end);
1185
1186  printf("hole: %lu - %lu (%lu bytes)\n", hole_index, hole_end, hole_len);
1187  printf("hole: 0x%lx - 0x%lx (0x%lx bytes)\n", hole_index, hole_end, hole_len);
1188  */
1189 
1190  /* 2. Change all section and segment sizes and offsets: */
1191  remap_symtab(dynsym);
1192  if (symtab)
1193    remap_symtab(symtab);
1194
1195  if (machine_type == EM_386)
1196    remap_i386_got();
1197  if (machine_type == EM_PPC)
1198    remap_ppc_got();
1199 
1200  remap_dynamic(dynamic, new_dynstr_size);
1201  remap_sections(); /* After this line the section headers are wrong */
1202  remap_segments();
1203  remap_elf_header();
1204   
1205  /* 3. Do the real compacting. */
1206
1207  memmove(mapping + hole_index,
1208          mapping + hole_index + hole_len,
1209          size - (hole_index + hole_len));
1210 
1211  munmap(mapping, size);
1212
1213  ftruncate(fd, size - hole_len);
1214  close(fd);
1215
1216  return 0;
1217}
1218
1219
1220
Note: See TracBrowser for help on using the repository browser.