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/. */
20 #include <sys/types.h>
29 Elf32_Ehdr
*elf_header
= NULL
;
30 #define FILE_OFFSET(offset) ((unsigned char *)(elf_header) + (offset))
32 struct dynamic_symbol
{
38 GHashTable
*used_dynamic_symbols
= NULL
;
39 /* Data is dynamic_symbols, hashes on old_index */
40 Elf32_Word hole_index
;
44 Elf32_Addr hole_addr_start
;
45 Elf32_Addr hole_addr_remap_start
;
46 Elf32_Addr hole_addr_remap_end
;
50 unsigned char machine_type
;
53 read_word(Elf32_Word w
)
56 w
= GUINT32_SWAP_LE_BE(w
);
61 read_sword(Elf32_Sword w
)
64 w
= (Elf32_Sword
)GUINT32_SWAP_LE_BE((guint32
)w
);
69 write_word(Elf32_Word
*ptr
, Elf32_Word w
)
72 w
= GUINT32_SWAP_LE_BE(w
);
77 read_half(Elf32_Half h
)
80 h
= GUINT16_SWAP_LE_BE(h
);
85 write_half(Elf32_Half
*ptr
, Elf32_Half h
)
88 h
= GUINT16_SWAP_LE_BE(h
);
93 setup_byteswapping(unsigned char ei_data
)
96 #if G_BYTE_ORDER == G_BIG_ENDIAN
97 if (ei_data
== ELFDATA2LSB
)
100 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
101 if (ei_data
== ELFDATA2MSB
)
108 elf_find_section_num(int section_index
)
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
);
122 elf_find_section_named(char *name
)
125 Elf32_Shdr
*strtab_section
;
126 Elf32_Word sectionsize
;
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) {
144 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
151 elf_find_section(Elf32_Word sh_type
)
154 Elf32_Word sectionsize
;
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
) {
166 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
172 elf_find_next_higher_section(Elf32_Word offset
)
176 Elf32_Word sectionsize
;
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
);
186 for (i
=0;i
<numsections
;i
++) {
187 if (read_word(section
->sh_offset
) >= offset
) {
188 if (higher
== NULL
) {
190 } else if (read_word(section
->sh_offset
) < read_word(higher
->sh_offset
)) {
195 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
202 vma_to_offset(Elf32_Addr addr
)
206 Elf32_Word sectionsize
;
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
);
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",
232 find_segment_addr_min_max(Elf32_Word file_offset
,
233 Elf32_Addr
*start
, Elf32_Addr
*end
)
236 Elf32_Word segmentsize
;
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
);
252 segment
= (Elf32_Phdr
*)((char *)segment
+ segmentsize
);
254 fprintf(stderr
, "Error: Couldn't find segment in find_segment_addr_min_max()\n");
258 dynamic_find_tag(Elf32_Shdr
*dynamic
, Elf32_Sword d_tag
)
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
));
274 fixup_offset(Elf32_Word offset
)
276 if (offset
>= hole_index
) {
277 return offset
- hole_len
;
283 fixup_size(Elf32_Word offset
, Elf32_Word size
)
285 /* Note: Doesn't handle the cases where the hole and the size intersect
288 if ( (hole_index
>= offset
) &&
289 (hole_index
< offset
+ size
)){
290 return size
- hole_len
;
297 fixup_addr(Elf32_Addr addr
)
303 if ( (addr < hole_addr_remap_start) ||
304 (addr >= hole_addr_remap_end))
308 if (addr
>= hole_addr_start
) {
309 return addr
- hole_len
;
315 fixup_addr_size(Elf32_Addr addr
, Elf32_Word size
)
317 /* Note: Doesn't handle the cases where the hole and the size intersect
320 if ( (addr < hole_addr_remap_start) ||
321 (addr >= hole_addr_remap_end))
324 if ( (hole_addr_start
>= addr
) &&
325 (hole_addr_start
< addr
+ size
)){
326 return size
- hole_len
;
333 possibly_add_string(int name_idx
, const char *name
)
335 struct dynamic_symbol
*dynamic_symbol
;
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);*/
354 fixup_string(Elf32_Word old_idx
)
356 struct dynamic_symbol
*dynamic_symbol
;
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
);
368 return dynamic_symbol
->new_index
;
374 add_strings_from_dynsym(Elf32_Shdr
*dynsym
, char *strtab
)
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
) {
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
);
399 fixup_strings_in_dynsym(Elf32_Shdr
*dynsym
)
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
);
422 add_strings_from_dynamic(Elf32_Shdr
*dynamic
, char *strtab
)
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
)) {
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
]);
445 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
448 element
= (Elf32_Dyn
*)((char *)element
+ entry_size
);
454 fixup_strings_in_dynamic(Elf32_Shdr
*dynamic
)
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
)) {
470 write_word(&element
->d_un
.d_val
,
471 fixup_string(read_word(element
->d_un
.d_val
)));
475 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
478 element
= (Elf32_Dyn
*)((char *)element
+ entry_size
);
485 add_strings_from_ver_d(Elf32_Shdr
*ver_d
, char *strtab
)
487 Elf32_Verdaux
*veraux
;
488 Elf32_Verdef
*verdef
;
494 verdef
= (Elf32_Verdef
*)FILE_OFFSET(read_word(ver_d
->sh_offset
));
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
));
512 fixup_strings_in_ver_d(Elf32_Shdr
*ver_d
)
514 Elf32_Verdaux
*veraux
;
515 Elf32_Verdef
*verdef
;
521 verdef
= (Elf32_Verdef
*)FILE_OFFSET(read_word(ver_d
->sh_offset
));
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
));
539 add_strings_from_ver_r(Elf32_Shdr
*ver_r
, char *strtab
)
541 Elf32_Vernaux
*veraux
;
542 Elf32_Verneed
*verneed
;
548 verneed
= (Elf32_Verneed
*)FILE_OFFSET(read_word(ver_r
->sh_offset
));
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
));
567 fixup_strings_in_ver_r(Elf32_Shdr
*ver_r
)
569 Elf32_Vernaux
*veraux
;
570 Elf32_Verneed
*verneed
;
576 verneed
= (Elf32_Verneed
*)FILE_OFFSET(read_word(ver_r
->sh_offset
));
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
));
594 gboolean
sum_size(gpointer key
,
595 struct dynamic_symbol
*sym
,
598 *size
+= strlen(sym
->string
) + 1;
602 struct index_n_dynstr
{
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;
619 generate_new_dynstr(Elf32_Word
*size_out
)
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
,
631 new_dynstr
= g_malloc(size
);
635 x
.dynstr
= new_dynstr
;
636 g_hash_table_foreach (used_dynamic_symbols
,
637 (GHFunc
)output_string
,
648 Elf32_Word sectionsize
;
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(§ion
->sh_size
,
658 fixup_size(read_word(section
->sh_offset
),
659 read_word(section
->sh_size
)));
660 write_word(§ion
->sh_offset
,
661 fixup_offset(read_word(section
->sh_offset
)));
662 write_word(§ion
->sh_addr
,
663 fixup_addr(read_word(section
->sh_addr
)));
665 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
674 Elf32_Word segmentsize
;
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
);
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
);
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
)));
724 remap_symtab(Elf32_Shdr
*symtab
)
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;
749 remap_rel_section(Elf32_Rel
*rel
, Elf32_Word size
, Elf32_Word entry_size
)
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
) {
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
);
768 fixup_addr(read_word(*addr
)));
770 write_word(&rel
->r_offset
,
771 fixup_addr(read_word(rel
->r_offset
)));
774 /* The PPC always uses RELA relocations */
779 rel
= (Elf32_Rel
*)((char *)rel
+ entry_size
);
784 remap_rela_section(Elf32_Rela
*rela
, Elf32_Word size
, Elf32_Word entry_size
)
786 Elf32_Rela
*rela_end
;
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
) {
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
);
804 fixup_addr(read_word(*addr
)));
806 write_word(&rela
->r_offset
,
807 fixup_addr(read_word(rela
->r_offset
)));
810 /* Some systems do not have PowerPC relocations defined */
814 write_word((Elf32_Word
*)&rela
->r_addend
,
815 fixup_addr(read_word(rela
->r_addend
)));
816 /* Fall through for 32bit offset fixup */
820 write_word(&rela
->r_offset
,
821 fixup_addr(read_word(rela
->r_offset
)));
826 fprintf(stderr
, "Warning, unhandled PPC relocation type %d\n", type
);
832 rela
= (Elf32_Rela
*)((char *)rela
+ entry_size
);
839 Elf32_Shdr
*got_section
;
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");
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
);
858 fixup_addr(read_word(*got
))); /* Pointer to .dynamic */
864 Elf32_Shdr
*got_section
;
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");
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 */
889 fixup_addr(read_word(*got
))); /* Pointer to .dynamic */
894 get_dynamic_val(Elf32_Shdr
*dynamic
, Elf32_Sword tag
)
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
);
912 remap_dynamic(Elf32_Shdr
*dynamic
, Elf32_Word new_dynstr_size
)
915 Elf32_Word entry_size
;
917 Elf32_Word rel_entry_size
;
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
);
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
);
936 if ((jmprel_start
>= rel_start
) && (jmprel_start
< rel_end
))
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
)) {
943 write_word(&element
->d_un
.d_val
, new_dynstr_size
);
953 write_word(&element
->d_un
.d_ptr
,
954 fixup_addr(read_word(element
->d_un
.d_ptr
)));
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
);
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
)));
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
)));
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
)));
991 /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/
995 element
= (Elf32_Dyn
*)((char *)element
+ entry_size
);
1000 align_hole(Elf32_Word
*start
, Elf32_Word
*end
)
1004 Elf32_Shdr
*section
;
1005 Elf32_Word sectionsize
;
1010 len
= *end
- *start
;
1013 sectionsize
= read_half(elf_header
->e_shentsize
);
1014 numsections
= read_half(elf_header
->e_shnum
);
1016 section
= (Elf32_Shdr
*)FILE_OFFSET(read_word(elf_header
->e_shoff
));
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) ) {
1025 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
1032 } while (unaligned
);
1038 main(int argc
, char *argv
[])
1041 unsigned char *mapping
;
1043 struct stat statbuf
;
1044 Elf32_Shdr
*dynamic
;
1049 Elf32_Shdr
*higher_section
;
1050 Elf32_Word dynstr_index
;
1054 unsigned char *new_dynstr
;
1055 Elf32_Word old_dynstr_size
;
1056 Elf32_Word new_dynstr_size
;
1059 fprintf(stderr
, "Usage: %s <filename>\n", argv
[0]);
1063 fd
= open(argv
[1], O_RDWR
);
1065 fprintf(stderr
, "Cannot open file %s\n", argv
[1]);
1069 if (fstat(fd
, &statbuf
) == -1) {
1070 fprintf(stderr
, "Cannot stat file %s\n", argv
[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]);
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");
1092 if (elf_header
->e_ident
[EI_VERSION
] != EV_CURRENT
) {
1093 fprintf(stderr
, "Wrong ELF file version\n");
1097 if (elf_header
->e_ident
[EI_CLASS
] != ELFCLASS32
) {
1098 fprintf(stderr
, "Only 32bit ELF files supported\n");
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");
1111 if (read_half(elf_header
->e_type
) != ET_DYN
) {
1112 fprintf(stderr
, "Not an ELF shared object\n");
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
) {
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
);
1185 remap_symtab(symtab
);
1187 if (machine_type
== EM_386
)
1189 if (machine_type
== EM_PPC
)
1192 remap_dynamic(dynamic
, new_dynstr_size
);
1193 remap_sections(); /* After this line the section headers are wrong */
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
);