| Index: third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp | 
| diff --git a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp | 
| index 559c09e4f721ffcce67fca454edd92524fe692e4..5691ed383a76db34d118f6285eb82468fb85a154 100644 | 
| --- a/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp | 
| +++ b/third_party/android_crazy_linker/src/src/crazy_linker_elf_relocations.cpp | 
| @@ -4,6 +4,7 @@ | 
|  | 
| #include "crazy_linker_elf_relocations.h" | 
|  | 
| +#include <assert.h> | 
| #include <errno.h> | 
|  | 
| #include "crazy_linker_debug.h" | 
| @@ -32,6 +33,23 @@ | 
| #define DT_FLAGS 30 | 
| #endif | 
|  | 
| +// Extension dynamic tags for Android packed relocations. | 
| +#ifndef DT_LOOS | 
| +#define DT_LOOS 0x6000000d | 
| +#endif | 
| +#ifndef DT_ANDROID_REL | 
| +#define DT_ANDROID_REL (DT_LOOS + 2) | 
| +#endif | 
| +#ifndef DT_ANDROID_RELSZ | 
| +#define DT_ANDROID_RELSZ (DT_LOOS + 3) | 
| +#endif | 
| +#ifndef DT_ANDROID_RELA | 
| +#define DT_ANDROID_RELA (DT_LOOS + 4) | 
| +#endif | 
| +#ifndef DT_ANDROID_RELASZ | 
| +#define DT_ANDROID_RELASZ (DT_LOOS + 5) | 
| +#endif | 
| + | 
| // Processor-specific relocation types supported by the linker. | 
| #ifdef __arm__ | 
|  | 
| @@ -168,9 +186,6 @@ bool ElfRelocations::Init(const ElfView* view, Error* error) { | 
| phdr_ = view->phdr(); | 
| phdr_count_ = view->phdr_count(); | 
| load_bias_ = view->load_bias(); | 
| -#if defined(__arm__) || defined(__aarch64__) | 
| -  packed_relocations_ = view->packed_relocations(); | 
| -#endif | 
|  | 
| // We handle only Rel or Rela, but not both. If DT_RELA or DT_RELASZ | 
| // then we require DT_PLTREL to agree. | 
| @@ -231,6 +246,38 @@ bool ElfRelocations::Init(const ElfView* view, Error* error) { | 
| else | 
| has_rel_relocations = true; | 
| break; | 
| +      case DT_ANDROID_RELA: | 
| +      case DT_ANDROID_REL: | 
| +        RLOG("  %s addr=%p\n", | 
| +             (tag == DT_ANDROID_RELA) ? "DT_ANDROID_RELA" : "DT_ANDROID_REL", | 
| +             dyn_addr); | 
| +        if (android_relocations_) { | 
| +          *error = "Unsupported DT_ANDROID_RELA/DT_ANDROID_REL " | 
| +                   "combination in dynamic section"; | 
| +          return false; | 
| +        } | 
| +        android_relocations_ = reinterpret_cast<uint8_t*>(dyn_addr); | 
| +        if (tag == DT_ANDROID_RELA) | 
| +          has_rela_relocations = true; | 
| +        else | 
| +          has_rel_relocations = true; | 
| +        break; | 
| +      case DT_ANDROID_RELASZ: | 
| +      case DT_ANDROID_RELSZ: | 
| +        RLOG("  %s size=%d\n", | 
| +             (tag == DT_ANDROID_RELASZ) | 
| +                 ? "DT_ANDROID_RELASZ" : "DT_ANDROID_RELSZ", dyn_addr); | 
| +        if (android_relocations_size_) { | 
| +          *error = "Unsupported DT_ANDROID_RELASZ/DT_ANDROID_RELSZ " | 
| +                   "combination in dyn section"; | 
| +          return false; | 
| +        } | 
| +        android_relocations_size_ = dyn_value; | 
| +        if (tag == DT_ANDROID_RELASZ) | 
| +          has_rela_relocations = true; | 
| +        else | 
| +          has_rel_relocations = true; | 
| +        break; | 
| case DT_PLTGOT: | 
| // Only used on MIPS currently. Could also be used on other platforms | 
| // when lazy binding (i.e. RTLD_LAZY) is implemented. | 
| @@ -250,7 +297,7 @@ bool ElfRelocations::Init(const ElfView* view, Error* error) { | 
| has_text_relocations_ = true; | 
| if (dyn_value & DF_SYMBOLIC) | 
| has_symbolic_ = true; | 
| -        RLOG(" DT_FLAGS has_text_relocations=%s has_symbolic=%s\n", | 
| +        RLOG("  DT_FLAGS has_text_relocations=%s has_symbolic=%s\n", | 
| has_text_relocations_ ? "true" : "false", | 
| has_symbolic_ ? "true" : "false"); | 
| break; | 
| @@ -276,7 +323,8 @@ bool ElfRelocations::Init(const ElfView* view, Error* error) { | 
| } | 
|  | 
| if (has_rel_relocations && has_rela_relocations) { | 
| -    *error = "Combining DT_REL and DT_RELA is not currently supported"; | 
| +    *error = "Combining relocations with and without addends is not " | 
| +             "currently supported"; | 
| return false; | 
| } | 
|  | 
| @@ -290,11 +338,13 @@ bool ElfRelocations::Init(const ElfView* view, Error* error) { | 
| } | 
|  | 
| if (relocations_type_ == DT_REL && has_rela_relocations) { | 
| -    *error = "Found DT_RELA in dyn section, but DT_PLTREL is DT_REL"; | 
| +    *error = "Found relocations with addends in dyn section, " | 
| +             "but DT_PLTREL is DT_REL"; | 
| return false; | 
| } | 
| if (relocations_type_ == DT_RELA && has_rel_relocations) { | 
| -    *error = "Found DT_REL in dyn section, but DT_PLTREL is DT_RELA"; | 
| +    *error = "Found relocations without addends in dyn section, " | 
| +             "but DT_PLTREL is DT_RELA"; | 
| return false; | 
| } | 
|  | 
| @@ -313,10 +363,8 @@ bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, | 
| } | 
| } | 
|  | 
| -#if defined(__arm__) || defined(__aarch64__) | 
| -  if (!ApplyPackedRelocations(error)) | 
| +  if (!ApplyAndroidRelocations(symbols, resolver, error)) | 
| return false; | 
| -#endif | 
|  | 
| if (relocations_type_ == DT_REL) { | 
| if (!ApplyRelRelocs(reinterpret_cast<ELF::Rel*>(relocations_), | 
| @@ -364,142 +412,189 @@ bool ElfRelocations::ApplyAll(const ElfSymbols* symbols, | 
| return true; | 
| } | 
|  | 
| -#if defined(__arm__) || defined(__aarch64__) | 
| +// Helper class for Android packed relocations.  Encapsulates the packing | 
| +// flags used by Android for packed relocation groups. | 
| +class AndroidPackedRelocationGroupFlags { | 
| + public: | 
| +  explicit AndroidPackedRelocationGroupFlags(size_t flags) : flags_(flags) { } | 
| + | 
| +  bool is_relocation_grouped_by_info() const { | 
| +    return hasFlag(RELOCATION_GROUPED_BY_INFO_FLAG); | 
| +  } | 
| +  bool is_relocation_grouped_by_offset_delta() const { | 
| +    return hasFlag(RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG); | 
| +  } | 
| +  bool is_relocation_grouped_by_addend() const { | 
| +    return hasFlag(RELOCATION_GROUPED_BY_ADDEND_FLAG); | 
| +  } | 
| +  bool is_relocation_group_has_addend() const { | 
| +    return hasFlag(RELOCATION_GROUP_HAS_ADDEND_FLAG); | 
| +  } | 
| + | 
| + private: | 
| +  bool hasFlag(size_t flag) const { return (flags_ & flag) != 0; } | 
|  | 
| -bool ElfRelocations::ForEachPackedRel(const uint8_t* packed_relocations, | 
| -                                      RelRelocationHandler handler, | 
| -                                      void* opaque) { | 
| -  Leb128Decoder decoder(packed_relocations); | 
| +  static const size_t RELOCATION_GROUPED_BY_INFO_FLAG = 1 << 0; | 
| +  static const size_t RELOCATION_GROUPED_BY_OFFSET_DELTA_FLAG = 1 << 1; | 
| +  static const size_t RELOCATION_GROUPED_BY_ADDEND_FLAG = 1 << 2; | 
| +  static const size_t RELOCATION_GROUP_HAS_ADDEND_FLAG = 1 << 3; | 
|  | 
| -  // Find the count of pairs and the start address. | 
| -  size_t pairs = decoder.Dequeue(); | 
| -  const ELF::Addr start_address = decoder.Dequeue(); | 
| +  const size_t flags_; | 
| +}; | 
|  | 
| -  // Emit initial relative relocation. | 
| -  ELF::Rel relocation; | 
| -  relocation.r_offset = start_address; | 
| -  relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE); | 
| -  const ELF::Addr sym_addr = 0; | 
| -  const bool resolved = false; | 
| -  if (!handler(this, &relocation, opaque)) | 
| -    return false; | 
| +bool ElfRelocations::ForEachAndroidRelocation(RelocationHandler handler, | 
| +                                              void* opaque) { | 
| +  // Skip over the "APS2" signature. | 
| +  Sleb128Decoder decoder(android_relocations_ + 4, | 
| +                         android_relocations_size_ - 4); | 
| + | 
| +  // Unpacking into a relocation with addend, both for REL and RELA, is | 
| +  // convenient at this point. If REL, the handler needs to take care of | 
| +  // any conversion before use. | 
| +  ELF::Rela relocation; | 
| +  memset(&relocation, 0, sizeof(relocation)); | 
| + | 
| +  // Read the relocation count and initial offset. | 
| +  const size_t relocation_count = decoder.pop_front(); | 
| +  relocation.r_offset = decoder.pop_front(); | 
| + | 
| +  LOG("%s: relocation_count=%d, initial r_offset=%p\n", | 
| +      __FUNCTION__, | 
| +      relocation_count, | 
| +      relocation.r_offset); | 
| + | 
| +  size_t relocations_handled = 0; | 
| +  while (relocations_handled < relocation_count) { | 
| +    // Read the start of the group header to obtain its size and flags. | 
| +    const size_t group_size = decoder.pop_front(); | 
| +    AndroidPackedRelocationGroupFlags group_flags(decoder.pop_front()); | 
| + | 
| +    // Read other group header fields, depending on the flags read above. | 
| +    size_t group_r_offset_delta = 0; | 
| +    if (group_flags.is_relocation_grouped_by_offset_delta()) | 
| +      group_r_offset_delta = decoder.pop_front(); | 
| + | 
| +    if (group_flags.is_relocation_grouped_by_info()) | 
| +      relocation.r_info = decoder.pop_front(); | 
| + | 
| +    if (group_flags.is_relocation_group_has_addend() && | 
| +        group_flags.is_relocation_grouped_by_addend()) | 
| +      relocation.r_addend += decoder.pop_front(); | 
| +    else if (!group_flags.is_relocation_group_has_addend()) | 
| +      relocation.r_addend = 0; | 
| + | 
| +    // Expand the group into individual relocations. | 
| +    for (size_t group_index = 0; group_index < group_size; group_index++) { | 
| +      if (group_flags.is_relocation_grouped_by_offset_delta()) | 
| +        relocation.r_offset += group_r_offset_delta; | 
| +      else | 
| +        relocation.r_offset += decoder.pop_front(); | 
|  | 
| -  size_t unpacked_count = 1; | 
| +      if (!group_flags.is_relocation_grouped_by_info()) | 
| +        relocation.r_info = decoder.pop_front(); | 
|  | 
| -  // Emit relocations for each count-delta pair. | 
| -  while (pairs) { | 
| -    size_t count = decoder.Dequeue(); | 
| -    const size_t delta = decoder.Dequeue(); | 
| +      if (group_flags.is_relocation_group_has_addend() && | 
| +          !group_flags.is_relocation_grouped_by_addend()) | 
| +        relocation.r_addend += decoder.pop_front(); | 
|  | 
| -    // Emit count relative relocations with delta offset. | 
| -    while (count) { | 
| -      relocation.r_offset += delta; | 
| -      if (!handler(this, &relocation, opaque)) | 
| +      // Pass the relocation to the supplied handler function. If the handler | 
| +      // returns false we view this as failure and return false to our caller. | 
| +      if (!handler(this, &relocation, opaque)) { | 
| +        LOG("%s: failed handling relocation %d\n", | 
| +            __FUNCTION__, | 
| +            relocations_handled); | 
| return false; | 
| -      unpacked_count++; | 
| -      count--; | 
| +      } | 
| + | 
| +      relocations_handled++; | 
| } | 
| -    pairs--; | 
| } | 
|  | 
| -  RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count); | 
| +  LOG("%s: relocations_handled=%d\n", __FUNCTION__, relocations_handled); | 
| return true; | 
| } | 
|  | 
| -bool ElfRelocations::ForEachPackedRela(const uint8_t* packed_relocations, | 
| -                                       RelaRelocationHandler handler, | 
| -                                       void* opaque) { | 
| -  Sleb128Decoder decoder(packed_relocations); | 
| +namespace { | 
|  | 
| -  // Find the count of pairs. | 
| -  size_t pairs = decoder.Dequeue(); | 
| +// Validate the Android packed relocations signature. | 
| +bool IsValidAndroidPackedRelocations(const uint8_t* android_relocations, | 
| +                                     size_t android_relocations_size) { | 
| +  if (android_relocations_size < 4) | 
| +    return false; | 
|  | 
| -  ELF::Addr offset = 0; | 
| -  ELF::Sxword addend = 0; | 
| +  // Check for an initial APS2 Android packed relocations header. | 
| +  return (android_relocations[0] == 'A' && | 
| +          android_relocations[1] == 'P' && | 
| +          android_relocations[2] == 'S' && | 
| +          android_relocations[3] == '2'); | 
| +} | 
|  | 
| -  const ELF::Addr sym_addr = 0; | 
| -  const bool resolved = false; | 
| +// Narrow a Rela to its equivalent Rel. The r_addend field in the input | 
| +// Rela must be zero. | 
| +void ConvertRelaToRel(const ELF::Rela* rela, ELF::Rel* rel) { | 
| +  assert(rela->r_addend == 0); | 
| +  rel->r_offset = rela->r_offset; | 
| +  rel->r_info = rela->r_info; | 
| +} | 
|  | 
| -  size_t unpacked_count = 0; | 
| +}  // namespace | 
|  | 
| -  // Emit relocations for each deltas pair. | 
| -  while (pairs) { | 
| -    offset += decoder.Dequeue(); | 
| -    addend += decoder.Dequeue(); | 
| +// Args for ApplyAndroidRelocation handler function. | 
| +struct ApplyAndroidRelocationArgs { | 
| +  ELF::Addr relocations_type; | 
| +  const ElfSymbols* symbols; | 
| +  ElfRelocations::SymbolResolver* resolver; | 
| +  Error* error; | 
| +}; | 
|  | 
| -    ELF::Rela relocation; | 
| -    relocation.r_offset = offset; | 
| -    relocation.r_info = ELF_R_INFO(0, RELATIVE_RELOCATION_CODE); | 
| -    relocation.r_addend = addend; | 
| -    if (!handler(this, &relocation, opaque)) | 
| -      return false; | 
| -    unpacked_count++; | 
| -    pairs--; | 
| +// Static ForEachAndroidRelocation() handler. | 
| +bool ElfRelocations::ApplyAndroidRelocation(ElfRelocations* relocations, | 
| +                                            const ELF::Rela* relocation, | 
| +                                            void* opaque) { | 
| +  // Unpack args from opaque. | 
| +  ApplyAndroidRelocationArgs* args = | 
| +      reinterpret_cast<ApplyAndroidRelocationArgs*>(opaque); | 
| +  const ELF::Addr relocations_type = args->relocations_type; | 
| +  const ElfSymbols* symbols = args->symbols; | 
| +  ElfRelocations::SymbolResolver* resolver = args->resolver; | 
| +  Error* error = args->error; | 
| + | 
| +  // For REL relocations, convert from RELA to REL and apply the conversion. | 
| +  // For RELA relocations, apply RELA directly. | 
| +  if (relocations_type == DT_REL) { | 
| +    ELF::Rel converted; | 
| +    ConvertRelaToRel(relocation, &converted); | 
| +    return relocations->ApplyRelReloc(&converted, symbols, resolver, error); | 
| } | 
|  | 
| -  RLOG("%s: unpacked_count=%d\n", __FUNCTION__, unpacked_count); | 
| -  return true; | 
| -} | 
| - | 
| -bool ElfRelocations::ApplyPackedRel(ElfRelocations* relocations, | 
| -                                    const ELF::Rel* relocation, | 
| -                                    void* opaque) { | 
| -  Error* error = reinterpret_cast<Error*>(opaque); | 
| -  const ELF::Addr sym_addr = 0; | 
| -  const bool resolved = false; | 
| -  return relocations->ApplyRelReloc(relocation, sym_addr, resolved, error); | 
| -} | 
| +  if (relocations_type == DT_RELA) | 
| +    return relocations->ApplyRelaReloc(relocation, symbols, resolver, error); | 
|  | 
| -bool ElfRelocations::ApplyPackedRels(const uint8_t* packed_relocations, | 
| -                                     Error* error) { | 
| -  void* opaque = error; | 
| -  return ForEachPackedRel(packed_relocations, &ApplyPackedRel, opaque); | 
| -} | 
| - | 
| -bool ElfRelocations::ApplyPackedRela(ElfRelocations* relocations, | 
| -                                     const ELF::Rela* relocation, | 
| -                                     void* opaque) { | 
| -  Error* error = reinterpret_cast<Error*>(opaque); | 
| -  const ELF::Addr sym_addr = 0; | 
| -  const bool resolved = false; | 
| -  return relocations->ApplyRelaReloc(relocation, sym_addr, resolved, error); | 
| -} | 
| - | 
| -bool ElfRelocations::ApplyPackedRelas(const uint8_t* packed_relocations, | 
| -                                      Error* error) { | 
| -  void* opaque = error; | 
| -  return ForEachPackedRela(packed_relocations, &ApplyPackedRela, opaque); | 
| +  return true; | 
| } | 
|  | 
| -bool ElfRelocations::ApplyPackedRelocations(Error* error) { | 
| -  if (!packed_relocations_) | 
| +bool ElfRelocations::ApplyAndroidRelocations(const ElfSymbols* symbols, | 
| +                                             SymbolResolver* resolver, | 
| +                                             Error* error) { | 
| +  if (!android_relocations_) | 
| return true; | 
|  | 
| -  // Check for an initial APR1 header, packed relocations. | 
| -  if (packed_relocations_[0] == 'A' && | 
| -      packed_relocations_[1] == 'P' && | 
| -      packed_relocations_[2] == 'R' && | 
| -      packed_relocations_[3] == '1') { | 
| -    return ApplyPackedRels(packed_relocations_ + 4, error); | 
| -  } | 
| - | 
| -  // Check for an initial APA1 header, packed relocations with addend. | 
| -  if (packed_relocations_[0] == 'A' && | 
| -      packed_relocations_[1] == 'P' && | 
| -      packed_relocations_[2] == 'A' && | 
| -      packed_relocations_[3] == '1') { | 
| -    return ApplyPackedRelas(packed_relocations_ + 4, error); | 
| -  } | 
| +  if (!IsValidAndroidPackedRelocations(android_relocations_, | 
| +                                       android_relocations_size_)) | 
| +    return false; | 
|  | 
| -  error->Format("Bad packed relocations ident, expected APR1 or APA1"); | 
| -  return false; | 
| +  ApplyAndroidRelocationArgs args; | 
| +  args.relocations_type = relocations_type_; | 
| +  args.symbols = symbols; | 
| +  args.resolver = resolver; | 
| +  args.error = error; | 
| +  return ForEachAndroidRelocation(&ApplyAndroidRelocation, &args); | 
| } | 
| -#endif  // __arm__ || __aarch64__ | 
|  | 
| -bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela, | 
| -                                    ELF::Addr sym_addr, | 
| -                                    bool resolved CRAZY_UNUSED, | 
| -                                    Error* error) { | 
| +bool ElfRelocations::ApplyResolvedRelaReloc(const ELF::Rela* rela, | 
| +                                            ELF::Addr sym_addr, | 
| +                                            bool resolved CRAZY_UNUSED, | 
| +                                            Error* error) { | 
| const ELF::Word rela_type = ELF_R_TYPE(rela->r_info); | 
| const ELF::Word CRAZY_UNUSED rela_symbol = ELF_R_SYM(rela->r_info); | 
| const ELF::Sword CRAZY_UNUSED addend = rela->r_addend; | 
| @@ -591,10 +686,10 @@ bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela, | 
| return true; | 
| } | 
|  | 
| -bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel, | 
| -                                   ELF::Addr sym_addr, | 
| -                                   bool resolved CRAZY_UNUSED, | 
| -                                   Error* error) { | 
| +bool ElfRelocations::ApplyResolvedRelReloc(const ELF::Rel* rel, | 
| +                                           ELF::Addr sym_addr, | 
| +                                           bool resolved CRAZY_UNUSED, | 
| +                                           Error* error) { | 
| const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); | 
| const ELF::Word CRAZY_UNUSED rel_symbol = ELF_R_SYM(rel->r_info); | 
|  | 
| @@ -752,6 +847,43 @@ bool ElfRelocations::ResolveSymbol(ELF::Word rel_type, | 
| return false; | 
| } | 
|  | 
| +bool ElfRelocations::ApplyRelReloc(const ELF::Rel* rel, | 
| +                                   const ElfSymbols* symbols, | 
| +                                   SymbolResolver* resolver, | 
| +                                   Error* error) { | 
| +  const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); | 
| +  const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); | 
| + | 
| +  ELF::Addr sym_addr = 0; | 
| +  ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); | 
| +  RLOG("  reloc=%p offset=%p type=%d symbol=%d\n", | 
| +       reloc, | 
| +       rel->r_offset, | 
| +       rel_type, | 
| +       rel_symbol); | 
| + | 
| +  if (rel_type == 0) | 
| +    return true; | 
| + | 
| +  bool resolved = false; | 
| + | 
| +  // If this is a symbolic relocation, compute the symbol's address. | 
| +  if (__builtin_expect(rel_symbol != 0, 0)) { | 
| +    if (!ResolveSymbol(rel_type, | 
| +                       rel_symbol, | 
| +                       symbols, | 
| +                       resolver, | 
| +                       reloc, | 
| +                       &sym_addr, | 
| +                       error)) { | 
| +      return false; | 
| +    } | 
| +    resolved = true; | 
| +  } | 
| + | 
| +  return ApplyResolvedRelReloc(rel, sym_addr, resolved, error); | 
| +} | 
| + | 
| bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel, | 
| size_t rel_count, | 
| const ElfSymbols* symbols, | 
| @@ -763,43 +895,50 @@ bool ElfRelocations::ApplyRelRelocs(const ELF::Rel* rel, | 
| return true; | 
|  | 
| for (size_t rel_n = 0; rel_n < rel_count; rel++, rel_n++) { | 
| -    const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); | 
| -    const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); | 
| +    RLOG("  Relocation %d of %d:\n", rel_n + 1, rel_count); | 
|  | 
| -    ELF::Addr sym_addr = 0; | 
| -    ELF::Addr reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias_); | 
| -    RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n", | 
| -         rel_n + 1, | 
| -         rel_count, | 
| -         reloc, | 
| -         rel->r_offset, | 
| -         rel_type, | 
| -         rel_symbol); | 
| - | 
| -    if (rel_type == 0) | 
| -      continue; | 
| +    if (!ApplyRelReloc(rel, symbols, resolver, error)) | 
| +      return false; | 
| +  } | 
|  | 
| -    bool resolved = false; | 
| +  return true; | 
| +} | 
|  | 
| -    // If this is a symbolic relocation, compute the symbol's address. | 
| -    if (__builtin_expect(rel_symbol != 0, 0)) { | 
| -      if (!ResolveSymbol(rel_type, | 
| -                         rel_symbol, | 
| -                         symbols, | 
| -                         resolver, | 
| -                         reloc, | 
| -                         &sym_addr, | 
| -                         error)) { | 
| -        return false; | 
| -      } | 
| -      resolved = true; | 
| -    } | 
| +bool ElfRelocations::ApplyRelaReloc(const ELF::Rela* rela, | 
| +                                    const ElfSymbols* symbols, | 
| +                                    SymbolResolver* resolver, | 
| +                                    Error* error) { | 
| +  const ELF::Word rel_type = ELF_R_TYPE(rela->r_info); | 
| +  const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info); | 
| + | 
| +  ELF::Addr sym_addr = 0; | 
| +  ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); | 
| +  RLOG("  reloc=%p offset=%p type=%d symbol=%d\n", | 
| +       reloc, | 
| +       rela->r_offset, | 
| +       rel_type, | 
| +       rel_symbol); | 
| + | 
| +  if (rel_type == 0) | 
| +    return true; | 
|  | 
| -    if (!ApplyRelReloc(rel, sym_addr, resolved, error)) | 
| +  bool resolved = false; | 
| + | 
| +  // If this is a symbolic relocation, compute the symbol's address. | 
| +  if (__builtin_expect(rel_symbol != 0, 0)) { | 
| +    if (!ResolveSymbol(rel_type, | 
| +                       rel_symbol, | 
| +                       symbols, | 
| +                       resolver, | 
| +                       reloc, | 
| +                       &sym_addr, | 
| +                       error)) { | 
| return false; | 
| +    } | 
| +    resolved = true; | 
| } | 
|  | 
| -  return true; | 
| +  return ApplyResolvedRelaReloc(rela, sym_addr, resolved, error); | 
| } | 
|  | 
| bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela, | 
| @@ -813,39 +952,9 @@ bool ElfRelocations::ApplyRelaRelocs(const ELF::Rela* rela, | 
| return true; | 
|  | 
| for (size_t rel_n = 0; rel_n < rela_count; rela++, rel_n++) { | 
| -    const ELF::Word rel_type = ELF_R_TYPE(rela->r_info); | 
| -    const ELF::Word rel_symbol = ELF_R_SYM(rela->r_info); | 
| - | 
| -    ELF::Addr sym_addr = 0; | 
| -    ELF::Addr reloc = static_cast<ELF::Addr>(rela->r_offset + load_bias_); | 
| -    RLOG("  %d/%d reloc=%p offset=%p type=%d symbol=%d\n", | 
| -         rel_n + 1, | 
| -         rela_count, | 
| -         reloc, | 
| -         rela->r_offset, | 
| -         rel_type, | 
| -         rel_symbol); | 
| - | 
| -    if (rel_type == 0) | 
| -      continue; | 
| - | 
| -    bool resolved = false; | 
| +    RLOG("  Relocation %d of %d:\n", rel_n + 1, rela_count); | 
|  | 
| -    // If this is a symbolic relocation, compute the symbol's address. | 
| -    if (__builtin_expect(rel_symbol != 0, 0)) { | 
| -      if (!ResolveSymbol(rel_type, | 
| -                         rel_symbol, | 
| -                         symbols, | 
| -                         resolver, | 
| -                         reloc, | 
| -                         &sym_addr, | 
| -                         error)) { | 
| -        return false; | 
| -      } | 
| -      resolved = true; | 
| -    } | 
| - | 
| -    if (!ApplyRelaReloc(rela, sym_addr, resolved, error)) | 
| +    if (!ApplyRelaReloc(rela, symbols, resolver, error)) | 
| return false; | 
| } | 
|  | 
| @@ -941,115 +1050,90 @@ void ElfRelocations::AdjustRelocation(ELF::Word rel_type, | 
| } | 
| } | 
|  | 
| -#if defined(__arm__) || defined(__aarch64__) | 
| - | 
| -struct AdjustRelocationArgs { | 
| -  size_t src_addr; | 
| -  size_t dst_addr; | 
| -  size_t map_addr; | 
| -  size_t size; | 
| -}; | 
| - | 
| -template<typename Rel> | 
| -bool ElfRelocations::RelocatePackedRelocation(ElfRelocations* relocations, | 
| -                                              const Rel* rel, | 
| -                                              void* opaque) { | 
| -  AdjustRelocationArgs* args = reinterpret_cast<AdjustRelocationArgs*>(opaque); | 
| -  const size_t src_addr = args->src_addr; | 
| -  const size_t dst_addr = args->dst_addr; | 
| -  const size_t map_addr = args->map_addr; | 
| -  const size_t size = args->size; | 
| - | 
| -  const size_t load_bias = relocations->load_bias_; | 
| - | 
| +void ElfRelocations::AdjustAndroidRelocation(const ELF::Rela* relocation, | 
| +                                             size_t src_addr, | 
| +                                             size_t dst_addr, | 
| +                                             size_t map_addr, | 
| +                                             size_t size) { | 
| +  // Add this value to each source address to get the corresponding | 
| +  // destination address. | 
| const size_t dst_delta = dst_addr - src_addr; | 
| const size_t map_delta = map_addr - src_addr; | 
|  | 
| -  const ELF::Word rel_type = ELF_R_TYPE(rel->r_info); | 
| -  const ELF::Word rel_symbol = ELF_R_SYM(rel->r_info); | 
| -  ELF::Addr src_reloc = static_cast<ELF::Addr>(rel->r_offset + load_bias); | 
| +  const ELF::Word rel_type = ELF_R_TYPE(relocation->r_info); | 
| +  const ELF::Word rel_symbol = ELF_R_SYM(relocation->r_info); | 
| +  ELF::Addr src_reloc = | 
| +      static_cast<ELF::Addr>(relocation->r_offset + load_bias_); | 
|  | 
| if (rel_type == 0 || rel_symbol != 0) { | 
| // Ignore empty and symbolic relocations | 
| -    return true; | 
| +    return; | 
| } | 
|  | 
| if (src_reloc < src_addr || src_reloc >= src_addr + size) { | 
| // Ignore entries that don't relocate addresses inside the source section. | 
| -    return true; | 
| +    return; | 
| } | 
|  | 
| -  relocations->AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta); | 
| +  AdjustRelocation(rel_type, src_reloc, dst_delta, map_delta); | 
| +} | 
| + | 
| +// Args for ApplyAndroidRelocation handler function. | 
| +struct RelocateAndroidRelocationArgs { | 
| +  size_t src_addr; | 
| +  size_t dst_addr; | 
| +  size_t map_addr; | 
| +  size_t size; | 
| +}; | 
| + | 
| +// Static ForEachAndroidRelocation() handler. | 
| +bool ElfRelocations::RelocateAndroidRelocation(ElfRelocations* relocations, | 
| +                                               const ELF::Rela* relocation, | 
| +                                               void* opaque) { | 
| +  // Unpack args from opaque, to obtain addrs and size; | 
| +  RelocateAndroidRelocationArgs* args = | 
| +      reinterpret_cast<RelocateAndroidRelocationArgs*>(opaque); | 
| +  const size_t src_addr = args->src_addr; | 
| +  const size_t dst_addr = args->dst_addr; | 
| +  const size_t map_addr = args->map_addr; | 
| +  const size_t size = args->size; | 
| + | 
| +  // Relocate the given relocation.  Because the r_addend field is ignored | 
| +  // in relocating RELA relocations we do not need to convert from REL to | 
| +  // RELA and supply alternative relocator functions; instead we can work | 
| +  // here directly on the RELA supplied by ForEachAndroidRelocation(), even | 
| +  // on REL architectures. | 
| +  relocations->AdjustAndroidRelocation(relocation, | 
| +                                       src_addr, | 
| +                                       dst_addr, | 
| +                                       map_addr, | 
| +                                       size); | 
| return true; | 
| } | 
|  | 
| -template bool ElfRelocations::RelocatePackedRelocation<ELF::Rel>( | 
| -    ElfRelocations* relocations, const ELF::Rel* rel, void* opaque); | 
| +void ElfRelocations::RelocateAndroidRelocations(size_t src_addr, | 
| +                                                size_t dst_addr, | 
| +                                                size_t map_addr, | 
| +                                                size_t size) { | 
| +  if (!android_relocations_) | 
| +    return; | 
|  | 
| -template bool ElfRelocations::RelocatePackedRelocation<ELF::Rela>( | 
| -    ElfRelocations* relocations, const ELF::Rela* rel, void* opaque); | 
| +  assert(IsValidAndroidPackedRelocations(android_relocations_, | 
| +                                         android_relocations_size_)); | 
|  | 
| -void ElfRelocations::RelocatePackedRels(const uint8_t* packed_relocations, | 
| -                                        size_t src_addr, | 
| -                                        size_t dst_addr, | 
| -                                        size_t map_addr, | 
| -                                        size_t size) { | 
| -  AdjustRelocationArgs args; | 
| +  RelocateAndroidRelocationArgs args; | 
| args.src_addr = src_addr; | 
| args.dst_addr = dst_addr; | 
| args.map_addr = map_addr; | 
| args.size = size; | 
| -  ForEachPackedRel(packed_relocations, | 
| -                   &RelocatePackedRelocation<ELF::Rel>, &args); | 
| +  ForEachAndroidRelocation(&RelocateAndroidRelocation, &args); | 
| } | 
|  | 
| -void ElfRelocations::RelocatePackedRelas(const uint8_t* packed_relocations, | 
| -                                         size_t src_addr, | 
| +template<typename Rel> | 
| +void ElfRelocations::RelocateRelocations(size_t src_addr, | 
| size_t dst_addr, | 
| size_t map_addr, | 
| size_t size) { | 
| -  AdjustRelocationArgs args; | 
| -  args.src_addr = src_addr; | 
| -  args.dst_addr = dst_addr; | 
| -  args.map_addr = map_addr; | 
| -  args.size = size; | 
| -  ForEachPackedRela(packed_relocations, | 
| -                    &RelocatePackedRelocation<ELF::Rela>, &args); | 
| -} | 
| - | 
| -void ElfRelocations::RelocatePackedRelocations(size_t src_addr, | 
| -                                               size_t dst_addr, | 
| -                                               size_t map_addr, | 
| -                                               size_t size) { | 
| -  if (!packed_relocations_) | 
| -    return; | 
| - | 
| -  // Check for an initial APR1 header, packed relocations. | 
| -  if (packed_relocations_[0] == 'A' && | 
| -      packed_relocations_[1] == 'P' && | 
| -      packed_relocations_[2] == 'R' && | 
| -      packed_relocations_[3] == '1') { | 
| -    RelocatePackedRels(packed_relocations_ + 4, | 
| -                       src_addr, dst_addr, map_addr, size); | 
| -  } | 
| - | 
| -  // Check for an initial APA1 header, packed relocations with addend. | 
| -  if (packed_relocations_[0] == 'A' && | 
| -      packed_relocations_[1] == 'P' && | 
| -      packed_relocations_[2] == 'A' && | 
| -      packed_relocations_[3] == '1') { | 
| -    RelocatePackedRelas(packed_relocations_ + 4, | 
| -                        src_addr, dst_addr, map_addr, size); | 
| -  } | 
| -} | 
| - | 
| -#endif  // __arm__ || __aarch64__ | 
| - | 
| -template<typename Rel> | 
| -void ElfRelocations::RelocateRelocation(size_t src_addr, | 
| -                                        size_t dst_addr, | 
| -                                        size_t map_addr, | 
| -                                        size_t size) { | 
| // Add this value to each source address to get the corresponding | 
| // destination address. | 
| const size_t dst_delta = dst_addr - src_addr; | 
| @@ -1079,10 +1163,10 @@ void ElfRelocations::RelocateRelocation(size_t src_addr, | 
| } | 
| } | 
|  | 
| -template void ElfRelocations::RelocateRelocation<ELF::Rel>( | 
| +template void ElfRelocations::RelocateRelocations<ELF::Rel>( | 
| size_t src_addr, size_t dst_addr, size_t map_addr, size_t size); | 
|  | 
| -template void ElfRelocations::RelocateRelocation<ELF::Rela>( | 
| +template void ElfRelocations::RelocateRelocations<ELF::Rela>( | 
| size_t src_addr, size_t dst_addr, size_t map_addr, size_t size); | 
|  | 
| void ElfRelocations::CopyAndRelocate(size_t src_addr, | 
| @@ -1094,17 +1178,15 @@ void ElfRelocations::CopyAndRelocate(size_t src_addr, | 
| reinterpret_cast<void*>(src_addr), | 
| size); | 
|  | 
| -#if defined(__arm__) || defined(__aarch64__) | 
| -  // Relocate packed relative relocations. | 
| -  RelocatePackedRelocations(src_addr, dst_addr, map_addr, size); | 
| -#endif | 
| +  // Relocate android relocations. | 
| +  RelocateAndroidRelocations(src_addr, dst_addr, map_addr, size); | 
|  | 
| // Relocate relocations. | 
| if (relocations_type_ == DT_REL) | 
| -    RelocateRelocation<ELF::Rel>(src_addr, dst_addr, map_addr, size); | 
| +    RelocateRelocations<ELF::Rel>(src_addr, dst_addr, map_addr, size); | 
|  | 
| if (relocations_type_ == DT_RELA) | 
| -    RelocateRelocation<ELF::Rela>(src_addr, dst_addr, map_addr, size); | 
| +    RelocateRelocations<ELF::Rela>(src_addr, dst_addr, map_addr, size); | 
|  | 
| #ifdef __mips__ | 
| // Add this value to each source address to get the corresponding | 
|  |