Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / config / elf-dynstr-gc.c
blobf9a8008bd3a91c8d3412370b5f62274071bcbfa7
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 * ***** BEGIN LICENSE BLOCK *****
13 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
15 * The contents of this file are subject to the Mozilla Public License Version
16 * 1.1 (the "License"); you may not use this file except in compliance with
17 * the License. You may obtain a copy of the License at
18 * http://www.mozilla.org/MPL/
20 * Software distributed under the License is distributed on an "AS IS" basis,
21 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
22 * for the specific language governing rights and limitations under the
23 * License.
25 * The Original Code is mozilla.org Code.
27 * The Initial Developer of the Original Code is
28 * Netscape Communications Corporation.
29 * Portions created by the Initial Developer are Copyright (C) 2001
30 * the Initial Developer. All Rights Reserved.
32 * Contributor(s):
34 * Alternatively, the contents of this file may be used under the terms of
35 * either of the GNU General Public License Version 2 or later (the "GPL"),
36 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
37 * in which case the provisions of the GPL or the LGPL are applicable instead
38 * of those above. If you wish to allow use of your version of this file only
39 * under the terms of either the GPL or the LGPL, and not to allow others to
40 * use your version of this file under the terms of the MPL, indicate your
41 * decision by deleting the provisions above and replace them with the notice
42 * and other provisions required by the GPL or the LGPL. If you do not delete
43 * the provisions above, a recipient may use your version of this file under
44 * the terms of any one of the MPL, the GPL or the LGPL.
46 * ***** END LICENSE BLOCK ***** */
49 #include <stdio.h>
50 #include <unistd.h>
51 #include <fcntl.h>
52 #include <sys/types.h>
53 #include <sys/stat.h>
54 #include <sys/mman.h>
56 #include <elf.h>
57 #include <glib.h>
58 #include <string.h>
61 Elf32_Ehdr *elf_header = NULL;
62 #define FILE_OFFSET(offset) ((unsigned char *)(elf_header) + (offset))
64 struct dynamic_symbol {
65 Elf32_Word old_index;
66 Elf32_Word new_index;
67 char *string;
70 GHashTable *used_dynamic_symbols = NULL;
71 /* Data is dynamic_symbols, hashes on old_index */
72 Elf32_Word hole_index;
73 Elf32_Word hole_end;
74 Elf32_Word hole_len;
76 Elf32_Addr hole_addr_start;
77 Elf32_Addr hole_addr_remap_start;
78 Elf32_Addr hole_addr_remap_end;
80 int need_byteswap;
82 unsigned char machine_type;
84 Elf32_Word
85 read_word(Elf32_Word w)
87 if (need_byteswap)
88 w = GUINT32_SWAP_LE_BE(w);
89 return w;
92 Elf32_Sword
93 read_sword(Elf32_Sword w)
95 if (need_byteswap)
96 w = (Elf32_Sword)GUINT32_SWAP_LE_BE((guint32)w);
97 return w;
100 void
101 write_word(Elf32_Word *ptr, Elf32_Word w)
103 if (need_byteswap)
104 w = GUINT32_SWAP_LE_BE(w);
105 *ptr = w;
108 Elf32_Half
109 read_half(Elf32_Half h)
111 if (need_byteswap)
112 h = GUINT16_SWAP_LE_BE(h);
113 return h;
116 void
117 write_half(Elf32_Half *ptr, Elf32_Half h)
119 if (need_byteswap)
120 h = GUINT16_SWAP_LE_BE(h);
121 *ptr = h;
124 void
125 setup_byteswapping(unsigned char ei_data)
127 need_byteswap = 0;
128 #if G_BYTE_ORDER == G_BIG_ENDIAN
129 if (ei_data == ELFDATA2LSB)
130 need_byteswap = 1;
131 #endif
132 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
133 if (ei_data == ELFDATA2MSB)
134 need_byteswap = 1;
135 #endif
139 Elf32_Shdr *
140 elf_find_section_num(int section_index)
142 Elf32_Shdr *section;
143 Elf32_Word sectionsize;
145 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
146 sectionsize = read_half(elf_header->e_shentsize);
148 section = (Elf32_Shdr *)((char *)section + sectionsize*section_index);
150 return section;
153 Elf32_Shdr *
154 elf_find_section_named(char *name)
156 Elf32_Shdr *section;
157 Elf32_Shdr *strtab_section;
158 Elf32_Word sectionsize;
159 int numsections;
160 char *strtab;
161 int i = 0;
163 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
165 strtab_section = elf_find_section_num(read_half(elf_header->e_shstrndx));
167 strtab = (char *)FILE_OFFSET(read_word(strtab_section->sh_offset));
169 sectionsize = read_half(elf_header->e_shentsize);
170 numsections = read_half(elf_header->e_shnum);
172 for (i=0;i<numsections;i++) {
173 if (strcmp(&strtab[read_word(section->sh_name)], name) == 0) {
174 return section;
176 section = (Elf32_Shdr *)((char *)section + sectionsize);
178 return NULL;
182 Elf32_Shdr *
183 elf_find_section(Elf32_Word sh_type)
185 Elf32_Shdr *section;
186 Elf32_Word sectionsize;
187 int numsections;
188 int i = 0;
190 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
191 sectionsize = read_half(elf_header->e_shentsize);
192 numsections = read_half(elf_header->e_shnum);
194 for (i=0;i<numsections;i++) {
195 if (read_word(section->sh_type) == sh_type) {
196 return section;
198 section = (Elf32_Shdr *)((char *)section + sectionsize);
200 return NULL;
203 Elf32_Shdr *
204 elf_find_next_higher_section(Elf32_Word offset)
206 Elf32_Shdr *section;
207 Elf32_Shdr *higher;
208 Elf32_Word sectionsize;
209 int numsections;
210 int i = 0;
212 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
213 sectionsize = read_half(elf_header->e_shentsize);
214 numsections = read_half(elf_header->e_shnum);
216 higher = NULL;
218 for (i=0;i<numsections;i++) {
219 if (read_word(section->sh_offset) >= offset) {
220 if (higher == NULL) {
221 higher = section;
222 } else if (read_word(section->sh_offset) < read_word(higher->sh_offset)) {
223 higher = section;
227 section = (Elf32_Shdr *)((char *)section + sectionsize);
230 return higher;
233 Elf32_Word
234 vma_to_offset(Elf32_Addr addr)
236 Elf32_Shdr *section;
237 Elf32_Shdr *higher;
238 Elf32_Word sectionsize;
239 int numsections;
240 int i = 0;
242 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
243 sectionsize = read_half(elf_header->e_shentsize);
244 numsections = read_half(elf_header->e_shnum);
246 higher = NULL;
248 for (i=0;i<numsections;i++) {
249 if ( (addr >= read_word(section->sh_addr)) &&
250 (addr < read_word(section->sh_addr) + read_word(section->sh_size)) ) {
251 return read_word(section->sh_offset) + (addr - read_word(section->sh_addr));
254 section = (Elf32_Shdr *)((char *)section + sectionsize);
257 fprintf(stderr, "Warning, unable to convert address %d (0x%x) to file offset\n",
258 addr, addr);
259 return 0;
263 void
264 find_segment_addr_min_max(Elf32_Word file_offset,
265 Elf32_Addr *start, Elf32_Addr *end)
267 Elf32_Phdr *segment;
268 Elf32_Word segmentsize;
269 int numsegments;
270 int i = 0;
272 segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
273 segmentsize = read_half(elf_header->e_phentsize);
274 numsegments = read_half(elf_header->e_phnum);
276 for (i=0;i<numsegments;i++) {
277 if ((file_offset >= read_word(segment->p_offset)) &&
278 (file_offset < read_word(segment->p_offset) + read_word(segment->p_filesz))) {
279 *start = read_word(segment->p_vaddr);
280 *end = read_word(segment->p_vaddr) + read_word(segment->p_memsz);
281 return;
284 segment = (Elf32_Phdr *)((char *)segment + segmentsize);
286 fprintf(stderr, "Error: Couldn't find segment in find_segment_addr_min_max()\n");
289 void *
290 dynamic_find_tag(Elf32_Shdr *dynamic, Elf32_Sword d_tag)
292 int i;
293 Elf32_Dyn *element;
295 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
296 for (i=0; read_sword(element[i].d_tag) != DT_NULL; i++) {
297 if (read_sword(element[i].d_tag) == d_tag) {
298 return FILE_OFFSET(read_word(element[i].d_un.d_ptr));
302 return NULL;
305 Elf32_Word
306 fixup_offset(Elf32_Word offset)
308 if (offset >= hole_index) {
309 return offset - hole_len;
311 return offset;
314 Elf32_Word
315 fixup_size(Elf32_Word offset, Elf32_Word size)
317 /* Note: Doesn't handle the cases where the hole and the size intersect
318 partially. */
320 if ( (hole_index >= offset) &&
321 (hole_index < offset + size)){
322 return size - hole_len;
325 return size;
328 Elf32_Addr
329 fixup_addr(Elf32_Addr addr)
331 if (addr == 0)
332 return 0;
335 if ( (addr < hole_addr_remap_start) ||
336 (addr >= hole_addr_remap_end))
337 return addr;
340 if (addr >= hole_addr_start) {
341 return addr - hole_len;
343 return addr;
346 Elf32_Word
347 fixup_addr_size(Elf32_Addr addr, Elf32_Word size)
349 /* Note: Doesn't handle the cases where the hole and the size intersect
350 partially. */
352 if ( (addr < hole_addr_remap_start) ||
353 (addr >= hole_addr_remap_end))
354 return size;
356 if ( (hole_addr_start >= addr) &&
357 (hole_addr_start < addr + size)){
358 return size - hole_len;
361 return size;
364 void
365 possibly_add_string(int name_idx, const char *name)
367 struct dynamic_symbol *dynamic_symbol;
368 if (name_idx != 0) {
369 dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) name_idx);
371 if (dynamic_symbol == NULL) {
373 dynamic_symbol = g_new(struct dynamic_symbol, 1);
375 dynamic_symbol->old_index = name_idx;
376 dynamic_symbol->new_index = 0;
377 dynamic_symbol->string = g_strdup(name);
379 g_hash_table_insert(used_dynamic_symbols, (gpointer)name_idx, dynamic_symbol);
380 /*printf("added dynamic string: %s (%d)\n", dynamic_symbol->string, name_idx);*/
385 Elf32_Word
386 fixup_string(Elf32_Word old_idx)
388 struct dynamic_symbol *dynamic_symbol;
390 if (old_idx == 0)
391 return 0;
393 dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) old_idx);
395 if (dynamic_symbol == NULL) {
396 fprintf(stderr, "AAAAAAAAAAAARGH!? Unknown string found in fixup (index: %d)!\n", old_idx);
397 return 0;
400 return dynamic_symbol->new_index;
405 void
406 add_strings_from_dynsym(Elf32_Shdr *dynsym, char *strtab)
408 Elf32_Sym *symbol;
409 Elf32_Sym *symbol_end;
410 Elf32_Word entry_size;
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);
417 while (symbol < symbol_end) {
418 int name_idx;
419 struct dynamic_symbol *dynamic_symbol;
421 name_idx = read_word(symbol->st_name);
422 possibly_add_string(name_idx, &strtab[name_idx]);
425 symbol = (Elf32_Sym *)((char *)symbol + entry_size);
430 void
431 fixup_strings_in_dynsym(Elf32_Shdr *dynsym)
433 Elf32_Sym *symbol;
434 Elf32_Sym *symbol_end;
435 Elf32_Word entry_size;
438 symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset));
439 symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size));
440 entry_size = read_word(dynsym->sh_entsize);
442 while (symbol < symbol_end) {
443 struct dynamic_symbol *dynamic_symbol;
445 write_word(&symbol->st_name,
446 fixup_string(read_word(symbol->st_name)));
448 symbol = (Elf32_Sym *)((char *)symbol + entry_size);
453 void
454 add_strings_from_dynamic(Elf32_Shdr *dynamic, char *strtab)
456 int i;
457 int name_idx;
458 Elf32_Dyn *element;
459 Elf32_Word entry_size;
461 entry_size = read_word(dynamic->sh_entsize);
464 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
465 while (read_sword(element->d_tag) != DT_NULL) {
467 switch(read_sword(element->d_tag)) {
468 case DT_NEEDED:
469 case DT_SONAME:
470 case DT_RPATH:
471 name_idx = read_word(element->d_un.d_val);
472 /*if (name_idx) printf("d_tag: %d\n", element->d_tag);*/
473 possibly_add_string(name_idx, &strtab[name_idx]);
474 break;
475 default:
477 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
480 element = (Elf32_Dyn *)((char *)element + entry_size);
485 void
486 fixup_strings_in_dynamic(Elf32_Shdr *dynamic)
488 int i;
489 int name_idx;
490 Elf32_Dyn *element;
491 Elf32_Word entry_size;
493 entry_size = read_word(dynamic->sh_entsize);
495 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
496 while (read_sword(element->d_tag) != DT_NULL) {
498 switch(read_sword(element->d_tag)) {
499 case DT_NEEDED:
500 case DT_SONAME:
501 case DT_RPATH:
502 write_word(&element->d_un.d_val,
503 fixup_string(read_word(element->d_un.d_val)));
504 break;
505 default:
507 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
510 element = (Elf32_Dyn *)((char *)element + entry_size);
516 void
517 add_strings_from_ver_d(Elf32_Shdr *ver_d, char *strtab)
519 Elf32_Verdaux *veraux;
520 Elf32_Verdef *verdef;
521 int num_aux;
522 int name_idx;
523 int i;
524 int cont;
526 verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
528 do {
529 num_aux = read_half(verdef->vd_cnt);
530 veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
531 for (i=0; i<num_aux; i++) {
532 name_idx = read_word(veraux->vda_name);
533 possibly_add_string(name_idx, &strtab[name_idx]);
534 veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
537 cont = read_word(verdef->vd_next) != 0;
538 verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
539 } while (cont);
543 void
544 fixup_strings_in_ver_d(Elf32_Shdr *ver_d)
546 Elf32_Verdaux *veraux;
547 Elf32_Verdef *verdef;
548 int num_aux;
549 int name_idx;
550 int i;
551 int cont;
553 verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
555 do {
556 num_aux = read_half(verdef->vd_cnt);
557 veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
558 for (i=0; i<num_aux; i++) {
559 write_word(&veraux->vda_name,
560 fixup_string(read_word(veraux->vda_name)));
561 veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
564 cont = read_word(verdef->vd_next) != 0;
565 verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
566 } while (cont);
570 void
571 add_strings_from_ver_r(Elf32_Shdr *ver_r, char *strtab)
573 Elf32_Vernaux *veraux;
574 Elf32_Verneed *verneed;
575 int num_aux;
576 int name_idx;
577 int i;
578 int cont;
580 verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
582 do {
583 name_idx = read_word(verneed->vn_file);
584 possibly_add_string(name_idx, &strtab[name_idx]);
585 num_aux = read_half(verneed->vn_cnt);
586 veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
587 for (i=0; i<num_aux; i++) {
588 name_idx = read_word(veraux->vna_name);
589 possibly_add_string(name_idx, &strtab[name_idx]);
590 veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
593 cont = read_word(verneed->vn_next) != 0;
594 verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
595 } while (cont);
598 void
599 fixup_strings_in_ver_r(Elf32_Shdr *ver_r)
601 Elf32_Vernaux *veraux;
602 Elf32_Verneed *verneed;
603 int num_aux;
604 int name_idx;
605 int i;
606 int cont;
608 verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
610 do {
611 write_word(&verneed->vn_file,
612 fixup_string(read_word(verneed->vn_file)));
613 num_aux = read_half(verneed->vn_cnt);
614 veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
615 for (i=0; i<num_aux; i++) {
616 write_word(&veraux->vna_name,
617 fixup_string(read_word(veraux->vna_name)));
618 veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
621 cont = read_word(verneed->vn_next) != 0;
622 verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
623 } while (cont);
626 gboolean sum_size(gpointer key,
627 struct dynamic_symbol *sym,
628 int *size)
630 *size += strlen(sym->string) + 1;
631 return 1;
634 struct index_n_dynstr {
635 int index;
636 unsigned char *dynstr;
639 gboolean output_string(gpointer key,
640 struct dynamic_symbol *sym,
641 struct index_n_dynstr *x)
643 sym->new_index = x->index;
644 memcpy(x->dynstr + x->index, sym->string, strlen(sym->string) + 1);
645 x->index += strlen(sym->string) + 1;
646 return 1;
650 unsigned char *
651 generate_new_dynstr(Elf32_Word *size_out)
653 int size;
654 unsigned char *new_dynstr;
655 struct index_n_dynstr x;
657 size = 1; /* first a zero */
658 g_hash_table_foreach (used_dynamic_symbols,
659 (GHFunc)sum_size,
660 &size);
663 new_dynstr = g_malloc(size);
665 new_dynstr[0] = 0;
666 x.index = 1;
667 x.dynstr = new_dynstr;
668 g_hash_table_foreach (used_dynamic_symbols,
669 (GHFunc)output_string,
670 &x);
672 *size_out = size;
673 return new_dynstr;
676 void
677 remap_sections(void)
679 Elf32_Shdr *section;
680 Elf32_Word sectionsize;
681 int numsections;
682 int i = 0;
684 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
685 sectionsize = read_half(elf_header->e_shentsize);
686 numsections = read_half(elf_header->e_shnum);
688 for (i=0;i<numsections;i++) {
689 write_word(&section->sh_size,
690 fixup_size(read_word(section->sh_offset),
691 read_word(section->sh_size)));
692 write_word(&section->sh_offset,
693 fixup_offset(read_word(section->sh_offset)));
694 write_word(&section->sh_addr,
695 fixup_addr(read_word(section->sh_addr)));
697 section = (Elf32_Shdr *)((char *)section + sectionsize);
702 void
703 remap_segments(void)
705 Elf32_Phdr *segment;
706 Elf32_Word segmentsize;
707 Elf32_Word p_align;
708 int numsegments;
709 int i = 0;
711 segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
712 segmentsize = read_half(elf_header->e_phentsize);
713 numsegments = read_half(elf_header->e_phnum);
715 for (i=0;i<numsegments;i++) {
716 write_word(&segment->p_filesz,
717 fixup_size(read_word(segment->p_offset),
718 read_word(segment->p_filesz)));
719 write_word(&segment->p_offset,
720 fixup_offset(read_word(segment->p_offset)));
722 write_word(&segment->p_memsz,
723 fixup_addr_size(read_word(segment->p_vaddr),
724 read_word(segment->p_memsz)));
725 write_word(&segment->p_vaddr,
726 fixup_addr(read_word(segment->p_vaddr)));
727 write_word(&segment->p_paddr,
728 read_word(segment->p_vaddr));
730 /* Consistancy checking: */
731 p_align = read_word(segment->p_align);
732 if (p_align > 1) {
733 if ((read_word(segment->p_vaddr) - read_word(segment->p_offset))%p_align != 0) {
734 fprintf(stderr, "Warning, creating non-aligned segment addr: %x offset: %x allign: %x\n",
735 read_word(segment->p_vaddr), read_word(segment->p_offset), p_align);
739 segment = (Elf32_Phdr *)((char *)segment + segmentsize);
743 void
744 remap_elf_header(void)
746 write_word(&elf_header->e_phoff,
747 fixup_offset(read_word(elf_header->e_phoff)));
748 write_word(&elf_header->e_shoff,
749 fixup_offset(read_word(elf_header->e_shoff)));
751 write_word(&elf_header->e_entry,
752 fixup_addr(read_word(elf_header->e_entry)));
755 void
756 remap_symtab(Elf32_Shdr *symtab)
758 Elf32_Sym *symbol;
759 Elf32_Sym *symbol_end;
760 Elf32_Word entry_size;
762 symbol = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset));
763 symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset) +
764 read_word(symtab->sh_size));
765 entry_size = read_word(symtab->sh_entsize);
767 while (symbol < symbol_end) {
768 write_word(&symbol->st_value,
769 fixup_addr(read_word(symbol->st_value)));
770 symbol = (Elf32_Sym *)((char *)symbol + entry_size);
775 /* Ugly global variables: */
776 Elf32_Addr got_data_start = 0;
777 Elf32_Addr got_data_end = 0;
780 void
781 remap_rel_section(Elf32_Rel *rel, Elf32_Word size, Elf32_Word entry_size)
783 Elf32_Rel *rel_end;
784 Elf32_Word offset;
785 Elf32_Addr *addr;
786 Elf32_Word type;
788 rel_end = (Elf32_Rel *)((char *)rel + size);
790 while (rel < rel_end) {
791 type = ELF32_R_TYPE(read_word(rel->r_info));
792 switch (machine_type) {
793 case EM_386:
794 if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
795 /* We need to relocate the data this is pointing to too. */
796 offset = vma_to_offset(read_word(rel->r_offset));
798 addr = (Elf32_Addr *)FILE_OFFSET(offset);
799 write_word(addr,
800 fixup_addr(read_word(*addr)));
802 write_word(&rel->r_offset,
803 fixup_addr(read_word(rel->r_offset)));
804 break;
805 case EM_PPC:
806 /* The PPC always uses RELA relocations */
807 break;
811 rel = (Elf32_Rel *)((char *)rel + entry_size);
815 void
816 remap_rela_section(Elf32_Rela *rela, Elf32_Word size, Elf32_Word entry_size)
818 Elf32_Rela *rela_end;
819 Elf32_Addr *addr;
820 Elf32_Word offset;
821 Elf32_Word type;
822 Elf32_Word bitmask;
824 rela_end = (Elf32_Rela *)((char *)rela + size);
826 while (rela < rela_end) {
827 type = ELF32_R_TYPE(read_word(rela->r_info));
828 switch (machine_type) {
829 case EM_386:
830 if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
831 /* We need to relocate the data this is pointing to too. */
832 offset = vma_to_offset(read_word(rela->r_offset));
834 addr = (Elf32_Addr *)FILE_OFFSET(offset);
835 write_word(addr,
836 fixup_addr(read_word(*addr)));
838 write_word(&rela->r_offset,
839 fixup_addr(read_word(rela->r_offset)));
840 break;
841 case EM_PPC:
842 /* Some systems do not have PowerPC relocations defined */
843 #ifdef R_PPC_NONE
844 switch (type) {
845 case R_PPC_RELATIVE:
846 write_word((Elf32_Word *)&rela->r_addend,
847 fixup_addr(read_word(rela->r_addend)));
848 /* Fall through for 32bit offset fixup */
849 case R_PPC_ADDR32:
850 case R_PPC_GLOB_DAT:
851 case R_PPC_JMP_SLOT:
852 write_word(&rela->r_offset,
853 fixup_addr(read_word(rela->r_offset)));
854 break;
855 case R_PPC_NONE:
856 break;
857 default:
858 fprintf(stderr, "Warning, unhandled PPC relocation type %d\n", type);
860 #endif
861 break;
864 rela = (Elf32_Rela *)((char *)rela + entry_size);
868 void
869 remap_i386_got(void)
871 Elf32_Shdr *got_section;
872 Elf32_Addr *got;
873 Elf32_Addr *got_end;
874 Elf32_Word entry_size;
876 got_section = elf_find_section_named(".got");
877 if (got_section == NULL) {
878 fprintf(stderr, "Warning, no .got section\n");
879 return;
882 got_data_start = read_word(got_section->sh_offset);
883 got_data_end = got_data_start + read_word(got_section->sh_size);
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);
889 write_word(got,
890 fixup_addr(read_word(*got))); /* Pointer to .dynamic */
893 void
894 remap_ppc_got(void)
896 Elf32_Shdr *got_section;
897 Elf32_Addr *got;
898 Elf32_Addr *got_end;
899 Elf32_Word entry_size;
901 got_section = elf_find_section_named(".got");
902 if (got_section == NULL) {
903 fprintf(stderr, "Warning, no .got section\n");
904 return;
907 got_data_start = read_word(got_section->sh_offset);
908 got_data_end = got_data_start + read_word(got_section->sh_size);
910 got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
911 got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
912 entry_size = read_word(got_section->sh_entsize);
914 /* Skip reserved part.
915 * Note that this should really be found by finding the
916 * _GLOBAL_OFFSET_TABLE symbol, as it could (according to
917 * the spec) point to the middle of the got.
919 got = (Elf32_Addr *)((char *)got + entry_size); /* Skip blrl instruction */
920 write_word(got,
921 fixup_addr(read_word(*got))); /* Pointer to .dynamic */
925 Elf32_Word
926 get_dynamic_val(Elf32_Shdr *dynamic, Elf32_Sword tag)
928 Elf32_Dyn *element;
929 Elf32_Word entry_size;
931 entry_size = read_word(dynamic->sh_entsize);
933 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
934 while (read_sword(element->d_tag) != DT_NULL) {
935 if (read_sword(element->d_tag) == tag) {
936 return read_word(element->d_un.d_val);
938 element = (Elf32_Dyn *)((char *)element + entry_size);
940 return 0;
943 void
944 remap_dynamic(Elf32_Shdr *dynamic, Elf32_Word new_dynstr_size)
946 Elf32_Dyn *element;
947 Elf32_Word entry_size;
948 Elf32_Word rel_size;
949 Elf32_Word rel_entry_size;
950 Elf32_Rel *rel;
951 Elf32_Rela *rela;
952 int jmprel_overlaps;
953 Elf32_Word rel_start, rel_end, jmprel_start, jmprel_end;
955 entry_size = read_word(dynamic->sh_entsize);
957 /* Find out if REL/RELA and JMPREL overlaps: */
958 if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
959 rel_start = get_dynamic_val(dynamic, DT_REL);
960 rel_end = rel_start + get_dynamic_val(dynamic, DT_RELSZ);
961 } else {
962 rel_start = get_dynamic_val(dynamic, DT_RELA);
963 rel_end = rel_start + get_dynamic_val(dynamic, DT_RELASZ);
965 jmprel_start = get_dynamic_val(dynamic, DT_JMPREL);
967 jmprel_overlaps = 0;
968 if ((jmprel_start >= rel_start) && (jmprel_start < rel_end))
969 jmprel_overlaps = 1;
971 element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
972 while (read_sword(element->d_tag) != DT_NULL) {
973 switch(read_sword(element->d_tag)) {
974 case DT_STRSZ:
975 write_word(&element->d_un.d_val, new_dynstr_size);
976 break;
977 case DT_PLTGOT:
978 case DT_HASH:
979 case DT_STRTAB:
980 case DT_INIT:
981 case DT_FINI:
982 case DT_VERDEF:
983 case DT_VERNEED:
984 case DT_VERSYM:
985 write_word(&element->d_un.d_ptr,
986 fixup_addr(read_word(element->d_un.d_ptr)));
987 break;
988 case DT_JMPREL:
989 rel_size = get_dynamic_val(dynamic, DT_PLTRELSZ);
990 if (!jmprel_overlaps) {
991 if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
992 rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
993 rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
994 remap_rel_section(rel, rel_size, rel_entry_size);
995 } else {
996 rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
997 rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
998 remap_rela_section(rela, rel_size, rel_entry_size);
1001 write_word(&element->d_un.d_ptr,
1002 fixup_addr(read_word(element->d_un.d_ptr)));
1003 break;
1004 case DT_REL:
1005 rel_size = get_dynamic_val(dynamic, DT_RELSZ);
1006 rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
1007 rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
1008 remap_rel_section(rel, rel_size, rel_entry_size);
1010 write_word(&element->d_un.d_ptr,
1011 fixup_addr(read_word(element->d_un.d_ptr)));
1012 break;
1013 case DT_RELA:
1014 rel_size = get_dynamic_val(dynamic, DT_RELASZ);
1015 rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
1016 rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
1017 remap_rela_section(rela, rel_size, rel_entry_size);
1019 write_word(&element->d_un.d_ptr,
1020 fixup_addr(read_word(element->d_un.d_ptr)));
1021 break;
1022 default:
1023 /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/
1024 break;
1027 element = (Elf32_Dyn *)((char *)element + entry_size);
1031 void
1032 align_hole(Elf32_Word *start, Elf32_Word *end)
1034 Elf32_Word len;
1035 Elf32_Word align;
1036 Elf32_Shdr *section;
1037 Elf32_Word sectionsize;
1038 int numsections;
1039 int i = 0;
1040 int unaligned;
1042 len = *end - *start;
1043 align = 0;
1045 sectionsize = read_half(elf_header->e_shentsize);
1046 numsections = read_half(elf_header->e_shnum);
1047 do {
1048 section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
1049 unaligned = 0;
1051 for (i=0;i<numsections;i++) {
1052 if ( (read_word(section->sh_addralign) > 1) &&
1053 ( (read_word(section->sh_offset) - len + align)%read_word(section->sh_addralign) != 0) ) {
1054 unaligned = 1;
1057 section = (Elf32_Shdr *)((char *)section + sectionsize);
1060 if (unaligned) {
1061 align++;
1064 } while (unaligned);
1066 *start += align;
1070 main(int argc, char *argv[])
1072 int fd;
1073 unsigned char *mapping;
1074 Elf32_Word size;
1075 struct stat statbuf;
1076 Elf32_Shdr *dynamic;
1077 Elf32_Shdr *dynsym;
1078 Elf32_Shdr *symtab;
1079 Elf32_Shdr *dynstr;
1080 Elf32_Shdr *hash;
1081 Elf32_Shdr *higher_section;
1082 Elf32_Word dynstr_index;
1083 Elf32_Shdr *ver_r;
1084 Elf32_Shdr *ver_d;
1085 char *dynstr_data;
1086 unsigned char *new_dynstr;
1087 Elf32_Word old_dynstr_size;
1088 Elf32_Word new_dynstr_size;
1090 if (argc != 2) {
1091 fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
1092 return 1;
1095 fd = open(argv[1], O_RDWR);
1096 if (fd == -1) {
1097 fprintf(stderr, "Cannot open file %s\n", argv[1]);
1098 return 1;
1101 if (fstat(fd, &statbuf) == -1) {
1102 fprintf(stderr, "Cannot stat file %s\n", argv[1]);
1103 return 1;
1106 size = statbuf.st_size;
1108 mapping = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1110 if (mapping == (unsigned char *)-1) {
1111 fprintf(stderr, "Cannot mmap file %s\n", argv[1]);
1112 return 1;
1115 used_dynamic_symbols = g_hash_table_new(g_direct_hash, g_direct_equal);
1117 elf_header = (Elf32_Ehdr *)mapping;
1119 if (strncmp((void *)elf_header, ELFMAG, SELFMAG)!=0) {
1120 fprintf(stderr, "Not an ELF file\n");
1121 return 1;
1124 if (elf_header->e_ident[EI_VERSION] != EV_CURRENT) {
1125 fprintf(stderr, "Wrong ELF file version\n");
1126 return 1;
1129 if (elf_header->e_ident[EI_CLASS] != ELFCLASS32) {
1130 fprintf(stderr, "Only 32bit ELF files supported\n");
1131 return 1;
1134 setup_byteswapping(elf_header->e_ident[EI_DATA]);
1136 machine_type = read_half(elf_header->e_machine);
1137 if ( (machine_type != EM_386) &&
1138 (machine_type != EM_PPC) ) {
1139 fprintf(stderr, "Unsupported architecture. Supported are: x86, ppc\n");
1140 return 1;
1143 if (read_half(elf_header->e_type) != ET_DYN) {
1144 fprintf(stderr, "Not an ELF shared object\n");
1145 return 1;
1148 dynamic = elf_find_section(SHT_DYNAMIC);
1149 dynsym = elf_find_section(SHT_DYNSYM);
1150 symtab = elf_find_section(SHT_SYMTAB);
1151 dynstr_index = read_word(dynsym->sh_link);
1152 dynstr = elf_find_section_num(dynstr_index);
1153 dynstr_data = (char *)FILE_OFFSET(read_word(dynstr->sh_offset));
1154 old_dynstr_size = read_word(dynstr->sh_size);
1155 ver_d = elf_find_section(SHT_GNU_verdef);
1156 ver_r = elf_find_section(SHT_GNU_verneed);
1157 hash = elf_find_section(SHT_HASH);
1159 /* Generate hash table with all used strings: */
1161 add_strings_from_dynsym(dynsym, dynstr_data);
1162 add_strings_from_dynamic(dynamic, dynstr_data);
1163 if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
1164 add_strings_from_ver_d(ver_d, dynstr_data);
1165 if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
1166 add_strings_from_ver_r(ver_r, dynstr_data);
1168 /* Generate new dynstr section from the used strings hashtable: */
1170 new_dynstr = generate_new_dynstr(&new_dynstr_size);
1172 printf("New dynstr size: %d\n", new_dynstr_size);
1173 printf("Old dynstr size: %d\n", old_dynstr_size);
1176 if (new_dynstr_size >= old_dynstr_size) {
1177 return 0;
1180 /* Fixup all references: */
1181 fixup_strings_in_dynsym(dynsym);
1182 fixup_strings_in_dynamic(dynamic);
1183 if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
1184 fixup_strings_in_ver_d(ver_d);
1185 if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
1186 fixup_strings_in_ver_r(ver_r);
1188 /* Copy over the new dynstr: */
1189 memcpy(dynstr_data, new_dynstr, new_dynstr_size);
1190 memset(dynstr_data + new_dynstr_size, ' ', old_dynstr_size-new_dynstr_size);
1192 /* Compact the dynstr section and the file: */
1194 /* 1. Set up the data for the fixup_offset() function: */
1195 hole_index = read_word(dynstr->sh_offset) + new_dynstr_size;
1196 higher_section = elf_find_next_higher_section(hole_index);
1197 hole_end = read_word(higher_section->sh_offset);
1199 align_hole(&hole_index, &hole_end);
1200 hole_len = hole_end - hole_index;
1202 hole_addr_start = hole_index; /* TODO: Fix this to something better */
1204 find_segment_addr_min_max(read_word(dynstr->sh_offset),
1205 &hole_addr_remap_start, &hole_addr_remap_end);
1208 printf("Hole remap: 0x%lx - 0x%lx\n", hole_addr_remap_start, hole_addr_remap_end);
1210 printf("hole: %lu - %lu (%lu bytes)\n", hole_index, hole_end, hole_len);
1211 printf("hole: 0x%lx - 0x%lx (0x%lx bytes)\n", hole_index, hole_end, hole_len);
1214 /* 2. Change all section and segment sizes and offsets: */
1215 remap_symtab(dynsym);
1216 if (symtab)
1217 remap_symtab(symtab);
1219 if (machine_type == EM_386)
1220 remap_i386_got();
1221 if (machine_type == EM_PPC)
1222 remap_ppc_got();
1224 remap_dynamic(dynamic, new_dynstr_size);
1225 remap_sections(); /* After this line the section headers are wrong */
1226 remap_segments();
1227 remap_elf_header();
1229 /* 3. Do the real compacting. */
1231 memmove(mapping + hole_index,
1232 mapping + hole_index + hole_len,
1233 size - (hole_index + hole_len));
1235 munmap(mapping, size);
1237 ftruncate(fd, size - hole_len);
1238 close(fd);
1240 return 0;