Home | History | Annotate | Download | only in src
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 // Tool to pack and unpack relative relocations in a shared library.
      6 //
      7 // Packing removes relative relocations from .rel.dyn and writes them
      8 // in a more compact form to .android.rel.dyn.  Unpacking does the reverse.
      9 //
     10 // Invoke with -v to trace actions taken when packing or unpacking.
     11 // Invoke with -p to pad removed relocations with R_*_NONE.  Suppresses
     12 // shrinking of .rel.dyn.
     13 // See PrintUsage() below for full usage details.
     14 //
     15 // NOTE: Breaks with libelf 0.152, which is buggy.  libelf 0.158 works.
     16 
     17 #include <errno.h>
     18 #include <fcntl.h>
     19 #include <getopt.h>
     20 #include <stdio.h>
     21 #include <stdlib.h>
     22 #include <sys/types.h>
     23 #include <unistd.h>
     24 #include <string>
     25 
     26 #include "debug.h"
     27 #include "elf_file.h"
     28 #include "libelf.h"
     29 
     30 namespace {
     31 
     32 void PrintUsage(const char* argv0) {
     33   std::string temporary = argv0;
     34   const size_t last_slash = temporary.find_last_of("/");
     35   if (last_slash != temporary.npos) {
     36     temporary.erase(0, last_slash + 1);
     37   }
     38   const char* basename = temporary.c_str();
     39 
     40   printf(
     41       "Usage: %s [-u] [-v] [-p] file\n\n"
     42       "Pack or unpack relative relocations in a shared library.\n\n"
     43       "  -u, --unpack   unpack previously packed relative relocations\n"
     44       "  -v, --verbose  trace object file modifications (for debugging)\n"
     45       "  -p, --pad      do not shrink relocations, but pad (for debugging)\n\n",
     46       basename);
     47 
     48   if (ELF::kMachine == EM_ARM) {
     49     printf(
     50         "Extracts relative relocations from the .rel.dyn section, packs them\n"
     51         "into a more compact format, and stores the packed relocations in\n"
     52         ".android.rel.dyn.  Expands .android.rel.dyn to hold the packed\n"
     53         "data, and shrinks .rel.dyn by the amount of unpacked data removed\n"
     54         "from it.\n\n"
     55         "Before being packed, a shared library needs to be prepared by adding\n"
     56         "a null .android.rel.dyn section.\n\n"
     57         "To pack relocations in a shared library:\n\n"
     58         "    echo -n 'NULL' >/tmp/small\n"
     59         "    arm-linux-androideabi-objcopy \\\n"
     60         "        --add-section .android.rel.dyn=/tmp/small \\\n"
     61         "        libchrome.<version>.so\n"
     62         "    rm /tmp/small\n"
     63         "    %s libchrome.<version>.so\n\n"
     64         "To unpack and restore the shared library to its original state:\n\n"
     65         "    %s -u libchrome.<version>.so\n"
     66         "    arm-linux-androideabi-objcopy \\\n"
     67         "        --remove-section=.android.rel.dyn libchrome.<version>.so\n\n",
     68         basename, basename);
     69   } else if (ELF::kMachine == EM_AARCH64) {
     70     printf(
     71         "Extracts relative relocations from the .rela.dyn section, packs them\n"
     72         "into a more compact format, and stores the packed relocations in\n"
     73         ".android.rela.dyn.  Expands .android.rela.dyn to hold the packed\n"
     74         "data, and shrinks .rela.dyn by the amount of unpacked data removed\n"
     75         "from it.\n\n"
     76         "Before being packed, a shared library needs to be prepared by adding\n"
     77         "a null .android.rela.dyn section.\n\n"
     78         "To pack relocations in a shared library:\n\n"
     79         "    echo -n 'NULL' >/tmp/small\n"
     80         "    aarch64-linux-android-objcopy \\\n"
     81         "        --add-section .android.rela.dyn=/tmp/small \\\n"
     82         "        libchrome.<version>.so\n"
     83         "    rm /tmp/small\n"
     84         "    %s libchrome.<version>.so\n\n"
     85         "To unpack and restore the shared library to its original state:\n\n"
     86         "    %s -u libchrome.<version>.so\n"
     87         "    aarch64-linux-android-objcopy \\\n"
     88         "        --remove-section=.android.rela.dyn libchrome.<version>.so\n\n",
     89         basename, basename);
     90   } else {
     91     NOTREACHED();
     92   }
     93 
     94   printf(
     95       "Debug sections are not handled, so packing should not be used on\n"
     96       "shared libraries compiled for debugging or otherwise unstripped.\n");
     97 }
     98 
     99 }  // namespace
    100 
    101 int main(int argc, char* argv[]) {
    102   bool is_unpacking = false;
    103   bool is_verbose = false;
    104   bool is_padding = false;
    105 
    106   static const option options[] = {
    107     {"unpack", 0, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"pad", 0, 0, 'p'},
    108     {"help", 0, 0, 'h'}, {NULL, 0, 0, 0}
    109   };
    110   bool has_options = true;
    111   while (has_options) {
    112     int c = getopt_long(argc, argv, "uvph", options, NULL);
    113     switch (c) {
    114       case 'u':
    115         is_unpacking = true;
    116         break;
    117       case 'v':
    118         is_verbose = true;
    119         break;
    120       case 'p':
    121         is_padding = true;
    122         break;
    123       case 'h':
    124         PrintUsage(argv[0]);
    125         return 0;
    126       case '?':
    127         LOG(INFO) << "Try '" << argv[0] << " --help' for more information.";
    128         return 1;
    129       case -1:
    130         has_options = false;
    131         break;
    132       default:
    133         NOTREACHED();
    134         return 1;
    135     }
    136   }
    137   if (optind != argc - 1) {
    138     LOG(INFO) << "Try '" << argv[0] << " --help' for more information.";
    139     return 1;
    140   }
    141 
    142   if (elf_version(EV_CURRENT) == EV_NONE) {
    143     LOG(WARNING) << "Elf Library is out of date!";
    144   }
    145 
    146   LOG(INFO) << "Configured for " << ELF::Machine();
    147 
    148   const char* file = argv[argc - 1];
    149   const int fd = open(file, O_RDWR);
    150   if (fd == -1) {
    151     LOG(ERROR) << file << ": " << strerror(errno);
    152     return 1;
    153   }
    154 
    155   if (is_verbose)
    156     relocation_packer::Logger::SetVerbose(1);
    157 
    158   relocation_packer::ElfFile elf_file(fd);
    159   elf_file.SetPadding(is_padding);
    160 
    161   bool status;
    162   if (is_unpacking)
    163     status = elf_file.UnpackRelocations();
    164   else
    165     status = elf_file.PackRelocations();
    166 
    167   close(fd);
    168 
    169   if (!status) {
    170     LOG(ERROR) << file << ": failed to pack/unpack file";
    171     return 1;
    172   }
    173 
    174   return 0;
    175 }
    176