Encontrar el rango de direcciones del segmento de datos

6 minutos de lectura

Como ejercicio de programación, estoy escribiendo un recolector de basura de marca y barrido en C. Deseo escanear el segmento de datos (globales, etc.) en busca de punteros a la memoria asignada, pero no sé cómo obtener el rango de las direcciones de este segmento. ¿Cómo podría hacer esto?

  • Estoy de acuerdo, pero ¿hay alguna forma de incluir esto dentro del programa, como con una llamada al sistema?

    – Nick

    29 de noviembre de 2010 a las 23:17

  • ¿Cómo podemos responder eso si no nos dices cuál es el sistema?

    – Cachorro

    29 de noviembre de 2010 a las 23:28

  • Estoy ejecutando la última versión de Ubuntu Linux. Pero pensé que las llamadas al sistema eran una especie de interfaz (es decir, podrían implementarse de manera diferente pero aún existen)?

    – Nick

    29 de noviembre de 2010 a las 23:36


  • No. Básicamente. En qué sistema operativo se ejecuta es la pregunta más importante. Windows vs POSIX es la pregunta más importante y, hasta donde yo sé, todas las variantes de Linux son POSIX. Una vez que dice “Estoy en Windows” o “Estoy en POSIX”, entonces sí, está hablando de una interfaz conocida, pero si no conoce el sistema, no conoce la interfaz.

    – Cachorro

    29 de noviembre de 2010 a las 23:53


avatar de usuario
Nawaz

Si está trabajando en Windows, entonces hay una API de Windows que lo ayudará.

//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++;
}

Definir ImageSectionInfo como,

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

Aquí hay un programa de consola WIN32 mínimo y completo que puede ejecutar en Visual Studio que demuestra el uso de la API de Windows:

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

Esta página puede ser útil si está interesado en usos adicionales de la biblioteca DbgHelp.

Puede leer el formato de imagen PE aquí, para conocerlo en detalle. Una vez que comprenda el formato PE, podrá trabajar con el código anterior e incluso podrá modificarlo para satisfacer sus necesidades.

  • Formato PE

Mirando dentro del PE: un recorrido por el formato de archivo ejecutable portátil Win32

Una mirada en profundidad al formato de archivo ejecutable portátil Win32, parte 1

Una mirada en profundidad al formato de archivo ejecutable portátil Win32, parte 2

  • Estructuras y API de Windows

Estructura IMAGE_SECTION_HEADER

Función ImageNtHeader

Estructura IMAGE_NT_HEADERS

Creo que esto te ayudaría en gran medida, y el resto puedes investigarlo tú mismo 🙂

Por cierto, también puedes ver este hilo, ya que todos estos están relacionados de alguna manera con esto:

Escenario: variables globales en DLL que utiliza la aplicación de subprocesos múltiples

  • ¡Perfecto!!!!!!!!!!!!!, debe marcarse como la respuesta, no como esa respuesta basura que se acepta.

    – SShabló

    8 de abril de 2020 a las 2:32


  • @SSpoke: ¡Me alegro de que te haya ayudado, incluso después de una década! :O

    – Nawaz

    8 de abril de 2020 a las 7:48

avatar de usuario
jim mcnamara

Los límites para texto (código de programa) y datos para linux (y otros 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;
}

De dónde vienen esos símbolos: ¿Dónde están definidos los símbolos etext, edata y end?

  • brk() y sbrk() son omnipresentes, pero no POSIX, por diseño. Esto se debe a que los argumentos están definidos por la implementación. Consulte su página de manual para obtener información específica.

    – jim mcnamara

    30 de noviembre de 2010 a las 0:59

  • Entonces, dado que estos representan el final de cada uno de los tres segmentos, para buscar a través del segmento de datos buscaríamos desde &etext hasta &edata, ¿verdad?

    – Nick

    30 de noviembre de 2010 a las 1:26

  • ¿Cómo se escala eso al objeto compartido? Si cargo un so, también tiene un segmento de datos y bss. Estos símbolos no funcionarán en ese caso. ¿O ellos? ¿Puedes iluminarme?

    – deadalnix

    16 de agosto de 2015 a las 7:59

Dado que probablemente tendrá que hacer que su recolector de basura sea el entorno en el que se ejecuta el programa, puede obtenerlo directamente del archivo elf.

Cargue el archivo del que proviene el ejecutable y analice los encabezados PE, para Win32. No tengo idea acerca de otros sistemas operativos. Recuerde que si su programa consta de varios archivos (por ejemplo, DLL), es posible que tenga varios segmentos de datos.

avatar de usuario
davids

Para iOS puede usar esta solución. Muestra cómo encontrar el rango del segmento de texto, pero puede cambiarlo fácilmente para encontrar cualquier segmento que desee.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad