aboutsummaryrefslogtreecommitdiff
path: root/disassembler_win32.cc
diff options
context:
space:
mode:
authorSamuel Huang <huangs@chromium.org>2018-10-10 15:48:10 +0000
committerCopybara-Service <copybara-worker@google.com>2021-07-25 20:38:54 -0700
commit98dd0173969ff0905b49bf6236d51f69c5c05f65 (patch)
treed82ee350388331a379d0324f5e60439a0e9d2208 /disassembler_win32.cc
parente53806a25b988acd67fe57b42eaa611f2ba96a75 (diff)
downloadzucchini-98dd0173969ff0905b49bf6236d51f69c5c05f65.tar.gz
[Zucchini] Fix patch apply failure from untranslatable abs32 references.
Disassembler (Win32 and ELF) uses reloc to find abs32 locations, which are stored in (1) |abs32_locations_|. Later on, (1) is filtered to generate (2) actual abs32 locations. A patching failure case was discovered: Equivalence blocks must never cut across reference boundaries. However, it turns out blocks generated using (2) were subject to checks using (1), which triggers a failure since (1) - (2) is nonempty. One way for (1) != (2) to happen is from CURRENT_MODULE() usage, which creates an abs32 reference outside a section. This results in an abs32 target whose RVA does not map to an offset using section data, and gets rejected by filtering logic for (2). Fix: Apply the filtering logic direcly to (1), so (1) == (2). Details: * Add RemoveUntranslatableAbs32() (abs32_utils.h), which uses the filtering logic for (2) to preemptively remove problematic RVAs from (1), so |abs32_locations_| matches (2). Extensive unit tests are added. * DisassemblerWin32<Traits>::ParseAndStoreAbs32(): Initialize |abs32_locations_| with 3 steps: Naive extraction from relocs, RemoveUntranslatableAbs32(), and RemoveOverlappingAbs32Locations(). * DisassemblerElf<Traits>::GetAbs32FromRelocSections(): Do the same, noting that ELF's image base is always 0. Additional fixes: * address_translator.h: kInvalidRva was -1, but it should be -2 to better match kInvalidOffset. * Abs32RvaExtractorWin32::Abs32RvaExtractorWin32: The lambda |find_and_check| binds |addr|, which has been std::move()'ed. Better to just bind |this| and use |addr_|. Bug: 892284 Change-Id: I628f4668ea231c7e06f35bd924652ca4d74bb848 Reviewed-on: https://chromium-review.googlesource.com/c/1263877 Reviewed-by: Greg Thompson <grt@chromium.org> Reviewed-by: Samuel Huang <huangs@chromium.org> Commit-Queue: Samuel Huang <huangs@chromium.org> Cr-Commit-Position: refs/heads/master@{#598342} NOKEYCHECK=True GitOrigin-RevId: b6d108f1cabab2a9f3fe46a7cdeb92685a2c790e
Diffstat (limited to 'disassembler_win32.cc')
-rw-r--r--disassembler_win32.cc20
1 files changed, 14 insertions, 6 deletions
diff --git a/disassembler_win32.cc b/disassembler_win32.cc
index b3f568b..9067ad7 100644
--- a/disassembler_win32.cc
+++ b/disassembler_win32.cc
@@ -316,20 +316,28 @@ bool DisassemblerWin32<Traits>::ParseAndStoreAbs32() {
return true;
has_parsed_abs32_ = true;
- ParseAndStoreRelocBlocks();
-
+ // Read reloc targets as preliminary abs32 locations.
std::unique_ptr<ReferenceReader> relocs = MakeReadRelocs(0, offset_t(size()));
for (auto ref = relocs->GetNext(); ref.has_value(); ref = relocs->GetNext())
abs32_locations_.push_back(ref->target);
- abs32_locations_.shrink_to_fit();
std::sort(abs32_locations_.begin(), abs32_locations_.end());
+ // Abs32 references must have targets translatable to offsets. Remove those
+ // that are unable to do so.
+ size_t num_untranslatable = RemoveUntranslatableAbs32(
+ image_, {Traits::kBitness, image_base_}, translator_, &abs32_locations_);
+ LOG_IF(WARNING, num_untranslatable) << "Removed " << num_untranslatable
+ << " untranslatable abs32 references.";
+
// Abs32 reference bodies must not overlap. If found, simply remove them.
- size_t num_removed =
+ size_t num_overlapping =
RemoveOverlappingAbs32Locations(Traits::kVAWidth, &abs32_locations_);
- LOG_IF(WARNING, num_removed) << "Found and removed " << num_removed
- << " abs32 locations with overlapping bodies.";
+ LOG_IF(WARNING, num_overlapping)
+ << "Removed " << num_overlapping
+ << " abs32 references with overlapping bodies.";
+
+ abs32_locations_.shrink_to_fit();
return true;
}