17

Como ejercicio de programación, estoy escribiendo un recolector de basura con marca y barrido en C. Deseo escanear el segmento de datos (globales, etc.) para los 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?Encontrar el rango de direcciones del segmento de datos

+4

Yo diría que depende del sistema operativo. – ruslik

+0

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

+0

¿Cómo podemos responder eso si no nos dice qué es el sistema? – Puppy

Respuesta

19

Los límites para el texto (código de programa) y los datos para Linux (y otros sistemas Unix):

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

Cuando estos símbolos provienen de: Where are the symbols etext ,edata and end defined?

+0

brk() y sbrk() son omnipresentes, pero no POSIX, por diseño. Eso es porque los argumentos son implementación definida. Verifique su página de hombre para detalles. –

+0

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

+0

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

0

Cargue el archivo del que proviene el ejecutable y analice los encabezados PE, para Win32. No tengo idea sobre otros sistemas operativos. Recuerde que si su programa consta de varios archivos (por ejemplo, archivos DLL), puede tener múltiples segmentos de datos.

1

Dado que probablemente deba hacer de su recolector de basura el entorno en el que se ejecuta el programa, puede obtenerlo directamente desde el archivo elf.

21

Si está trabajando en Windows, entonces hay son API de Windows que te ayudarían.

//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 completo, mínimo de consola Win32 puede ejecutar en Visual Studio que muestra 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) 
} 

This page puede ser útil si está interesado en usos adicionales de la biblioteca DbgHelp.

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

  • PE Formato

Peering Inside the PE: A Tour of the Win32 Portable Executable File Format

An In-Depth Look into the Win32 Portable Executable File Format, Part 1

An In-Depth Look into the Win32 Portable Executable File Format, Part 2

  • API de Windows y Estructuras

IMAGE_SECTION_HEADER Structure

ImageNtHeader Function

IMAGE_NT_HEADERS Structure

creo que esto le ayudaría a gran medida, y el resto se puede investigar a sí mismo :-)

Por cierto, también se puede ver este hilo, como todos estos están de alguna manera relacionados con esto:

Scenario: Global variables in DLL which is used by Multi-threaded Application

0

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

Cuestiones relacionadas