首页
社区
课程
招聘
[原创]Android ART invoke 代码生成
发表于: 2019-3-4 09:50 6623

[原创]Android ART invoke 代码生成

2019-3-4 09:50
6623

在前面 SandHook 系列我们知道 ArtMethod 入口替换并不能覆盖所有的方法,而且这个问题比预想的严重的多的多。
而导致 Hook 不到的原因不仅仅是 inline 优化,在 Android O 之前 Inline 只是小头,真正主要的原因是 Art Optimizing 代码生成的 Sharpening 优化。

ART 中的 Compiler 有两种

Quick 在 4.4 就引入,直到 6.0 一直作为默认 Compiler, 直到 7.0 被移除。

Optimizing 5.0 引入,7.0 - 9.0 作为唯一 Compiler。

下面以 Optimizing Compiler 为例分析 ART 方法调用的生成。

Optimizing 比 Quick 生成速度慢,但是会附带各种优化,包括:

。。。

其中包括 Invoke 代码生成:

invoke-static/invoke-direct 代码生成默认使用 Sharpening 优化

Sharpening 做了两件事情:

结果保存在 MethodLoadKind & CodePtrLocation 两个 enum 中

我们重点关注 CodePtrLocation:
但是 CodePtrLocation 在 8.0 有重大变化:

可以看到只有 kCallArtMethod 才使用:

生成了从 ArtMethod 加载 CodeEntry 的代码:

其他情况都是直接 B CodeEntry

8.0 之后情况有所改观,说实话,从我的角度来说并没有感觉这项优化能带来多大的性能提升,所以 8.0 之后索性除了递归都先从 ArtMethod 里面找入口。

invoke-virtual/interface 默认走另外一套

步骤如下:

主要服务于需要在 Runtime 时期才能确定的 Invoke,例如类初始化 <cinit> 函数。(kQuickInitializeType)

InvokeRuntime 会从当前 Thread 中查找 CodeEntry:

tr 就是线程寄存器,一般 ARM64 是 X19

所以代码出来一般长这样:

ART 额外维护了一批系统函数的高效实现,这些高效实现利用了CPU的指令,直接跳过了方法调用。

以 Thread.currentThread() 方法为例,此次调用在 intrinsics 的优化下变成了这段代码:

最后出来的代码类似这样,直接就把 Thread.nativePeer ldr 给目标寄存器,根本不是方法调用了:

当 8.0 以上时,我们使用 ArtMethod 入口替换即可基本满足 Hook 需求。但如果 8.0 以下,如果不开启 debug 或者 deoptimize 的话,则必须使用 inline hook,否则会漏掉很多调用。

 
 
 
 
 
 
 // Determines the location of the code pointer.
  enum class CodePtrLocation {
    // Recursive call, use local PC-relative call instruction.
    kCallSelf,

    // Use PC-relative call instruction patched at link time.
    // Used for calls within an oat file, boot->boot or app->app.
    kCallPCRelative,

    // Call to a known target address, embed the direct address in code.
    // Used for app->boot call with non-relocatable image and for JIT-compiled calls.
    kCallDirect,

    // Call to a target address that will be known at link time, embed the direct
    // address in code. If the image is relocatable, emit .patch_oat entry.
    // Used for app->boot calls with relocatable image and boot->boot calls, whether
    // the image relocatable or not.
    kCallDirectWithFixup,

    // Use code pointer from the ArtMethod*.
    // Used when we don't know the target code. This is also the last-resort-kind used when
    // other kinds are unimplemented or impractical (i.e. slow) on a particular architecture.
    kCallArtMethod,
  };
void CodeGeneratorARM64::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {


//处理 ArtMethod 加载位置
...........

//生成跳转代码
switch (invoke->GetCodePtrLocation()) {
    case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
      __ Bl(&frame_entry_label_);
      break;
    case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
      relative_call_patches_.emplace_back(invoke->GetTargetMethod());
      vixl::Label* label = &relative_call_patches_.back().label;
      vixl::SingleEmissionCheckScope guard(GetVIXLAssembler());
      __ Bind(label);
      __ bl(0);  // Branch and link to itself. This will be overriden at link time.
      break;
    }
    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
    case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
      // LR prepared above for better instruction scheduling.
      DCHECK(direct_code_loaded);
      // lr()
      __ Blr(lr);
      break;
    case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
      // LR = callee_method->entry_point_from_quick_compiled_code_;
      __ Ldr(lr, MemOperand(
          XRegisterFrom(callee_method),
       ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize).Int32Value()));
      // lr()
      __ Blr(lr);
      break;
  }
}
__ Ldr(lr, MemOperand(XRegisterFrom(callee_method),ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64WordSize).Int32Value()));
ldr lr [RegMethod, #CodeEntryOffset]

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 3
支持
分享
打赏 + 2.00雪花
打赏次数 1 雪花 + 2.00
 
赞赏  junkboy   +2.00 2019/03/04 感谢分享~
最新回复 (3)
雪    币: 351
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
2019-3-4 12:33
0
雪    币: 217
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
666,已收藏
2019-3-4 19:42
0
雪    币: 916
活跃值: (3434)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
4
膜,大佬
2019-3-5 20:13
0
游客
登录 | 注册 方可回帖
返回
//