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
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.
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 ***** */
52 #include <sys/types.h>
61 Elf32_Ehdr
*elf_header
= NULL
;
62 #define FILE_OFFSET(offset) ((unsigned char *)(elf_header) + (offset))
64 struct dynamic_symbol
{
70 GHashTable
*used_dynamic_symbols
= NULL
;
71 /* Data is dynamic_symbols, hashes on old_index */
72 Elf32_Word hole_index
;
76 Elf32_Addr hole_addr_start
;
77 Elf32_Addr hole_addr_remap_start
;
78 Elf32_Addr hole_addr_remap_end
;
82 unsigned char machine_type
;
85 read_word(Elf32_Word w
)
88 w
= GUINT32_SWAP_LE_BE(w
);
93 read_sword(Elf32_Sword w
)
96 w
= (Elf32_Sword
)GUINT32_SWAP_LE_BE((guint32
)w
);
101 write_word(Elf32_Word
*ptr
, Elf32_Word w
)
104 w
= GUINT32_SWAP_LE_BE(w
);
109 read_half(Elf32_Half h
)
112 h
= GUINT16_SWAP_LE_BE(h
);
117 write_half(Elf32_Half
*ptr
, Elf32_Half h
)
120 h
= GUINT16_SWAP_LE_BE(h
);
125 setup_byteswapping(unsigned char ei_data
)
128 #if G_BYTE_ORDER == G_BIG_ENDIAN
129 if (ei_data
== ELFDATA2LSB
)
132 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
133 if (ei_data
== ELFDATA2MSB
)
140 elf_find_section_num(int section_index
)
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
);
154 elf_find_section_named(char *name
)
157 Elf32_Shdr
*strtab_section
;
158 Elf32_Word sectionsize
;
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) {
176 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
183 elf_find_section(Elf32_Word sh_type
)
186 Elf32_Word sectionsize
;
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
) {
198 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
204 elf_find_next_higher_section(Elf32_Word offset
)
208 Elf32_Word sectionsize
;
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
);
218 for (i
=0;i
<numsections
;i
++) {
219 if (read_word(section
->sh_offset
) >= offset
) {
220 if (higher
== NULL
) {
222 } else if (read_word(section
->sh_offset
) < read_word(higher
->sh_offset
)) {
227 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
234 vma_to_offset(Elf32_Addr addr
)
238 Elf32_Word sectionsize
;
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
);
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",
264 find_segment_addr_min_max(Elf32_Word file_offset
,
265 Elf32_Addr
*start
, Elf32_Addr
*end
)
268 Elf32_Word segmentsize
;
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
);
284 segment
= (Elf32_Phdr
*)((char *)segment
+ segmentsize
);
286 fprintf(stderr
, "Error: Couldn't find segment in find_segment_addr_min_max()\n");
290 dynamic_find_tag(Elf32_Shdr
*dynamic
, Elf32_Sword d_tag
)
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
));
306 fixup_offset(Elf32_Word offset
)
308 if (offset
>= hole_index
) {
309 return offset
- hole_len
;
315 fixup_size(Elf32_Word offset
, Elf32_Word size
)
317 /* Note: Doesn't handle the cases where the hole and the size intersect
320 if ( (hole_index
>= offset
) &&
321 (hole_index
< offset
+ size
)){
322 return size
- hole_len
;
329 fixup_addr(Elf32_Addr addr
)
335 if ( (addr < hole_addr_remap_start) ||
336 (addr >= hole_addr_remap_end))
340 if (addr
>= hole_addr_start
) {
341 return addr
- hole_len
;
347 fixup_addr_size(Elf32_Addr addr
, Elf32_Word size
)
349 /* Note: Doesn't handle the cases where the hole and the size intersect
352 if ( (addr < hole_addr_remap_start) ||
353 (addr >= hole_addr_remap_end))
356 if ( (hole_addr_start
>= addr
) &&
357 (hole_addr_start
< addr
+ size
)){
358 return size
- hole_len
;
365 possibly_add_string(int name_idx
, const char *name
)
367 struct dynamic_symbol
*dynamic_symbol
;
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);*/
386 fixup_string(Elf32_Word old_idx
)
388 struct dynamic_symbol
*dynamic_symbol
;
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
);
400 return dynamic_symbol
->new_index
;
406 add_strings_from_dynsym(Elf32_Shdr
*dynsym
, char *strtab
)
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
) {
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
);
431 fixup_strings_in_dynsym(Elf32_Shdr
*dynsym
)
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
);
454 add_strings_from_dynamic(Elf32_Shdr
*dynamic
, char *strtab
)
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
)) {
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
]);
477 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
480 element
= (Elf32_Dyn
*)((char *)element
+ entry_size
);
486 fixup_strings_in_dynamic(Elf32_Shdr
*dynamic
)
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
)) {
502 write_word(&element
->d_un
.d_val
,
503 fixup_string(read_word(element
->d_un
.d_val
)));
507 /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
510 element
= (Elf32_Dyn
*)((char *)element
+ entry_size
);
517 add_strings_from_ver_d(Elf32_Shdr
*ver_d
, char *strtab
)
519 Elf32_Verdaux
*veraux
;
520 Elf32_Verdef
*verdef
;
526 verdef
= (Elf32_Verdef
*)FILE_OFFSET(read_word(ver_d
->sh_offset
));
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
));
544 fixup_strings_in_ver_d(Elf32_Shdr
*ver_d
)
546 Elf32_Verdaux
*veraux
;
547 Elf32_Verdef
*verdef
;
553 verdef
= (Elf32_Verdef
*)FILE_OFFSET(read_word(ver_d
->sh_offset
));
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
));
571 add_strings_from_ver_r(Elf32_Shdr
*ver_r
, char *strtab
)
573 Elf32_Vernaux
*veraux
;
574 Elf32_Verneed
*verneed
;
580 verneed
= (Elf32_Verneed
*)FILE_OFFSET(read_word(ver_r
->sh_offset
));
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
));
599 fixup_strings_in_ver_r(Elf32_Shdr
*ver_r
)
601 Elf32_Vernaux
*veraux
;
602 Elf32_Verneed
*verneed
;
608 verneed
= (Elf32_Verneed
*)FILE_OFFSET(read_word(ver_r
->sh_offset
));
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
));
626 gboolean
sum_size(gpointer key
,
627 struct dynamic_symbol
*sym
,
630 *size
+= strlen(sym
->string
) + 1;
634 struct index_n_dynstr
{
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;
651 generate_new_dynstr(Elf32_Word
*size_out
)
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
,
663 new_dynstr
= g_malloc(size
);
667 x
.dynstr
= new_dynstr
;
668 g_hash_table_foreach (used_dynamic_symbols
,
669 (GHFunc
)output_string
,
680 Elf32_Word sectionsize
;
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(§ion
->sh_size
,
690 fixup_size(read_word(section
->sh_offset
),
691 read_word(section
->sh_size
)));
692 write_word(§ion
->sh_offset
,
693 fixup_offset(read_word(section
->sh_offset
)));
694 write_word(§ion
->sh_addr
,
695 fixup_addr(read_word(section
->sh_addr
)));
697 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
706 Elf32_Word segmentsize
;
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
);
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
);
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
)));
756 remap_symtab(Elf32_Shdr
*symtab
)
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;
781 remap_rel_section(Elf32_Rel
*rel
, Elf32_Word size
, Elf32_Word entry_size
)
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
) {
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
);
800 fixup_addr(read_word(*addr
)));
802 write_word(&rel
->r_offset
,
803 fixup_addr(read_word(rel
->r_offset
)));
806 /* The PPC always uses RELA relocations */
811 rel
= (Elf32_Rel
*)((char *)rel
+ entry_size
);
816 remap_rela_section(Elf32_Rela
*rela
, Elf32_Word size
, Elf32_Word entry_size
)
818 Elf32_Rela
*rela_end
;
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
) {
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
);
836 fixup_addr(read_word(*addr
)));
838 write_word(&rela
->r_offset
,
839 fixup_addr(read_word(rela
->r_offset
)));
842 /* Some systems do not have PowerPC relocations defined */
846 write_word((Elf32_Word
*)&rela
->r_addend
,
847 fixup_addr(read_word(rela
->r_addend
)));
848 /* Fall through for 32bit offset fixup */
852 write_word(&rela
->r_offset
,
853 fixup_addr(read_word(rela
->r_offset
)));
858 fprintf(stderr
, "Warning, unhandled PPC relocation type %d\n", type
);
864 rela
= (Elf32_Rela
*)((char *)rela
+ entry_size
);
871 Elf32_Shdr
*got_section
;
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");
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
);
890 fixup_addr(read_word(*got
))); /* Pointer to .dynamic */
896 Elf32_Shdr
*got_section
;
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");
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 */
921 fixup_addr(read_word(*got
))); /* Pointer to .dynamic */
926 get_dynamic_val(Elf32_Shdr
*dynamic
, Elf32_Sword tag
)
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
);
944 remap_dynamic(Elf32_Shdr
*dynamic
, Elf32_Word new_dynstr_size
)
947 Elf32_Word entry_size
;
949 Elf32_Word rel_entry_size
;
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
);
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
);
968 if ((jmprel_start
>= rel_start
) && (jmprel_start
< rel_end
))
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
)) {
975 write_word(&element
->d_un
.d_val
, new_dynstr_size
);
985 write_word(&element
->d_un
.d_ptr
,
986 fixup_addr(read_word(element
->d_un
.d_ptr
)));
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
);
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
)));
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
)));
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
)));
1023 /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/
1027 element
= (Elf32_Dyn
*)((char *)element
+ entry_size
);
1032 align_hole(Elf32_Word
*start
, Elf32_Word
*end
)
1036 Elf32_Shdr
*section
;
1037 Elf32_Word sectionsize
;
1042 len
= *end
- *start
;
1045 sectionsize
= read_half(elf_header
->e_shentsize
);
1046 numsections
= read_half(elf_header
->e_shnum
);
1048 section
= (Elf32_Shdr
*)FILE_OFFSET(read_word(elf_header
->e_shoff
));
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) ) {
1057 section
= (Elf32_Shdr
*)((char *)section
+ sectionsize
);
1064 } while (unaligned
);
1070 main(int argc
, char *argv
[])
1073 unsigned char *mapping
;
1075 struct stat statbuf
;
1076 Elf32_Shdr
*dynamic
;
1081 Elf32_Shdr
*higher_section
;
1082 Elf32_Word dynstr_index
;
1086 unsigned char *new_dynstr
;
1087 Elf32_Word old_dynstr_size
;
1088 Elf32_Word new_dynstr_size
;
1091 fprintf(stderr
, "Usage: %s <filename>\n", argv
[0]);
1095 fd
= open(argv
[1], O_RDWR
);
1097 fprintf(stderr
, "Cannot open file %s\n", argv
[1]);
1101 if (fstat(fd
, &statbuf
) == -1) {
1102 fprintf(stderr
, "Cannot stat file %s\n", argv
[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]);
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");
1124 if (elf_header
->e_ident
[EI_VERSION
] != EV_CURRENT
) {
1125 fprintf(stderr
, "Wrong ELF file version\n");
1129 if (elf_header
->e_ident
[EI_CLASS
] != ELFCLASS32
) {
1130 fprintf(stderr
, "Only 32bit ELF files supported\n");
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");
1143 if (read_half(elf_header
->e_type
) != ET_DYN
) {
1144 fprintf(stderr
, "Not an ELF shared object\n");
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
) {
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
);
1217 remap_symtab(symtab
);
1219 if (machine_type
== EM_386
)
1221 if (machine_type
== EM_PPC
)
1224 remap_dynamic(dynamic
, new_dynstr_size
);
1225 remap_sections(); /* After this line the section headers are wrong */
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
);