1f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
2f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
3f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// found in the LICENSE file.
4f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
5f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// ELF shared object file updates handler.
6f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Provides functions to remove relative relocations from the .rel.dyn
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// or .rela.dyn sections and pack into .android.rel.dyn or .android.rela.dyn,
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// and unpack to return the file to its pre-packed state.
10f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
11f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Files to be packed or unpacked must include an existing .android.rel.dyn
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// or android.rela.dyn section.  A standard libchrome.<version>.so will not
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// contain this section, so the following can be used to add one:
14f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
15f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   echo -n 'NULL' >/tmp/small
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//   if file libchrome.<version>.so | grep -q 'ELF 32'; then
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//     arm-linux-androideabi-objcopy
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//         --add-section .android.rel.dyn=/tmp/small
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//         libchrome.<version>.so libchrome.<version>.so.packed
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//   else
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//     aarch64-linux-android-objcopy
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//         --add-section .android.rela.dyn=/tmp/small
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//         libchrome.<version>.so libchrome.<version>.so.packed
245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)//   fi
25f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   rm /tmp/small
26f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
27f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// To use, open the file and pass the file descriptor to the constructor,
28f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// then pack or unpack as desired.  Packing or unpacking will flush the file
29f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// descriptor on success.  Example:
30f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
31f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   int fd = open(..., O_RDWR);
32f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   ElfFile elf_file(fd);
33f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   bool status;
34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   if (is_packing)
35f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     status = elf_file.PackRelocations();
36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   else
37f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//     status = elf_file.UnpackRelocations();
38f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//   close(fd);
39f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// SetPadding() causes PackRelocations() to pad .rel.dyn or .rela.dyn with
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// NONE-type entries rather than cutting a hole out of the shared object
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// file.  This keeps all load addresses and offsets constant, and enables
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// easier debugging and testing.
44f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// A packed shared object file has all of its relative relocations
465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// removed from .rel.dyn or .rela.dyn, and replaced as packed data in
475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// .android.rel.dyn or .android.rela.dyn respectively.  The resulting file
485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// is shorter than its non-packed original.
49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)//
50f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)// Unpacking a packed file restores the file to its non-packed state, by
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// expanding the packed data in .android.rel.dyn or .android.rela.dyn,
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// combining the relative relocations with the data already in .rel.dyn
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// or .rela.dyn, and then writing back the now expanded section.
54f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
55f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#ifndef TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
56f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
57f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <string.h>
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include <vector>
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "elf.h"
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "libelf.h"
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include "packer.h"
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)namespace relocation_packer {
66f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// An ElfFile reads shared objects, and shuttles relative relocations
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// between .rel.dyn or .rela.dyn and .android.rel.dyn or .android.rela.dyn
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// sections.
70f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)class ElfFile {
71f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) public:
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  explicit ElfFile(int fd)
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      : fd_(fd), is_padding_relocations_(false), elf_(NULL),
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        relocations_section_(NULL), dynamic_section_(NULL),
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        android_relocations_section_(NULL), relocations_type_(NONE) {}
76f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  ~ElfFile() {}
77f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
78f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Set padding mode.  When padding, PackRelocations() will not shrink
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // the .rel.dyn or .rela.dyn section, but instead replace relative with
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // NONE-type entries.
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // |flag| is true to pad .rel.dyn or .rela.dyn, false to shrink it.
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  inline void SetPadding(bool flag) { is_padding_relocations_ = flag; }
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Transfer relative relocations from .rel.dyn or .rela.dyn to a packed
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // representation in .android.rel.dyn or .android.rela.dyn.  Returns true
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // on success.
87f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool PackRelocations();
88f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Transfer relative relocations from a packed representation in
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // .android.rel.dyn or .android.rela.dyn to .rel.dyn or .rela.dyn.  Returns
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // true on success.
92f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool UnpackRelocations();
93f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
94f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) private:
95f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Load a new ElfFile from a filedescriptor.  If flushing, the file must
96f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // be open for read/write.  Returns true on successful ELF file load.
97f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // |fd| is an open file descriptor for the shared object.
98f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  bool Load();
99f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Templated packer, helper for PackRelocations().  Rel type is one of
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // ELF::Rel or ELF::Rela.
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  template <typename Rel>
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool PackTypedRelocations(const std::vector<Rel>& relocations,
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                            Elf_Data* data);
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Templated unpacker, helper for UnpackRelocations().  Rel type is one of
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // ELF::Rel or ELF::Rela.
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  template <typename Rel>
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool UnpackTypedRelocations(const std::vector<uint8_t>& packed,
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                              Elf_Data* data);
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
112f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Write ELF file changes.
113f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  void Flush();
114f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
115f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // File descriptor opened on the shared object.
116f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  int fd_;
117f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // If set, pad rather than shrink .rel.dyn or .rela.dyn.  Primarily for
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // debugging, allows packing to be checked without affecting load addresses.
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  bool is_padding_relocations_;
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
122f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Libelf handle, assigned by Load().
123f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Elf* elf_;
124f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
125f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  // Sections that we manipulate, assigned by Load().
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Elf_Scn* relocations_section_;
127f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)  Elf_Scn* dynamic_section_;
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  Elf_Scn* android_relocations_section_;
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Relocation type found, assigned by Load().
1315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  enum { NONE = 0, REL, RELA } relocations_type_;
132f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)};
133f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
134f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)}  // namespace relocation_packer
135f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)
136f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif  // TOOLS_RELOCATION_PACKER_SRC_ELF_FILE_H_
137