dsa算法(14)

来源:互联网 发布:淘宝怎么免费拿货上车 编辑:程序博客网 时间:2024/05/21 08:19
1.3.3.4.2. 传播未知标记

至此,我们成功创建了一个函数图。接着在LocalDataStructures::runOnModule的1485行,把函数图的FucntionCalls拷贝入AuxFucntionCalls,这样可以开始处理这些函数调用了。DataStructures的成员DSInfo用于绑定Function与相应的DSGraph,在1486行完成这个绑定。接着把未知标记传播到从具有未知标记的节点可到达的节点。

 

221      static void propagateUnknownFlag(DSGraph * G) {

222        std::vector<DSNode *> workList;

223        DenseSet<DSNode *> visited;

224        for(DSGraph::node_iterator I = G->node_begin(), E = G->node_end(); I != E;++I)

225          if (I->isUnknownNode())

226            workList.push_back(&*I);

227     

228        while(!workList.empty()) {

229          DSNode * N = workList.back();

230          workList.pop_back();

231          if (visited.count(N) != 0)continue;

232          visited.insert(N);

233          N->setUnknownMarker();

234          for(DSNode::edge_iterator I = N->edge_begin(), E = N->edge_end(); I != E;++I)

235            if (!I->second.isNull())

236             workList.push_back(I->second.getNode());

237        }

238      }

 

具体来说,未知标记出现在这样的情形中:DSNode的某个偏移处同时代表整数类型及指针类型、ConstantExpr到不是PointerType的转换、既不是转换也不是GetElementPtr操作的ConstantExpr、整数到指针的转换、非x86平台上的变长参数、intrinsicllvm.stacksave、intrinsic llvm.stackstore、intrinsic llvm.returnaddress、intrinsic llvm.frameaddress、其他DSA不处理的指令(visitInstruction)。

1.3.3.4.3. 构建调用图

在LocalDataStructures::runOnModule的1488行,callgraph是DataStructure的成员,其insureEntry方法确保在SimpleCallees(Function到Function集合的std::map)中已经创建了对应的Function集合(显然集合是空的)。

接着,通过下面的函数在callgraph中构建调用图。注意,这只是调用图构建的第一步,这个调用图会传递给后续的DSA遍进行后续处理。

 

