Bug 849918 - Initial support for PannerNode's 3D positional audio (equalpower panning...
[gecko.git] / config / elf-dynstr-gc.c
blobffed03ac288a2d91406ca3c1ccef9d408e2d1681
1 /* elf_gc_dynst
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.
7 * This program was written and copyrighted by:
8 * Alexander Larsson <alla@lysator.liu.se>
12 * This Source Code Form is subject to the terms of the Mozilla Public
13 * License, v. 2.0. If a copy of the MPL was not distributed with this
14 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <fcntl.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <sys/mman.h>
24 #include <elf.h>
25 #include <glib.h>
26 #include <string.h>
29 Elf32_Ehdr *elf_header = NULL;
30 #define FILE_OFFSET(offset) ((unsigned char *)(elf_header) + (offset))
32 struct dynamic_symbol {
33 Elf32_Word old_index;
34 Elf32_Word new_index;
35 char *string;
38 GHashTable *used_dynamic_symbols = NULL;
39 /* Data is dynamic_symbols, hashes on old_index */
40 Elf32_Word hole_index;
41 Elf32_Word hole_end;
42 Elf32_Word hole_len;
44 Elf32_Addr hole_addr_start;
45 Elf32_Addr hole_addr_remap_start;
46 Elf32_Addr hole_addr_remap_end;
48 int need_byteswap;
50 unsigned char machine_type;
52 Elf32_Word
53 read_word(Elf32_Word w)
55 if (need_byteswap)
56 w = GUINT32_SWAP_LE_BE(w);
57 return w;
60 Elf32_Sword
61 read_sword(Elf32_Sword w)
63 if (need_byteswap)
64 w = (Elf32_Sword)GUINT32_SWAP_LE_BE((guint32)w);
65 return w;
68 void
69 write_word(Elf32_Word *ptr, Elf32_Word w)
71 if (need_byteswap)
72 w = GUINT32_SWAP_LE_BE(w);
73 *ptr = w;
76 Elf32_Half
77 read_half(Elf32_Half h)
79 if (need_byteswap)
80 h = GUINT16_SWAP_LE_BE(h);
81 return h;
84 void
85 write_half(Elf32_Half *ptr, Elf32_Half h)
87 if (need_byteswap)
88 h = GUINT16_SWAP_LE_BE(h);
89 *ptr = h;
92 void
93 setup_byteswapping(unsigned char ei_data)
95 need_byteswap = 0;
96 #if G_BYTE_ORDER == G_BIG_ENDIAN
97 if (ei_data == ELFDATA2LSB)
98 need_byteswap = 1;
99 #endif
100 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
101 if (ei_data == ELFDATA2MSB)
102 need_byteswap = 1;
103 #endif
107 Elf32_Shdr *
108 elf_find_section_num(int section_index)
110 Elf32_Shdr *section;
111 Elf32_Word sectionsize;
113 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
114 sectionsize = read_half(elf_header->e_shentsize);
116 section = (Elf32_Shdr *)((char *)section + sectionsize*section_index);
118 return section;
121 Elf32_Shdr *
122 elf_find_section_named(char *name)
124 Elf32_Shdr *section;
125 Elf32_Shdr *strtab_section;
126 Elf32_Word sectionsize;
127 int numsections;
128 char *strtab;
129 int i = 0;
131 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
133 strtab_section = elf_find_section_num(read_half(elf_header->e_shstrndx));
135 strtab = (char *)FILE_OFFSET(read_word(strtab_section->sh_offset));
137 sectionsize = read_half(elf_header->e_shentsize);
138 numsections = read_half(elf_header->e_shnum);
140 for (i=0;i<numsections;i++) {
141 if (strcmp(&strtab[read_word(section->sh_name)], name) == 0) {
142 return section;
144 section = (Elf32_Shdr *)((char *)section + sectionsize);
146 return NULL;
150 Elf32_Shdr *
151 elf_find_section(Elf32_Word sh_type)
153 Elf32_Shdr *section;
154 Elf32_Word sectionsize;
155 int numsections;
156 int i = 0;
158 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
159 sectionsize = read_half(elf_header->e_shentsize);
160 numsections = read_half(elf_header->e_shnum);
162 for (i=0;i<numsections;i++) {
163 if (read_word(section->sh_type) == sh_type) {
164 return section;
166 section = (Elf32_Shdr *)((char *)section + sectionsize);
168 return NULL;
171 Elf32_Shdr *
172 elf_find_next_higher_section(Elf32_Word offset)
174 Elf32_Shdr *section;
175 Elf32_Shdr *higher;
176 Elf32_Word sectionsize;
177 int numsections;
178 int i = 0;
180 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
181 sectionsize = read_half(elf_header->e_shentsize);
182 numsections = read_half(elf_header->e_shnum);
184 higher = NULL;
186 for (i=0;i<numsections;i++) {
187 if (read_word(section->sh_offset) >= offset) {
188 if (higher == NULL) {
189 higher = section;
190 } else if (read_word(section->sh_offset) < read_word(higher->sh_offset)) {
191 higher = section;
195 section = (Elf32_Shdr *)((char *)section + sectionsize);
198 return higher;
201 Elf32_Word
202 vma_to_offset(Elf32_Addr addr)
204 Elf32_Shdr *section;
205 Elf32_Shdr *higher;
206 Elf32_Word sectionsize;
207 int numsections;
208 int i = 0;
210 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
211 sectionsize = read_half(elf_header->e_shentsize);
212 numsections = read_half(elf_header->e_shnum);
214 higher = NULL;
216 for (i=0;i<numsections;i++) {
217 if ( (addr >= read_word(section->sh_addr)) &&
218 (addr < read_word(section->sh_addr) + read_word(section->sh_size)) ) {
219 return read_word(section->sh_offset) + (addr - read_word(section->sh_addr));
222 section = (Elf32_Shdr *)((char *)section + sectionsize);
225 fprintf(stderr, "Warning, unable to convert address %d (0x%x) to file offset\n",
226 addr, addr);
227 return 0;
231 void
232 find_segment_addr_min_max(Elf32_Word file_offset,
233 Elf32_Addr *start, Elf32_Addr *end)
235 Elf32_Phdr *segment;
236 Elf32_Word segmentsize;
237 int numsegments;
238 int i = 0;
240 segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
241 segmentsize = read_half(elf_header->e_phentsize);
242 numsegments = read_half(elf_header->e_phnum);
244 for (i=0;i<numsegments;i++) {
245 if ((file_offset >= read_word(segment->p_offset)) &&
246 (file_offset < read_word(segment->p_offset) + read_word(segment->p_filesz))) {
247 *start = read_word(segment->p_vaddr);
248 *end = read_word(segment->p_vaddr) + read_word(segment->p_memsz);
249 return;
252 segment = (Elf32_Phdr *)((char *)segment + segmentsize);
254 fprintf(stderr, "Error: Couldn't find segment in find_segment_addr_min_max()\n");
257 void *
258 dynamic_find_tag(Elf32_Shdr *dynamic, Elf32_Sword d_tag)
260 int i;
261 Elf32_Dyn *element;
263 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
264 for (i=0; read_sword(element[i].d_tag) != DT_NULL; i++) {
265 if (read_sword(element[i].d_tag) == d_tag) {
266 return FILE_OFFSET(read_word(element[i].d_un.d_ptr));
270 return NULL;
273 Elf32_Word
274 fixup_offset(Elf32_Word offset)
276 if (offset >= hole_index) {
277 return offset - hole_len;
279 return offset;
282 Elf32_Word
283 fixup_size(Elf32_Word offset, Elf32_Word size)
285 /* Note: Doesn't handle the cases where the hole and the size intersect
286 partially. */
288 if ( (hole_index >= offset) &&
289 (hole_index < offset + size)){
290 return size - hole_len;
293 return size;
296 Elf32_Addr
297 fixup_addr(Elf32_Addr addr)
299 if (addr == 0)
300 return 0;
303 if ( (addr < hole_addr_remap_start) ||
304 (addr >= hole_addr_remap_end))
305 return addr;
308 if (addr >= hole_addr_start) {
309 return addr - hole_len;
311 return addr;
314 Elf32_Word
315 fixup_addr_size(Elf32_Addr addr, Elf32_Word size)
317 /* Note: Doesn't handle the cases where the hole and the size intersect
318 partially. */
320 if ( (addr < hole_addr_remap_start) ||
321 (addr >= hole_addr_remap_end))
322 return size;
324 if ( (hole_addr_start >= addr) &&
325 (hole_addr_start < addr + size)){
326 return size - hole_len;
329 return size;
332 void
333 possibly_add_string(int name_idx, const char *name)
335 struct dynamic_symbol *dynamic_symbol;
336 if (name_idx != 0) {
337 dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) name_idx);
339 if (dynamic_symbol == NULL) {
341 dynamic_symbol = g_new(struct dynamic_symbol, 1);
343 dynamic_symbol->old_index = name_idx;
344 dynamic_symbol->new_index = 0;
345 dynamic_symbol->string = g_strdup(name);
347 g_hash_table_insert(used_dynamic_symbols, (gpointer)name_idx, dynamic_symbol);
348 /*printf("added dynamic string: %s (%d)\n", dynamic_symbol->string, name_idx);*/
353 Elf32_Word
354 fixup_string(Elf32_Word old_idx)
356 struct dynamic_symbol *dynamic_symbol;
358 if (old_idx == 0)
359 return 0;
361 dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) old_idx);
363 if (dynamic_symbol == NULL) {
364 fprintf(stderr, "AAAAAAAAAAAARGH!? Unknown string found in fixup (index: %d)!\n", old_idx);
365 return 0;
368 return dynamic_symbol->new_index;
373 void
374 add_strings_from_dynsym(Elf32_Shdr *dynsym, char *strtab)
376 Elf32_Sym *symbol;
377 Elf32_Sym *symbol_end;
378 Elf32_Word entry_size;
381 symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset));
382 symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size));
383 entry_size = read_word(dynsym->sh_entsize);
385 while (symbol < symbol_end) {
386 int name_idx;
387 struct dynamic_symbol *dynamic_symbol;
389 name_idx = read_word(symbol->st_name);
390 possibly_add_string(name_idx, &strtab[name_idx]);
393 symbol = (Elf32_Sym *)((char *)symbol + entry_size);
398 void
399 fixup_strings_in_dynsym(Elf32_Shdr *dynsym)
401 Elf32_Sym *symbol;
402 Elf32_Sym *symbol_end;
403 Elf32_Word entry_size;
406 symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset));
407 symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size));
408 entry_size = read_word(dynsym->sh_entsize);
410 while (symbol < symbol_end) {
411 struct dynamic_symbol *dynamic_symbol;
413 write_word(&symbol->st_name,
414 fixup_string(read_word(symbol->st_name)));
416 symbol = (Elf32_Sym *)((char *)symbol + entry_size);
421 void
422 add_strings_from_dynamic(Elf32_Shdr *dynamic, char *strtab)
424 int i;
425 int name_idx;
426 Elf32_Dyn *element;
427 Elf32_Word entry_size;
429 entry_size = read_word(dynamic->sh_entsize);
432 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
433 while (read_sword(element->d_tag) != DT_NULL) {
435 switch(read_sword(element->d_tag)) {
436 case DT_NEEDED:
437 case DT_SONAME:
438 case DT_RPATH:
439 name_idx = read_word(element->d_un.d_val);
440 /*if (name_idx) printf("d_tag: %d\n", element->d_tag);*/
441 possibly_add_string(name_idx, &strtab[name_idx]);
442 break;
443 default:
445 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
448 element = (Elf32_Dyn *)((char *)element + entry_size);
453 void
454 fixup_strings_in_dynamic(Elf32_Shdr *dynamic)
456 int i;
457 int name_idx;
458 Elf32_Dyn *element;
459 Elf32_Word entry_size;
461 entry_size = read_word(dynamic->sh_entsize);
463 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
464 while (read_sword(element->d_tag) != DT_NULL) {
466 switch(read_sword(element->d_tag)) {
467 case DT_NEEDED:
468 case DT_SONAME:
469 case DT_RPATH:
470 write_word(&element->d_un.d_val,
471 fixup_string(read_word(element->d_un.d_val)));
472 break;
473 default:
475 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
478 element = (Elf32_Dyn *)((char *)element + entry_size);
484 void
485 add_strings_from_ver_d(Elf32_Shdr *ver_d, char *strtab)
487 Elf32_Verdaux *veraux;
488 Elf32_Verdef *verdef;
489 int num_aux;
490 int name_idx;
491 int i;
492 int cont;
494 verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
496 do {
497 num_aux = read_half(verdef->vd_cnt);
498 veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
499 for (i=0; i<num_aux; i++) {
500 name_idx = read_word(veraux->vda_name);
501 possibly_add_string(name_idx, &strtab[name_idx]);
502 veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
505 cont = read_word(verdef->vd_next) != 0;
506 verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
507 } while (cont);
511 void
512 fixup_strings_in_ver_d(Elf32_Shdr *ver_d)
514 Elf32_Verdaux *veraux;
515 Elf32_Verdef *verdef;
516 int num_aux;
517 int name_idx;
518 int i;
519 int cont;
521 verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
523 do {
524 num_aux = read_half(verdef->vd_cnt);
525 veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
526 for (i=0; i<num_aux; i++) {
527 write_word(&veraux->vda_name,
528 fixup_string(read_word(veraux->vda_name)));
529 veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
532 cont = read_word(verdef->vd_next) != 0;
533 verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
534 } while (cont);
538 void
539 add_strings_from_ver_r(Elf32_Shdr *ver_r, char *strtab)
541 Elf32_Vernaux *veraux;
542 Elf32_Verneed *verneed;
543 int num_aux;
544 int name_idx;
545 int i;
546 int cont;
548 verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
550 do {
551 name_idx = read_word(verneed->vn_file);
552 possibly_add_string(name_idx, &strtab[name_idx]);
553 num_aux = read_half(verneed->vn_cnt);
554 veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
555 for (i=0; i<num_aux; i++) {
556 name_idx = read_word(veraux->vna_name);
557 possibly_add_string(name_idx, &strtab[name_idx]);
558 veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
561 cont = read_word(verneed->vn_next) != 0;
562 verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
563 } while (cont);
566 void
567 fixup_strings_in_ver_r(Elf32_Shdr *ver_r)
569 Elf32_Vernaux *veraux;
570 Elf32_Verneed *verneed;
571 int num_aux;
572 int name_idx;
573 int i;
574 int cont;
576 verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
578 do {
579 write_word(&verneed->vn_file,
580 fixup_string(read_word(verneed->vn_file)));
581 num_aux = read_half(verneed->vn_cnt);
582 veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
583 for (i=0; i<num_aux; i++) {
584 write_word(&veraux->vna_name,
585 fixup_string(read_word(veraux->vna_name)));
586 veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
589 cont = read_word(verneed->vn_next) != 0;
590 verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
591 } while (cont);
594 gboolean sum_size(gpointer key,
595 struct dynamic_symbol *sym,
596 int *size)
598 *size += strlen(sym->string) + 1;
599 return 1;
602 struct index_n_dynstr {
603 int index;
604 unsigned char *dynstr;
607 gboolean output_string(gpointer key,
608 struct dynamic_symbol *sym,
609 struct index_n_dynstr *x)
611 sym->new_index = x->index;
612 memcpy(x->dynstr + x->index, sym->string, strlen(sym->string) + 1);
613 x->index += strlen(sym->string) + 1;
614 return 1;
618 unsigned char *
619 generate_new_dynstr(Elf32_Word *size_out)
621 int size;
622 unsigned char *new_dynstr;
623 struct index_n_dynstr x;
625 size = 1; /* first a zero */
626 g_hash_table_foreach (used_dynamic_symbols,
627 (GHFunc)sum_size,
628 &size);
631 new_dynstr = g_malloc(size);
633 new_dynstr[0] = 0;
634 x.index = 1;
635 x.dynstr = new_dynstr;
636 g_hash_table_foreach (used_dynamic_symbols,
637 (GHFunc)output_string,
638 &x);
640 *size_out = size;
641 return new_dynstr;
644 void
645 remap_sections(void)
647 Elf32_Shdr *section;
648 Elf32_Word sectionsize;
649 int numsections;
650 int i = 0;
652 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
653 sectionsize = read_half(elf_header->e_shentsize);
654 numsections = read_half(elf_header->e_shnum);
656 for (i=0;i<numsections;i++) {
657 write_word(&section->sh_size,
658 fixup_size(read_word(section->sh_offset),
659 read_word(section->sh_size)));
660 write_word(&section->sh_offset,
661 fixup_offset(read_word(section->sh_offset)));
662 write_word(&section->sh_addr,
663 fixup_addr(read_word(section->sh_addr)));
665 section = (Elf32_Shdr *)((char *)section + sectionsize);
670 void
671 remap_segments(void)
673 Elf32_Phdr *segment;
674 Elf32_Word segmentsize;
675 Elf32_Word p_align;
676 int numsegments;
677 int i = 0;
679 segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
680 segmentsize = read_half(elf_header->e_phentsize);
681 numsegments = read_half(elf_header->e_phnum);
683 for (i=0;i<numsegments;i++) {
684 write_word(&segment->p_filesz,
685 fixup_size(read_word(segment->p_offset),
686 read_word(segment->p_filesz)));
687 write_word(&segment->p_offset,
688 fixup_offset(read_word(segment->p_offset)));
690 write_word(&segment->p_memsz,
691 fixup_addr_size(read_word(segment->p_vaddr),
692 read_word(segment->p_memsz)));
693 write_word(&segment->p_vaddr,
694 fixup_addr(read_word(segment->p_vaddr)));
695 write_word(&segment->p_paddr,
696 read_word(segment->p_vaddr));
698 /* Consistancy checking: */
699 p_align = read_word(segment->p_align);
700 if (p_align > 1) {
701 if ((read_word(segment->p_vaddr) - read_word(segment->p_offset))%p_align != 0) {
702 fprintf(stderr, "Warning, creating non-aligned segment addr: %x offset: %x allign: %x\n",
703 read_word(segment->p_vaddr), read_word(segment->p_offset), p_align);
707 segment = (Elf32_Phdr *)((char *)segment + segmentsize);
711 void
712 remap_elf_header(void)
714 write_word(&elf_header->e_phoff,
715 fixup_offset(read_word(elf_header->e_phoff)));
716 write_word(&elf_header->e_shoff,
717 fixup_offset(read_word(elf_header->e_shoff)));
719 write_word(&elf_header->e_entry,
720 fixup_addr(read_word(elf_header->e_entry)));
723 void
724 remap_symtab(Elf32_Shdr *symtab)
726 Elf32_Sym *symbol;
727 Elf32_Sym *symbol_end;
728 Elf32_Word entry_size;
730 symbol = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset));
731 symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset) +
732 read_word(symtab->sh_size));
733 entry_size = read_word(symtab->sh_entsize);
735 while (symbol < symbol_end) {
736 write_word(&symbol->st_value,
737 fixup_addr(read_word(symbol->st_value)));
738 symbol = (Elf32_Sym *)((char *)symbol + entry_size);
743 /* Ugly global variables: */
744 Elf32_Addr got_data_start = 0;
745 Elf32_Addr got_data_end = 0;
748 void
749 remap_rel_section(Elf32_Rel *rel, Elf32_Word size, Elf32_Word entry_size)
751 Elf32_Rel *rel_end;
752 Elf32_Word offset;
753 Elf32_Addr *addr;
754 Elf32_Word type;
756 rel_end = (Elf32_Rel *)((char *)rel + size);
758 while (rel < rel_end) {
759 type = ELF32_R_TYPE(read_word(rel->r_info));
760 switch (machine_type) {
761 case EM_386:
762 if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
763 /* We need to relocate the data this is pointing to too. */
764 offset = vma_to_offset(read_word(rel->r_offset));
766 addr = (Elf32_Addr *)FILE_OFFSET(offset);
767 write_word(addr,
768 fixup_addr(read_word(*addr)));
770 write_word(&rel->r_offset,
771 fixup_addr(read_word(rel->r_offset)));
772 break;
773 case EM_PPC:
774 /* The PPC always uses RELA relocations */
775 break;
779 rel = (Elf32_Rel *)((char *)rel + entry_size);
783 void
784 remap_rela_section(Elf32_Rela *rela, Elf32_Word size, Elf32_Word entry_size)
786 Elf32_Rela *rela_end;
787 Elf32_Addr *addr;
788 Elf32_Word offset;
789 Elf32_Word type;
790 Elf32_Word bitmask;
792 rela_end = (Elf32_Rela *)((char *)rela + size);
794 while (rela < rela_end) {
795 type = ELF32_R_TYPE(read_word(rela->r_info));
796 switch (machine_type) {
797 case EM_386:
798 if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
799 /* We need to relocate the data this is pointing to too. */
800 offset = vma_to_offset(read_word(rela->r_offset));
802 addr = (Elf32_Addr *)FILE_OFFSET(offset);
803 write_word(addr,
804 fixup_addr(read_word(*addr)));
806 write_word(&rela->r_offset,
807 fixup_addr(read_word(rela->r_offset)));
808 break;
809 case EM_PPC:
810 /* Some systems do not have PowerPC relocations defined */
811 #ifdef R_PPC_NONE
812 switch (type) {
813 case R_PPC_RELATIVE:
814 write_word((Elf32_Word *)&rela->r_addend,
815 fixup_addr(read_word(rela->r_addend)));
816 /* Fall through for 32bit offset fixup */
817 case R_PPC_ADDR32:
818 case R_PPC_GLOB_DAT:
819 case R_PPC_JMP_SLOT:
820 write_word(&rela->r_offset,
821 fixup_addr(read_word(rela->r_offset)));
822 break;
823 case R_PPC_NONE:
824 break;
825 default:
826 fprintf(stderr, "Warning, unhandled PPC relocation type %d\n", type);
828 #endif
829 break;
832 rela = (Elf32_Rela *)((char *)rela + entry_size);
836 void
837 remap_i386_got(void)
839 Elf32_Shdr *got_section;
840 Elf32_Addr *got;
841 Elf32_Addr *got_end;
842 Elf32_Word entry_size;
844 got_section = elf_find_section_named(".got");
845 if (got_section == NULL) {
846 fprintf(stderr, "Warning, no .got section\n");
847 return;
850 got_data_start = read_word(got_section->sh_offset);
851 got_data_end = got_data_start + read_word(got_section->sh_size);
853 got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
854 got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
855 entry_size = read_word(got_section->sh_entsize);
857 write_word(got,
858 fixup_addr(read_word(*got))); /* Pointer to .dynamic */
861 void
862 remap_ppc_got(void)
864 Elf32_Shdr *got_section;
865 Elf32_Addr *got;
866 Elf32_Addr *got_end;
867 Elf32_Word entry_size;
869 got_section = elf_find_section_named(".got");
870 if (got_section == NULL) {
871 fprintf(stderr, "Warning, no .got section\n");
872 return;
875 got_data_start = read_word(got_section->sh_offset);
876 got_data_end = got_data_start + read_word(got_section->sh_size);
878 got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
879 got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
880 entry_size = read_word(got_section->sh_entsize);
882 /* Skip reserved part.
883 * Note that this should really be found by finding the
884 * _GLOBAL_OFFSET_TABLE symbol, as it could (according to
885 * the spec) point to the middle of the got.
887 got = (Elf32_Addr *)((char *)got + entry_size); /* Skip blrl instruction */
888 write_word(got,
889 fixup_addr(read_word(*got))); /* Pointer to .dynamic */
893 Elf32_Word
894 get_dynamic_val(Elf32_Shdr *dynamic, Elf32_Sword tag)
896 Elf32_Dyn *element;
897 Elf32_Word entry_size;
899 entry_size = read_word(dynamic->sh_entsize);
901 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
902 while (read_sword(element->d_tag) != DT_NULL) {
903 if (read_sword(element->d_tag) == tag) {
904 return read_word(element->d_un.d_val);
906 element = (Elf32_Dyn *)((char *)element + entry_size);
908 return 0;
911 void
912 remap_dynamic(Elf32_Shdr *dynamic, Elf32_Word new_dynstr_size)
914 Elf32_Dyn *element;
915 Elf32_Word entry_size;
916 Elf32_Word rel_size;
917 Elf32_Word rel_entry_size;
918 Elf32_Rel *rel;
919 Elf32_Rela *rela;
920 int jmprel_overlaps;
921 Elf32_Word rel_start, rel_end, jmprel_start, jmprel_end;
923 entry_size = read_word(dynamic->sh_entsize);
925 /* Find out if REL/RELA and JMPREL overlaps: */
926 if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
927 rel_start = get_dynamic_val(dynamic, DT_REL);
928 rel_end = rel_start + get_dynamic_val(dynamic, DT_RELSZ);
929 } else {
930 rel_start = get_dynamic_val(dynamic, DT_RELA);
931 rel_end = rel_start + get_dynamic_val(dynamic, DT_RELASZ);
933 jmprel_start = get_dynamic_val(dynamic, DT_JMPREL);
935 jmprel_overlaps = 0;
936 if ((jmprel_start >= rel_start) && (jmprel_start < rel_end))
937 jmprel_overlaps = 1;
939 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
940 while (read_sword(element->d_tag) != DT_NULL) {
941 switch(read_sword(element->d_tag)) {
942 case DT_STRSZ:
943 write_word(&element->d_un.d_val, new_dynstr_size);
944 break;
945 case DT_PLTGOT:
946 case DT_HASH:
947 case DT_STRTAB:
948 case DT_INIT:
949 case DT_FINI:
950 case DT_VERDEF:
951 case DT_VERNEED:
952 case DT_VERSYM:
953 write_word(&element->d_un.d_ptr,
954 fixup_addr(read_word(element->d_un.d_ptr)));
955 break;
956 case DT_JMPREL:
957 rel_size = get_dynamic_val(dynamic, DT_PLTRELSZ);
958 if (!jmprel_overlaps) {
959 if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
960 rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
961 rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
962 remap_rel_section(rel, rel_size, rel_entry_size);
963 } else {
964 rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
965 rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
966 remap_rela_section(rela, rel_size, rel_entry_size);
969 write_word(&element->d_un.d_ptr,
970 fixup_addr(read_word(element->d_un.d_ptr)));
971 break;
972 case DT_REL:
973 rel_size = get_dynamic_val(dynamic, DT_RELSZ);
974 rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
975 rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
976 remap_rel_section(rel, rel_size, rel_entry_size);
978 write_word(&element->d_un.d_ptr,
979 fixup_addr(read_word(element->d_un.d_ptr)));
980 break;
981 case DT_RELA:
982 rel_size = get_dynamic_val(dynamic, DT_RELASZ);
983 rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
984 rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
985 remap_rela_section(rela, rel_size, rel_entry_size);
987 write_word(&element->d_un.d_ptr,
988 fixup_addr(read_word(element->d_un.d_ptr)));
989 break;
990 default:
991 /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/
992 break;
995 element = (Elf32_Dyn *)((char *)element + entry_size);
999 void
1000 align_hole(Elf32_Word *start, Elf32_Word *end)
1002 Elf32_Word len;
1003 Elf32_Word align;
1004 Elf32_Shdr *section;
1005 Elf32_Word sectionsize;
1006 int numsections;
1007 int i = 0;
1008 int unaligned;
1010 len = *end - *start;
1011 align = 0;
1013 sectionsize = read_half(elf_header->e_shentsize);
1014 numsections = read_half(elf_header->e_shnum);
1015 do {
1016 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
1017 unaligned = 0;
1019 for (i=0;i<numsections;i++) {
1020 if ( (read_word(section->sh_addralign) > 1) &&
1021 ( (read_word(section->sh_offset) - len + align)%read_word(section->sh_addralign) != 0) ) {
1022 unaligned = 1;
1025 section = (Elf32_Shdr *)((char *)section + sectionsize);
1028 if (unaligned) {
1029 align++;
1032 } while (unaligned);
1034 *start += align;
1038 main(int argc, char *argv[])
1040 int fd;
1041 unsigned char *mapping;
1042 Elf32_Word size;
1043 struct stat statbuf;
1044 Elf32_Shdr *dynamic;
1045 Elf32_Shdr *dynsym;
1046 Elf32_Shdr *symtab;
1047 Elf32_Shdr *dynstr;
1048 Elf32_Shdr *hash;
1049 Elf32_Shdr *higher_section;
1050 Elf32_Word dynstr_index;
1051 Elf32_Shdr *ver_r;
1052 Elf32_Shdr *ver_d;
1053 char *dynstr_data;
1054 unsigned char *new_dynstr;
1055 Elf32_Word old_dynstr_size;
1056 Elf32_Word new_dynstr_size;
1058 if (argc != 2) {
1059 fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
1060 return 1;
1063 fd = open(argv[1], O_RDWR);
1064 if (fd == -1) {
1065 fprintf(stderr, "Cannot open file %s\n", argv[1]);
1066 return 1;
1069 if (fstat(fd, &statbuf) == -1) {
1070 fprintf(stderr, "Cannot stat file %s\n", argv[1]);
1071 return 1;
1074 size = statbuf.st_size;
1076 mapping = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1078 if (mapping == (unsigned char *)-1) {
1079 fprintf(stderr, "Cannot mmap file %s\n", argv[1]);
1080 return 1;
1083 used_dynamic_symbols = g_hash_table_new(g_direct_hash, g_direct_equal);
1085 elf_header = (Elf32_Ehdr *)mapping;
1087 if (strncmp((void *)elf_header, ELFMAG, SELFMAG)!=0) {
1088 fprintf(stderr, "Not an ELF file\n");
1089 return 1;
1092 if (elf_header->e_ident[EI_VERSION] != EV_CURRENT) {
1093 fprintf(stderr, "Wrong ELF file version\n");
1094 return 1;
1097 if (elf_header->e_ident[EI_CLASS] != ELFCLASS32) {
1098 fprintf(stderr, "Only 32bit ELF files supported\n");
1099 return 1;
1102 setup_byteswapping(elf_header->e_ident[EI_DATA]);
1104 machine_type = read_half(elf_header->e_machine);
1105 if ( (machine_type != EM_386) &&
1106 (machine_type != EM_PPC) ) {
1107 fprintf(stderr, "Unsupported architecture. Supported are: x86, ppc\n");
1108 return 1;
1111 if (read_half(elf_header->e_type) != ET_DYN) {
1112 fprintf(stderr, "Not an ELF shared object\n");
1113 return 1;
1116 dynamic = elf_find_section(SHT_DYNAMIC);
1117 dynsym = elf_find_section(SHT_DYNSYM);
1118 symtab = elf_find_section(SHT_SYMTAB);
1119 dynstr_index = read_word(dynsym->sh_link);
1120 dynstr = elf_find_section_num(dynstr_index);
1121 dynstr_data = (char *)FILE_OFFSET(read_word(dynstr->sh_offset));
1122 old_dynstr_size = read_word(dynstr->sh_size);
1123 ver_d = elf_find_section(SHT_GNU_verdef);
1124 ver_r = elf_find_section(SHT_GNU_verneed);
1125 hash = elf_find_section(SHT_HASH);
1127 /* Generate hash table with all used strings: */
1129 add_strings_from_dynsym(dynsym, dynstr_data);
1130 add_strings_from_dynamic(dynamic, dynstr_data);
1131 if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
1132 add_strings_from_ver_d(ver_d, dynstr_data);
1133 if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
1134 add_strings_from_ver_r(ver_r, dynstr_data);
1136 /* Generate new dynstr section from the used strings hashtable: */
1138 new_dynstr = generate_new_dynstr(&new_dynstr_size);
1140 printf("New dynstr size: %d\n", new_dynstr_size);
1141 printf("Old dynstr size: %d\n", old_dynstr_size);
1144 if (new_dynstr_size >= old_dynstr_size) {
1145 return 0;
1148 /* Fixup all references: */
1149 fixup_strings_in_dynsym(dynsym);
1150 fixup_strings_in_dynamic(dynamic);
1151 if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
1152 fixup_strings_in_ver_d(ver_d);
1153 if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
1154 fixup_strings_in_ver_r(ver_r);
1156 /* Copy over the new dynstr: */
1157 memcpy(dynstr_data, new_dynstr, new_dynstr_size);
1158 memset(dynstr_data + new_dynstr_size, ' ', old_dynstr_size-new_dynstr_size);
1160 /* Compact the dynstr section and the file: */
1162 /* 1. Set up the data for the fixup_offset() function: */
1163 hole_index = read_word(dynstr->sh_offset) + new_dynstr_size;
1164 higher_section = elf_find_next_higher_section(hole_index);
1165 hole_end = read_word(higher_section->sh_offset);
1167 align_hole(&hole_index, &hole_end);
1168 hole_len = hole_end - hole_index;
1170 hole_addr_start = hole_index; /* TODO: Fix this to something better */
1172 find_segment_addr_min_max(read_word(dynstr->sh_offset),
1173 &hole_addr_remap_start, &hole_addr_remap_end);
1176 printf("Hole remap: 0x%lx - 0x%lx\n", hole_addr_remap_start, hole_addr_remap_end);
1178 printf("hole: %lu - %lu (%lu bytes)\n", hole_index, hole_end, hole_len);
1179 printf("hole: 0x%lx - 0x%lx (0x%lx bytes)\n", hole_index, hole_end, hole_len);
1182 /* 2. Change all section and segment sizes and offsets: */
1183 remap_symtab(dynsym);
1184 if (symtab)
1185 remap_symtab(symtab);
1187 if (machine_type == EM_386)
1188 remap_i386_got();
1189 if (machine_type == EM_PPC)
1190 remap_ppc_got();
1192 remap_dynamic(dynamic, new_dynstr_size);
1193 remap_sections(); /* After this line the section headers are wrong */
1194 remap_segments();
1195 remap_elf_header();
1197 /* 3. Do the real compacting. */
1199 memmove(mapping + hole_index,
1200 mapping + hole_index + hole_len,
1201 size - (hole_index + hole_len));
1203 munmap(mapping, size);
1205 ftruncate(fd, size - hole_len);
1206 close(fd);
1208 return 0;