Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 查找数据段的地址范围_C_Memory Management_Garbage Collection_Global Variables_Memory Layout - Fatal编程技术网

C 查找数据段的地址范围

C 查找数据段的地址范围,c,memory-management,garbage-collection,global-variables,memory-layout,C,Memory Management,Garbage Collection,Global Variables,Memory Layout,作为一个编程练习,我正在用C编写一个标记和扫描垃圾收集器。我希望扫描数据段(globals等)以寻找指向已分配内存的指针,但我不知道如何获取该段地址的范围。我如何才能做到这一点?为Win32加载可执行文件来源的文件并解析PE头。我不知道在其他操作系统上。请记住,如果您的程序由多个文件(例如DLL)组成,则可能有多个数据段。由于您可能必须使垃圾收集器成为程序运行的环境,因此可以直接从elf文件中获取它。linux(和其他Unix)的文本(程序代码)和数据的界限: #包括 #包括 /*这些文件不在头

作为一个编程练习,我正在用C编写一个标记和扫描垃圾收集器。我希望扫描数据段(globals等)以寻找指向已分配内存的指针,但我不知道如何获取该段地址的范围。我如何才能做到这一点?

为Win32加载可执行文件来源的文件并解析PE头。我不知道在其他操作系统上。请记住,如果您的程序由多个文件(例如DLL)组成,则可能有多个数据段。

由于您可能必须使垃圾收集器成为程序运行的环境,因此可以直接从elf文件中获取它。

linux(和其他Unix)的文本(程序代码)和数据的界限:

#包括
#包括
/*这些文件不在头文件中,并且在一些
他们有预先准备好的系统
必须键入这些符号才能使编译器满意
有关信息,请查看brk()和sbrk()
关于堆*/
extern CHARE etext,edata,end;
int
主(内部argc,字符**argv)
{
printf(“超出以下地址的第一个地址:\n”);
printf(“程序文本段(etext)%10p\n”,&etext);
printf(“初始化数据段(edata)%10p\n”,&edata);
printf(“未初始化数据段(结束)%10p\n”,&end);
返回退出成功;
}

这些符号的来源:

如果您使用的是Windows,那么Windows API将对您有所帮助

//store the base address the loaded Module
dllImageBase = (char*)hModule; //suppose hModule is the handle to the loaded Module (.exe or .dll)

//get the address of NT Header
IMAGE_NT_HEADERS *pNtHdr = ImageNtHeader(hModule);

//after Nt headers comes the table of section, so get the addess of section table
IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *) (pNtHdr + 1);

ImageSectionInfo *pSectionInfo = NULL;

//iterate through the list of all sections, and check the section name in the if conditon. etc
for ( int i = 0 ; i < pNtHdr->FileHeader.NumberOfSections ; i++ )
{
     char *name = (char*) pSectionHdr->Name;
     if ( memcmp(name, ".data", 5) == 0 )
     {
          pSectionInfo = new ImageSectionInfo(".data");
          pSectionInfo->SectionAddress = dllImageBase + pSectionHdr->VirtualAddress;

          **//range of the data segment - something you're looking for**
          pSectionInfo->SectionSize = pSectionHdr->Misc.VirtualSize;
          break;
      }
      pSectionHdr++;
}
下面是一个完整的、最小的WIN32控制台程序,您可以在Visual Studio中运行,该程序演示了Windows API的使用:

#include <stdio.h>
#include <Windows.h>
#include <DbgHelp.h>
#pragma comment( lib, "dbghelp.lib" )

void print_PE_section_info(HANDLE hModule) // hModule is the handle to a loaded Module (.exe or .dll)
{
   // get the location of the module's IMAGE_NT_HEADERS structure
   IMAGE_NT_HEADERS *pNtHdr = ImageNtHeader(hModule);

   // section table immediately follows the IMAGE_NT_HEADERS
   IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *)(pNtHdr + 1);

   const char* imageBase = (const char*)hModule;
   char scnName[sizeof(pSectionHdr->Name) + 1];
   scnName[sizeof(scnName) - 1] = '\0'; // enforce nul-termination for scn names that are the whole length of pSectionHdr->Name[]

   for (int scn = 0; scn < pNtHdr->FileHeader.NumberOfSections; ++scn)
   {
      // Note: pSectionHdr->Name[] is 8 bytes long. If the scn name is 8 bytes long, ->Name[] will
      // not be nul-terminated. For this reason, copy it to a local buffer that's nul-terminated
      // to be sure we only print the real scn name, and no extra garbage beyond it.
      strncpy(scnName, (const char*)pSectionHdr->Name, sizeof(pSectionHdr->Name));

      printf("  Section %3d: %p...%p %-10s (%u bytes)\n",
         scn,
         imageBase + pSectionHdr->VirtualAddress,
         imageBase + pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize - 1,
         scnName,
         pSectionHdr->Misc.VirtualSize);
      ++pSectionHdr;
   }
}

// For demo purpopses, create an extra constant data section whose name is exactly 8 bytes long (the max)
#pragma const_seg(".t_const") // begin allocating const data in a new section whose name is 8 bytes long (the max)
const char const_string1[] = "This string is allocated in a special const data segment named \".t_const\".";
#pragma const_seg() // resume allocating const data in the normal .rdata section

int main(int argc, const char* argv[])
{
   print_PE_section_info(GetModuleHandle(NULL)); // print section info for "this process's .exe file" (NULL)
}
#包括
#包括
#包括
#pragma注释(lib,“dbghelp.lib”)
void print\u PE\u section\u info(句柄hModule)//hModule是加载模块(.exe或.dll)的句柄
{
//获取模块的图像\u NT\u头结构的位置
图像头*pNtHdr=ImageNtHeader(hModule);
//节表紧跟在图像标题之后
图像部分标题*pSectionHdr=(图像部分标题*)(pNtHdr+1);
常量字符*imageBase=(常量字符*)hModule;
char scnName[sizeof(pSectionHdr->Name)+1];
scnName[sizeof(scnName)-1]='\0';//对整个pSectionHdr->Name[]长度的scn名称强制nul终止
对于(int-scn=0;scnFileHeader.NumberOfSections;++scn)
{
//注意:pSectionHdr->Name[]的长度为8字节。如果scn名称的长度为8字节,-->Name[]将
//不能以nul终止。因此,请将其复制到以nul终止的本地缓冲区
//为了确保我们只打印真实的scn名称,除此之外没有额外的垃圾。
strncpy(scnName,(const char*)pSectionHdr->Name,sizeof(pSectionHdr->Name));
printf(“第%3d节:%p..%p%-10s(%u字节)\n”,
scn,
imageBase+pSectionHdr->VirtualAddress,
imageBase+pSectionHdr->VirtualAddress+pSectionHdr->Misc.VirtualSize-1,
斯克纳姆,
pSectionHdr->Misc.VirtualSize);
++pshdr;
}
}
//对于演示目的,创建一个额外的常量数据段,其名称正好为8字节长(最大值)
#pragma const_seg(“.t_const”)//开始在名称为8字节长(最大值)的新节中分配const数据
const char const_string1[]=“此字符串分配在名为\“.t_const\”的特殊常量数据段中”;
#pragma const_seg()//继续在normal.rdata节中分配const数据
int main(int argc,const char*argv[]
{
print_PE_section_info(GetModuleHandle(NULL));//打印“此进程的.exe文件”的节信息(NULL)
}
如果您对DbgHelp库的其他用途感兴趣,可能会有所帮助

您可以在这里阅读PE图像格式,以了解详细信息。一旦您理解了PE格式,就可以使用上述代码,甚至可以修改它以满足您的需要

  • PE格式

  • Windows API和结构

我认为这将在很大程度上帮助你,其余的你可以自己研究:-)

