Back to index

lightning-sunbird  0.9+nobinonly
elf-gc-dynstr.c
Go to the documentation of this file.
00001 /* elf_gc_dynst
00002  *
00003  * This is a program that removes unreferenced strings from the .dynstr
00004  * section in ELF shared objects. It also shrinks the .dynstr section and
00005  * relocates all symbols after it.
00006  *
00007  * This program was written and copyrighted by:
00008  *   Alexander Larsson <alla@lysator.liu.se>
00009  *
00010  *
00011  *
00012  * ***** BEGIN LICENSE BLOCK *****
00013  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00014  *
00015  * The contents of this file are subject to the Mozilla Public License Version
00016  * 1.1 (the "License"); you may not use this file except in compliance with
00017  * the License. You may obtain a copy of the License at
00018  * http://www.mozilla.org/MPL/
00019  *
00020  * Software distributed under the License is distributed on an "AS IS" basis,
00021  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00022  * for the specific language governing rights and limitations under the
00023  * License.
00024  *
00025  * The Original Code is mozilla.org Code.
00026  *
00027  * The Initial Developer of the Original Code is
00028  * Netscape Communications Corporation.
00029  * Portions created by the Initial Developer are Copyright (C) 2001
00030  * the Initial Developer. All Rights Reserved.
00031  *
00032  * Contributor(s):
00033  *
00034  * Alternatively, the contents of this file may be used under the terms of
00035  * either of the GNU General Public License Version 2 or later (the "GPL"),
00036  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00037  * in which case the provisions of the GPL or the LGPL are applicable instead
00038  * of those above. If you wish to allow use of your version of this file only
00039  * under the terms of either the GPL or the LGPL, and not to allow others to
00040  * use your version of this file under the terms of the MPL, indicate your
00041  * decision by deleting the provisions above and replace them with the notice
00042  * and other provisions required by the GPL or the LGPL. If you do not delete
00043  * the provisions above, a recipient may use your version of this file under
00044  * the terms of any one of the MPL, the GPL or the LGPL.
00045  *
00046  * ***** END LICENSE BLOCK ***** */
00047 
00048 
00049 #include <stdio.h>
00050 #include <unistd.h>
00051 #include <fcntl.h>
00052 #include <sys/types.h>
00053 #include <sys/stat.h>
00054 #include <sys/mman.h>
00055 
00056 #include <elf.h>
00057 #include <glib.h>
00058 #include <string.h>
00059 
00060 
00061 Elf32_Ehdr *elf_header = NULL;
00062 #define FILE_OFFSET(offset) ((unsigned char *)(elf_header) + (offset))
00063 
00064 struct dynamic_symbol {
00065   Elf32_Word old_index;
00066   Elf32_Word new_index;
00067   char *string;
00068 };
00069 
00070 GHashTable *used_dynamic_symbols = NULL;
00071 /* Data is dynamic_symbols, hashes on old_index */
00072 Elf32_Word hole_index;
00073 Elf32_Word hole_end;
00074 Elf32_Word hole_len;
00075 
00076 Elf32_Addr hole_addr_start;
00077 Elf32_Addr hole_addr_remap_start;
00078 Elf32_Addr hole_addr_remap_end;
00079 
00080 int need_byteswap;
00081 
00082 unsigned char machine_type;
00083 
00084 Elf32_Word
00085 read_word(Elf32_Word w)
00086 {
00087   if (need_byteswap) 
00088     w = GUINT32_SWAP_LE_BE(w);
00089   return w;
00090 }
00091 
00092 Elf32_Sword
00093 read_sword(Elf32_Sword w)
00094 {
00095   if (need_byteswap) 
00096     w = (Elf32_Sword)GUINT32_SWAP_LE_BE((guint32)w);
00097   return w;
00098 }
00099 
00100 void 
00101 write_word(Elf32_Word *ptr, Elf32_Word w)
00102 {
00103   if (need_byteswap) 
00104     w = GUINT32_SWAP_LE_BE(w);
00105   *ptr = w;
00106 }
00107 
00108 Elf32_Half
00109 read_half(Elf32_Half h)
00110 {
00111   if (need_byteswap) 
00112     h = GUINT16_SWAP_LE_BE(h);
00113   return h;
00114 }
00115 
00116 void 
00117 write_half(Elf32_Half *ptr, Elf32_Half h)
00118 {
00119   if (need_byteswap) 
00120     h = GUINT16_SWAP_LE_BE(h);
00121   *ptr = h;
00122 }
00123 
00124 void
00125 setup_byteswapping(unsigned char ei_data)
00126 {
00127   need_byteswap = 0;
00128 #if G_BYTE_ORDER == G_BIG_ENDIAN
00129   if (ei_data == ELFDATA2LSB)
00130     need_byteswap = 1;
00131 #endif
00132 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
00133   if (ei_data == ELFDATA2MSB)
00134     need_byteswap = 1;
00135 #endif
00136 }
00137 
00138 
00139 Elf32_Shdr *
00140 elf_find_section_num(int section_index)
00141 {
00142   Elf32_Shdr *section;
00143   Elf32_Word sectionsize;
00144 
00145   section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
00146   sectionsize = read_half(elf_header->e_shentsize);
00147 
00148   section = (Elf32_Shdr *)((char *)section + sectionsize*section_index);
00149 
00150   return section;
00151 }
00152 
00153 Elf32_Shdr *
00154 elf_find_section_named(char *name)
00155 {
00156   Elf32_Shdr *section;
00157   Elf32_Shdr *strtab_section;
00158   Elf32_Word sectionsize;
00159   int numsections;
00160   char *strtab;
00161   int i = 0;
00162 
00163   section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
00164 
00165   strtab_section = elf_find_section_num(read_half(elf_header->e_shstrndx));
00166   
00167   strtab = (char *)FILE_OFFSET(read_word(strtab_section->sh_offset));
00168   
00169   sectionsize = read_half(elf_header->e_shentsize);
00170   numsections = read_half(elf_header->e_shnum);
00171 
00172   for (i=0;i<numsections;i++) {
00173     if (strcmp(&strtab[read_word(section->sh_name)], name) == 0) {
00174       return section;
00175     }
00176     section = (Elf32_Shdr *)((char *)section + sectionsize);
00177   }
00178   return NULL;
00179 }
00180 
00181 
00182 Elf32_Shdr *
00183 elf_find_section(Elf32_Word sh_type)
00184 {
00185   Elf32_Shdr *section;
00186   Elf32_Word sectionsize;
00187   int numsections;
00188   int i = 0;
00189 
00190   section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
00191   sectionsize = read_half(elf_header->e_shentsize);
00192   numsections = read_half(elf_header->e_shnum);
00193 
00194   for (i=0;i<numsections;i++) {
00195     if (read_word(section->sh_type) == sh_type) {
00196       return section;
00197     }
00198     section = (Elf32_Shdr *)((char *)section + sectionsize);
00199   }
00200   return NULL;
00201 }
00202 
00203 Elf32_Shdr *
00204 elf_find_next_higher_section(Elf32_Word offset)
00205 {
00206   Elf32_Shdr *section;
00207   Elf32_Shdr *higher;
00208   Elf32_Word sectionsize;
00209   int numsections;
00210   int i = 0;
00211 
00212   section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
00213   sectionsize = read_half(elf_header->e_shentsize);
00214   numsections = read_half(elf_header->e_shnum);
00215 
00216   higher = NULL;
00217 
00218   for (i=0;i<numsections;i++) {
00219     if (read_word(section->sh_offset) >= offset) {
00220       if (higher == NULL) {
00221        higher = section;
00222       } else if (read_word(section->sh_offset) < read_word(higher->sh_offset)) {
00223        higher = section;
00224       }
00225     }
00226     
00227     section = (Elf32_Shdr *)((char *)section + sectionsize);
00228   }
00229   
00230   return higher;
00231 }
00232 
00233 Elf32_Word
00234 vma_to_offset(Elf32_Addr addr)
00235 {
00236   Elf32_Shdr *section;
00237   Elf32_Shdr *higher;
00238   Elf32_Word sectionsize;
00239   int numsections;
00240   int i = 0;
00241 
00242   section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
00243   sectionsize = read_half(elf_header->e_shentsize);
00244   numsections = read_half(elf_header->e_shnum);
00245 
00246   higher = NULL;
00247 
00248   for (i=0;i<numsections;i++) {
00249     if ( (addr >= read_word(section->sh_addr)) &&
00250         (addr < read_word(section->sh_addr) + read_word(section->sh_size)) ) {
00251       return read_word(section->sh_offset) + (addr - read_word(section->sh_addr));
00252     }
00253     
00254     section = (Elf32_Shdr *)((char *)section + sectionsize);
00255   }
00256 
00257   fprintf(stderr, "Warning, unable to convert address %d (0x%x) to file offset\n",
00258         addr, addr);
00259   return 0;
00260 }
00261 
00262 
00263 void
00264 find_segment_addr_min_max(Elf32_Word file_offset,
00265                        Elf32_Addr *start, Elf32_Addr *end)
00266 {
00267   Elf32_Phdr *segment;
00268   Elf32_Word segmentsize;
00269   int numsegments;
00270   int i = 0;
00271 
00272   segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
00273   segmentsize = read_half(elf_header->e_phentsize);
00274   numsegments = read_half(elf_header->e_phnum);
00275 
00276   for (i=0;i<numsegments;i++) {
00277     if ((file_offset >= read_word(segment->p_offset)) &&
00278        (file_offset < read_word(segment->p_offset) + read_word(segment->p_filesz)))  {
00279       *start = read_word(segment->p_vaddr);
00280       *end = read_word(segment->p_vaddr) + read_word(segment->p_memsz);
00281       return;
00282     }
00283 
00284     segment = (Elf32_Phdr *)((char *)segment + segmentsize);
00285   }
00286   fprintf(stderr, "Error: Couldn't find segment in find_segment_addr_min_max()\n");
00287 }
00288 
00289 void *
00290 dynamic_find_tag(Elf32_Shdr *dynamic, Elf32_Sword d_tag)
00291 {
00292   int i;
00293   Elf32_Dyn *element;
00294 
00295   element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
00296   for (i=0; read_sword(element[i].d_tag) != DT_NULL; i++) {
00297     if (read_sword(element[i].d_tag) == d_tag) {
00298       return FILE_OFFSET(read_word(element[i].d_un.d_ptr));
00299     }
00300   }
00301   
00302   return NULL;
00303 }
00304 
00305 Elf32_Word
00306 fixup_offset(Elf32_Word offset)
00307 {
00308   if (offset >= hole_index) {
00309     return offset - hole_len;
00310   }
00311   return offset;
00312 }
00313 
00314 Elf32_Word
00315 fixup_size(Elf32_Word offset, Elf32_Word size)
00316 {
00317   /* Note: Doesn't handle the cases where the hole and the size intersect
00318      partially. */
00319   
00320   if ( (hole_index >= offset) &&
00321        (hole_index < offset + size)){
00322     return size - hole_len;
00323   }
00324   
00325   return size;
00326 }
00327 
00328 Elf32_Addr
00329 fixup_addr(Elf32_Addr addr)
00330 {
00331   if (addr == 0)
00332     return 0;
00333 
00334   /*
00335   if ( (addr < hole_addr_remap_start) ||
00336        (addr >= hole_addr_remap_end))
00337     return addr;
00338   */
00339   
00340   if (addr >= hole_addr_start) {
00341     return addr - hole_len;
00342   }
00343   return addr;
00344 }
00345 
00346 Elf32_Word
00347 fixup_addr_size(Elf32_Addr addr, Elf32_Word size)
00348 {
00349   /* Note: Doesn't handle the cases where the hole and the size intersect
00350      partially. */
00351   /*
00352   if ( (addr < hole_addr_remap_start) ||
00353        (addr >= hole_addr_remap_end))
00354     return size;
00355   */
00356   if ( (hole_addr_start >= addr) &&
00357        (hole_addr_start < addr + size)){
00358     return size - hole_len;
00359   }
00360   
00361   return size;
00362 }
00363 
00364 void
00365 possibly_add_string(int name_idx, const char *name)
00366 {
00367   struct dynamic_symbol *dynamic_symbol;
00368   if (name_idx != 0) {
00369     dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) name_idx);
00370     
00371     if (dynamic_symbol == NULL) {
00372       
00373       dynamic_symbol = g_new(struct dynamic_symbol, 1);
00374       
00375       dynamic_symbol->old_index = name_idx;
00376       dynamic_symbol->new_index = 0;
00377       dynamic_symbol->string = g_strdup(name);
00378       
00379       g_hash_table_insert(used_dynamic_symbols, (gpointer)name_idx, dynamic_symbol);
00380       /*printf("added dynamic string: %s (%d)\n", dynamic_symbol->string, name_idx);*/
00381     }
00382   }
00383 }
00384 
00385 Elf32_Word
00386 fixup_string(Elf32_Word old_idx)
00387 {
00388   struct dynamic_symbol *dynamic_symbol;
00389 
00390   if (old_idx == 0)
00391     return 0;
00392   
00393   dynamic_symbol = g_hash_table_lookup(used_dynamic_symbols, (gpointer) old_idx);
00394 
00395   if (dynamic_symbol == NULL) {
00396     fprintf(stderr, "AAAAAAAAAAAARGH!? Unknown string found in fixup (index: %d)!\n", old_idx);
00397     return 0;
00398   }
00399   
00400   return dynamic_symbol->new_index;
00401 }
00402 
00403 
00404 
00405 void
00406 add_strings_from_dynsym(Elf32_Shdr *dynsym, char *strtab)
00407 {
00408   Elf32_Sym *symbol;
00409   Elf32_Sym *symbol_end;
00410   Elf32_Word entry_size;
00411   
00412 
00413   symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset));
00414   symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size));
00415   entry_size = read_word(dynsym->sh_entsize);
00416 
00417   while (symbol < symbol_end) {
00418     int name_idx;
00419     struct dynamic_symbol *dynamic_symbol;
00420 
00421     name_idx = read_word(symbol->st_name);
00422     possibly_add_string(name_idx, &strtab[name_idx]);
00423 
00424     
00425     symbol = (Elf32_Sym *)((char *)symbol + entry_size);
00426   }
00427 }
00428 
00429 
00430 void
00431 fixup_strings_in_dynsym(Elf32_Shdr *dynsym)
00432 {
00433   Elf32_Sym *symbol;
00434   Elf32_Sym *symbol_end;
00435   Elf32_Word entry_size;
00436   
00437 
00438   symbol = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset));
00439   symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(dynsym->sh_offset) + read_word(dynsym->sh_size));
00440   entry_size = read_word(dynsym->sh_entsize);
00441   
00442   while (symbol < symbol_end) {
00443     struct dynamic_symbol *dynamic_symbol;
00444 
00445     write_word(&symbol->st_name,
00446               fixup_string(read_word(symbol->st_name)));
00447                       
00448     symbol = (Elf32_Sym *)((char *)symbol + entry_size);
00449   }
00450 }
00451 
00452 
00453 void
00454 add_strings_from_dynamic(Elf32_Shdr *dynamic, char *strtab)
00455 {
00456   int i;
00457   int name_idx;
00458   Elf32_Dyn *element;
00459   Elf32_Word entry_size;
00460 
00461   entry_size = read_word(dynamic->sh_entsize);
00462   
00463 
00464   element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
00465   while (read_sword(element->d_tag) != DT_NULL) {
00466 
00467     switch(read_sword(element->d_tag)) {
00468     case DT_NEEDED:
00469     case DT_SONAME:
00470     case DT_RPATH:
00471       name_idx = read_word(element->d_un.d_val);
00472       /*if (name_idx) printf("d_tag: %d\n", element->d_tag);*/
00473       possibly_add_string(name_idx, &strtab[name_idx]);
00474       break;
00475     default:
00476       ;
00477       /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
00478     }
00479 
00480     element = (Elf32_Dyn *)((char *)element + entry_size);
00481   }
00482   
00483 }
00484 
00485 void
00486 fixup_strings_in_dynamic(Elf32_Shdr *dynamic)
00487 {
00488   int i;
00489   int name_idx;
00490   Elf32_Dyn *element;
00491   Elf32_Word entry_size;
00492 
00493   entry_size = read_word(dynamic->sh_entsize);
00494 
00495   element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
00496   while (read_sword(element->d_tag) != DT_NULL) {
00497 
00498     switch(read_sword(element->d_tag)) {
00499     case DT_NEEDED:
00500     case DT_SONAME:
00501     case DT_RPATH:
00502       write_word(&element->d_un.d_val,
00503                fixup_string(read_word(element->d_un.d_val)));
00504       break;
00505     default:
00506       ;
00507       /*printf("unhandled d_tag: %d (0x%x)\n", element->d_tag, element->d_tag);*/
00508     }
00509 
00510     element = (Elf32_Dyn *)((char *)element + entry_size);
00511   }
00512   
00513 }
00514 
00515 
00516 void
00517 add_strings_from_ver_d(Elf32_Shdr *ver_d, char *strtab)
00518 {
00519   Elf32_Verdaux *veraux;
00520   Elf32_Verdef *verdef;
00521   int num_aux;
00522   int name_idx;
00523   int i;
00524   int cont;
00525 
00526   verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
00527 
00528   do {
00529     num_aux = read_half(verdef->vd_cnt);
00530     veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
00531     for (i=0; i<num_aux; i++) {
00532       name_idx = read_word(veraux->vda_name);
00533       possibly_add_string(name_idx, &strtab[name_idx]);
00534       veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
00535     }
00536 
00537     cont = read_word(verdef->vd_next) != 0;
00538     verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
00539   } while (cont);
00540   
00541 }
00542 
00543 void
00544 fixup_strings_in_ver_d(Elf32_Shdr *ver_d)
00545 {
00546   Elf32_Verdaux *veraux;
00547   Elf32_Verdef *verdef;
00548   int num_aux;
00549   int name_idx;
00550   int i;
00551   int cont;
00552 
00553   verdef = (Elf32_Verdef *)FILE_OFFSET(read_word(ver_d->sh_offset));
00554 
00555   do {
00556     num_aux = read_half(verdef->vd_cnt);
00557     veraux = (Elf32_Verdaux *)((char *)verdef + read_word(verdef->vd_aux));
00558     for (i=0; i<num_aux; i++) {
00559       write_word(&veraux->vda_name,
00560                fixup_string(read_word(veraux->vda_name)));
00561       veraux = (Elf32_Verdaux *)((char *)veraux + read_word(veraux->vda_next));
00562     }
00563 
00564     cont = read_word(verdef->vd_next) != 0;
00565     verdef = (Elf32_Verdef *)((char *)verdef + read_word(verdef->vd_next));
00566   } while (cont);
00567   
00568 }
00569 
00570 void
00571 add_strings_from_ver_r(Elf32_Shdr *ver_r, char *strtab)
00572 {
00573   Elf32_Vernaux *veraux;
00574   Elf32_Verneed *verneed;
00575   int num_aux;
00576   int name_idx;
00577   int i;
00578   int cont;
00579 
00580   verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
00581 
00582   do {
00583     name_idx = read_word(verneed->vn_file);
00584     possibly_add_string(name_idx, &strtab[name_idx]);
00585     num_aux = read_half(verneed->vn_cnt);
00586     veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
00587     for (i=0; i<num_aux; i++) {
00588       name_idx = read_word(veraux->vna_name);
00589       possibly_add_string(name_idx, &strtab[name_idx]);
00590       veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
00591     }
00592 
00593     cont = read_word(verneed->vn_next) != 0;
00594     verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
00595   } while (cont);
00596 }
00597 
00598 void
00599 fixup_strings_in_ver_r(Elf32_Shdr *ver_r)
00600 {
00601   Elf32_Vernaux *veraux;
00602   Elf32_Verneed *verneed;
00603   int num_aux;
00604   int name_idx;
00605   int i;
00606   int cont;
00607 
00608   verneed = (Elf32_Verneed *)FILE_OFFSET(read_word(ver_r->sh_offset));
00609 
00610   do {
00611     write_word(&verneed->vn_file,
00612               fixup_string(read_word(verneed->vn_file)));
00613     num_aux = read_half(verneed->vn_cnt);
00614     veraux = (Elf32_Vernaux *)((char *)verneed + read_word(verneed->vn_aux));
00615     for (i=0; i<num_aux; i++) {
00616       write_word(&veraux->vna_name,
00617                fixup_string(read_word(veraux->vna_name)));
00618       veraux = (Elf32_Vernaux *)((char *)veraux + read_word(veraux->vna_next));
00619     }
00620 
00621     cont = read_word(verneed->vn_next) != 0;
00622     verneed = (Elf32_Verneed *)((char *)verneed + read_word(verneed->vn_next));
00623   } while (cont);
00624 }
00625 
00626 gboolean sum_size(gpointer  key,
00627                 struct dynamic_symbol *sym,
00628                 int *size)
00629 {
00630   *size += strlen(sym->string) + 1;
00631   return 1;
00632 }
00633 
00634 struct index_n_dynstr {
00635   int index;
00636   unsigned char *dynstr;
00637 };
00638 
00639 gboolean output_string(gpointer    key,
00640                      struct dynamic_symbol *sym,
00641                      struct index_n_dynstr *x)
00642 {
00643   sym->new_index = x->index;
00644   memcpy(x->dynstr + x->index, sym->string, strlen(sym->string) + 1);
00645   x->index += strlen(sym->string) + 1;
00646   return 1;
00647 }
00648 
00649 
00650 unsigned char *
00651 generate_new_dynstr(Elf32_Word *size_out)
00652 {
00653   int size;
00654   unsigned char *new_dynstr;
00655   struct index_n_dynstr x;
00656 
00657   size = 1; /* first a zero */
00658   g_hash_table_foreach      (used_dynamic_symbols,
00659                       (GHFunc)sum_size,
00660                       &size);
00661 
00662 
00663   new_dynstr = g_malloc(size);
00664 
00665   new_dynstr[0] = 0;
00666   x.index = 1;
00667   x.dynstr = new_dynstr;
00668   g_hash_table_foreach      (used_dynamic_symbols,
00669                       (GHFunc)output_string,
00670                       &x);
00671   
00672   *size_out = size;
00673   return new_dynstr;
00674 }
00675 
00676 void
00677 remap_sections(void)
00678 {
00679   Elf32_Shdr *section;
00680   Elf32_Word sectionsize;
00681   int numsections;
00682   int i = 0;
00683 
00684   section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
00685   sectionsize = read_half(elf_header->e_shentsize);
00686   numsections = read_half(elf_header->e_shnum);
00687 
00688   for (i=0;i<numsections;i++) {
00689     write_word(&section->sh_size,
00690               fixup_size(read_word(section->sh_offset),
00691                        read_word(section->sh_size)));
00692     write_word(&section->sh_offset,
00693               fixup_offset(read_word(section->sh_offset)));
00694     write_word(&section->sh_addr,
00695               fixup_addr(read_word(section->sh_addr)));
00696     
00697     section = (Elf32_Shdr *)((char *)section + sectionsize);
00698   }
00699 }
00700 
00701 
00702 void
00703 remap_segments(void)
00704 {
00705   Elf32_Phdr *segment;
00706   Elf32_Word segmentsize;
00707   Elf32_Word p_align;
00708   int numsegments;
00709   int i = 0;
00710 
00711   segment = (Elf32_Phdr *)FILE_OFFSET(read_word(elf_header->e_phoff));
00712   segmentsize = read_half(elf_header->e_phentsize);
00713   numsegments = read_half(elf_header->e_phnum);
00714 
00715   for (i=0;i<numsegments;i++) {
00716     write_word(&segment->p_filesz,
00717               fixup_size(read_word(segment->p_offset),
00718                        read_word(segment->p_filesz)));
00719     write_word(&segment->p_offset,
00720               fixup_offset(read_word(segment->p_offset)));
00721 
00722     write_word(&segment->p_memsz,
00723               fixup_addr_size(read_word(segment->p_vaddr),
00724                             read_word(segment->p_memsz)));
00725     write_word(&segment->p_vaddr,
00726               fixup_addr(read_word(segment->p_vaddr)));
00727     write_word(&segment->p_paddr,
00728               read_word(segment->p_vaddr));
00729 
00730     /* Consistancy checking: */
00731     p_align = read_word(segment->p_align);
00732     if (p_align > 1) {
00733       if ((read_word(segment->p_vaddr) - read_word(segment->p_offset))%p_align != 0) {
00734        fprintf(stderr, "Warning, creating non-aligned segment addr: %x offset: %x allign: %x\n",
00735               read_word(segment->p_vaddr), read_word(segment->p_offset), p_align);
00736       }
00737     }
00738     
00739     segment = (Elf32_Phdr *)((char *)segment + segmentsize);
00740   }
00741 }
00742 
00743 void
00744 remap_elf_header(void)
00745 {
00746   write_word(&elf_header->e_phoff,
00747             fixup_offset(read_word(elf_header->e_phoff)));
00748   write_word(&elf_header->e_shoff,
00749             fixup_offset(read_word(elf_header->e_shoff)));
00750 
00751   write_word(&elf_header->e_entry,
00752             fixup_addr(read_word(elf_header->e_entry)));
00753 }
00754 
00755 void
00756 remap_symtab(Elf32_Shdr *symtab)
00757 {
00758   Elf32_Sym *symbol;
00759   Elf32_Sym *symbol_end;
00760   Elf32_Word entry_size;
00761 
00762   symbol = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset));
00763   symbol_end = (Elf32_Sym *)FILE_OFFSET(read_word(symtab->sh_offset) +
00764                                    read_word(symtab->sh_size));
00765   entry_size = read_word(symtab->sh_entsize);
00766 
00767   while (symbol < symbol_end) {
00768     write_word(&symbol->st_value,
00769               fixup_addr(read_word(symbol->st_value)));
00770     symbol = (Elf32_Sym *)((char *)symbol + entry_size);
00771   }
00772 }
00773 
00774 
00775 /* Ugly global variables: */
00776 Elf32_Addr got_data_start = 0;
00777 Elf32_Addr got_data_end = 0;
00778 
00779 
00780 void
00781 remap_rel_section(Elf32_Rel *rel, Elf32_Word size, Elf32_Word entry_size)
00782 {
00783   Elf32_Rel *rel_end;
00784   Elf32_Word offset;
00785   Elf32_Addr *addr;
00786   Elf32_Word type;
00787 
00788   rel_end = (Elf32_Rel *)((char *)rel + size);
00789 
00790   while (rel < rel_end) {
00791     type = ELF32_R_TYPE(read_word(rel->r_info)); 
00792     switch (machine_type) {
00793     case EM_386:
00794       if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
00795        /* We need to relocate the data this is pointing to too. */
00796        offset = vma_to_offset(read_word(rel->r_offset));
00797        
00798        addr =  (Elf32_Addr *)FILE_OFFSET(offset);
00799        write_word(addr, 
00800                  fixup_addr(read_word(*addr)));
00801       }
00802       write_word(&rel->r_offset,
00803                fixup_addr(read_word(rel->r_offset)));
00804       break;
00805     case EM_PPC:
00806       /* The PPC always uses RELA relocations */
00807       break;
00808     }
00809 
00810     
00811     rel = (Elf32_Rel *)((char *)rel + entry_size);
00812   }
00813 }
00814 
00815 void
00816 remap_rela_section(Elf32_Rela *rela, Elf32_Word size, Elf32_Word entry_size)
00817 {
00818   Elf32_Rela *rela_end;
00819   Elf32_Addr *addr;
00820   Elf32_Word offset;
00821   Elf32_Word type;
00822   Elf32_Word bitmask;
00823 
00824   rela_end = (Elf32_Rela *)((char *)rela + size);
00825 
00826   while (rela < rela_end) {
00827     type = ELF32_R_TYPE(read_word(rela->r_info));
00828     switch (machine_type) {
00829     case EM_386:
00830       if ((type == R_386_RELATIVE) || (type == R_386_JMP_SLOT)) {
00831        /* We need to relocate the data this is pointing to too. */
00832        offset = vma_to_offset(read_word(rela->r_offset));
00833        
00834        addr =  (Elf32_Addr *)FILE_OFFSET(offset);
00835        write_word(addr,
00836                  fixup_addr(read_word(*addr)));
00837       }
00838       write_word(&rela->r_offset,
00839                fixup_addr(read_word(rela->r_offset)));
00840       break;
00841     case EM_PPC:
00842       switch (type) {
00843       case R_PPC_RELATIVE:
00844        write_word((Elf32_Word *)&rela->r_addend,
00845                  fixup_addr(read_word(rela->r_addend)));
00846        /* Fall through for 32bit offset fixup */
00847       case R_PPC_ADDR32:
00848       case R_PPC_GLOB_DAT:
00849       case R_PPC_JMP_SLOT:
00850        write_word(&rela->r_offset,
00851                  fixup_addr(read_word(rela->r_offset)));
00852        break;
00853       case R_PPC_NONE:
00854        break;
00855       default:
00856        fprintf(stderr, "Warning, unhandled PPC relocation type %d\n", type);
00857       }
00858       
00859       break;
00860     }
00861     
00862     rela = (Elf32_Rela *)((char *)rela + entry_size);
00863   }
00864 }
00865 
00866 void 
00867 remap_i386_got(void)
00868 {
00869   Elf32_Shdr *got_section;
00870   Elf32_Addr *got;
00871   Elf32_Addr *got_end;
00872   Elf32_Word entry_size;
00873 
00874   got_section = elf_find_section_named(".got");
00875   if (got_section == NULL) {
00876     fprintf(stderr, "Warning, no .got section\n");
00877     return;
00878   }
00879 
00880   got_data_start = read_word(got_section->sh_offset);
00881   got_data_end = got_data_start + read_word(got_section->sh_size);
00882   
00883   got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
00884   got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
00885   entry_size = read_word(got_section->sh_entsize);
00886 
00887   write_word(got,
00888             fixup_addr(read_word(*got))); /* Pointer to .dynamic */
00889 }
00890 
00891 void 
00892 remap_ppc_got(void)
00893 {
00894   Elf32_Shdr *got_section;
00895   Elf32_Addr *got;
00896   Elf32_Addr *got_end;
00897   Elf32_Word entry_size;
00898 
00899   got_section = elf_find_section_named(".got");
00900   if (got_section == NULL) {
00901     fprintf(stderr, "Warning, no .got section\n");
00902     return;
00903   }
00904 
00905   got_data_start = read_word(got_section->sh_offset);
00906   got_data_end = got_data_start + read_word(got_section->sh_size);
00907   
00908   got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
00909   got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
00910   entry_size = read_word(got_section->sh_entsize);
00911 
00912   /* Skip reserved part.
00913    * Note that this should really be found by finding the
00914    * _GLOBAL_OFFSET_TABLE symbol, as it could (according to
00915    * the spec) point to the middle of the got.
00916    */
00917   got = (Elf32_Addr *)((char *)got + entry_size); /* Skip blrl instruction */
00918   write_word(got,
00919             fixup_addr(read_word(*got))); /* Pointer to .dynamic */
00920 }
00921 
00922 
00923 Elf32_Word
00924 get_dynamic_val(Elf32_Shdr *dynamic, Elf32_Sword tag)
00925 {
00926   Elf32_Dyn *element;
00927   Elf32_Word entry_size;
00928 
00929   entry_size = read_word(dynamic->sh_entsize);
00930 
00931   element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
00932   while (read_sword(element->d_tag) != DT_NULL) {
00933     if (read_sword(element->d_tag) == tag) {
00934       return read_word(element->d_un.d_val);
00935     }
00936     element = (Elf32_Dyn *)((char *)element + entry_size);
00937   }
00938   return 0;
00939 }
00940 
00941 void
00942 remap_dynamic(Elf32_Shdr *dynamic, Elf32_Word new_dynstr_size)
00943 {
00944   Elf32_Dyn *element;
00945   Elf32_Word entry_size;
00946   Elf32_Word rel_size;
00947   Elf32_Word rel_entry_size;
00948   Elf32_Rel *rel;
00949   Elf32_Rela *rela;
00950   int jmprel_overlaps;
00951   Elf32_Word rel_start, rel_end, jmprel_start, jmprel_end;
00952     
00953   entry_size = read_word(dynamic->sh_entsize);
00954 
00955   /* Find out if REL/RELA and JMPREL overlaps: */
00956   if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
00957     rel_start = get_dynamic_val(dynamic, DT_REL);
00958     rel_end = rel_start + get_dynamic_val(dynamic, DT_RELSZ);
00959   } else {
00960     rel_start = get_dynamic_val(dynamic, DT_RELA);
00961     rel_end = rel_start + get_dynamic_val(dynamic, DT_RELASZ);
00962   }
00963   jmprel_start = get_dynamic_val(dynamic, DT_JMPREL);
00964   
00965   jmprel_overlaps = 0;
00966   if ((jmprel_start >= rel_start) && (jmprel_start < rel_end))
00967     jmprel_overlaps = 1;
00968     
00969   element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
00970   while (read_sword(element->d_tag) != DT_NULL) {
00971     switch(read_sword(element->d_tag)) {
00972     case DT_STRSZ:
00973       write_word(&element->d_un.d_val, new_dynstr_size);
00974       break;
00975     case DT_PLTGOT:
00976     case DT_HASH:
00977     case DT_STRTAB:
00978     case DT_INIT:
00979     case DT_FINI:
00980     case DT_VERDEF:
00981     case DT_VERNEED:
00982     case DT_VERSYM:
00983       write_word(&element->d_un.d_ptr,
00984                fixup_addr(read_word(element->d_un.d_ptr)));
00985       break;
00986     case DT_JMPREL:
00987       rel_size = get_dynamic_val(dynamic, DT_PLTRELSZ);
00988       if (!jmprel_overlaps) {
00989        if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
00990          rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
00991          rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
00992          remap_rel_section(rel, rel_size, rel_entry_size);
00993        } else {
00994          rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
00995          rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
00996          remap_rela_section(rela, rel_size, rel_entry_size);
00997        }
00998       }
00999       write_word(&element->d_un.d_ptr,
01000                fixup_addr(read_word(element->d_un.d_ptr)));
01001       break;
01002     case DT_REL:
01003       rel_size = get_dynamic_val(dynamic, DT_RELSZ);
01004       rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
01005       rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
01006       remap_rel_section(rel, rel_size, rel_entry_size);
01007 
01008       write_word(&element->d_un.d_ptr,
01009                fixup_addr(read_word(element->d_un.d_ptr)));
01010       break;
01011     case DT_RELA:
01012       rel_size = get_dynamic_val(dynamic, DT_RELASZ);
01013       rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
01014       rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
01015       remap_rela_section(rela, rel_size, rel_entry_size);
01016 
01017       write_word(&element->d_un.d_ptr,
01018                fixup_addr(read_word(element->d_un.d_ptr)));
01019       break;
01020     default:
01021       /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/
01022       break;
01023     }
01024 
01025     element = (Elf32_Dyn *)((char *)element + entry_size);
01026   }
01027 }
01028 
01029 void
01030 align_hole(Elf32_Word *start, Elf32_Word *end)
01031 {
01032   Elf32_Word len;
01033   Elf32_Word align;
01034   Elf32_Shdr *section;
01035   Elf32_Word sectionsize;
01036   int numsections;
01037   int i = 0;
01038   int unaligned;
01039   
01040   len = *end - *start;
01041   align = 0;
01042     
01043   sectionsize = read_half(elf_header->e_shentsize);
01044   numsections = read_half(elf_header->e_shnum);
01045   do {
01046     section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
01047     unaligned = 0;
01048     
01049     for (i=0;i<numsections;i++) {
01050       if ( (read_word(section->sh_addralign) > 1) &&
01051           ( (read_word(section->sh_offset) - len + align)%read_word(section->sh_addralign) != 0) ) {
01052        unaligned = 1;
01053       }
01054       
01055       section = (Elf32_Shdr *)((char *)section + sectionsize);
01056     }
01057 
01058     if (unaligned) {
01059       align++;
01060     }
01061       
01062   } while (unaligned);
01063 
01064   *start += align;
01065 }
01066 
01067 int
01068 main(int argc, char *argv[])
01069 {
01070   int fd;
01071   unsigned char *mapping;
01072   Elf32_Word size;
01073   struct stat statbuf;
01074   Elf32_Shdr *dynamic;
01075   Elf32_Shdr *dynsym;
01076   Elf32_Shdr *symtab;
01077   Elf32_Shdr *dynstr;
01078   Elf32_Shdr *hash;
01079   Elf32_Shdr *higher_section;
01080   Elf32_Word dynstr_index;
01081   Elf32_Shdr *ver_r;
01082   Elf32_Shdr *ver_d;
01083   char *dynstr_data;
01084   unsigned char *new_dynstr;
01085   Elf32_Word old_dynstr_size;
01086   Elf32_Word new_dynstr_size;
01087   
01088   if (argc != 2) {
01089     fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
01090     return 1;
01091   }
01092 
01093   fd = open(argv[1], O_RDWR);
01094   if (fd == -1) {
01095     fprintf(stderr, "Cannot open file %s\n", argv[1]);
01096     return 1;
01097   }
01098   
01099   if (fstat(fd, &statbuf) == -1) {
01100     fprintf(stderr, "Cannot stat file %s\n", argv[1]);
01101     return 1;
01102   }
01103   
01104   size = statbuf.st_size;
01105     
01106   mapping = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
01107 
01108   if (mapping == (unsigned char *)-1) {
01109     fprintf(stderr, "Cannot mmap file %s\n", argv[1]);
01110     return 1;
01111   }
01112 
01113   used_dynamic_symbols = g_hash_table_new(g_direct_hash, g_direct_equal);
01114 
01115   elf_header = (Elf32_Ehdr *)mapping;
01116 
01117   if (strncmp((void *)elf_header, ELFMAG, SELFMAG)!=0) {
01118     fprintf(stderr, "Not an ELF file\n");
01119     return 1;
01120   }
01121 
01122   if (elf_header->e_ident[EI_VERSION] != EV_CURRENT) {
01123     fprintf(stderr, "Wrong ELF file version\n");
01124     return 1;
01125   }
01126 
01127   if (elf_header->e_ident[EI_CLASS] != ELFCLASS32) {
01128     fprintf(stderr, "Only 32bit ELF files supported\n");
01129     return 1;
01130   }
01131   
01132   setup_byteswapping(elf_header->e_ident[EI_DATA]);
01133 
01134   machine_type = read_half(elf_header->e_machine);
01135   if ( (machine_type != EM_386) &&
01136        (machine_type != EM_PPC) ) {
01137     fprintf(stderr, "Unsupported architecture. Supported are: x86, ppc\n");
01138     return 1;
01139   }
01140 
01141   if (read_half(elf_header->e_type) != ET_DYN) {
01142     fprintf(stderr, "Not an ELF shared object\n");
01143     return 1;
01144   }
01145   
01146   dynamic = elf_find_section(SHT_DYNAMIC);
01147   dynsym = elf_find_section(SHT_DYNSYM);
01148   symtab = elf_find_section(SHT_SYMTAB);
01149   dynstr_index = read_word(dynsym->sh_link);
01150   dynstr = elf_find_section_num(dynstr_index);
01151   dynstr_data = (char *)FILE_OFFSET(read_word(dynstr->sh_offset));
01152   old_dynstr_size = read_word(dynstr->sh_size);
01153   ver_d = elf_find_section(SHT_GNU_verdef);
01154   ver_r = elf_find_section(SHT_GNU_verneed);
01155   hash = elf_find_section(SHT_HASH);
01156 
01157   /* Generate hash table with all used strings: */
01158   
01159   add_strings_from_dynsym(dynsym, dynstr_data);
01160   add_strings_from_dynamic(dynamic, dynstr_data);
01161   if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
01162     add_strings_from_ver_d(ver_d, dynstr_data);
01163   if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
01164     add_strings_from_ver_r(ver_r, dynstr_data);
01165 
01166   /* Generate new dynstr section from the used strings hashtable: */
01167   
01168   new_dynstr = generate_new_dynstr(&new_dynstr_size);
01169   /*
01170   printf("New dynstr size: %d\n", new_dynstr_size);
01171   printf("Old dynstr size: %d\n", old_dynstr_size);
01172   */
01173   
01174   if (new_dynstr_size >= old_dynstr_size) {
01175     fprintf(stderr, "Couldn't GC any strings, exiting.\n");
01176     return 0;
01177   }
01178 
01179   /* Fixup all references: */
01180   fixup_strings_in_dynsym(dynsym);
01181   fixup_strings_in_dynamic(dynamic);
01182   if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
01183     fixup_strings_in_ver_d(ver_d);
01184   if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
01185     fixup_strings_in_ver_r(ver_r);
01186   
01187   /* Copy over the new dynstr: */
01188   memcpy(dynstr_data, new_dynstr, new_dynstr_size);
01189   memset(dynstr_data + new_dynstr_size, ' ', old_dynstr_size-new_dynstr_size);
01190 
01191   /* Compact the dynstr section and the file: */
01192 
01193   /* 1. Set up the data for the fixup_offset() function: */
01194   hole_index = read_word(dynstr->sh_offset) + new_dynstr_size;
01195   higher_section = elf_find_next_higher_section(hole_index);
01196   hole_end = read_word(higher_section->sh_offset);
01197 
01198   align_hole(&hole_index, &hole_end);
01199   hole_len = hole_end - hole_index;
01200 
01201   hole_addr_start = hole_index; /* TODO: Fix this to something better */
01202 
01203   find_segment_addr_min_max(read_word(dynstr->sh_offset),
01204                          &hole_addr_remap_start, &hole_addr_remap_end);
01205   
01206   /*
01207   printf("Hole remap: 0x%lx - 0x%lx\n", hole_addr_remap_start, hole_addr_remap_end);
01208 
01209   printf("hole: %lu - %lu (%lu bytes)\n", hole_index, hole_end, hole_len);
01210   printf("hole: 0x%lx - 0x%lx (0x%lx bytes)\n", hole_index, hole_end, hole_len);
01211   */
01212   
01213   /* 2. Change all section and segment sizes and offsets: */
01214   remap_symtab(dynsym);
01215   if (symtab)
01216     remap_symtab(symtab);
01217 
01218   if (machine_type == EM_386)
01219     remap_i386_got();
01220   if (machine_type == EM_PPC)
01221     remap_ppc_got();
01222   
01223   remap_dynamic(dynamic, new_dynstr_size);
01224   remap_sections(); /* After this line the section headers are wrong */
01225   remap_segments();
01226   remap_elf_header();
01227     
01228   /* 3. Do the real compacting. */
01229 
01230   memmove(mapping + hole_index,
01231          mapping + hole_index + hole_len,
01232          size - (hole_index + hole_len));
01233   
01234   munmap(mapping, size);
01235 
01236   ftruncate(fd, size - hole_len);
01237   close(fd);
01238 
01239   return 0;
01240 }
01241 
01242 
01243