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 // ELF shared object file updates handler.
      6 //
      7 // Provides functions to remove R_ARM_RELATIVE relocations from the .rel.dyn
      8 // section and pack them in .android.rel.dyn, and unpack to return the file
      9 // to its pre-packed state.
     10 //
     11 // Files to be packed or unpacked must include an existing .android.rel.dyn
     12 // section.  A standard libchrome.<version>.so will not contain this section,
     13 // so the following can be used to add one:
     14 //
     15 //   echo -n 'NULL' >/tmp/small
     16 //   arm-linux-gnueabi-objcopy
     17 //       --add-section .android.rel.dyn=/tmp/small
     18 //       libchrome.<version>.so libchrome.<version>.so.packed
     19 //   rm /tmp/small
     20 //
     21 // To use, open the file and pass the file descriptor to the constructor,
     22 // then pack or unpack as desired.  Packing or unpacking will flush the file
     23 // descriptor on success.  Example:
     24 //
     25 //   int fd = open(..., O_RDWR);
     26 //   ElfFile elf_file(fd);
     27 //   bool status;
     28 //   if (is_packing)
     29 //     status = elf_file.PackRelocations();
     30 //   else
     31 //     status = elf_file.UnpackRelocations();
     32 //   close(fd);
     33 //
     34 // SetPadding() causes PackRelocations() to pad .rel.dyn with R_ARM_NONE
     35 // entries rather than cutting a hole out of the shared object file.  This
     36 // keeps all load addresses and offsets constant, and enables easier
     37 // debugging and testing.
     38 //
     39 // A packed shared object file has all of its R_ARM_RELATIVE relocations
     40 // removed from .rel.dyn, and replaced as packed data in .android.rel.dyn.
     41 // The resulting file is shorter than its non-packed original.
     42 //
     43 // Unpacking a packed file restores the file to its non-packed state, by
     44 // expanding the packed data in android.rel.dyn, combining the R_ARM_RELATIVE
     45 // relocations with the data already in .rel.dyn, and then writing back the
     46 // now expanded .rel.dyn section.
     47 
     48 #ifndef TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
     49 #define TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
     50 
     51 #include <string.h>
     52 
     53 #include "elf.h"
     54 #include "libelf.h"
     55 #include "packer.h"
     56 
     57 namespace relocation_packer {
     58 
     59 // An ElfFile reads shared objects, and shuttles R_ARM_RELATIVE relocations
     60 // between .rel.dyn and .android.rel.dyn sections.
     61 class ElfFile {
     62  public:
     63   explicit ElfFile(int fd) { memset(this, 0, sizeof(*this)); fd_ = fd; }
     64   ~ElfFile() {}
     65 
     66   // Set padding mode.  When padding, PackRelocations() will not shrink
     67   // the .rel.dyn section, but instead replace R_ARM_RELATIVE with
     68   // R_ARM_NONE entries.
     69   // |flag| is true to pad .rel.dyn, false to shrink it.
     70   inline void SetPadding(bool flag) { is_padding_rel_dyn_ = flag; }
     71 
     72   // Transfer R_ARM_RELATIVE relocations from .rel.dyn to a packed
     73   // representation in .android.rel.dyn.  Returns true on success.
     74   bool PackRelocations();
     75 
     76   // Transfer R_ARM_RELATIVE relocations from a packed representation in
     77   // .android.rel.dyn to .rel.dyn.  Returns true on success.
     78   bool UnpackRelocations();
     79 
     80  private:
     81   // Load a new ElfFile from a filedescriptor.  If flushing, the file must
     82   // be open for read/write.  Returns true on successful ELF file load.
     83   // |fd| is an open file descriptor for the shared object.
     84   bool Load();
     85 
     86   // Write ELF file changes.
     87   void Flush();
     88 
     89   // If set, pad rather than shrink .rel.dyn.  Primarily for debugging,
     90   // allows packing to be checked without affecting load addresses.
     91   bool is_padding_rel_dyn_;
     92 
     93   // File descriptor opened on the shared object.
     94   int fd_;
     95 
     96   // Libelf handle, assigned by Load().
     97   Elf* elf_;
     98 
     99   // Sections that we manipulate, assigned by Load().
    100   Elf_Scn* rel_dyn_section_;
    101   Elf_Scn* dynamic_section_;
    102   Elf_Scn* android_rel_dyn_section_;
    103 };
    104 
    105 }  // namespace relocation_packer
    106 
    107 #endif  // TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
    108