01. LLVM staking in iOS

I found this article on the Internet that describes how to use LLVM Pass to implement function staking.

However, following his article step by step to sit down, found various errors, or pass can not be loaded by Xcode, but encountered a lot of problems.

And the author did not write many core parts, I do not know because it is too simple, or do not want to let others know ~

After more than two weeks of research, as LLVM little white, finally running ~ not easy ~

Note: the following, preferably you already have an LLVM environment!!

02. C function manual piling

long _ly_fun_b()
{
  struct timeval star;
  gettimeofday(&star, NULL);
  long b = star.tv_sec * 1000000 + star.tv_usec;
  return b;
}

void _ly_fun_e(char *name, long b)
{
  struct timeval end;
  gettimeofday(&end, NULL);
  long e = end.tv_sec * 1000000 + end.tv_usec;
  long t = e - b;
  printf("%s %ld us\n",name, t);
}

int main(a)
{
  long b = _ly_fun_b();
  printf("hello world!");
  _ly_fun_e("main", b);
  return 0;
}
Copy the code

Manual staking is essentially writing pre-written calls to the start and end functions before and after main().

So automatic piling? The above two functions are automatically inserted before and after main() during compilation, instead of being manually modified in main().

So how do you insert other function calls in main() at compile time?

03. Automatic piling process through LLVM Pass

There are some LLVM IR things involved here, I will not list them here, you can learn them by yourself. Anyway, we can do this in the orange Optimizer section.

LLVM also allows developers to read and write IR in the Optimizer phase in a number of ways, such as Pass, ClangPlugin.. As for the comparison between Pass and ClangPlugin, you can look at it yourself. This article uses Pass to achieve it.

04. Achieve the function of Pass pile insertion

04-01. $LLVM_SOURCE/lib/Transforms/MyPlacement/MyPlacementPass.cpp

#include <string>
#include <system_error>
#include <iostream>

#include "llvm/Support/raw_ostream.h"
#include "llvm/Pass.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/LegacyPassManager.h"
#include "llvm/IR/IRBuilder.h"
//#include "llvm/IR/BasicBlock.h"
//#include "llvm/IR/Constants.h"
//#include "llvm/IR/LLVMContext.h"
//#include "llvm/IR/Type.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"

using namespace llvm;

struct MyPlacementPass : public FunctionPass
{
  static char ID;
  MyPlacementPass() : FunctionPass(ID){}
    
  bool runOnFunction(Function &F) override
  {
    printf("------------- runOnFunction --------------\n");
    if (F.getName().startswith("_ly_fun"))
    {
      return false;
    }

    LLVMContext &context = F.getParent()->getContext();
    BasicBlock &bb = F.getEntryBlock();
    
    Instruction *beginInst = dyn_cast<Instruction>(bb.begin());
    FunctionType *type = FunctionType::get(Type::getInt64Ty(context), {}, false);
    Constant *beginFun = F.getParent()->getOrInsertFunction("_ly_fun_b", type);
    Value *beginTime = nullptr;

    if (Function *fun = dyn_cast<Function>(beginFun))
    {
      CallInst *inst = CallInst::Create(fun);
      inst->insertBefore(beginInst);
      beginTime = inst;
    }
    
    for(Function::iterator I = F.begin(), E = F.end(); I ! = E; ++I) { BasicBlock &BB = *I;for(BasicBlock::iterator I = BB.begin(), E = BB.end(); I ! = E; ++I) { ReturnInst *IST = dyn_cast<ReturnInst>(I);if (IST)
        {
          FunctionType *type = FunctionType::get(Type::getVoidTy(context), {Type::getInt8PtrTy(context),Type::getInt64Ty(context)}, false);
          Constant *s = BB.getModule()->getOrInsertFunction("_ly_fun_e", type);
          if(Function *fun = dyn_cast<Function>(s)) { IRBuilder<> builder(&BB); CallInst *inst = CallInst::Create(fun, {builder.CreateGlobalStringPtr(BB.getParent()->getName()), beginTime}); inst->insertBefore(IST); }}}}return false; }};char MyPlacementPass::ID = 0;

// Automatically enable the pass.
// http://adriansampson.net/blog/clangpass.html
static void registerSkeletonPass(const PassManagerBuilder &, legacy::PassManagerBase &PM) 
{
  PM.add(new MyPlacementPass());
}

static RegisterStandardPasses RegisterMyPass(PassManagerBuilder::EP_EarlyAsPossible, registerSkeletonPass);
Copy the code

The above code is basically the same as the previous blog post, but the bottom few lines of code, that blog post did not post, this is also I experienced a week or two to explore ~

Without these words, dylib will never be compiled and executed by Clang.

Note that the code above is LLVM 8.0.1, which corresponds to the LLVM Github repository for the Release_80 branch.

I was using the LLVM Github source repository with release_90 branch code. The above code kept compiling errors and found that many APIS had changed, so I searched many documents to find a new API to use.

This is a bug with Pass because it relies on the libclang library, whose API is unstable and often changes.

04-02. $LLVM_SOURCE/lib/Transforms/MyPlacement/CMakeLists.txt

add_llvm_library( MyPlacementPass MODULE
  MyPlacementPass.cpp
)
Copy the code

04-03. Build and generate Pass dylib

╭ -- Xiongzenghui at Xiongzenghui MacBook Proin~ / LLVM - 8.0.1. SRC/build/Debug/lib using ‹ ruby - against 2.4.1 holds the ╰ ─ "ll | grep -i'MyPlacementPass'
-rwxr-xr-x  1 xiongzenghui  staff   149K 10 10 22:52 MyPlacementPass.dylib
Copy the code

The dynamic library myPlacementPass. dylib is the LLVM Pass to use.

05. Create a Mac App project using Pass

05-01. Add CC and CXX user-defined Settings in Build Settings to point to the self-compiled CLang

05-02. Build Settings Change OTHER_CFLAGS load pass dylib

05-03. Error: Unknown argument index…

Search for index in the Build Settings TAB and change Enable index-wihle-building Functionality to NO by Default

05-04. Run the MAC App

🎉 🎉 🎉 Successful Automatic piling

Note that the above method will add the function calls before and after the final translation of the (objC method) C function.

The code for the Mac App project above: gitee.com/garywade/LL…

Reference materials

  • Blog.csdn.net/qq_23599965…
  • www.leadroyal.cn/?p=647
  • www.jianshu.com/p/4d392b16d…