1566  void DSGraph::buildCallGraph(DSCallGraph& DCG,std::vector<const Function*>&

                                                           GlobalFunctionList, bool filter)const {

1567    //

1568    // Get the list ofunresolved call sites.

1569    //

1570    constFunctionListTy& Calls = getFunctionCalls();

1571    for(FunctionListTy::const_iterator ii = Calls.begin(),

1572        ee = Calls.end();

1573        ii != ee; ++ii) {

1574      //

1575      // Direct callsare easy.  We know to where they go.

1576      //

1577 

1578      if (ii->isDirectCall()) {

1579        DCG. insert(ii->getCallSite(),ii->getCalleeFunc());

 

在当前函数中调用的函数指令都记录在FunctionCalls中,1571行的循环遍历这个集合。如果是直接函数调用,调用下面的函数处理。在llvm IR中instruction基类的Parent总是BasicBlock(包含它的基本块),而BasicBlock的Parent总是Function(包含它的方法),因此235行获得了包含这个函数调用的Function对象(的地址)。

 

230    void

231    DSCallGraph::insert(llvm::CallSiteCS,const llvm::Function* F) {

232      //

233      // Find thefunction to which the call site belongs.

234      //

235      constllvm::Function * Parent = CS.getInstruction()->getParent()->getParent();

236   

237      //

238      // Determine theSCC leaders for both the calling function and the called

239      // function.  If they don't belong to an SCC, add them asleaders.

240      //

241      SCCs.insert (Parent);

242      SCCs.insert (F);

243      constllvm::Function * ParentLeader = SCCs.getLeaderValue (Parent);

244      constllvm::Function * FLeader      =SCCs.getLeaderValue (F);

245   

246      //

247      // Create an emptyset for the callee; hence, all called functions get to be

248      // in the callgraph also.  This simplifies SCCformation.

249      //

250      SimpleCallees[ParentLeader];

251      if (F) {

252        ActualCallees[CS].insert(FLeader);

253       SimpleCallees[ParentLeader].insert(FLeader);

254      }

255    }

 

241行的SCCs的类型是llvm::EquivalenceClasses<constllvm::Function*>,这是一个同类集的集合,借这个同类集构成一个强连同分量(stronglyconnected component),故以此命名。252行的ActualCallees是CallSite到Function集合的std::map。成员SimpleCallees记录了调用者与被调用者一对多的关系,而ActualCallees则记录了调用点与被调用者一对多的关系(比如函数指针)。

 

DSGraph::buildCallGraph(续)

 

1580      } else {

1581        CallSite CS = ii->getCallSite();

1582        std::vector<constFunction*> MaybeTargets;

1583 

1584       if(ii->getCalleeNode()->isIncompleteNode())

1585          continue;

1586        //

1587        // Get the listof known targets of this function.

1588        //

1589        ii->getCalleeNode()->addFullFunctionList(MaybeTargets);

1590 

1591        //

1592        // Ensure thatthe call graph at least knows about (has a record of) this

1593        //  call site.

1594        //

1595        DCG.insert(CS,0);

1596 

1597        //

1598        // Add to thecall graph only function targets that have well-defined

1599        // behaviorusing LLVM semantics.

1600        //

1601        for(std::vector<const Function*>::iteratorFi = MaybeTargets.begin(),

1602             Fe = MaybeTargets.end(); Fi != Fe;++Fi)

1603          if (!filter || functionIsCallable(CS, *Fi))

1604            DCG.insert(CS, *Fi);

1605          else

1606            ++NumFiltered;

1607        for(DSCallSite::MappedSites_t::iterator I = ii->ms_begin(),

1608             E = ii->ms_end(); I != E; ++I) {

1609          CallSite MCS = *I;

1610          for(std::vector<const Function*>::iteratorFi = MaybeTargets.begin(),

1611               Fe = MaybeTargets.end(); Fi != Fe;++Fi)

1612            if (!filter ||functionIsCallable(MCS, *Fi))

1613              DCG.insert(MCS, *Fi);

1614            else

1615              ++NumFiltered;

1616        }

1617      }

1618    }

1619  }

 

在1589行,addFullFunctionList把父图中所有作为同类集Leader的Function对象记录在MaybeTargets里,因为我们假定所有的函数都可以是间接调用的目标。1601行遍历这个集合,查找可被指定CallSite调用的函数。另外,前面看到,DSCallSite的MappedSites记录了对同一个函数调用的CallSite对象,这是由CallSite简并产生的,在1607行遍历这个集合。

1.3.3.4.4.合并全局对象回全局图

接下来在LocalDataStructures::runOnModule的1490行,清除当前函数图中节点的未完成标记。接着调用markIncompleteNodes,只把参数标记为未完成(在前面,我们还把全局对象标记为未完成)。

而在对cloneIntoGlobals的调用中,第二个参数起作用只有DSGraph::StripAllocaBit。通过ReachabilityCloner,函数图中的全局对象节点合并回全局图中对应的节点里。这一步是必须的,因为当前函数可能操作了全局对象,这必须反映在全局图里。这是把全局图与函数图中全局对象DSNode统一起来的第二步。

 

1463  void DataStructures::cloneIntoGlobals(DSGraph*Graph, unsigned cloneFlags) {

1464    // When this graphis finalized, clone the globals in the graph into the

1465    // globals graph tomake sure it has everything, from all graphs.

1466    DSScalarMap &MainSM =Graph->getScalarMap();

1467    ReachabilityCloner RC(GlobalsGraph, Graph,cloneFlags);

1468 

1469    // Clone everythingreachable from globals in the function graph into the

1470    // globals graph.

1471    for(DSScalarMap::global_iterator I = MainSM.global_begin(),

1472         E = MainSM.global_end(); I != E; ++I)

1473      RC.getClonedNH(MainSM[*I]);

1474  }

 

