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) {
1177
fprintf(stderr, "Couldn't GC any strings, exiting.\n");
1181
/* Fixup all references: */
1182
fixup_strings_in_dynsym(dynsym);
1183
fixup_strings_in_dynamic(dynamic);
1184
if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
1185
fixup_strings_in_ver_d(ver_d);
1186
if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
1187
fixup_strings_in_ver_r(ver_r);
1189
/* Copy over the new dynstr: */
1190
memcpy(dynstr_data, new_dynstr, new_dynstr_size);
1191
memset(dynstr_data + new_dynstr_size, ' ', old_dynstr_size-new_dynstr_size);
1193
/* Compact the dynstr section and the file: */
1195
/* 1. Set up the data for the fixup_offset() function: */
1196
hole_index = read_word(dynstr->sh_offset) + new_dynstr_size;
1197
higher_section = elf_find_next_higher_section(hole_index);
1198
hole_end = read_word(higher_section->sh_offset);
1200
align_hole(&hole_index, &hole_end);
1201
hole_len = hole_end - hole_index;
1203
hole_addr_start = hole_index; /* TODO: Fix this to something better */
1205
find_segment_addr_min_max(read_word(dynstr->sh_offset),
1206
&hole_addr_remap_start, &hole_addr_remap_end);
1209
printf("Hole remap: 0x%lx - 0x%lx\n", hole_addr_remap_start, hole_addr_remap_end);
1211
printf("hole: %lu - %lu (%lu bytes)\n", hole_index, hole_end, hole_len);
1212
printf("hole: 0x%lx - 0x%lx (0x%lx bytes)\n", hole_index, hole_end, hole_len);
1215
/* 2. Change all section and segment sizes and offsets: */
1216
remap_symtab(dynsym);
1218
remap_symtab(symtab);
1220
if (machine_type == EM_386)
1222
if (machine_type == EM_PPC)
1225
remap_dynamic(dynamic, new_dynstr_size);
1226
remap_sections(); /* After this line the section headers are wrong */
1230
/* 3. Do the real compacting. */
1232
memmove(mapping + hole_index,
1233
mapping + hole_index + hole_len,
1234
size - (hole_index + hole_len));
1236
munmap(mapping, size);
1238
ftruncate(fd, size - hole_len);