Поиск диапазона адресов сегмента данных

17

Как упражнение по программированию, я пишу сборщик мусора маркировки и разметки в C. Я хочу отсканировать сегмент данных (глобалы и т. д.) для указателей на выделенную память, но я не знаю, как получить диапазон адресов этого сегмента. Как я могу это сделать?

    
задан Nick 30.11.2010 в 00:03
источник
  • Я бы сказал, что это зависит от ОС. –  ruslik 30.11.2010 в 00:05
  • Я согласен, но есть ли способ получить это внутри программы, например, с помощью системного вызова? –  Nick 30.11.2010 в 00:17
  • Как мы можем ответить на это, если вы не сообщите нам, что такое система? –  Puppy 30.11.2010 в 00:28
  • Я запускаю последнюю версию Ubuntu Linux. Но я думал, что системные вызовы - это своего рода интерфейс (т. Е. Они могут быть реализованы по-другому, но они все еще существуют)? –  Nick 30.11.2010 в 00:36
  • Нет. В принципе. Какую ОС вы запускаете, это самый важный вопрос. Windows vs POSIX - самый важный вопрос, и, насколько я знаю, все варианты Linux - это POSIX. Когда вы скажете «Я на Windows» или «Я на POSIX», то да, вы говорите об известном интерфейсе, но если вы не знаете систему, вы не знаете интерфейс. –  Puppy 30.11.2010 в 00:53

5 ответов

19

Границы для текста (программный код) и данные для linux (и других unixes):

#include <stdio.h>
#include <stdlib.h>

/* these are in no header file, and on some
systems they have a _ prepended 
These symbols have to be typed to keep the compiler happy
Also check out brk() and sbrk() for information
about heap */

extern char  etext, edata, end; 

int
main(int argc, char **argv)
{
    printf("First address beyond:\n");
    printf("    program text segment(etext)      %10p\n", &etext);
    printf("    initialized data segment(edata)  %10p\n", &edata);
    printf("    uninitialized data segment (end) %10p\n", &end);

    return EXIT_SUCCESS;
}

Если эти символы взяты из: Где символы etext, edata и конец определен?

    
ответ дан jim mcnamara 30.11.2010 в 01:56
  • brk () и sbrk () являются вездесущими, но не POSIX, по дизайну. Это связано с тем, что аргументы определяются реализацией. Проверьте свою страницу руководства на предмет специфики. –  jim mcnamara 30.11.2010 в 01:59
  • Итак, поскольку они представляют собой конец каждого из трех сегментов, для поиска по сегменту данных мы будем искать от & etext до & edata, не так ли? –  Nick 30.11.2010 в 02:26
  • Как этот масштаб используется для общего объекта? Если я загружаю так, он также имеет сегмент данных и bss. В этом случае этот символ не будет работать. Или они? Можете ли вы просветить меня? –  deadalnix 16.08.2015 в 09:59
  • Любой способ получить эту информацию по системному коду? –  deFreitas 19.07.2016 в 21:42
25

Если вы работаете в 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++;
}

Определить ImageSectionInfo как,

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); 
       }
};

Вот полная, минимальная консольная консоль 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] = '%pr_e%'; // 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)
}

Эта страница может быть полезна, если вы заинтересованы в дополнительном использовании Библиотека DbgHelp.

Здесь вы можете прочитать формат изображения PE, чтобы узнать его подробно. После того, как вы поймете формат PE, вы сможете работать с указанным выше кодом и можете даже модифицировать его в соответствии с вашими потребностями.

  • Формат PE

Peering Inside PE: обзор портативного исполняемого файла Win32

Глубокий взгляд на формат исполняемого файла Win32 Portable, часть 1

Глубокий взгляд на формат исполняемого файла Win32 Portable, часть 2

  • API и структуры Windows

Структура IMAGE_SECTION_HEADER

Функция ImageNtHeader

Структура IMAGE_NT_HEADERS

Я думаю, это поможет вам в значительной степени, а остальное вы можете исследовать себя: -)

Кстати, вы также можете увидеть этот поток, так как все это как-то связано с этим:

Сценарий: глобальные переменные в DLL, которая используется многопоточным приложением

    
ответ дан Nawaz 30.11.2010 в 18:50
1

Поскольку вам, вероятно, придется сделать ваш сборщик мусора средой, в которой работает программа, вы можете получить ее непосредственно из файла эльфа.

    
ответ дан nmichaels 30.11.2010 в 00:10
0

Загрузите файл, из которого пришел исполняемый файл, и проанализируйте заголовки PE для Win32. Я понятия не имею о других ОС. Помните, что если ваша программа состоит из нескольких файлов (например, DLL), у вас может быть несколько сегментов данных.

    
ответ дан Puppy 30.11.2010 в 00:09
0

Для iOS вы можете использовать это решение . Он показывает, как найти диапазон сегмента текста, но вы можете легко изменить его, чтобы найти любой сегмент, который вам нравится.

    
ответ дан DavidS 24.08.2014 в 13:20