c++ - 使用 intel pin 工具的堆栈分配大小

标签 c++ c x86 profiling intel-pin

我有以下 C 代码:

#include <stdio.h>

int foo()
{
  int a = 4;
  int *p = &a;
  printf("%i\n", *p);
  int b[10];
  b[1] = 3;
}

int main(void)
{
  int a[10], b[20];
  a[2] = 7;
  b[7] = 9;
  foo();
  return 0;
}

我创建了以下 PIN 工具:

#include <fstream>
#include <iostream>
#include "pin.H"

// Additional library calls go here

/*********************/

// Output file object
ofstream OutFile;

//static uint64_t counter = 0;

uint32_t lock = 0;
uint32_t unlock = 1;
std::string rtin = "";
// Make this lock if you want to print from _start
uint32_t key = unlock;

void printmaindisas(uint64_t addr, std::string disassins)
{
    std::stringstream tempstream;
    tempstream << std::hex << addr;
    std::string address = tempstream.str();
    if (key)
        return;
    if (addr > 0x700000000000)
        return;
    std::cout<<address<<"\t"<<disassins<<std::endl;
}

void mutex_lock()
{

key = !lock;
std::cout<<"out\n";

}
void mutex_unlock()
{

    key = lock;
    std::cout<<"in\n";

}

void Instruction(INS ins, VOID *v)
{

    // if (INS_IsStackWrite(ins) == true)
    // {
    //  std::cout << "Stack write instruction: " << INS_Disassemble(ins) << '\n';
    // }
  // Insert a call to docount before every instruction, no arguments are passed
  INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR)printmaindisas, IARG_ADDRINT, INS_Address(ins),
  IARG_PTR, new string(INS_Disassemble(ins)), IARG_END);
    //std::cout<<INS_Disassemble(ins)<<std::endl;
}

void Routine(RTN rtn, VOID *V)
{
    if (RTN_Name(rtn) == "main")
    {
        //std::cout<<"Loading: "<<RTN_Name(rtn) << endl;
        RTN_Open(rtn);
        RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR)mutex_unlock, IARG_END);
        RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR)mutex_lock, IARG_END);
        RTN_Close(rtn);
    }
}

KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool", "o", "mytool.out", "specify output file name");
/*
VOID Fini(INT32 code, VOID *v)
{
    // Write to a file since cout and cerr maybe closed by the application
    OutFile.setf(ios::showbase);
    OutFile << "Count " << count << endl;
    OutFile.close();
}
*/

int32_t Usage()
{
  cerr << "This is my custom tool" << endl;
  cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
  return -1;
}

int main(int argc, char * argv[])
{
  // It must be called for image instrumentation
  // Initialize the symbol table
  PIN_InitSymbols();
  // Initialize pin
    // PIN_Init must be called before PIN_StartProgram
    // as mentioned in the documentation
  if (PIN_Init(argc, argv)) return Usage();

  // Open the output file to write
  OutFile.open(KnobOutputFile.Value().c_str());

  // Set instruction format as intel
    // Not needed because my machine is intel
  PIN_SetSyntaxIntel();

  RTN_AddInstrumentFunction(Routine, 0);
  //IMG_AddInstrumentFunction(Image, 0);

  // Add an isntruction instrumentation
  INS_AddInstrumentFunction(Instruction, 0);

  //PIN_AddFiniFunction(Fini, 0);

  // Start the program here
  PIN_StartProgram();

  return 0;

}

它给了我以下输出:

in
40051e  push rbp
40051f  mov rbp, rsp
400522  add rsp, 0xffffffffffffff80
400526  mov dword ptr [rbp-0x28], 0x7
40052d  mov dword ptr [rbp-0x64], 0x9
400534  mov eax, 0x0
400539  call 0x4004e6
4004e6  push rbp
4004e7  mov rbp, rsp
4004ea  sub rsp, 0x40
4004ee  mov dword ptr [rbp-0xc], 0x4
4004f5  lea rax, ptr [rbp-0xc]
4004f9  mov qword ptr [rbp-0x8], rax
4004fd  mov rax, qword ptr [rbp-0x8]
400501  mov eax, dword ptr [rax]
400503  mov esi, eax
400505  mov edi, 0x4005d0
40050a  mov eax, 0x0
40050f  call 0x4003f0
4003f0  jmp qword ptr [rip+0x200c22]
4003f6  push 0x0
4003fb  jmp 0x4003e0
4003e0  push qword ptr [rip+0x200c22]
4003e6  jmp qword ptr [rip+0x200c24]
4
400514  mov dword ptr [rbp-0x3c], 0x3
40051b  nop
40051c  leave 
40051d  ret 
40053e  mov eax, 0x0
400543  leave 
out

我想在 main 函数的情况下获取值 0xffffffffffffff80,在函数 foo 的情况下获取值 0x40 >。简而言之,我想在创建函数后获得已分配的堆栈位置。因此,可以做到这一点的一种方法是检测特定指令,在这种情况下说 add/sub rsp,然后修剪输出以获得特定字符串。另一种方法是获取 rbp 或 rsp 的值(如果我在这里错了请纠正我)。

我查看 pin api 文档 here还看到了一些例子 here , 但仍然找不到获取特定字符串值的方法。

根据我试过的文档:

if (INS_RegR(ins, 0) == REG_RSP)
        std::cout << "rsp: " << REG_Size(REG_RSP) << '\n';

但是,仍然无法弄清楚如何获取这些值。

最佳答案

source/tools/SimpleExamples/oper-imm.cpp 中的示例 pintool 展示了如何获取立即操作数。它看起来像这样:

if (INS_OperandIsImmediate(ins, i))
{
    // Get the value itself
    ADDRINT value = INS_OperandImmediate(ins, i);

    // Determine the size and the signedness of the immediate value.
}

在您的例子中,i 为 1,因为您需要检查第二个操作数是否为立即值。您还需要检查第一个操作数是否是显式 RSP 寄存器以及指令是 ADD 还是 SUB。本质上,您需要找到第一个这样的指令。

if((INS_Opcode(ins) == XED_ICLASS_ADD || INS_Opcode(ins) == XED_ICLASS_SUB) && 
   REG(INS_OperandReg(ins, 0)) == REG_STACK_PTR && INS_OperandIsImmediate(ins, 1))
{
  // Obtain the immediate operand information as shown above.
  // You can obtain the RSP register value before or after the instruction by
  // passing IARG_REG_VALUE, REG_STACK_PTR to INS_Insert*.
}

某些编程语言或特定实现可能允许在动态大小的堆栈上分配变量。例如,大多数 C/C++ 实现都提供 alloca,它通常从堆栈分配内存。再举一个例子,C# 语言提供了 stackalloc 关键字。因此,第二个操作数不一定总是立即数,可以有多个 ADD/SUB 指令分散从堆栈分配/释放内存的函数的吞吐量。

关于c++ - 使用 intel pin 工具的堆栈分配大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55264577/

相关文章:

c++ - 这个问题是否有重叠的子问题?

c - OS X KEXT 打印指针导致 <ptr>

assembly - 在 x86 程序集中制作鼠标处理程序

c++ - 超出范围错误,而请求的项目应该在绑定(bind)中

c++ - 定义转换构造函数和转换运算符时哪个优先,为什么编译器会对此转换有所不同?

c - 设置 uint32 key 位置并将其写入文件时遇到问题

c++ - 避开 CRT

assembly - 这段汇编代码有什么作用? (测试、异或、JNZ)

compilation - x86 中的基本 block 和控制流

C++ - 重置字符串流是否不会重置获取位置或清除标志?