上述的操作涉及全局对象节点的简并,因此接下来要再次找出新形成的同类集,并使用同类集的Leader替换图中的同类集成员。

1.3.3.4.5.全局图与局部图的标记

因为在节点简并时,NodeType的简并操作是“|”操作符,这意味着打上的标记不可能通过简并去掉。要获得正确的NodeType,必须要小心地处理。尤其是未完成标记,如前所述,这个标记对DSA算法有深刻的影响。首先,在1478行,maskIncompleteMarkers去掉全局图的节点的未完成标记。在1490行,指定的函数图也通过maskIncompleteMarkers去掉了所有节点的未完成标记。接着在1491行,将指针参数、返回值、可变参数以及调用的函数标记为未完成。随后,把其中的全局对象节点克隆、简并回全局图(在这个过程中,还去掉了AllocaNode标记)。而在1501行,把全局图中全局对象以外的节点标记为未完成。在1509行再次计算全局对象的同类集(这个调用似乎并不必要)。接着传播未知标记。

 

LocalDataStructures::runOnModule(续)

 

1500    //GlobalsGraph->removeTriviallyDeadNodes();

1501    GlobalsGraph->markIncompleteNodes(DSGraph::MarkFormalArgs

1502                                     |DSGraph::IgnoreGlobals);

1503    GlobalsGraph->computeExternalFlags(DSGraph::ProcessCallSites);

1504 

1505    // Now that we've computed all of the graphs,and merged all of the info into

1506    // the globalsgraph, see if we have further constrained the globals in the

1507    // program if so,update GlobalECs and remove the extraneous globals from the

1508    // program.

1509    formGlobalECs();

1510 

1511    propagateUnknownFlag(GlobalsGraph);

1512    for(Module::iterator I = M.begin(), E = M.end(); I != E; ++I)

1513      if (!I->isDeclaration()) {

1514        DSGraph *Graph = getOrCreateGraph(I);

1515        Graph->maskIncompleteMarkers();

1516        cloneGlobalsInto(Graph,DSGraph::DontCloneCallNodes |

1517                        DSGraph::DontCloneAuxCallNodes);

1518        Graph->markIncompleteNodes(DSGraph::MarkFormalArgs

1519                                  |DSGraph::IgnoreGlobals);

1520      }

1521 

1522    return false;

1523  }

 

在1512行,又一次遍历当前模块中的函数,对于LocalDataStructures的安排,1514行的getOrCreateGraph不做任何事。同样在1515行,清除全局图中节点的未完成标记,并在1518行设置函数参数节点的未完成标记。

在1516行,通过下面的函数从全局图向函数图导入全局对象的信息。这是把全局图与函数图中全局对象DSNode统一起来的最后一步。

 

1448  void DataStructures::cloneGlobalsInto(DSGraph*Graph, unsigned cloneFlags) {

1449    // If this graphcontains main, copy the contents of the globals graph over.

1450    // Note that thisis *required* for correctness.  If acallee contains a use

1451    // of a global, wehave to make sure to link up nodes due to global-argument

1452    // bindings.

1453    constDSGraph* GG = Graph->getGlobalsGraph();

1454    ReachabilityCloner RC(Graph, GG, cloneFlags);

1455 

1456    // Clone the globalnodes into this graph.

1457    for(DSScalarMap::global_iterator I = Graph->getScalarMap().global_begin(),

1458         E =Graph->getScalarMap().global_end(); I != E; ++I)

1459      RC.getClonedNH(GG->getNodeForValue(*I));

1460  }

 

最后LocalDataStructures::runOnModule返回false,表示当前模块没有发生变化。

0 0
原创粉丝点击