reloc_elf.cc 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. // Copyright 2018 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. #include "components/zucchini/reloc_elf.h"
  5. #include <algorithm>
  6. #include "base/logging.h"
  7. #include "components/zucchini/algorithm.h"
  8. namespace zucchini {
  9. /******** RelocReaderElf ********/
  10. RelocReaderElf::RelocReaderElf(
  11. ConstBufferView image,
  12. Bitness bitness,
  13. const std::vector<SectionDimensionsElf>& reloc_section_dims,
  14. uint32_t rel_type,
  15. offset_t lo,
  16. offset_t hi,
  17. const AddressTranslator& translator)
  18. : image_(image),
  19. bitness_(bitness),
  20. rel_type_(rel_type),
  21. reloc_section_dimensions_(reloc_section_dims),
  22. hi_(hi),
  23. target_rva_to_offset_(translator) {
  24. DCHECK(bitness_ == kBit32 || bitness_ == kBit64);
  25. // Find the relocation section at or right before |lo|.
  26. cur_section_dimensions_ = std::upper_bound(
  27. reloc_section_dimensions_.begin(), reloc_section_dimensions_.end(), lo);
  28. if (cur_section_dimensions_ != reloc_section_dimensions_.begin())
  29. --cur_section_dimensions_;
  30. // |lo| and |hi_| do not cut across a reloc reference (e.g.,
  31. // Elf_Rel::r_offset), but may cut across a reloc struct (e.g. Elf_Rel)!
  32. // GetNext() emits all reloc references in |[lo, hi_)|, but needs to examine
  33. // the entire reloc struct for context. Knowing that |r_offset| is the first
  34. // entry in a reloc struct, |cursor_| and |hi_| are adjusted by the following:
  35. // - If |lo| is in a reloc section, then |cursor_| is chosen, as |lo| aligned
  36. // up to the next reloc struct, to exclude reloc struct that |lo| may cut
  37. // across.
  38. // - If |hi_| is in a reloc section, then align it up, to include reloc struct
  39. // that |hi_| may cut across.
  40. cursor_ =
  41. base::checked_cast<offset_t>(cur_section_dimensions_->region.offset);
  42. if (cursor_ < lo)
  43. cursor_ +=
  44. AlignCeil<offset_t>(lo - cursor_, cur_section_dimensions_->entry_size);
  45. auto end_section = std::upper_bound(reloc_section_dimensions_.begin(),
  46. reloc_section_dimensions_.end(), hi_);
  47. if (end_section != reloc_section_dimensions_.begin()) {
  48. --end_section;
  49. if (hi_ - end_section->region.offset < end_section->region.size) {
  50. offset_t end_region_offset =
  51. base::checked_cast<offset_t>(end_section->region.offset);
  52. hi_ = end_region_offset + AlignCeil<offset_t>(hi_ - end_region_offset,
  53. end_section->entry_size);
  54. }
  55. }
  56. }
  57. RelocReaderElf::~RelocReaderElf() = default;
  58. rva_t RelocReaderElf::GetRelocationTarget(elf::Elf32_Rel rel) const {
  59. // The least significant byte of |rel.r_info| is the type. The other 3 bytes
  60. // store the symbol, which we ignore.
  61. uint32_t type = static_cast<uint32_t>(rel.r_info & 0xFF);
  62. if (type == rel_type_)
  63. return rel.r_offset;
  64. return kInvalidRva;
  65. }
  66. rva_t RelocReaderElf::GetRelocationTarget(elf::Elf64_Rel rel) const {
  67. // The least significant 4 bytes of |rel.r_info| is the type. The other 4
  68. // bytes store the symbol, which we ignore.
  69. uint32_t type = static_cast<uint32_t>(rel.r_info & 0xFFFFFFFF);
  70. if (type == rel_type_) {
  71. // Assume |rel.r_offset| fits within 32-bit integer.
  72. if ((rel.r_offset & 0xFFFFFFFF) == rel.r_offset)
  73. return static_cast<rva_t>(rel.r_offset);
  74. // Otherwise output warning.
  75. LOG(WARNING) << "Warning: Skipping r_offset whose value exceeds 32-bits.";
  76. }
  77. return kInvalidRva;
  78. }
  79. absl::optional<Reference> RelocReaderElf::GetNext() {
  80. offset_t cur_entry_size = cur_section_dimensions_->entry_size;
  81. offset_t cur_section_dimensions_end =
  82. base::checked_cast<offset_t>(cur_section_dimensions_->region.hi());
  83. for (; cursor_ + cur_entry_size <= hi_; cursor_ += cur_entry_size) {
  84. while (cursor_ >= cur_section_dimensions_end) {
  85. ++cur_section_dimensions_;
  86. if (cur_section_dimensions_ == reloc_section_dimensions_.end())
  87. return absl::nullopt;
  88. cur_entry_size = cur_section_dimensions_->entry_size;
  89. cursor_ =
  90. base::checked_cast<offset_t>(cur_section_dimensions_->region.offset);
  91. if (cursor_ + cur_entry_size > hi_)
  92. return absl::nullopt;
  93. cur_section_dimensions_end =
  94. base::checked_cast<offset_t>(cur_section_dimensions_->region.hi());
  95. }
  96. rva_t target_rva = kInvalidRva;
  97. // TODO(huangs): Fix RELA sections: Need to process |r_addend|.
  98. switch (bitness_) {
  99. case kBit32:
  100. target_rva = GetRelocationTarget(image_.read<elf::Elf32_Rel>(cursor_));
  101. break;
  102. case kBit64:
  103. target_rva = GetRelocationTarget(image_.read<elf::Elf64_Rel>(cursor_));
  104. break;
  105. }
  106. if (target_rva == kInvalidRva)
  107. continue;
  108. // TODO(huangs): Make the check more strict: The reference body should not
  109. // straddle section boundary.
  110. offset_t target = target_rva_to_offset_.Convert(target_rva);
  111. if (target == kInvalidOffset)
  112. continue;
  113. // |target| will be used to obtain abs32 references, so we must ensure that
  114. // it lies inside |image_|.
  115. if (!image_.covers({target, WidthOf(bitness_)}))
  116. continue;
  117. offset_t location = cursor_;
  118. cursor_ += cur_entry_size;
  119. return Reference{location, target};
  120. }
  121. return absl::nullopt;
  122. }
  123. /******** RelocWriterElf ********/
  124. RelocWriterElf::RelocWriterElf(MutableBufferView image,
  125. Bitness bitness,
  126. const AddressTranslator& translator)
  127. : image_(image), bitness_(bitness), target_offset_to_rva_(translator) {
  128. DCHECK(bitness_ == kBit32 || bitness_ == kBit64);
  129. }
  130. RelocWriterElf::~RelocWriterElf() = default;
  131. void RelocWriterElf::PutNext(Reference ref) {
  132. switch (bitness_) {
  133. case kBit32:
  134. image_.modify<elf::Elf32_Rel>(ref.location).r_offset =
  135. target_offset_to_rva_.Convert(ref.target);
  136. break;
  137. case kBit64:
  138. image_.modify<elf::Elf64_Rel>(ref.location).r_offset =
  139. target_offset_to_rva_.Convert(ref.target);
  140. break;
  141. }
  142. // Leave |reloc.r_info| alone.
  143. }
  144. } // namespace zucchini