Back to index

enigmail  1.4.3
elf-dynstr-gc.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 /* Some systems do not have PowerPC relocations defined */
00843 #ifdef R_PPC_NONE
00844       switch (type) {
00845       case R_PPC_RELATIVE:
00846        write_word((Elf32_Word *)&rela->r_addend,
00847                  fixup_addr(read_word(rela->r_addend)));
00848        /* Fall through for 32bit offset fixup */
00849       case R_PPC_ADDR32:
00850       case R_PPC_GLOB_DAT:
00851       case R_PPC_JMP_SLOT:
00852        write_word(&rela->r_offset,
00853                  fixup_addr(read_word(rela->r_offset)));
00854        break;
00855       case R_PPC_NONE:
00856        break;
00857       default:
00858        fprintf(stderr, "Warning, unhandled PPC relocation type %d\n", type);
00859       }
00860 #endif
00861       break;
00862     }
00863     
00864     rela = (Elf32_Rela *)((char *)rela + entry_size);
00865   }
00866 }
00867 
00868 void 
00869 remap_i386_got(void)
00870 {
00871   Elf32_Shdr *got_section;
00872   Elf32_Addr *got;
00873   Elf32_Addr *got_end;
00874   Elf32_Word entry_size;
00875 
00876   got_section = elf_find_section_named(".got");
00877   if (got_section == NULL) {
00878     fprintf(stderr, "Warning, no .got section\n");
00879     return;
00880   }
00881 
00882   got_data_start = read_word(got_section->sh_offset);
00883   got_data_end = got_data_start + read_word(got_section->sh_size);
00884   
00885   got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
00886   got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
00887   entry_size = read_word(got_section->sh_entsize);
00888 
00889   write_word(got,
00890             fixup_addr(read_word(*got))); /* Pointer to .dynamic */
00891 }
00892 
00893 void 
00894 remap_ppc_got(void)
00895 {
00896   Elf32_Shdr *got_section;
00897   Elf32_Addr *got;
00898   Elf32_Addr *got_end;
00899   Elf32_Word entry_size;
00900 
00901   got_section = elf_find_section_named(".got");
00902   if (got_section == NULL) {
00903     fprintf(stderr, "Warning, no .got section\n");
00904     return;
00905   }
00906 
00907   got_data_start = read_word(got_section->sh_offset);
00908   got_data_end = got_data_start + read_word(got_section->sh_size);
00909   
00910   got = (Elf32_Addr *)FILE_OFFSET(got_data_start);
00911   got_end = (Elf32_Addr *)FILE_OFFSET(got_data_end);
00912   entry_size = read_word(got_section->sh_entsize);
00913 
00914   /* Skip reserved part.
00915    * Note that this should really be found by finding the
00916    * _GLOBAL_OFFSET_TABLE symbol, as it could (according to
00917    * the spec) point to the middle of the got.
00918    */
00919   got = (Elf32_Addr *)((char *)got + entry_size); /* Skip blrl instruction */
00920   write_word(got,
00921             fixup_addr(read_word(*got))); /* Pointer to .dynamic */
00922 }
00923 
00924 
00925 Elf32_Word
00926 get_dynamic_val(Elf32_Shdr *dynamic, Elf32_Sword tag)
00927 {
00928   Elf32_Dyn *element;
00929   Elf32_Word entry_size;
00930 
00931   entry_size = read_word(dynamic->sh_entsize);
00932 
00933   element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
00934   while (read_sword(element->d_tag) != DT_NULL) {
00935     if (read_sword(element->d_tag) == tag) {
00936       return read_word(element->d_un.d_val);
00937     }
00938     element = (Elf32_Dyn *)((char *)element + entry_size);
00939   }
00940   return 0;
00941 }
00942 
00943 void
00944 remap_dynamic(Elf32_Shdr *dynamic, Elf32_Word new_dynstr_size)
00945 {
00946   Elf32_Dyn *element;
00947   Elf32_Word entry_size;
00948   Elf32_Word rel_size;
00949   Elf32_Word rel_entry_size;
00950   Elf32_Rel *rel;
00951   Elf32_Rela *rela;
00952   int jmprel_overlaps;
00953   Elf32_Word rel_start, rel_end, jmprel_start, jmprel_end;
00954     
00955   entry_size = read_word(dynamic->sh_entsize);
00956 
00957   /* Find out if REL/RELA and JMPREL overlaps: */
00958   if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
00959     rel_start = get_dynamic_val(dynamic, DT_REL);
00960     rel_end = rel_start + get_dynamic_val(dynamic, DT_RELSZ);
00961   } else {
00962     rel_start = get_dynamic_val(dynamic, DT_RELA);
00963     rel_end = rel_start + get_dynamic_val(dynamic, DT_RELASZ);
00964   }
00965   jmprel_start = get_dynamic_val(dynamic, DT_JMPREL);
00966   
00967   jmprel_overlaps = 0;
00968   if ((jmprel_start >= rel_start) && (jmprel_start < rel_end))
00969     jmprel_overlaps = 1;
00970     
00971   element = (Elf32_Dyn *)FILE_OFFSET(read_word(dynamic->sh_offset));
00972   while (read_sword(element->d_tag) != DT_NULL) {
00973     switch(read_sword(element->d_tag)) {
00974     case DT_STRSZ:
00975       write_word(&element->d_un.d_val, new_dynstr_size);
00976       break;
00977     case DT_PLTGOT:
00978     case DT_HASH:
00979     case DT_STRTAB:
00980     case DT_INIT:
00981     case DT_FINI:
00982     case DT_VERDEF:
00983     case DT_VERNEED:
00984     case DT_VERSYM:
00985       write_word(&element->d_un.d_ptr,
00986                fixup_addr(read_word(element->d_un.d_ptr)));
00987       break;
00988     case DT_JMPREL:
00989       rel_size = get_dynamic_val(dynamic, DT_PLTRELSZ);
00990       if (!jmprel_overlaps) {
00991        if (get_dynamic_val(dynamic, DT_PLTREL) == DT_REL) {
00992          rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
00993          rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
00994          remap_rel_section(rel, rel_size, rel_entry_size);
00995        } else {
00996          rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
00997          rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
00998          remap_rela_section(rela, rel_size, rel_entry_size);
00999        }
01000       }
01001       write_word(&element->d_un.d_ptr,
01002                fixup_addr(read_word(element->d_un.d_ptr)));
01003       break;
01004     case DT_REL:
01005       rel_size = get_dynamic_val(dynamic, DT_RELSZ);
01006       rel_entry_size = get_dynamic_val(dynamic, DT_RELENT);
01007       rel = (Elf32_Rel *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
01008       remap_rel_section(rel, rel_size, rel_entry_size);
01009 
01010       write_word(&element->d_un.d_ptr,
01011                fixup_addr(read_word(element->d_un.d_ptr)));
01012       break;
01013     case DT_RELA:
01014       rel_size = get_dynamic_val(dynamic, DT_RELASZ);
01015       rel_entry_size = get_dynamic_val(dynamic, DT_RELAENT);
01016       rela = (Elf32_Rela *)FILE_OFFSET(vma_to_offset(read_word(element->d_un.d_ptr)));
01017       remap_rela_section(rela, rel_size, rel_entry_size);
01018 
01019       write_word(&element->d_un.d_ptr,
01020                fixup_addr(read_word(element->d_un.d_ptr)));
01021       break;
01022     default:
01023       /*printf("unhandled d_tag: %d (0x%x)\n", read_sword(element->d_tag), read_sword(element->d_tag));*/
01024       break;
01025     }
01026 
01027     element = (Elf32_Dyn *)((char *)element + entry_size);
01028   }
01029 }
01030 
01031 void
01032 align_hole(Elf32_Word *start, Elf32_Word *end)
01033 {
01034   Elf32_Word len;
01035   Elf32_Word align;
01036   Elf32_Shdr *section;
01037   Elf32_Word sectionsize;
01038   int numsections;
01039   int i = 0;
01040   int unaligned;
01041   
01042   len = *end - *start;
01043   align = 0;
01044     
01045   sectionsize = read_half(elf_header->e_shentsize);
01046   numsections = read_half(elf_header->e_shnum);
01047   do {
01048     section = (Elf32_Shdr *)FILE_OFFSET(read_word(elf_header->e_shoff));
01049     unaligned = 0;
01050     
01051     for (i=0;i<numsections;i++) {
01052       if ( (read_word(section->sh_addralign) > 1) &&
01053           ( (read_word(section->sh_offset) - len + align)%read_word(section->sh_addralign) != 0) ) {
01054        unaligned = 1;
01055       }
01056       
01057       section = (Elf32_Shdr *)((char *)section + sectionsize);
01058     }
01059 
01060     if (unaligned) {
01061       align++;
01062     }
01063       
01064   } while (unaligned);
01065 
01066   *start += align;
01067 }
01068 
01069 int
01070 main(int argc, char *argv[])
01071 {
01072   int fd;
01073   unsigned char *mapping;
01074   Elf32_Word size;
01075   struct stat statbuf;
01076   Elf32_Shdr *dynamic;
01077   Elf32_Shdr *dynsym;
01078   Elf32_Shdr *symtab;
01079   Elf32_Shdr *dynstr;
01080   Elf32_Shdr *hash;
01081   Elf32_Shdr *higher_section;
01082   Elf32_Word dynstr_index;
01083   Elf32_Shdr *ver_r;
01084   Elf32_Shdr *ver_d;
01085   char *dynstr_data;
01086   unsigned char *new_dynstr;
01087   Elf32_Word old_dynstr_size;
01088   Elf32_Word new_dynstr_size;
01089   
01090   if (argc != 2) {
01091     fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
01092     return 1;
01093   }
01094 
01095   fd = open(argv[1], O_RDWR);
01096   if (fd == -1) {
01097     fprintf(stderr, "Cannot open file %s\n", argv[1]);
01098     return 1;
01099   }
01100   
01101   if (fstat(fd, &statbuf) == -1) {
01102     fprintf(stderr, "Cannot stat file %s\n", argv[1]);
01103     return 1;
01104   }
01105   
01106   size = statbuf.st_size;
01107     
01108   mapping = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
01109 
01110   if (mapping == (unsigned char *)-1) {
01111     fprintf(stderr, "Cannot mmap file %s\n", argv[1]);
01112     return 1;
01113   }
01114 
01115   used_dynamic_symbols = g_hash_table_new(g_direct_hash, g_direct_equal);
01116 
01117   elf_header = (Elf32_Ehdr *)mapping;
01118 
01119   if (strncmp((void *)elf_header, ELFMAG, SELFMAG)!=0) {
01120     fprintf(stderr, "Not an ELF file\n");
01121     return 1;
01122   }
01123 
01124   if (elf_header->e_ident[EI_VERSION] != EV_CURRENT) {
01125     fprintf(stderr, "Wrong ELF file version\n");
01126     return 1;
01127   }
01128 
01129   if (elf_header->e_ident[EI_CLASS] != ELFCLASS32) {
01130     fprintf(stderr, "Only 32bit ELF files supported\n");
01131     return 1;
01132   }
01133   
01134   setup_byteswapping(elf_header->e_ident[EI_DATA]);
01135 
01136   machine_type = read_half(elf_header->e_machine);
01137   if ( (machine_type != EM_386) &&
01138        (machine_type != EM_PPC) ) {
01139     fprintf(stderr, "Unsupported architecture. Supported are: x86, ppc\n");
01140     return 1;
01141   }
01142 
01143   if (read_half(elf_header->e_type) != ET_DYN) {
01144     fprintf(stderr, "Not an ELF shared object\n");
01145     return 1;
01146   }
01147   
01148   dynamic = elf_find_section(SHT_DYNAMIC);
01149   dynsym = elf_find_section(SHT_DYNSYM);
01150   symtab = elf_find_section(SHT_SYMTAB);
01151   dynstr_index = read_word(dynsym->sh_link);
01152   dynstr = elf_find_section_num(dynstr_index);
01153   dynstr_data = (char *)FILE_OFFSET(read_word(dynstr->sh_offset));
01154   old_dynstr_size = read_word(dynstr->sh_size);
01155   ver_d = elf_find_section(SHT_GNU_verdef);
01156   ver_r = elf_find_section(SHT_GNU_verneed);
01157   hash = elf_find_section(SHT_HASH);
01158 
01159   /* Generate hash table with all used strings: */
01160   
01161   add_strings_from_dynsym(dynsym, dynstr_data);
01162   add_strings_from_dynamic(dynamic, dynstr_data);
01163   if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
01164     add_strings_from_ver_d(ver_d, dynstr_data);
01165   if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
01166     add_strings_from_ver_r(ver_r, dynstr_data);
01167 
01168   /* Generate new dynstr section from the used strings hashtable: */
01169   
01170   new_dynstr = generate_new_dynstr(&new_dynstr_size);
01171   /*
01172   printf("New dynstr size: %d\n", new_dynstr_size);
01173   printf("Old dynstr size: %d\n", old_dynstr_size);
01174   */
01175   
01176   if (new_dynstr_size >= old_dynstr_size) {
01177     return 0;
01178   }
01179 
01180   /* Fixup all references: */
01181   fixup_strings_in_dynsym(dynsym);
01182   fixup_strings_in_dynamic(dynamic);
01183   if (ver_d && (read_word(ver_d->sh_link) == dynstr_index))
01184     fixup_strings_in_ver_d(ver_d);
01185   if (ver_r && (read_word(ver_r->sh_link) == dynstr_index))
01186     fixup_strings_in_ver_r(ver_r);
01187   
01188   /* Copy over the new dynstr: */
01189   memcpy(dynstr_data, new_dynstr, new_dynstr_size);
01190   memset(dynstr_data + new_dynstr_size, ' ', old_dynstr_size-new_dynstr_size);
01191 
01192   /* Compact the dynstr section and the file: */
01193 
01194   /* 1. Set up the data for the fixup_offset() function: */
01195   hole_index = read_word(dynstr->sh_offset) + new_dynstr_size;
01196   higher_section = elf_find_next_higher_section(hole_index);
01197   hole_end = read_word(higher_section->sh_offset);
01198 
01199   align_hole(&hole_index, &hole_end);
01200   hole_len = hole_end - hole_index;
01201 
01202   hole_addr_start = hole_index; /* TODO: Fix this to something better */
01203 
01204   find_segment_addr_min_max(read_word(dynstr->sh_offset),
01205                          &hole_addr_remap_start, &hole_addr_remap_end);
01206   
01207   /*
01208   printf("Hole remap: 0x%lx - 0x%lx\n", hole_addr_remap_start, hole_addr_remap_end);
01209 
01210   printf("hole: %lu - %lu (%lu bytes)\n", hole_index, hole_end, hole_len);
01211   printf("hole: 0x%lx - 0x%lx (0x%lx bytes)\n", hole_index, hole_end, hole_len);
01212   */
01213   
01214   /* 2. Change all section and segment sizes and offsets: */
01215   remap_symtab(dynsym);
01216   if (symtab)
01217     remap_symtab(symtab);
01218 
01219   if (machine_type == EM_386)
01220     remap_i386_got();
01221   if (machine_type == EM_PPC)
01222     remap_ppc_got();
01223   
01224   remap_dynamic(dynamic, new_dynstr_size);
01225   remap_sections(); /* After this line the section headers are wrong */
01226   remap_segments();
01227   remap_elf_header();
01228     
01229   /* 3. Do the real compacting. */
01230 
01231   memmove(mapping + hole_index,
01232          mapping + hole_index + hole_len,
01233          size - (hole_index + hole_len));
01234   
01235   munmap(mapping, size);
01236 
01237   ftruncate(fd, size - hole_len);
01238   close(fd);
01239 
01240   return 0;
01241 }
01242 
01243 
01244