Quick: PC-relative loads from dex cache arrays on x86.
Rewrite all PC-relative addressing on x86 and implement
PC-relative loads from dex cache arrays. Don't adjust the
base to point to the start of the method, let it point to
the anchor, i.e. the target of the "call +0" insn.
Change-Id: Ic22544a8bc0c5e49eb00a75154dc8f3ead816989
diff --git a/compiler/linker/x86/relative_patcher_x86.cc b/compiler/linker/x86/relative_patcher_x86.cc
index 246cf11..315585d 100644
--- a/compiler/linker/x86/relative_patcher_x86.cc
+++ b/compiler/linker/x86/relative_patcher_x86.cc
@@ -16,14 +16,43 @@
#include "linker/x86/relative_patcher_x86.h"
+#include "compiled_method.h"
+
namespace art {
namespace linker {
-void X86RelativePatcher::PatchDexCacheReference(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
- const LinkerPatch& patch ATTRIBUTE_UNUSED,
- uint32_t patch_offset ATTRIBUTE_UNUSED,
- uint32_t target_offset ATTRIBUTE_UNUSED) {
- LOG(FATAL) << "Unexpected relative dex cache array patch.";
+void X86RelativePatcher::PatchDexCacheReference(std::vector<uint8_t>* code,
+ const LinkerPatch& patch,
+ uint32_t patch_offset,
+ uint32_t target_offset) {
+ uint32_t anchor_literal_offset = patch.PcInsnOffset();
+ uint32_t literal_offset = patch.LiteralOffset();
+
+ // Check that the anchor points to pop in a "call +0; pop <reg>" sequence.
+ DCHECK_GE(anchor_literal_offset, 5u);
+ DCHECK_LT(anchor_literal_offset, code->size());
+ DCHECK_EQ((*code)[anchor_literal_offset - 5u], 0xe8u);
+ DCHECK_EQ((*code)[anchor_literal_offset - 4u], 0x00u);
+ DCHECK_EQ((*code)[anchor_literal_offset - 3u], 0x00u);
+ DCHECK_EQ((*code)[anchor_literal_offset - 2u], 0x00u);
+ DCHECK_EQ((*code)[anchor_literal_offset - 1u], 0x00u);
+ DCHECK_EQ((*code)[anchor_literal_offset] & 0xf8u, 0x58u);
+
+ // Check that the patched data contains kDummy32BitOffset.
+ constexpr int kDummy32BitOffset = 256; // Must match X86Mir2Lir::kDummy32BitOffset.
+ DCHECK_LE(literal_offset, code->size());
+ DCHECK_EQ((*code)[literal_offset + 0u], static_cast<uint8_t>(kDummy32BitOffset >> 0));
+ DCHECK_EQ((*code)[literal_offset + 1u], static_cast<uint8_t>(kDummy32BitOffset >> 8));
+ DCHECK_EQ((*code)[literal_offset + 2u], static_cast<uint8_t>(kDummy32BitOffset >> 16));
+ DCHECK_EQ((*code)[literal_offset + 3u], static_cast<uint8_t>(kDummy32BitOffset >> 24));
+
+ // Apply patch.
+ uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset;
+ uint32_t diff = target_offset - anchor_offset;
+ (*code)[literal_offset + 0u] = static_cast<uint8_t>(diff >> 0);
+ (*code)[literal_offset + 1u] = static_cast<uint8_t>(diff >> 8);
+ (*code)[literal_offset + 2u] = static_cast<uint8_t>(diff >> 16);
+ (*code)[literal_offset + 3u] = static_cast<uint8_t>(diff >> 24);
}
} // namespace linker