The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | //#include <common.h> |
| 3 | #include <debug.h> |
| 4 | #include <libelf.h> |
| 5 | #include <libebl.h> |
| 6 | #include <libebl_arm.h> |
| 7 | #include <elf.h> |
| 8 | #include <gelf.h> |
| 9 | #include <string.h> |
| 10 | #include <errno.h> |
| 11 | #include <string.h> |
| 12 | #include <sys/types.h> |
| 13 | #include <sys/stat.h> |
| 14 | #include <fcntl.h> |
| 15 | #include <unistd.h> |
| 16 | #ifdef SUPPORT_ANDROID_PRELINK_TAGS |
| 17 | #include <prelink_info.h> |
| 18 | #endif |
| 19 | |
| 20 | #include <elfcopy.h> |
| 21 | |
| 22 | void clone_elf(Elf *elf, Elf *newelf, |
| 23 | const char *elf_name, |
| 24 | const char *newelf_name, |
| 25 | bool *sym_filter, int num_symbols, |
| 26 | int shady |
| 27 | #ifdef SUPPORT_ANDROID_PRELINK_TAGS |
| 28 | , int *prelinked, |
| 29 | int *elf_little, |
Hristo Bojinov | 96be720 | 2010-08-02 10:26:17 -0700 | [diff] [blame] | 30 | long *prelink_addr, |
| 31 | int *retouched, |
| 32 | unsigned int *retouch_byte_cnt, |
| 33 | char *retouch_buf |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 34 | #endif |
| 35 | , bool rebuild_shstrtab, |
| 36 | bool strip_debug, |
| 37 | bool dry_run) |
| 38 | { |
| 39 | GElf_Ehdr ehdr_mem, *ehdr; /* store ELF header of original library */ |
| 40 | size_t shstrndx; /* section-strings-section index */ |
| 41 | size_t shnum; /* number of sections in the original file */ |
| 42 | /* string table for section headers in new file */ |
| 43 | struct Ebl_Strtab *shst = NULL; |
| 44 | int dynamic_idx = -1; /* index in shdr_info[] of .dynamic section */ |
| 45 | int dynsym_idx = -1; /* index in shdr_info[] of dynamic symbol table |
| 46 | section */ |
| 47 | |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 48 | unsigned int cnt; /* general-purpose counter */ |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 49 | /* This flag is true when at least one section is dropped or when the |
| 50 | relative order of sections has changed, so that section indices in |
| 51 | the resulting file will be different from those in the original. */ |
| 52 | bool sections_dropped_or_rearranged; |
| 53 | Elf_Scn *scn; /* general-purpose section */ |
| 54 | size_t idx; /* general-purporse section index */ |
| 55 | |
| 56 | shdr_info_t *shdr_info = NULL; |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 57 | unsigned int shdr_info_len = 0; |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 58 | GElf_Phdr *phdr_info = NULL; |
| 59 | |
| 60 | /* Get the information from the old file. */ |
| 61 | ehdr = gelf_getehdr (elf, &ehdr_mem); |
| 62 | FAILIF_LIBELF(NULL == ehdr, gelf_getehdr); |
| 63 | |
| 64 | /* Create new program header for the elf file */ |
| 65 | FAILIF(gelf_newehdr (newelf, gelf_getclass (elf)) == 0 || |
| 66 | (ehdr->e_type != ET_REL && gelf_newphdr (newelf, |
| 67 | ehdr->e_phnum) == 0), |
| 68 | "Cannot create new file: %s", elf_errmsg (-1)); |
| 69 | |
| 70 | #ifdef SUPPORT_ANDROID_PRELINK_TAGS |
| 71 | ASSERT(prelinked); |
| 72 | ASSERT(prelink_addr); |
| 73 | ASSERT(elf_little); |
| 74 | *elf_little = (ehdr->e_ident[EI_DATA] == ELFDATA2LSB); |
| 75 | *prelinked = check_prelinked(elf_name, *elf_little, prelink_addr); |
Hristo Bojinov | 96be720 | 2010-08-02 10:26:17 -0700 | [diff] [blame] | 76 | ASSERT(retouched); |
| 77 | ASSERT(retouch_byte_cnt); |
| 78 | ASSERT(retouch_buf); |
| 79 | *retouched = check_retouched(elf_name, *elf_little, |
| 80 | retouch_byte_cnt, retouch_buf); |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 81 | #endif |
| 82 | |
| 83 | INFO("\n\nCALCULATING MODIFICATIONS\n\n"); |
| 84 | |
| 85 | /* Copy out the old program header: notice that if the ELF file does not |
| 86 | have a program header, this loop won't execute. |
| 87 | */ |
| 88 | INFO("Copying ELF program header...\n"); |
| 89 | phdr_info = (GElf_Phdr *)CALLOC(ehdr->e_phnum, sizeof(GElf_Phdr)); |
| 90 | for (cnt = 0; cnt < ehdr->e_phnum; ++cnt) { |
| 91 | INFO("\tRetrieving entry %d\n", cnt); |
| 92 | FAILIF_LIBELF(NULL == gelf_getphdr(elf, cnt, phdr_info + cnt), |
| 93 | gelf_getphdr); |
| 94 | /* -- we update the header at the end |
| 95 | FAILIF_LIBELF(gelf_update_phdr (newelf, cnt, phdr_info + cnt) == 0, |
| 96 | gelf_update_phdr); |
| 97 | */ |
| 98 | } |
| 99 | |
| 100 | /* Get the section-header strings section. This section contains the |
| 101 | strings used to name the other sections. */ |
| 102 | FAILIF_LIBELF(elf_getshstrndx(elf, &shstrndx) < 0, elf_getshstrndx); |
| 103 | |
| 104 | /* Get the number of sections. */ |
| 105 | FAILIF_LIBELF(elf_getshnum (elf, &shnum) < 0, elf_getshnum); |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 106 | INFO("Original ELF file has %zd sections.\n", shnum); |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 107 | |
| 108 | /* Allocate the section-header-info buffer. We allocate one more entry |
| 109 | for the section-strings section because we regenerate that one and |
| 110 | place it at the very end of the file. Note that just because we create |
| 111 | an extra entry in the shdr_info array, it does not mean that we create |
| 112 | one more section the header. We just mark the old section for removal |
| 113 | and create one as the last section. |
| 114 | */ |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 115 | INFO("Allocating section-header info structure (%zd) bytes...\n", |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 116 | shnum*sizeof (shdr_info_t)); |
| 117 | shdr_info_len = rebuild_shstrtab ? shnum + 1 : shnum; |
| 118 | shdr_info = (shdr_info_t *)CALLOC(shdr_info_len, sizeof (shdr_info_t)); |
| 119 | |
| 120 | /* Iterate over all the sections and initialize the internal section-info |
| 121 | array... |
| 122 | */ |
| 123 | INFO("Initializing section-header info structure...\n"); |
| 124 | /* Gather information about the sections in this file. */ |
| 125 | scn = NULL; |
| 126 | cnt = 1; |
| 127 | while ((scn = elf_nextscn (elf, scn)) != NULL) { |
| 128 | ASSERT(elf_ndxscn(scn) == cnt); |
| 129 | shdr_info[cnt].scn = scn; |
| 130 | FAILIF_LIBELF(NULL == gelf_getshdr(scn, &shdr_info[cnt].shdr), |
| 131 | gelf_getshdr); |
| 132 | |
| 133 | /* Get the name of the section. */ |
| 134 | shdr_info[cnt].name = elf_strptr (elf, shstrndx, |
| 135 | shdr_info[cnt].shdr.sh_name); |
| 136 | |
| 137 | INFO("\tname: %s\n", shdr_info[cnt].name); |
| 138 | FAILIF(shdr_info[cnt].name == NULL, |
| 139 | "Malformed file: section %d name is null\n", |
| 140 | cnt); |
| 141 | |
| 142 | /* Mark them as present but not yet investigated. By "investigating" |
| 143 | sections, we mean that we check to see if by stripping other |
| 144 | sections, the sections under investigation will be compromised. For |
| 145 | example, if we are removing a section of code, then we want to make |
| 146 | sure that the symbol table does not contain symbols that refer to |
| 147 | this code, so we investigate the symbol table. If we do find such |
| 148 | symbols, we will not strip the code section. |
| 149 | */ |
| 150 | shdr_info[cnt].idx = 1; |
| 151 | |
| 152 | /* Remember the shdr.sh_link value. We need to remember this value |
| 153 | for those sections that refer to other sections. For example, |
| 154 | we need to remember it for relocation-entry sections, because if |
| 155 | we modify the symbol table that a relocation-entry section is |
| 156 | relative to, then we need to patch the relocation section. By the |
| 157 | time we get to deciding whether we need to patch the relocation |
| 158 | section, we will have overwritten its header's sh_link field with |
| 159 | a new value. |
| 160 | */ |
| 161 | shdr_info[cnt].old_shdr = shdr_info[cnt].shdr; |
| 162 | INFO("\t\toriginal sh_link: %08d\n", shdr_info[cnt].old_shdr.sh_link); |
| 163 | INFO("\t\toriginal sh_addr: %lld\n", shdr_info[cnt].old_shdr.sh_addr); |
| 164 | INFO("\t\toriginal sh_offset: %lld\n", |
| 165 | shdr_info[cnt].old_shdr.sh_offset); |
| 166 | INFO("\t\toriginal sh_size: %lld\n", shdr_info[cnt].old_shdr.sh_size); |
| 167 | |
| 168 | if (shdr_info[cnt].shdr.sh_type == SHT_DYNAMIC) { |
| 169 | INFO("\t\tthis is the SHT_DYNAMIC section [%s] at index %d\n", |
| 170 | shdr_info[cnt].name, |
| 171 | cnt); |
| 172 | dynamic_idx = cnt; |
| 173 | } |
| 174 | else if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM) { |
| 175 | INFO("\t\tthis is the SHT_DYNSYM section [%s] at index %d\n", |
| 176 | shdr_info[cnt].name, |
| 177 | cnt); |
| 178 | dynsym_idx = cnt; |
| 179 | } |
| 180 | |
| 181 | FAILIF(shdr_info[cnt].shdr.sh_type == SHT_SYMTAB_SHNDX, |
| 182 | "Cannot handle sh_type SHT_SYMTAB_SHNDX!\n"); |
| 183 | FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GROUP, |
| 184 | "Cannot handle sh_type SHT_GROUP!\n"); |
| 185 | FAILIF(shdr_info[cnt].shdr.sh_type == SHT_GNU_versym, |
| 186 | "Cannot handle sh_type SHT_GNU_versym!\n"); |
| 187 | |
| 188 | /* Increment the counter. */ |
| 189 | ++cnt; |
| 190 | } /* while */ |
| 191 | |
| 192 | /* Get the EBL handling. */ |
| 193 | Ebl *ebl = ebl_openbackend (elf); |
| 194 | FAILIF_LIBELF(NULL == ebl, ebl_openbackend); |
| 195 | FAILIF_LIBELF(0 != arm_init(elf, ehdr->e_machine, ebl, sizeof(Ebl)), |
| 196 | arm_init); |
| 197 | |
| 198 | if (strip_debug) { |
| 199 | |
| 200 | /* This will actually strip more than just sections. It will strip |
| 201 | anything not essential to running the image. |
| 202 | */ |
| 203 | |
| 204 | INFO("Finding debug sections to strip.\n"); |
| 205 | |
| 206 | /* Now determine which sections can go away. The general rule is that |
| 207 | all sections which are not used at runtime are stripped out. But |
| 208 | there are a few exceptions: |
| 209 | |
| 210 | - special sections named ".comment" and ".note" are kept |
| 211 | - OS or architecture specific sections are kept since we might not |
| 212 | know how to handle them |
| 213 | - if a section is referred to from a section which is not removed |
| 214 | in the sh_link or sh_info element it cannot be removed either |
| 215 | */ |
| 216 | for (cnt = 1; cnt < shnum; ++cnt) { |
| 217 | /* Check whether the section can be removed. */ |
| 218 | if (SECTION_STRIP_P (ebl, elf, ehdr, &shdr_info[cnt].shdr, |
| 219 | shdr_info[cnt].name, |
| 220 | 1, /* remove .comment sections */ |
| 221 | 1 /* remove all debug sections */) || |
| 222 | /* The macro above is broken--check for .comment explicitly */ |
| 223 | !strcmp(".comment", shdr_info[cnt].name) |
| 224 | #ifdef ARM_SPECIFIC_HACKS |
| 225 | || |
| 226 | /* We ignore this section, that's why we can remove it. */ |
| 227 | !strcmp(".stack", shdr_info[cnt].name) |
| 228 | #endif |
| 229 | ) |
| 230 | { |
| 231 | /* For now assume this section will be removed. */ |
| 232 | INFO("Section [%s] will be stripped from image.\n", |
| 233 | shdr_info[cnt].name); |
| 234 | shdr_info[cnt].idx = 0; |
| 235 | } |
| 236 | #ifdef STRIP_STATIC_SYMBOLS |
| 237 | else if (shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) { |
| 238 | /* Mark the static symbol table for removal */ |
| 239 | INFO("Section [%s] (static symbol table) will be stripped from image.\n", |
| 240 | shdr_info[cnt].name); |
| 241 | shdr_info[cnt].idx = 0; |
| 242 | if (shdr_info[shdr_info[cnt].shdr.sh_link].shdr.sh_type == |
| 243 | SHT_STRTAB) |
| 244 | { |
| 245 | /* Mark the symbol table's string table for removal. */ |
| 246 | INFO("Section [%s] (static symbol-string table) will be stripped from image.\n", |
Iliyan Malchev | 9020995 | 2009-03-24 19:58:46 -0700 | [diff] [blame] | 247 | shdr_info[shdr_info[cnt].shdr.sh_link].name); |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 248 | shdr_info[shdr_info[cnt].shdr.sh_link].idx = 0; |
| 249 | } |
| 250 | else { |
| 251 | ERROR("Expecting the sh_link field of a symbol table to point to" |
| 252 | " associated symbol-strings table! This is not mandated by" |
| 253 | " the standard, but is a common practice and the only way " |
| 254 | " to know for sure which strings table corresponds to which" |
| 255 | " symbol table!\n"); |
| 256 | } |
| 257 | } |
| 258 | #endif |
| 259 | } |
| 260 | |
| 261 | /* Mark the SHT_NULL section as handled. */ |
| 262 | shdr_info[0].idx = 2; |
| 263 | |
| 264 | /* Handle exceptions: section groups and cross-references. We might have |
| 265 | to repeat this a few times since the resetting of the flag might |
| 266 | propagate. |
| 267 | */ |
| 268 | int exceptions_pass = 0; |
| 269 | bool changes; |
| 270 | do { |
| 271 | changes = false; |
| 272 | INFO("\nHandling exceptions, pass %d\n\n", exceptions_pass++); |
| 273 | for (cnt = 1; cnt < shnum; ++cnt) { |
| 274 | if (shdr_info[cnt].idx == 0) { |
| 275 | /* If a relocation section is marked as being removed but the |
| 276 | section it is relocating is not, then do not remove the |
| 277 | relocation section. |
| 278 | */ |
| 279 | if ((shdr_info[cnt].shdr.sh_type == SHT_REL |
| 280 | || shdr_info[cnt].shdr.sh_type == SHT_RELA) |
| 281 | && shdr_info[shdr_info[cnt].shdr.sh_info].idx != 0) { |
| 282 | PRINT("\tSection [%s] will not be removed because the " |
| 283 | "section it is relocating (%s) stays.\n", |
| 284 | shdr_info[cnt].name, |
| 285 | shdr_info[shdr_info[cnt].shdr.sh_info].name); |
| 286 | } |
| 287 | } |
| 288 | if (shdr_info[cnt].idx == 1) { |
| 289 | INFO("Processing section [%s]...\n", shdr_info[cnt].name); |
| 290 | |
| 291 | /* The content of symbol tables we don't remove must not |
| 292 | reference any section which we do remove. Otherwise |
| 293 | we cannot remove the referred section. |
| 294 | */ |
| 295 | if (shdr_info[cnt].shdr.sh_type == SHT_DYNSYM || |
| 296 | shdr_info[cnt].shdr.sh_type == SHT_SYMTAB) |
| 297 | { |
| 298 | Elf_Data *symdata; |
| 299 | size_t elsize; |
| 300 | |
| 301 | INFO("\tSection [%s] is a symbol table that's not being" |
| 302 | " removed.\n\tChecking to make sure that no symbols" |
| 303 | " refer to sections that are being removed.\n", |
| 304 | shdr_info[cnt].name); |
| 305 | |
| 306 | /* Make sure the data is loaded. */ |
| 307 | symdata = elf_getdata (shdr_info[cnt].scn, NULL); |
| 308 | FAILIF_LIBELF(NULL == symdata, elf_getdata); |
| 309 | |
| 310 | /* Go through all symbols and make sure the section they |
| 311 | reference is not removed. */ |
| 312 | elsize = gelf_fsize (elf, ELF_T_SYM, 1, ehdr->e_version); |
| 313 | |
| 314 | /* Check the length of the dynamic-symbol filter. */ |
| 315 | FAILIF(sym_filter != NULL && |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 316 | (size_t)num_symbols != symdata->d_size / elsize, |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 317 | "Length of dynsym filter (%d) must equal the number" |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 318 | " of dynamic symbols (%zd)!\n", |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 319 | num_symbols, |
| 320 | symdata->d_size / elsize); |
| 321 | |
| 322 | size_t inner; |
| 323 | for (inner = 0; |
| 324 | inner < symdata->d_size / elsize; |
| 325 | ++inner) |
| 326 | { |
| 327 | GElf_Sym sym_mem; |
| 328 | GElf_Sym *sym; |
| 329 | size_t scnidx; |
| 330 | |
| 331 | sym = gelf_getsymshndx (symdata, NULL, |
| 332 | inner, &sym_mem, NULL); |
| 333 | FAILIF_LIBELF(sym == NULL, gelf_getsymshndx); |
| 334 | |
| 335 | scnidx = sym->st_shndx; |
| 336 | FAILIF(scnidx == SHN_XINDEX, |
| 337 | "Can't handle SHN_XINDEX!\n"); |
| 338 | if (scnidx == SHN_UNDEF || |
| 339 | scnidx >= shnum || |
| 340 | (scnidx >= SHN_LORESERVE && |
| 341 | scnidx <= SHN_HIRESERVE) || |
| 342 | GELF_ST_TYPE (sym->st_info) == STT_SECTION) |
| 343 | { |
| 344 | continue; |
| 345 | } |
| 346 | |
| 347 | /* If the symbol is going to be thrown and it is a |
| 348 | global or weak symbol that is defined (not imported), |
| 349 | then continue. Since the symbol is going away, we |
| 350 | do not care whether it refers to a section that is |
| 351 | also going away. |
| 352 | */ |
| 353 | if (sym_filter && !sym_filter[inner]) |
| 354 | { |
| 355 | bool global_or_weak = |
| 356 | ELF32_ST_BIND(sym->st_info) == STB_GLOBAL || |
| 357 | ELF32_ST_BIND(sym->st_info) == STB_WEAK; |
| 358 | if (!global_or_weak && sym->st_shndx != SHN_UNDEF) |
| 359 | continue; |
| 360 | } |
| 361 | |
| 362 | /* -- far too much output |
| 363 | INFO("\t\t\tSymbol [%s] (%d)\n", |
| 364 | elf_strptr(elf, |
| 365 | shdr_info[cnt].shdr.sh_link, |
| 366 | sym->st_name), |
| 367 | shdr_info[cnt].shdr.sh_info); |
| 368 | */ |
| 369 | |
| 370 | if (shdr_info[scnidx].idx == 0) |
| 371 | { |
| 372 | PRINT("\t\t\tSymbol [%s] refers to section [%s], " |
| 373 | "which is being removed. Will keep that " |
| 374 | "section.\n", |
| 375 | elf_strptr(elf, |
| 376 | shdr_info[cnt].shdr.sh_link, |
| 377 | sym->st_name), |
| 378 | shdr_info[scnidx].name); |
| 379 | /* Mark this section as used. */ |
| 380 | shdr_info[scnidx].idx = 1; |
| 381 | changes |= scnidx < cnt; |
| 382 | } |
| 383 | } /* for each symbol */ |
| 384 | } /* section type is SHT_DYNSYM or SHT_SYMTAB */ |
| 385 | /* Cross referencing happens: |
| 386 | - for the cases the ELF specification says. That are |
| 387 | + SHT_DYNAMIC in sh_link to string table |
| 388 | + SHT_HASH in sh_link to symbol table |
| 389 | + SHT_REL and SHT_RELA in sh_link to symbol table |
| 390 | + SHT_SYMTAB and SHT_DYNSYM in sh_link to string table |
| 391 | + SHT_GROUP in sh_link to symbol table |
| 392 | + SHT_SYMTAB_SHNDX in sh_link to symbol table |
| 393 | Other (OS or architecture-specific) sections might as |
| 394 | well use this field so we process it unconditionally. |
| 395 | - references inside section groups |
| 396 | - specially marked references in sh_info if the SHF_INFO_LINK |
| 397 | flag is set |
| 398 | */ |
| 399 | |
| 400 | if (shdr_info[shdr_info[cnt].shdr.sh_link].idx == 0) { |
| 401 | shdr_info[shdr_info[cnt].shdr.sh_link].idx = 1; |
| 402 | changes |= shdr_info[cnt].shdr.sh_link < cnt; |
| 403 | } |
| 404 | |
| 405 | /* Handle references through sh_info. */ |
| 406 | if (SH_INFO_LINK_P (&shdr_info[cnt].shdr) && |
| 407 | shdr_info[shdr_info[cnt].shdr.sh_info].idx == 0) { |
| 408 | PRINT("\tSection [%s] links to section [%s], which was " |
| 409 | "marked for removal--it will not be removed.\n", |
| 410 | shdr_info[cnt].name, |
| 411 | shdr_info[shdr_info[cnt].shdr.sh_info].name); |
| 412 | |
| 413 | shdr_info[shdr_info[cnt].shdr.sh_info].idx = 1; |
| 414 | changes |= shdr_info[cnt].shdr.sh_info < cnt; |
| 415 | } |
| 416 | |
| 417 | /* Mark the section as investigated. */ |
| 418 | shdr_info[cnt].idx = 2; |
| 419 | } /* if (shdr_info[cnt].idx == 1) */ |
| 420 | } /* for (cnt = 1; cnt < shnum; ++cnt) */ |
| 421 | } while (changes); |
| 422 | } |
| 423 | else { |
| 424 | INFO("Not stripping sections.\n"); |
| 425 | /* Mark the SHT_NULL section as handled. */ |
| 426 | shdr_info[0].idx = 2; |
| 427 | } |
| 428 | |
| 429 | /* Mark the section header string table as unused, we will create |
| 430 | a new one as the very last section in the new ELF file. |
| 431 | */ |
| 432 | shdr_info[shstrndx].idx = rebuild_shstrtab ? 0 : 2; |
| 433 | |
| 434 | /* We need a string table for the section headers. */ |
| 435 | FAILIF_LIBELF((shst = ebl_strtabinit (1 /* null-terminated */)) == NULL, |
| 436 | ebl_strtabinit); |
| 437 | |
| 438 | /* Assign new section numbers. */ |
| 439 | INFO("Creating new sections...\n"); |
| 440 | //shdr_info[0].idx = 0; |
| 441 | for (cnt = idx = 1; cnt < shnum; ++cnt) { |
| 442 | if (shdr_info[cnt].idx > 0) { |
| 443 | shdr_info[cnt].idx = idx++; |
| 444 | |
| 445 | /* Create a new section. */ |
| 446 | FAILIF_LIBELF((shdr_info[cnt].newscn = |
| 447 | elf_newscn(newelf)) == NULL, elf_newscn); |
| 448 | ASSERT(elf_ndxscn (shdr_info[cnt].newscn) == shdr_info[cnt].idx); |
| 449 | |
| 450 | /* Add this name to the section header string table. */ |
| 451 | shdr_info[cnt].se = ebl_strtabadd (shst, shdr_info[cnt].name, 0); |
| 452 | |
| 453 | INFO("\tsection [%s] (old offset %lld, old size %lld) will have index %d " |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 454 | "(was %zd).\n", |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 455 | shdr_info[cnt].name, |
| 456 | shdr_info[cnt].old_shdr.sh_offset, |
| 457 | shdr_info[cnt].old_shdr.sh_size, |
| 458 | shdr_info[cnt].idx, |
| 459 | elf_ndxscn(shdr_info[cnt].scn)); |
| 460 | } else { |
Kenny Root | afb36e7 | 2010-06-26 22:39:38 -0700 | [diff] [blame] | 461 | INFO("\tIgnoring section [%s] (offset %lld, size %lld, index %zd), " |
The Android Open Source Project | 88b6079 | 2009-03-03 19:28:42 -0800 | [diff] [blame] | 462 | "it will be discarded.\n", |
| 463 | shdr_info[cnt].name, |
| 464 | shdr_info[cnt].shdr.sh_offset, |
| 465 | shdr_info[cnt].shdr.sh_size, |
| 466 | elf_ndxscn(shdr_info[cnt].scn)); |
| 467 | } |
| 468 | } /* for */ |
| 469 | |
| 470 | sections_dropped_or_rearranged = idx != cnt; |
| 471 | |
| 472 | Elf_Data *shstrtab_data = NULL; |
| 473 | |
| 474 | #if 0 |
| 475 | /* Fail if sections are being dropped or rearranged (except for moving shstrtab) or the |
| 476 | symbol filter is not empty, AND the file is an executable. |
| 477 | */ |
| 478 | FAILIF(((idx != cnt && !(cnt - idx == 1 && rebuild_shstrtab)) || sym_filter != NULL) && |
| 479 | ehdr->e_type != ET_DYN, |
| 480 | "You may not rearrange sections or strip symbols on an executable file!\n"); |
| 481 | #endif |
| 482 | |
| 483 | INFO("\n\nADJUSTING ELF FILE\n\n"); |
| 484 | |
| 485 | adjust_elf(elf, elf_name, |
| 486 | newelf, newelf_name, |
| 487 | ebl, |
| 488 | ehdr, /* store ELF header of original library */ |
| 489 | sym_filter, num_symbols, |
| 490 | shdr_info, shdr_info_len, |
| 491 | phdr_info, |
| 492 | idx, /* highest_scn_num */ |
| 493 | shnum, |
| 494 | shstrndx, |
| 495 | shst, |
| 496 | sections_dropped_or_rearranged, |
| 497 | dynamic_idx, /* index in shdr_info[] of .dynamic section */ |
| 498 | dynsym_idx, /* index in shdr_info[] of dynamic symbol table */ |
| 499 | shady, |
| 500 | &shstrtab_data, |
| 501 | ehdr->e_type == ET_DYN, /* adjust section ofsets only when the file is a shared library */ |
| 502 | rebuild_shstrtab); |
| 503 | |
| 504 | /* We have everything from the old file. */ |
| 505 | FAILIF_LIBELF(elf_cntl(elf, ELF_C_FDDONE) != 0, elf_cntl); |
| 506 | |
| 507 | /* The ELF library better follows our layout when this is not a |
| 508 | relocatable object file. */ |
| 509 | elf_flagelf (newelf, |
| 510 | ELF_C_SET, |
| 511 | (ehdr->e_type != ET_REL ? ELF_F_LAYOUT : 0)); |
| 512 | |
| 513 | /* Finally write the file. */ |
| 514 | FAILIF_LIBELF(!dry_run && elf_update(newelf, ELF_C_WRITE) == -1, elf_update); |
| 515 | |
| 516 | if (shdr_info != NULL) { |
| 517 | /* For some sections we might have created an table to map symbol |
| 518 | table indices. */ |
| 519 | for (cnt = 1; cnt < shdr_info_len; ++cnt) { |
| 520 | FREEIF(shdr_info[cnt].newsymidx); |
| 521 | FREEIF(shdr_info[cnt].symse); |
| 522 | if(shdr_info[cnt].dynsymst != NULL) |
| 523 | ebl_strtabfree (shdr_info[cnt].dynsymst); |
| 524 | } |
| 525 | /* Free the memory. */ |
| 526 | FREE (shdr_info); |
| 527 | } |
| 528 | FREEIF(phdr_info); |
| 529 | |
| 530 | ebl_closebackend(ebl); |
| 531 | |
| 532 | /* Free other resources. */ |
| 533 | if (shst != NULL) ebl_strtabfree (shst); |
| 534 | if (shstrtab_data != NULL) |
| 535 | FREEIF(shstrtab_data->d_buf); |
| 536 | } |