利用intel pin 工具统计C语言.data和.bss段内存写次数

Pin 工具

下面是一个很简单的pin工具,主要对指令插桩打印出内存写地址。对image插桩打印出Image的高地址和低地址。这个主要是动态编译的时候加载器会重定位数据段的地址。
pin在linux上的使用很简单,这里不再赘述。

#include <fstream>
#include <iomanip>
#include <iostream>
#include <string.h>
#include "pin.H"
FILE * trace;
// Print a memory write record
VOID RecordMemWrite(VOID * ip, VOID * addr)
{
    fprintf(trace,"%p: W %p\n", ip, addr);
}
// Is called for every instruction and instruments reads and writes
VOID Instruction(INS ins, VOID *v)
{
    // Instruments memory accesses using a predicated call, i.e.
    // the instrumentation is called iff the instruction will actually be executed.
    //
    // On the IA-32 and Intel(R) 64 architectures conditional moves and REP 
    // prefixed instructions appear as predicated instructions in Pin.
    UINT32 memOperands = INS_MemoryOperandCount(ins);
    // Iterate over each memory operand of the instruction.
    for (UINT32 memOp = 0; memOp < memOperands; memOp++)
    {
       
        if (INS_MemoryOperandIsWritten(ins, memOp))
        {
            INS_InsertPredicatedCall(
                ins, IPOINT_BEFORE, (AFUNPTR)RecordMemWrite,
                IARG_INST_PTR,
                IARG_MEMORYOP_EA, memOp,
                IARG_END);
        }
    }
}
ofstream outFile;
// Holds instruction count for a single procedure
typedef struct ImAddress
{
    string _name;
    ADDRINT _addlow;
    ADDRINT _addhigh;
    ADDRINT _addstart;
    struct ImAddress * _next;
} IMG_ADDRESS;
IMG_ADDRESS *ImageList = 0;
// Pin calls this function every time a new Image is executed
VOID Image(IMG img, VOID *v)
{
    IMG_ADDRESS  * rc = new IMG_ADDRESS;
    rc->_name = IMG_Name(img);
    
    rc->_addlow = IMG_LowAddress(img);
    rc->_addhigh = IMG_HighAddress(img);
    rc->_addstart = IMG_StartAddress(img);
    
    
    rc->_next = ImageList;
    ImageList = rc;
            
    // IMG_Open(Image);
    
    
    // IMG_Close(Image);
}
// This function is called when the application exits
// It prints the name and count for each procedure
VOID Fini(INT32 code, VOID *v)
{
    outFile << setw(40) << "Image" << " "
          << setw(20) << "low" << " "
          << setw(20) << "high" << " "
          << setw(20) << "start" << endl;
    for (IMG_ADDRESS * rc = ImageList; rc; rc = rc->_next)
    {
            outFile << setw(40) << rc->_name << " "
                 << setw(20) << hex << rc->_addlow << dec <<" "
                 << setw(20) << hex << rc->_addhigh << dec <<" "
                 << setw(20) << hex << rc->_addstart << dec <<" "<< endl;
    }
    fprintf(trace, "#eof\n");
    fclose(trace);
}
/* ===================================================================== */
/* Print Help Message                                                    */
/* ===================================================================== */
INT32 Usage()
{
    cerr << "This Pintool record  addresses of the images are executed" << endl;
    cerr << "and the low, high and start address of the image executed in a program" << endl;
    cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
    return -1;
}
/* ===================================================================== */
/* Main                                                                  */
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
    "o", "./output/low_high.out", "specify output file name");
int main(int argc, char * argv[])
{
    // Initialize symbol table code, needed for Image instrumentation
    PIN_InitSymbols();
    outFile.open(KnobOutputFile.Value().c_str());
    trace = fopen("./output/mytrace.out", "w");
    // Initialize pin
    if (PIN_Init(argc, argv)) return Usage();
    
    IMG_AddInstrumentFunction(Image,0);
    // Register Fini to be called when the application exits
    INS_AddInstrumentFunction(Instruction, 0);
    
    PIN_AddFiniFunction(Fini, 0);
    // Start the program, never returns
    PIN_StartProgram();
    return 0;
}

使用pin tool

pin -t ~/pin/pin-3.7/source/tools/ManualExamples/obj-intel64/mypintool.so – ./dijkstra_small input.dat >./output/output_small1.out

读取符号表

readelf -s dijkstra_small >output/systab

静态编译

对dijkstra程序静态编译并且使用pin工具和查看elf文件 的结果如下面的截图

程序的高低地址

程序的高低地址和开始地址

符号表

g_qCount是dikstra里的一个全局变量,这里value值为6d7330
在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/20191213170213865.png符号表

源程序

为了方便验证结果,在源码中打印出g_qCount的地址

在主函数中打印出g_qcount地址

g_qCount地址为0x6d7300和elf文件一致
上一步打印出的g_qcount地址

pinatrace 打印出的内存trace

pinatrace

动态编译

动态编译和静态编译区别是符号表的值加上image低地址的值才是最后变量在内存中的地址

dijkstra 低地址为0x560a3f2d5000

在这里插入图片描述

符号表

符号表中iPrev的值为202068 ,image开始地址+符号表的值=0x560a3f2d5000+202068=0x560A3F4D7068在这里插入图片描述

iPrev实际地址

与上一步对应的计算结果对应
在这里插入图片描述

写trace

pinatrace在这里插入图片描述

计算写次数

对于动态编译来说.data和.bss段落在image的低地址和稿地址之间,得到trace后统计这一区间地址写次数即可。
对于静态编译来说elf文件符号表的全局符号的值就是全局变量对应的地址。如果觉得一个一个找比较麻烦,我发现静态编译数据段的地址比堆区和栈区小的多。识别出这些小地址即可。

©️2020 CSDN 皮肤主题: 1024 设计师: 上身试试 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值