顺便说一下,您也可以看到此线程,因为所有这些线程都与此相关:


对于您可以使用的iOS。它显示了如何查找文本段范围,但您可以轻松地更改它以查找您喜欢的任何段。

我同意,但有没有办法在程序中实现这一点,比如通过系统调用?如果您不告诉我们系统是什么,我们如何回答?我正在运行最新版本的Ubuntu Linux。但我认为系统调用是一种接口(也就是说,它们的实现可能不同,但它们仍然存在)?不,基本上。运行什么操作系统是最重要的问题。Windows vs POSIX是最重要的问题,据我所知,所有Linux变体都是POSIX。一旦你说“我在Windows上”或“我在POSIX上”,那么是的,你说的是一个已知的接口,但是如果你不知道系统,你就不知道接口。brk()和sbrk()是无处不在的,但不是POSIX设计的。这是因为参数是由实现定义的。查看您的手册页以了解详细信息。因此,由于这三个部分代表了三个部分中每个部分的末尾,要搜索整个数据段,我们将从&etext搜索到&edata,对吗?如何扩展到共享对象?如果我加载一个so,它也有一个数据和bss段。在那种情况下,这些符号不起作用。还是他们?你能启发我吗?太好了!!!!!!!!!!!!!,应该被标记为答案,而不是被接受的垃圾答案。@SSpoke:很高兴它帮助了你,即使十年之后!:O
struct ImageSectionInfo
{
      char SectionName[IMAGE_SIZEOF_SHORT_NAME];//the macro is defined WinNT.h
      char *SectionAddress;
      int SectionSize;
      ImageSectionInfo(const char* name)
      {
            strcpy(SectioName, name); 
       }
};
#include <stdio.h>
#include <Windows.h>
#include <DbgHelp.h>
#pragma comment( lib, "dbghelp.lib" )

void print_PE_section_info(HANDLE hModule) // hModule is the handle to a loaded Module (.exe or .dll)
{
   // get the location of the module's IMAGE_NT_HEADERS structure
   IMAGE_NT_HEADERS *pNtHdr = ImageNtHeader(hModule);

   // section table immediately follows the IMAGE_NT_HEADERS
   IMAGE_SECTION_HEADER *pSectionHdr = (IMAGE_SECTION_HEADER *)(pNtHdr + 1);

   const char* imageBase = (const char*)hModule;
   char scnName[sizeof(pSectionHdr->Name) + 1];
   scnName[sizeof(scnName) - 1] = '\0'; // enforce nul-termination for scn names that are the whole length of pSectionHdr->Name[]

   for (int scn = 0; scn < pNtHdr->FileHeader.NumberOfSections; ++scn)
   {
      // Note: pSectionHdr->Name[] is 8 bytes long. If the scn name is 8 bytes long, ->Name[] will
      // not be nul-terminated. For this reason, copy it to a local buffer that's nul-terminated
      // to be sure we only print the real scn name, and no extra garbage beyond it.
      strncpy(scnName, (const char*)pSectionHdr->Name, sizeof(pSectionHdr->Name));

      printf("  Section %3d: %p...%p %-10s (%u bytes)\n",
         scn,
         imageBase + pSectionHdr->VirtualAddress,
         imageBase + pSectionHdr->VirtualAddress + pSectionHdr->Misc.VirtualSize - 1,
         scnName,
         pSectionHdr->Misc.VirtualSize);
      ++pSectionHdr;
   }
}

// For demo purpopses, create an extra constant data section whose name is exactly 8 bytes long (the max)
#pragma const_seg(".t_const") // begin allocating const data in a new section whose name is 8 bytes long (the max)
const char const_string1[] = "This string is allocated in a special const data segment named \".t_const\".";
#pragma const_seg() // resume allocating const data in the normal .rdata section

int main(int argc, const char* argv[])
{
   print_PE_section_info(GetModuleHandle(NULL)); // print section info for "this process's .exe file" (NULL)
}