2010-09-27 14 views
8

Sto scrivendo del codice che memorizza alcune strutture dati in una sezione binaria con un nome speciale. Si tratta di tutte le istanze della stessa struttura che sono disseminate in molti file C e non si trovano nell'ambito dell'altra. Inserendoli tutti nella sezione denominata, riesco a scorrere su tutti loro.Come ottenere un puntatore a una sezione binaria in MSVC?

In GCC, io uso _ attributo _ ((sezione (...)) più alcune indicazioni esternato appositamente nominati, che sono magicamente riempiti a cura del linker Ecco un esempio banale:.

#include <stdio.h> 

extern int __start___mysection[]; 
extern int __stop___mysection[]; 

static int x __attribute__((section("__mysection"))) = 4; 
static int y __attribute__((section("__mysection"))) = 10; 
static int z __attribute__((section("__mysection"))) = 22; 

#define SECTION_SIZE(sect) \ 
    ((size_t)((__stop_##sect - __start_##sect))) 

int main(void) 
{ 
    size_t sz = SECTION_SIZE(__mysection); 
    int i; 

    printf("Section size is %u\n", sz); 

    for (i=0; i < sz; i++) { 
     printf("%d\n", __start___mysection[i]); 
    } 

    return 0; 
} 

Sto cercando di capire come farlo in MSVC, ma sto disegnando uno spazio vuoto.Vedo dalla documentazione del compilatore che posso dichiarare la sezione usando __pragma (section (...)) e dichiarare i dati in questo sezione con __declspec (allocate (...)) ma non riesco a vedere come posso ottenere un puntatore all'inizio e alla fine della sezione in fase di esecuzione

Ho visto alcuni esempi sul web relativi all'effetto _ attributo _ ((costruttore)) in MSVC, ma sembra un hacking specifico per CRT e non un modo generale per ottenere un puntatore all'inizio/fine di un sezione. Qualcuno ha qualche idea?

+0

Posso chiedere perché si desidera controllare la denominazione delle sezioni binarie in primo luogo? – Reinderien

+0

È per un framework di strumentazione ad alte prestazioni. Immagina un'invocazione di printf (format, args ...), in cui tutte le stringhe di formato sono state memorizzate nella sezione binaria e l'unica cosa che viene registrata sono gli argomenti più un valore di ricerca. La sostituzione argomento ha luogo in post-elaborazione. –

+0

Un esempio migliore di questo è un programma che consente di aggiungere moduli ricollegando anziché ricompilando (e possibilmente rigenerando del codice). Se puoi trattare l'intera sezione come una matrice di qualche struct, puoi eseguirne l'iterazione ed eseguire un'azione su/per ogni voce, come ad esempio call 'cur_entry [i] -> init (& cur_entry)'. È inoltre possibile utilizzare conoscenze speciali sui modelli di utilizzo della memoria per ottimizzare il paging e la localizzazione della cache. Di solito non è legato a Windows (che io sappia), ma può anche essere richiesto per i processori di architettura di Harvard. – nategoose

risposta

4

C'è anche un modo per farlo senza usare un file di assembly.

#pragma section(".init$a") 
#pragma section(".init$u") 
#pragma section(".init$z") 

__declspec(allocate(".init$a")) int InitSectionStart = 0; 
__declspec(allocate(".init$z")) int InitSectionEnd = 0; 

__declspec(allocate(".init$u")) int token1 = 0xdeadbeef; 
__declspec(allocate(".init$u")) int token2 = 0xdeadc0de; 

La prima 3 riga definisce i segmenti. Questi definiscono le sezioni e prendono il posto del file assembly. A differenza del pragma data_seg, la sezione pragma crea solo la sezione. Le righe __declspec (allocate()) indicano al compilatore di inserire l'elemento in quel segmento.

Dalla pagina microsoft: L'ordine qui è importante. I nomi delle sezioni devono essere di 8 caratteri o meno. Le sezioni con lo stesso nome prima di $ sono unite in una sezione. L'ordine con cui vengono uniti è determinato ordinando i caratteri dopo $.

Un altro punto importante da ricordare sono le sezioni da 0 a 256 byte. I puntatori START e END NON saranno direttamente prima e dopo come ci si aspetterebbe.

Se si imposta il tavolo per essere puntatori a funzioni o altri valori NULL nessuno, dovrebbe essere facile da ignorare le voci NULL prima e dopo la tabella, grazie all'imbottitura sezione

Vedere this msdn page per maggiori dettagli

3

Prima di tutto, avrete bisogno di creare un ASM-file contenente tutte le sezioni che vi interessano (ad es, section.asm.):

.686 
.model flat 

PUBLIC C __InitSectionStart 
PUBLIC C __InitSectionEnd 

INIT$A SEGMENT DWORD PUBLIC FLAT alias(".init$a") 
     __InitSectionStart EQU $ 
INIT$A ENDS 

INIT$Z SEGMENT DWORD PUBLIC FLAT alias(".init$z") 
     __InitSectionEnd EQU $ 
INIT$Z ENDS 

END 

successiva, nel codice è possibile utilizzare la seguente:

#pragma data_seg(".init$u") 
int token1 = 0xdeadbeef; 
int token2 = 0xdeadc0de; 
#pragma data_seg() 

Questo dà un tale MAP-file:

Start   Length  Name     Class 
0003:00000000 00000000H .init$a     DATA 
0003:00000000 00000008H .init$u     DATA 
0003:00000008 00000000H .init$z     DATA 

    Address   Publics by Value    Rva+Base  Lib:Object 
0003:00000000  [email protected]@3HA    10005000  dllmain.obj 
0003:00000000  ___InitSectionStart  10005000  section.obj 
0003:00000004  [email protected]@3HA    10005004  dllmain.obj 
0003:00000008  ___InitSectionEnd   10005008  section.obj 

Quindi, come si può vedere, la sezione con il nam e .init$u si trova tra .init$a e .init$z e questo ti dà la possibilità di ottenere il puntatore all'inizio dei dati tramite il simbolo __InitSectionStart e alla fine dei dati tramite il simbolo __InitSectionEnd.

0

Stavo sperimentando un po 'e ho cercato di implementare la versione senza un file di assembly, tuttavia ero in difficoltà con il numero casuale di byte di riempimento tra le sezioni, il che rende quasi impossibile trovare l'inizio della sezione .init $ u parte se il contenuto non è solo puntatori o altri elementi semplici che potrebbero essere controllati per NULL o qualche altro modello noto. Se il padding inserito è correlato all'utilizzo dell'opzione di debug Zi. Quando viene dato, il padding è inserito, senza, tutte le sezioni appaiono esattamente nel modo in cui si vorrebbe averle.

Problemi correlati